Commit bfe8486a authored by unknown's avatar unknown

Merge mysql.com:/home/mydev/mysql-5.1

into  mysql.com:/home/mydev/mysql-5.1-bug11527

parents cab4f3bc 59b6ab1f
#######################################
# Author: JBM #
# Date: 2006-02-23 #
# Purpose: See if replication between #
# NDB -> MyISAM and InnoDB works. #
# and if #
# MyISAM and InnoDB -> NDB works. #
#######################################
# By JBM #
# Date 2006-02-28 #
# Change: Implemented review comments #
#######################################
--echo --- Doing pre test cleanup ---
connection master;
--disable_warnings
DROP TABLE IF EXISTS t1;
--enable_query_log
--echo --- Start test 1 Basic testing ---
--echo --- Create Table Section ---
#################################################
# Requirment: Create basic table, replicate #
# basice operations such at insert, update #
# delete between 2 different storage engines #
# Alter table and ensure table is handled #
# Correctly on the slave #
#################################################
CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(255),
bc CHAR(255), d DECIMAL(10,4) DEFAULT 0,
f FLOAT DEFAULT 0, total BIGINT UNSIGNED,
y YEAR, t DATE,PRIMARY KEY(id));
--echo --- Show table on master ---
SHOW CREATE TABLE t1;
--echo --- Show table on slave ---
sync_slave_with_master;
SHOW CREATE TABLE t1;
--echo --- Perform basic operation on master ---
--echo --- and ensure replicated correctly ---
--source include/rpl_multi_engine3.inc
# Okay lets see how it holds up to table changes
--echo --- Check that simple Alter statements are replicated correctly --
ALTER TABLE t1 MODIFY vc TEXT;
ALTER TABLE t1 DROP PRIMARY KEY, ADD PRIMARY KEY(id, total);
--echo --- Show the new improved table on the master ---
SHOW CREATE TABLE t1;
--echo --- Make sure that our tables on slave are still same engine ---
--echo --- and that the alter statements replicated correctly ---
sync_slave_with_master;
SHOW CREATE TABLE t1;
--echo --- Perform basic operation on master ---
--echo --- and ensure replicated correctly ---
--source include/rpl_multi_engine3.inc
--echo --- End test 1 Basic testing ---
--echo --- Do Cleanup --
DROP TABLE IF EXISTS t1;
#################################################################
--echo --- Start test 2 partition RANGE testing --
--echo --- Do setup --
#################################################
# Requirment: Create table that is partitioned #
# by range on year i.e. year(t) and replicate #
# basice operations such at insert, update #
# delete between 2 different storage engines #
# Alter table and ensure table is handled #
# Correctly on the slave #
#################################################
CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(255),
bc CHAR(255), d DECIMAL(10,4) DEFAULT 0,
f FLOAT DEFAULT 0, total BIGINT UNSIGNED,
y YEAR, t DATE)
PARTITION BY RANGE (YEAR(t))
(PARTITION p0 VALUES LESS THAN (1901),
PARTITION p1 VALUES LESS THAN (1946),
PARTITION p2 VALUES LESS THAN (1966),
PARTITION p3 VALUES LESS THAN (1986),
PARTITION p4 VALUES LESS THAN (2005),
PARTITION p5 VALUES LESS THAN MAXVALUE);
--echo --- Show table on master ---
SHOW CREATE TABLE t1;
--echo --- Show table on slave --
sync_slave_with_master;
SHOW CREATE TABLE t1;
--echo --- Perform basic operation on master ---
--echo --- and ensure replicated correctly ---
--source include/rpl_multi_engine3.inc
--echo --- Check that simple Alter statements are replicated correctly ---
ALTER TABLE t1 MODIFY vc TEXT;
--echo --- Show the new improved table on the master ---
SHOW CREATE TABLE t1;
--echo --- Make sure that our tables on slave are still same engine ---
--echo --- and that the alter statements replicated correctly ---
sync_slave_with_master;
SHOW CREATE TABLE t1;
--echo --- Perform basic operation on master ---
--echo --- and ensure replicated correctly ---
--enable_query_log
--source include/rpl_multi_engine3.inc
--echo --- End test 2 partition RANGE testing ---
--echo --- Do Cleanup ---
DROP TABLE IF EXISTS t1;
########################################################
--echo --- Start test 3 partition LIST testing ---
--echo --- Do setup ---
#################################################
# Requirment: Create table that is partitioned #
# by list on id i.e. (2,4). Pretend that we #
# missed one and alter to add. Then replicate #
# basice operations such at insert, update #
# delete between 2 different storage engines #
# Alter table and ensure table is handled #
# Correctly on the slave #
#################################################
CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(255),
bc CHAR(255), d DECIMAL(10,4) DEFAULT 0,
f FLOAT DEFAULT 0, total BIGINT UNSIGNED,
y YEAR, t DATE)
PARTITION BY LIST(id)
(PARTITION p0 VALUES IN (2, 4),
PARTITION p1 VALUES IN (42, 142));
--echo --- Test 3 Alter to add partition ---
ALTER TABLE t1 ADD PARTITION (PARTITION p2 VALUES IN (412));
--echo --- Show table on master ---
SHOW CREATE TABLE t1;
--echo --- Show table on slave ---
sync_slave_with_master;
SHOW CREATE TABLE t1;
--echo --- Perform basic operation on master ---
--echo --- and ensure replicated correctly ---
--source include/rpl_multi_engine3.inc
--echo --- Check that simple Alter statements are replicated correctly ---
ALTER TABLE t1 MODIFY vc TEXT;
--echo --- Show the new improved table on the master ---
SHOW CREATE TABLE t1;
--echo --- Make sure that our tables on slave are still same engine ---
--echo --- and that the alter statements replicated correctly ---
sync_slave_with_master;
SHOW CREATE TABLE t1;
--echo --- Perform basic operation on master ---
--echo --- and ensure replicated correctly ---
--source include/rpl_multi_engine3.inc
--echo --- End test 3 partition LIST testing ---
--echo --- Do Cleanup --
DROP TABLE IF EXISTS t1;
########################################################
--echo --- Start test 4 partition HASH testing ---
--echo --- Do setup ---
#################################################
# Requirment: Create table that is partitioned #
# by hash on year i.e. YEAR(t). Then replicate #
# basice operations such at insert, update #
# delete between 2 different storage engines #
# Alter table and ensure table is handled #
# Correctly on the slave #
#################################################
CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(255),
bc CHAR(255), d DECIMAL(10,4) DEFAULT 0,
f FLOAT DEFAULT 0, total BIGINT UNSIGNED,
y YEAR, t DATE)
PARTITION BY HASH( YEAR(t) )
PARTITIONS 4;
--echo --- show that tables have been created correctly ---
SHOW CREATE TABLE t1;
sync_slave_with_master;
SHOW CREATE TABLE t1;
--echo --- Perform basic operation on master ---
--echo --- and ensure replicated correctly ---
--source include/rpl_multi_engine3.inc
--echo --- Check that simple Alter statements are replicated correctly ---
ALTER TABLE t1 MODIFY vc TEXT;
--echo --- Show the new improved table on the master ---
SHOW CREATE TABLE t1;
--echo --- Make sure that our tables on slave are still same engine ---
--echo --- and that the alter statements replicated correctly ---
sync_slave_with_master;
SHOW CREATE TABLE t1;
--echo --- Perform basic operation on master ---
--echo --- and ensure replicated correctly ---
--source include/rpl_multi_engine3.inc
--echo --- End test 4 partition HASH testing ---
--echo --- Do Cleanup --
DROP TABLE IF EXISTS t1;
########################################################
--echo --- Start test 5 partition by key testing ---
--echo --- Create Table Section ---
#################################################
# Requirment: Create table that is partitioned #
# by key on id with 4 parts. Then replicate #
# basice operations such at insert, update #
# delete between 2 different storage engines #
# Alter table and ensure table is handled #
# Correctly on the slave #
#################################################
CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(255),
bc CHAR(255), d DECIMAL(10,4) DEFAULT 0,
f FLOAT DEFAULT 0, total BIGINT UNSIGNED,
y YEAR, t DATE,PRIMARY KEY(id))
PARTITION BY KEY()
PARTITIONS 4;
--echo --- Show that tables on master are ndbcluster tables ---
SHOW CREATE TABLE t1;
--echo --- Show that tables on slave ---
sync_slave_with_master;
SHOW CREATE TABLE t1;
--echo --- Perform basic operation on master ---
--echo --- and ensure replicated correctly ---
--source include/rpl_multi_engine3.inc
# Okay lets see how it holds up to table changes
--echo --- Check that simple Alter statements are replicated correctly ---
ALTER TABLE t1 DROP PRIMARY KEY, ADD PRIMARY KEY(id, total);
--echo --- Show the new improved table on the master ---
SHOW CREATE TABLE t1;
--echo --- Make sure that our tables on slave are still right type ---
--echo --- and that the alter statements replicated correctly ---
sync_slave_with_master;
SHOW CREATE TABLE t1;
--echo --- Perform basic operation on master ---
--echo --- and ensure replicated correctly ---
--source include/rpl_multi_engine3.inc
--echo --- Check that simple Alter statements are replicated correctly ---
ALTER TABLE t1 MODIFY vc TEXT;
--echo --- Show the new improved table on the master ---
SHOW CREATE TABLE t1;
--echo --- Make sure that our tables on slave are still same engine ---
--echo --- and that the alter statements replicated correctly ---
sync_slave_with_master;
SHOW CREATE TABLE t1;
--echo --- Perform basic operation on master ---
--echo --- and ensure replicated correctly ---
--source include/rpl_multi_engine3.inc
--echo --- End test 5 key partition testing ---
--echo --- Do Cleanup ---
DROP TABLE IF EXISTS t1;
# End of 5.1 test case
#############################################################
# Author: JBM
# Date: 2006-02-23
# Purpose: To reuse through out test and make maint easier
#############################################################
connection master;
--echo "--- Insert into t1 --" as "";
--disable_query_log
INSERT INTO t1 VALUES(42,1,'Testing MySQL databases is a cool ',
'Must make it bug free for the customer',
654321.4321,15.21,0,1965,"1905-11-14");
INSERT INTO t1 VALUES(2,1,'Testing MySQL databases is a cool ',
'Must make it bug free for the customer',
654321.4321,15.21,0,1965,"1965-11-14");
INSERT INTO t1 VALUES(4,1,'Testing MySQL databases is a cool ',
'Must make it bug free for the customer',
654321.4321,15.21,0,1965,"1985-11-14");
INSERT INTO t1 VALUES(142,1,'Testing MySQL databases is a cool ',
'Must make it bug free for the customer',
654321.4321,15.21,0,1965,"1995-11-14");
INSERT INTO t1 VALUES(412,1,'Testing MySQL databases is a cool ',
'Must make it bug free for the customer',
654321.4321,15.21,0,1965,"2005-11-14");
--enable_query_log
--echo --- Select from t1 on master ---
select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
sync_slave_with_master;
--echo --- Select from t1 on slave ---
select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
connection master;
--echo --- Update t1 on master --
UPDATE t1 SET b1 = 0, t="2006-02-22" WHERE id = 412;
--echo --- Check the update on master ---
SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
# Must give injector thread a little time to get update
# into the binlog other wise we will miss the update.
sleep 3;
sync_slave_with_master;
--echo --- Check Update on slave ---
SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
connection master;
--echo --- Remove a record from t1 on master ---
DELETE FROM t1 WHERE id = 42;
--echo --- Show current count on master for t1 ---
SELECT COUNT(*) FROM t1;
sync_slave_with_master;
--echo --- Show current count on slave for t1 ---
SELECT COUNT(*) FROM t1;
connection master;
DELETE FROM t1;
...@@ -37,6 +37,54 @@ alter event event3 rename to event2; ...@@ -37,6 +37,54 @@ alter event event3 rename to event2;
drop event event2; drop event event2;
create event event2 on schedule every 2 second starts now() ends date_add(now(), interval 5 hour) comment "some" DO begin end; create event event2 on schedule every 2 second starts now() ends date_add(now(), interval 5 hour) comment "some" DO begin end;
drop event event2; drop event event2;
CREATE EVENT event_starts_test ON SCHEDULE EVERY 10 SECOND COMMENT "" DO SELECT 1;
SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test event_starts_test root@localhost RECURRING NULL 10 SECOND # # ENABLED
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
starts IS NULL ends IS NULL comment
0 1
ALTER EVENT event_starts_test ON SCHEDULE AT '2020-02-02 20:00:02';
SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test event_starts_test root@localhost ONE TIME 2020-02-02 17:00:02 NULL NULL # # ENABLED
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
starts IS NULL ends IS NULL comment
1 1
ALTER EVENT event_starts_test COMMENT "non-empty comment";
SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test event_starts_test root@localhost ONE TIME 2020-02-02 17:00:02 NULL NULL # # ENABLED
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
starts IS NULL ends IS NULL comment
1 1 non-empty comment
ALTER EVENT event_starts_test COMMENT "";
SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test event_starts_test root@localhost ONE TIME 2020-02-02 17:00:02 NULL NULL # # ENABLED
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
starts IS NULL ends IS NULL comment
1 1
DROP EVENT event_starts_test;
CREATE EVENT event_starts_test ON SCHEDULE EVERY 20 SECOND STARTS '2020-02-02 20:00:02' ENDS '2022-02-02 20:00:02' DO SELECT 2;
SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test event_starts_test root@localhost RECURRING NULL 20 SECOND # # ENABLED
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
starts IS NULL ends IS NULL comment
0 0
ALTER EVENT event_starts_test COMMENT "non-empty comment";
SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test event_starts_test root@localhost RECURRING NULL 20 SECOND # # ENABLED
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
starts IS NULL ends IS NULL comment
0 0 non-empty comment
ALTER EVENT event_starts_test COMMENT "";
SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test event_starts_test root@localhost RECURRING NULL 20 SECOND # # ENABLED
DROP EVENT event_starts_test;
create event e_43 on schedule every 1 second do set @a = 5; create event e_43 on schedule every 1 second do set @a = 5;
set global event_scheduler = 1; set global event_scheduler = 1;
alter event e_43 do alter event e_43 do set @a = 4; alter event e_43 do alter event e_43 do set @a = 4;
......
...@@ -22,12 +22,16 @@ partition_03ndb : Bug#16385 ...@@ -22,12 +22,16 @@ partition_03ndb : Bug#16385
ps_7ndb : dbug assert in RBR mode when executing test suite ps_7ndb : dbug assert in RBR mode when executing test suite
rpl_bit_npk : Bug#13418 rpl_bit_npk : Bug#13418
rpl_ddl : Bug#15963 SBR does not show "Definer" correctly rpl_ddl : Bug#15963 SBR does not show "Definer" correctly
rpl_ndb_2innodb : Bugs#17400, 17687, 17701
rpl_ndb_2myisam : Bugs#17400, 17687, 17701
rpl_ndb_auto_inc : Bug#17086 rpl_ndb_auto_inc : Bug#17086
rpl_ndb_basic : Bug#16228 [IN REVIEW] rpl_ndb_basic : Bug#16228 [IN REVIEW]
rpl_ndb_charset : Bug#17246 rpl_ndb_charset : Bug#17246
rpl_ndb_ddl : Bug#17400: delete & update of rows in table without pk fails rpl_ndb_ddl : Bug#17400: delete & update of rows in table without pk fails
rpl_ndb_delete_nowhere : Bug#17400: delete & update of rows in table without pk fails rpl_ndb_delete_nowhere : Bug#17400: delete & update of rows in table without pk fails
rpl_ndb_innodb2ndb : Bugs#17400, 17687, 17701
rpl_ndb_insert_ignore : Bugs: #17431: INSERT IGNORE INTO returns failed: 1296 rpl_ndb_insert_ignore : Bugs: #17431: INSERT IGNORE INTO returns failed: 1296
rpl_ndb_myisam2ndb : Bugs#17400, 17687, 17701
rpl_ndb_log : result not deterministic rpl_ndb_log : result not deterministic
rpl_ndb_relay_space : Bug#16993 rpl_ndb_relay_space : Bug#16993
rpl_ndb_multi_update3 : Bug#17400: delete & update of rows in table without pk fails rpl_ndb_multi_update3 : Bug#17400: delete & update of rows in table without pk fails
......
...@@ -48,6 +48,38 @@ drop event event2; ...@@ -48,6 +48,38 @@ drop event event2;
create event event2 on schedule every 2 second starts now() ends date_add(now(), interval 5 hour) comment "some" DO begin end; create event event2 on schedule every 2 second starts now() ends date_add(now(), interval 5 hour) comment "some" DO begin end;
drop event event2; drop event event2;
# BUG #16537 (Events: mysql.event.starts is null)
CREATE EVENT event_starts_test ON SCHEDULE EVERY 10 SECOND COMMENT "" DO SELECT 1;
--replace_column 8 # 9 #
SHOW EVENTS;
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
ALTER EVENT event_starts_test ON SCHEDULE AT '2020-02-02 20:00:02';
--replace_column 8 # 9 #
SHOW EVENTS;
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
ALTER EVENT event_starts_test COMMENT "non-empty comment";
--replace_column 8 # 9 #
SHOW EVENTS;
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
ALTER EVENT event_starts_test COMMENT "";
--replace_column 8 # 9 #
SHOW EVENTS;
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
DROP EVENT event_starts_test;
CREATE EVENT event_starts_test ON SCHEDULE EVERY 20 SECOND STARTS '2020-02-02 20:00:02' ENDS '2022-02-02 20:00:02' DO SELECT 2;
--replace_column 8 # 9 #
SHOW EVENTS;
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
ALTER EVENT event_starts_test COMMENT "non-empty comment";
--replace_column 8 # 9 #
SHOW EVENTS;
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
ALTER EVENT event_starts_test COMMENT "";
--replace_column 8 # 9 #
SHOW EVENTS;
DROP EVENT event_starts_test;
#
#
create event e_43 on schedule every 1 second do set @a = 5; create event e_43 on schedule every 1 second do set @a = 5;
set global event_scheduler = 1; set global event_scheduler = 1;
--sleep 2 --sleep 2
......
--default-storage-engine=ndb --binlog-format=row
--innodb --default-storage-engine=innodb --binlog-format=row
#############################################################
# Author: JBM
# Date: 2006-02-24
# Purpose: Trying to test ability to replicate from cluster
# to innodb, or myisam, or replicate from innodb/myisam to
# cluster slave. Due to limitations I have created wrappers
# to be able to use the same code for all these different
# test and to have control over the tests.
##############################################################
-- source include/have_ndb.inc
-- source include/master-slave.inc
connection slave;
-- source include/have_innodb.inc
connection master;
SET storage_engine=ndb;
--source extra/rpl_tests/rpl_ndb_2multi_eng.test
--default-storage-engine=ndb --binlog-format=row
--default-storage-engine=myisam --binlog-format=row
#############################################################
# Author: JBM
# Date: 2006-02-24
# Purpose: Trying to test ability to replicate from cluster
# to innodb, or myisam, or replicate from innodb/myisam to
# cluster slave. Due to limitations I have created wrappers
# to be able to use the same code for all these different
# test and to have control over the tests.
##############################################################
-- source include/have_ndb.inc
-- source include/master-slave.inc
SET storage_engine=ndb;
--source extra/rpl_tests/rpl_ndb_2multi_eng.test
--binlog-format=row --default-storage-engine=ndb
#############################################################
# Author: JBM
# Date: 2006-02-24
# Purpose: Trying to test ability to replicate from cluster
# to innodb, or myisam, or replicate from innodb/myisam to
# cluster slave. Due to limitations I have created wrappers
# to be able to use the same code for all these different
# test and to have control over the tests.
##############################################################
-- source include/have_innodb.inc
-- source include/master-slave.inc
connection slave;
-- source include/have_ndb.inc
connection master;
SET storage_engine=innodb;
--source extra/rpl_tests/rpl_ndb_2multi_eng.test
--default-storage-engine=ndb --binlog-format=row
#############################################################
# Author: JBM
# Date: 2006-02-24
# Purpose: Trying to test ability to replicate from cluster
# to innodb, or myisam, or replicate from innodb/myisam to
# cluster slave. Due to limitations I have created wrappers
# to be able to use the same code for all these different
# test and to have control over the tests.
##############################################################
-- source include/master-slave.inc
connection slave;
--source include/have_ndb.inc
connection master;
SET storage_engine=myisam;
--source extra/rpl_tests/rpl_ndb_2multi_eng.test
...@@ -69,7 +69,7 @@ time_t mysql_event_last_create_time= 0L; ...@@ -69,7 +69,7 @@ time_t mysql_event_last_create_time= 0L;
static TABLE_FIELD_W_TYPE event_table_fields[EVEX_FIELD_COUNT] = { static TABLE_FIELD_W_TYPE event_table_fields[EVEX_FIELD_COUNT] = {
{ {
{(char *) STRING_WITH_LEN("db")}, {(char *) STRING_WITH_LEN("db")},
{(char *) STRING_WITH_LEN("char(64)")}, {(char *) STRING_WITH_LEN("char(64)")},
{(char *) STRING_WITH_LEN("utf8")} {(char *) STRING_WITH_LEN("utf8")}
}, },
...@@ -120,6 +120,7 @@ static TABLE_FIELD_W_TYPE event_table_fields[EVEX_FIELD_COUNT] = { ...@@ -120,6 +120,7 @@ static TABLE_FIELD_W_TYPE event_table_fields[EVEX_FIELD_COUNT] = {
{ {
{(char *) STRING_WITH_LEN("last_executed")}, {(char *) STRING_WITH_LEN("last_executed")},
{(char *) STRING_WITH_LEN("datetime")}, {(char *) STRING_WITH_LEN("datetime")},
{NULL, 0}
}, },
{ {
{(char *) STRING_WITH_LEN("starts")}, {(char *) STRING_WITH_LEN("starts")},
...@@ -162,25 +163,25 @@ static TABLE_FIELD_W_TYPE event_table_fields[EVEX_FIELD_COUNT] = { ...@@ -162,25 +163,25 @@ static TABLE_FIELD_W_TYPE event_table_fields[EVEX_FIELD_COUNT] = {
LEX_STRING interval_type_to_name[] = { LEX_STRING interval_type_to_name[] = {
{(char *) STRING_WITH_LEN("YEAR")}, {(char *) STRING_WITH_LEN("YEAR")},
{(char *) STRING_WITH_LEN("QUARTER")}, {(char *) STRING_WITH_LEN("QUARTER")},
{(char *) STRING_WITH_LEN("MONTH")}, {(char *) STRING_WITH_LEN("MONTH")},
{(char *) STRING_WITH_LEN("DAY")}, {(char *) STRING_WITH_LEN("DAY")},
{(char *) STRING_WITH_LEN("HOUR")}, {(char *) STRING_WITH_LEN("HOUR")},
{(char *) STRING_WITH_LEN("MINUTE")}, {(char *) STRING_WITH_LEN("MINUTE")},
{(char *) STRING_WITH_LEN("WEEK")}, {(char *) STRING_WITH_LEN("WEEK")},
{(char *) STRING_WITH_LEN("SECOND")}, {(char *) STRING_WITH_LEN("SECOND")},
{(char *) STRING_WITH_LEN("MICROSECOND")}, {(char *) STRING_WITH_LEN("MICROSECOND")},
{(char *) STRING_WITH_LEN("YEAR_MONTH")}, {(char *) STRING_WITH_LEN("YEAR_MONTH")},
{(char *) STRING_WITH_LEN("DAY_HOUR")}, {(char *) STRING_WITH_LEN("DAY_HOUR")},
{(char *) STRING_WITH_LEN("DAY_MINUTE")}, {(char *) STRING_WITH_LEN("DAY_MINUTE")},
{(char *) STRING_WITH_LEN("DAY_SECOND")}, {(char *) STRING_WITH_LEN("DAY_SECOND")},
{(char *) STRING_WITH_LEN("HOUR_MINUTE")}, {(char *) STRING_WITH_LEN("HOUR_MINUTE")},
{(char *) STRING_WITH_LEN("HOUR_SECOND")}, {(char *) STRING_WITH_LEN("HOUR_SECOND")},
{(char *) STRING_WITH_LEN("MINUTE_SECOND")}, {(char *) STRING_WITH_LEN("MINUTE_SECOND")},
{(char *) STRING_WITH_LEN("DAY_MICROSECOND")}, {(char *) STRING_WITH_LEN("DAY_MICROSECOND")},
{(char *) STRING_WITH_LEN("HOUR_MICROSECOND")}, {(char *) STRING_WITH_LEN("HOUR_MICROSECOND")},
{(char *) STRING_WITH_LEN("MINUTE_MICROSECOND")}, {(char *) STRING_WITH_LEN("MINUTE_MICROSECOND")},
{(char *) STRING_WITH_LEN("SECOND_MICROSECOND")} {(char *) STRING_WITH_LEN("SECOND_MICROSECOND")}
}; };
...@@ -188,10 +189,10 @@ LEX_STRING interval_type_to_name[] = { ...@@ -188,10 +189,10 @@ LEX_STRING interval_type_to_name[] = {
/* /*
Inits the scheduler queue - prioritized queue from mysys/queue.c Inits the scheduler queue - prioritized queue from mysys/queue.c
Synopsis Synopsis
evex_queue_init() evex_queue_init()
queue - pointer the the memory to be initialized as queue. has to be queue - pointer the the memory to be initialized as queue. has to be
allocated from the caller allocated from the caller
...@@ -211,10 +212,10 @@ evex_queue_init(EVEX_QUEUE_TYPE *queue) ...@@ -211,10 +212,10 @@ evex_queue_init(EVEX_QUEUE_TYPE *queue)
/* /*
Compares 2 LEX strings regarding case. Compares 2 LEX strings regarding case.
Synopsis Synopsis
my_time_compare() my_time_compare()
s - first LEX_STRING s - first LEX_STRING
t - second LEX_STRING t - second LEX_STRING
cs - charset cs - charset
...@@ -223,7 +224,7 @@ evex_queue_init(EVEX_QUEUE_TYPE *queue) ...@@ -223,7 +224,7 @@ evex_queue_init(EVEX_QUEUE_TYPE *queue)
-1 - s < t -1 - s < t
0 - s == t 0 - s == t
1 - s > t 1 - s > t
Notes Notes
TIME.second_part is not considered during comparison TIME.second_part is not considered during comparison
*/ */
...@@ -237,18 +238,18 @@ int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs) ...@@ -237,18 +238,18 @@ int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs)
/* /*
Compares 2 TIME structures Compares 2 TIME structures
Synopsis Synopsis
my_time_compare() my_time_compare()
a - first TIME a - first TIME
b - second time b - second time
RETURNS: RETURNS:
-1 - a < b -1 - a < b
0 - a == b 0 - a == b
1 - a > b 1 - a > b
Notes Notes
TIME.second_part is not considered during comparison TIME.second_part is not considered during comparison
*/ */
...@@ -276,18 +277,18 @@ my_time_compare(TIME *a, TIME *b) ...@@ -276,18 +277,18 @@ my_time_compare(TIME *a, TIME *b)
/* /*
Compares the execute_at members of 2 event_timed instances Compares the execute_at members of 2 event_timed instances
Synopsis Synopsis
event_timed_compare() event_timed_compare()
a - first event_timed object a - first event_timed object
b - second event_timed object b - second event_timed object
RETURNS: RETURNS:
-1 - a->execute_at < b->execute_at -1 - a->execute_at < b->execute_at
0 - a->execute_at == b->execute_at 0 - a->execute_at == b->execute_at
1 - a->execute_at > b->execute_at 1 - a->execute_at > b->execute_at
Notes Notes
execute_at.second_part is not considered during comparison execute_at.second_part is not considered during comparison
*/ */
...@@ -303,14 +304,14 @@ event_timed_compare(event_timed *a, event_timed *b) ...@@ -303,14 +304,14 @@ event_timed_compare(event_timed *a, event_timed *b)
Compares the execute_at members of 2 event_timed instances. Compares the execute_at members of 2 event_timed instances.
Used as callback for the prioritized queue when shifting Used as callback for the prioritized queue when shifting
elements inside. elements inside.
Synopsis Synopsis
event_timed_compare() event_timed_compare()
vptr - not used (set it to NULL) vptr - not used (set it to NULL)
a - first event_timed object a - first event_timed object
b - second event_timed object b - second event_timed object
RETURNS: RETURNS:
-1 - a->execute_at < b->execute_at -1 - a->execute_at < b->execute_at
0 - a->execute_at == b->execute_at 0 - a->execute_at == b->execute_at
...@@ -333,18 +334,16 @@ event_timed_compare_q(void *vptr, byte* a, byte *b) ...@@ -333,18 +334,16 @@ event_timed_compare_q(void *vptr, byte* a, byte *b)
For For
YEAR_MONTH - expression is in months YEAR_MONTH - expression is in months
DAY_MINUTE - expression is in minutes DAY_MINUTE - expression is in minutes
Synopsis Synopsis
event_reconstruct_interval_expression() event_reconstruct_interval_expression()
buf - preallocated String buffer to add the value to buf - preallocated String buffer to add the value to
interval - the interval type (for instance YEAR_MONTH) interval - the interval type (for instance YEAR_MONTH)
expression - the value in the lowest entity expression - the value in the lowest entity
RETURNS RETURNS
0 - OK 0 - OK
1 - Error 1 - Error
*/ */
int int
...@@ -369,7 +368,7 @@ event_reconstruct_interval_expression(String *buf, ...@@ -369,7 +368,7 @@ event_reconstruct_interval_expression(String *buf,
goto common_1_lev_code; goto common_1_lev_code;
case INTERVAL_HOUR_MINUTE: case INTERVAL_HOUR_MINUTE:
case INTERVAL_MINUTE_SECOND: case INTERVAL_MINUTE_SECOND:
multipl= 60; multipl= 60;
common_1_lev_code: common_1_lev_code:
buf->append('\''); buf->append('\'');
end= longlong10_to_str(expression/multipl, tmp_buff, 10); end= longlong10_to_str(expression/multipl, tmp_buff, 10);
...@@ -473,9 +472,9 @@ event_reconstruct_interval_expression(String *buf, ...@@ -473,9 +472,9 @@ event_reconstruct_interval_expression(String *buf,
table The table pointer table The table pointer
RETURN RETURN
1 Cannot lock table 1 Cannot lock table
2 The table is corrupted - different number of fields 2 The table is corrupted - different number of fields
0 OK 0 OK
*/ */
int int
...@@ -590,11 +589,11 @@ evex_db_find_event_by_name(THD *thd, const LEX_STRING dbname, ...@@ -590,11 +589,11 @@ evex_db_find_event_by_name(THD *thd, const LEX_STRING dbname,
thd THD thd THD
table the row to fill out table the row to fill out
et Event's data et Event's data
Returns Returns
0 - ok 0 - ok
EVEX_GENERAL_ERROR - bad data EVEX_GENERAL_ERROR - bad data
EVEX_GET_FIELD_FAILED - field count does not match. table corrupted? EVEX_GET_FIELD_FAILED - field count does not match. table corrupted?
DESCRIPTION DESCRIPTION
Used both when an event is created and when it is altered. Used both when an event is created and when it is altered.
...@@ -607,9 +606,9 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update) ...@@ -607,9 +606,9 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update)
DBUG_ENTER("evex_fill_row"); DBUG_ENTER("evex_fill_row");
DBUG_PRINT("info", ("dbname=[%s]", et->dbname.str)); DBUG_PRINT("info", ("dbname=[%s]", et->dbname.str));
DBUG_PRINT("info", ("name =[%s]", et->name.str)); DBUG_PRINT("info", ("name =[%s]", et->name.str));
DBUG_PRINT("info", ("body =[%s]", et->body.str)); DBUG_PRINT("info", ("body =[%s]", et->body.str));
if (table->field[field_num= EVEX_FIELD_DB]-> if (table->field[field_num= EVEX_FIELD_DB]->
store(et->dbname.str, et->dbname.length, system_charset_info)) store(et->dbname.str, et->dbname.length, system_charset_info))
...@@ -619,7 +618,7 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update) ...@@ -619,7 +618,7 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update)
store(et->name.str, et->name.length, system_charset_info)) store(et->name.str, et->name.length, system_charset_info))
goto trunc_err; goto trunc_err;
// both ON_COMPLETION and STATUS are NOT NULL thus not calling set_notnull() /* both ON_COMPLETION and STATUS are NOT NULL thus not calling set_notnull() */
table->field[EVEX_FIELD_ON_COMPLETION]->store((longlong)et->on_completion); table->field[EVEX_FIELD_ON_COMPLETION]->store((longlong)et->on_completion);
table->field[EVEX_FIELD_STATUS]->store((longlong)et->status); table->field[EVEX_FIELD_STATUS]->store((longlong)et->status);
...@@ -637,20 +636,6 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update) ...@@ -637,20 +636,6 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update)
goto trunc_err; goto trunc_err;
} }
if (et->starts.year)
{
table->field[EVEX_FIELD_STARTS]->set_notnull();// set NULL flag to OFF
table->field[EVEX_FIELD_STARTS]->
store_time(&et->starts, MYSQL_TIMESTAMP_DATETIME);
}
if (et->ends.year)
{
table->field[EVEX_FIELD_ENDS]->set_notnull();
table->field[EVEX_FIELD_ENDS]->
store_time(&et->ends, MYSQL_TIMESTAMP_DATETIME);
}
if (et->expression) if (et->expression)
{ {
table->field[EVEX_FIELD_INTERVAL_EXPR]->set_notnull(); table->field[EVEX_FIELD_INTERVAL_EXPR]->set_notnull();
...@@ -664,36 +649,54 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update) ...@@ -664,36 +649,54 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update)
table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->store((longlong)et->interval+1); table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->store((longlong)et->interval+1);
table->field[EVEX_FIELD_EXECUTE_AT]->set_null(); table->field[EVEX_FIELD_EXECUTE_AT]->set_null();
if (!et->starts_null)
{
table->field[EVEX_FIELD_STARTS]->set_notnull();
table->field[EVEX_FIELD_STARTS]->
store_time(&et->starts, MYSQL_TIMESTAMP_DATETIME);
}
if (!et->ends_null)
{
table->field[EVEX_FIELD_ENDS]->set_notnull();
table->field[EVEX_FIELD_ENDS]->
store_time(&et->ends, MYSQL_TIMESTAMP_DATETIME);
}
} }
else if (et->execute_at.year) else if (et->execute_at.year)
{ {
// fix_fields already called in init_execute_at
table->field[EVEX_FIELD_INTERVAL_EXPR]->set_null(); table->field[EVEX_FIELD_INTERVAL_EXPR]->set_null();
table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->set_null(); table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->set_null();
table->field[EVEX_FIELD_STARTS]->set_null();
table->field[EVEX_FIELD_ENDS]->set_null();
table->field[EVEX_FIELD_EXECUTE_AT]->set_notnull(); table->field[EVEX_FIELD_EXECUTE_AT]->set_notnull();
table->field[EVEX_FIELD_EXECUTE_AT]->store_time(&et->execute_at, table->field[EVEX_FIELD_EXECUTE_AT]->store_time(&et->execute_at,
MYSQL_TIMESTAMP_DATETIME); MYSQL_TIMESTAMP_DATETIME);
table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->set_null();
} }
else else
{ {
DBUG_ASSERT(is_update); DBUG_ASSERT(is_update);
// it is normal to be here when the action is update /*
// this is an error if the action is create. something is borked it is normal to be here when the action is update
this is an error if the action is create. something is borked
*/
} }
((Field_timestamp *)table->field[EVEX_FIELD_MODIFIED])->set_time(); ((Field_timestamp *)table->field[EVEX_FIELD_MODIFIED])->set_time();
if (et->comment.length) if (et->comment.str)
if (table->field[field_num= EVEX_FIELD_COMMENT]-> {
store(et->comment.str, et->comment.length, system_charset_info)) if (table->field[field_num= EVEX_FIELD_COMMENT]->store(et->comment.str,
et->comment.length,
system_charset_info))
goto trunc_err; goto trunc_err;
}
DBUG_RETURN(0); DBUG_RETURN(0);
trunc_err: trunc_err:
my_error(ER_EVENT_DATA_TOO_LONG, MYF(0)); my_error(ER_EVENT_DATA_TOO_LONG, MYF(0), table->field[field_num]->field_name);
DBUG_RETURN(EVEX_GENERAL_ERROR); DBUG_RETURN(EVEX_GENERAL_ERROR);
} }
...@@ -707,12 +710,12 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update) ...@@ -707,12 +710,12 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update)
et event_timed object containing information for the event et event_timed object containing information for the event
create_if_not - if an warning should be generated in case event exists create_if_not - if an warning should be generated in case event exists
rows_affected - how many rows were affected rows_affected - how many rows were affected
Return value Return value
0 - OK 0 - OK
EVEX_GENERAL_ERROR - Failure EVEX_GENERAL_ERROR - Failure
DESCRIPTION DESCRIPTION
Creates an event. Relies on evex_fill_row which is shared with Creates an event. Relies on evex_fill_row which is shared with
db_update_event. The name of the event is inside "et". db_update_event. The name of the event is inside "et".
*/ */
...@@ -735,16 +738,16 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not, ...@@ -735,16 +738,16 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not,
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0)); my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
goto err; goto err;
} }
DBUG_PRINT("info", ("check existance of an event with the same name")); DBUG_PRINT("info", ("check existance of an event with the same name"));
if (!evex_db_find_event_aux(thd, et, table)) if (!evex_db_find_event_aux(thd, et, table))
{ {
if (create_if_not) if (create_if_not)
{ {
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_EVENT_ALREADY_EXISTS, ER(ER_EVENT_ALREADY_EXISTS), ER_EVENT_ALREADY_EXISTS, ER(ER_EVENT_ALREADY_EXISTS),
et->name.str); et->name.str);
goto ok; goto ok;
} }
my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), et->name.str); my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), et->name.str);
goto err; goto err;
...@@ -756,8 +759,8 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not, ...@@ -756,8 +759,8 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not,
my_error(ER_BAD_DB_ERROR, MYF(0)); my_error(ER_BAD_DB_ERROR, MYF(0));
goto err; goto err;
} }
restore_record(table, s->default_values); // Get default values for fields restore_record(table, s->default_values); // Get default values for fields
if (system_charset_info->cset->numchars(system_charset_info, et->dbname.str, if (system_charset_info->cset->numchars(system_charset_info, et->dbname.str,
et->dbname.str + et->dbname.length) et->dbname.str + et->dbname.length)
...@@ -783,7 +786,7 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not, ...@@ -783,7 +786,7 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not,
if (!(et->expression) && !(et->execute_at.year)) if (!(et->expression) && !(et->execute_at.year))
{ {
DBUG_PRINT("error", ("neither expression nor execute_at are set!")); DBUG_PRINT("error", ("neither expression nor execute_at are set!"));
my_error(ER_EVENT_NEITHER_M_EXPR_NOR_M_AT, MYF(0)); my_error(ER_EVENT_NEITHER_M_EXPR_NOR_M_AT, MYF(0));
goto err; goto err;
} }
...@@ -797,7 +800,10 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not, ...@@ -797,7 +800,10 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not,
((Field_timestamp *)table->field[EVEX_FIELD_CREATED])->set_time(); ((Field_timestamp *)table->field[EVEX_FIELD_CREATED])->set_time();
// evex_fill_row() calls my_error() in case of error so no need to handle it here /*
evex_fill_row() calls my_error() in case of error so no need to
handle it here
*/
if ((ret= evex_fill_row(thd, table, et, false))) if ((ret= evex_fill_row(thd, table, et, false)))
goto err; goto err;
...@@ -806,7 +812,8 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not, ...@@ -806,7 +812,8 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not,
my_error(ER_EVENT_STORE_FAILED, MYF(0), et->name.str, ret); my_error(ER_EVENT_STORE_FAILED, MYF(0), et->name.str, ret);
goto err; goto err;
} }
#ifdef USE_THIS_CODE_AS_TEMPLATE_WHEN_EVENT_REPLICATION_IS_AGREED
if (mysql_bin_log.is_open()) if (mysql_bin_log.is_open())
{ {
thd->clear_error(); thd->clear_error();
...@@ -814,7 +821,8 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not, ...@@ -814,7 +821,8 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not,
thd->binlog_query(THD::MYSQL_QUERY_TYPE, thd->binlog_query(THD::MYSQL_QUERY_TYPE,
thd->query, thd->query_length, FALSE, FALSE); thd->query, thd->query_length, FALSE, FALSE);
} }
#endif
*rows_affected= 1; *rows_affected= 1;
ok: ok:
if (dbchanged) if (dbchanged)
...@@ -840,7 +848,7 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not, ...@@ -840,7 +848,7 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not,
thd THD thd THD
sp_name the name of the event to alter sp_name the name of the event to alter
et event's data et event's data
NOTES NOTES
sp_name is passed since this is the name of the event to sp_name is passed since this is the name of the event to
alter in case of RENAME TO. alter in case of RENAME TO.
...@@ -865,7 +873,7 @@ db_update_event(THD *thd, event_timed *et, sp_name *new_name) ...@@ -865,7 +873,7 @@ db_update_event(THD *thd, event_timed *et, sp_name *new_name)
goto err; goto err;
} }
// first look whether we overwrite /* first look whether we overwrite */
if (new_name) if (new_name)
{ {
if (!sortcmp_lex_string(et->name, new_name->m_name, system_charset_info) && if (!sortcmp_lex_string(et->name, new_name->m_name, system_charset_info) &&
...@@ -891,19 +899,18 @@ db_update_event(THD *thd, event_timed *et, sp_name *new_name) ...@@ -891,19 +899,18 @@ db_update_event(THD *thd, event_timed *et, sp_name *new_name)
if (EVEX_KEY_NOT_FOUND == evex_db_find_event_aux(thd, et, table)) if (EVEX_KEY_NOT_FOUND == evex_db_find_event_aux(thd, et, table))
{ {
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), et->name.str); my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), et->name.str);
goto err; goto err;
} }
store_record(table,record[1]); store_record(table,record[1]);
// Don't update create on row update. /* Don't update create on row update. */
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
// evex_fill_row() calls my_error() in case of error so no need to handle it here /* evex_fill_row() calls my_error() in case of error so no need to handle it here */
if ((ret= evex_fill_row(thd, table, et, true))) if ((ret= evex_fill_row(thd, table, et, true)))
goto err; goto err;
if (new_name) if (new_name)
{ {
table->field[EVEX_FIELD_DB]-> table->field[EVEX_FIELD_DB]->
...@@ -918,7 +925,7 @@ db_update_event(THD *thd, event_timed *et, sp_name *new_name) ...@@ -918,7 +925,7 @@ db_update_event(THD *thd, event_timed *et, sp_name *new_name)
goto err; goto err;
} }
// close mysql.event or we crash later when loading the event from disk /* close mysql.event or we crash later when loading the event from disk */
close_thread_tables(thd); close_thread_tables(thd);
DBUG_RETURN(0); DBUG_RETURN(0);
...@@ -940,7 +947,7 @@ db_update_event(THD *thd, event_timed *et, sp_name *new_name) ...@@ -940,7 +947,7 @@ db_update_event(THD *thd, event_timed *et, sp_name *new_name)
definer who owns the event definer who owns the event
ett event's data if event is found ett event's data if event is found
tbl TABLE object to use when not NULL tbl TABLE object to use when not NULL
NOTES NOTES
1) Use sp_name for look up, return in **ett if found 1) Use sp_name for look up, return in **ett if found
2) tbl is not closed at exit 2) tbl is not closed at exit
...@@ -995,7 +1002,7 @@ db_find_event(THD *thd, sp_name *name, LEX_STRING *definer, event_timed **ett, ...@@ -995,7 +1002,7 @@ db_find_event(THD *thd, sp_name *name, LEX_STRING *definer, event_timed **ett,
delete et; delete et;
et= 0; et= 0;
} }
// don't close the table if we haven't opened it ourselves /* don't close the table if we haven't opened it ourselves */
if (!tbl && table) if (!tbl && table)
close_thread_tables(thd); close_thread_tables(thd);
*ett= et; *ett= et;
...@@ -1013,11 +1020,10 @@ db_find_event(THD *thd, sp_name *name, LEX_STRING *definer, event_timed **ett, ...@@ -1013,11 +1020,10 @@ db_find_event(THD *thd, sp_name *name, LEX_STRING *definer, event_timed **ett,
spn the name of the event to alter spn the name of the event to alter
definer who is the owner definer who is the owner
use_lock whether to obtain a lock on LOCK_event_arrays or not use_lock whether to obtain a lock on LOCK_event_arrays or not
RETURN VALUE RETURN VALUE
0 - OK 0 - OK
< 0 - error (in this case underlying functions call my_error()). < 0 - error (in this case underlying functions call my_error()).
*/ */
static int static int
...@@ -1036,7 +1042,7 @@ evex_load_and_compile_event(THD * thd, sp_name *spn, LEX_STRING definer, ...@@ -1036,7 +1042,7 @@ evex_load_and_compile_event(THD * thd, sp_name *spn, LEX_STRING definer,
thd->mem_root= &evex_mem_root; thd->mem_root= &evex_mem_root;
thd->reset_n_backup_open_tables_state(&backup); thd->reset_n_backup_open_tables_state(&backup);
// no need to use my_error() here because db_find_event() has done it /* no need to use my_error() here because db_find_event() has done it */
ret= db_find_event(thd, spn, &definer, &ett, NULL, NULL); ret= db_find_event(thd, spn, &definer, &ett, NULL, NULL);
thd->restore_backup_open_tables_state(&backup); thd->restore_backup_open_tables_state(&backup);
if (ret) if (ret)
...@@ -1088,7 +1094,7 @@ evex_load_and_compile_event(THD * thd, sp_name *spn, LEX_STRING definer, ...@@ -1088,7 +1094,7 @@ evex_load_and_compile_event(THD * thd, sp_name *spn, LEX_STRING definer,
ALTER EVENT. ALTER EVENT.
RETURNS RETURNS
0 - OK (always) 0 OK (always)
*/ */
static int static int
...@@ -1111,7 +1117,7 @@ evex_remove_from_cache(LEX_STRING *db, LEX_STRING *name, bool use_lock, ...@@ -1111,7 +1117,7 @@ evex_remove_from_cache(LEX_STRING *db, LEX_STRING *name, bool use_lock,
for (i= 0; i < evex_queue_num_elements(EVEX_EQ_NAME); ++i) for (i= 0; i < evex_queue_num_elements(EVEX_EQ_NAME); ++i)
{ {
event_timed *et= evex_queue_element(&EVEX_EQ_NAME, i, event_timed*); event_timed *et= evex_queue_element(&EVEX_EQ_NAME, i, event_timed*);
DBUG_PRINT("info", ("[%s.%s]==[%s.%s]?",db->str,name->str, et->dbname.str, DBUG_PRINT("info", ("[%s.%s]==[%s.%s]?",db->str,name->str, et->dbname.str,
et->name.str)); et->name.str));
if (!sortcmp_lex_string(*name, et->name, system_charset_info) && if (!sortcmp_lex_string(*name, et->name, system_charset_info) &&
!sortcmp_lex_string(*db, et->dbname, system_charset_info)) !sortcmp_lex_string(*db, et->dbname, system_charset_info))
...@@ -1131,7 +1137,7 @@ evex_remove_from_cache(LEX_STRING *db, LEX_STRING *name, bool use_lock, ...@@ -1131,7 +1137,7 @@ evex_remove_from_cache(LEX_STRING *db, LEX_STRING *name, bool use_lock,
} }
DBUG_PRINT("evex_remove_from_cache", ("delete from queue")); DBUG_PRINT("evex_remove_from_cache", ("delete from queue"));
evex_queue_delete_element(&EVEX_EQ_NAME, i); evex_queue_delete_element(&EVEX_EQ_NAME, i);
// ok, we have cleaned /* ok, we have cleaned */
ret= 0; ret= 0;
goto done; goto done;
} }
...@@ -1155,7 +1161,7 @@ evex_remove_from_cache(LEX_STRING *db, LEX_STRING *name, bool use_lock, ...@@ -1155,7 +1161,7 @@ evex_remove_from_cache(LEX_STRING *db, LEX_STRING *name, bool use_lock,
create_options Options specified when in the query. We are create_options Options specified when in the query. We are
interested whether there is IF NOT EXISTS interested whether there is IF NOT EXISTS
rows_affected How many rows were affected rows_affected How many rows were affected
NOTES NOTES
- in case there is an event with the same name (db) and - in case there is an event with the same name (db) and
IF NOT EXISTS is specified, an warning is put into the W stack. IF NOT EXISTS is specified, an warning is put into the W stack.
...@@ -1185,7 +1191,7 @@ evex_create_event(THD *thd, event_timed *et, uint create_options, ...@@ -1185,7 +1191,7 @@ evex_create_event(THD *thd, event_timed *et, uint create_options,
VOID(pthread_mutex_unlock(&LOCK_evex_running)); VOID(pthread_mutex_unlock(&LOCK_evex_running));
done: done:
// No need to close the table, it will be closed in sql_parse::do_command /* No need to close the table, it will be closed in sql_parse::do_command */
DBUG_RETURN(ret); DBUG_RETURN(ret);
} }
...@@ -1199,7 +1205,7 @@ evex_create_event(THD *thd, event_timed *et, uint create_options, ...@@ -1199,7 +1205,7 @@ evex_create_event(THD *thd, event_timed *et, uint create_options,
thd THD thd THD
et event's data et event's data
new_name set in case of RENAME TO. new_name set in case of RENAME TO.
NOTES NOTES
et contains data about dbname and event name. et contains data about dbname and event name.
new_name is the new name of the event, if not null (this means new_name is the new name of the event, if not null (this means
...@@ -1259,7 +1265,6 @@ evex_update_event(THD *thd, event_timed *et, sp_name *new_name, ...@@ -1259,7 +1265,6 @@ evex_update_event(THD *thd, event_timed *et, sp_name *new_name,
et event's name et event's name
drop_if_exists if set and the event not existing => warning onto the stack drop_if_exists if set and the event not existing => warning onto the stack
rows_affected affected number of rows is returned heres rows_affected affected number of rows is returned heres
*/ */
int db_drop_event(THD *thd, event_timed *et, bool drop_if_exists, int db_drop_event(THD *thd, event_timed *et, bool drop_if_exists,
...@@ -1292,8 +1297,8 @@ int db_drop_event(THD *thd, event_timed *et, bool drop_if_exists, ...@@ -1292,8 +1297,8 @@ int db_drop_event(THD *thd, event_timed *et, bool drop_if_exists,
if (drop_if_exists) if (drop_if_exists)
{ {
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST), ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
"Event", et->name.str); "Event", et->name.str);
ret= 0; ret= 0;
} else } else
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), et->name.str); my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), et->name.str);
...@@ -1338,7 +1343,7 @@ evex_drop_event(THD *thd, event_timed *et, bool drop_if_exists, ...@@ -1338,7 +1343,7 @@ evex_drop_event(THD *thd, event_timed *et, bool drop_if_exists,
if (evex_is_running) if (evex_is_running)
ret= evex_remove_from_cache(&et->dbname, &et->name, true, true); ret= evex_remove_from_cache(&et->dbname, &et->name, true, true);
VOID(pthread_mutex_unlock(&LOCK_evex_running)); VOID(pthread_mutex_unlock(&LOCK_evex_running));
if (ret == 1) if (ret == 1)
ret= 0; ret= 0;
else if (ret == 0) else if (ret == 0)
...@@ -1358,11 +1363,10 @@ evex_drop_event(THD *thd, event_timed *et, bool drop_if_exists, ...@@ -1358,11 +1363,10 @@ evex_drop_event(THD *thd, event_timed *et, bool drop_if_exists,
thd THD thd THD
spn the name of the event (db, name) spn the name of the event (db, name)
definer the definer of the event definer the definer of the event
RETURNS RETURNS
0 - OK 0 - OK
1 - Error during writing to the wire 1 - Error during writing to the wire
*/ */
int int
...@@ -1380,14 +1384,14 @@ evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer) ...@@ -1380,14 +1384,14 @@ evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer)
thd->restore_backup_open_tables_state(&backup); thd->restore_backup_open_tables_state(&backup);
if (!ret && et) if (!ret && et)
{ {
Protocol *protocol= thd->protocol; Protocol *protocol= thd->protocol;
char show_str_buf[768]; char show_str_buf[768];
String show_str(show_str_buf, sizeof(show_str_buf), system_charset_info); String show_str(show_str_buf, sizeof(show_str_buf), system_charset_info);
List<Item> field_list; List<Item> field_list;
byte *sql_mode_str; byte *sql_mode_str;
ulong sql_mode_len=0; ulong sql_mode_len=0;
show_str.length(0); show_str.length(0);
show_str.set_charset(system_charset_info); show_str.set_charset(system_charset_info);
...@@ -1413,19 +1417,18 @@ evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer) ...@@ -1413,19 +1417,18 @@ evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer)
protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info); protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
protocol->store(show_str.c_ptr(), show_str.length(), system_charset_info); protocol->store(show_str.c_ptr(), show_str.length(), system_charset_info);
ret= protocol->write(); ret= protocol->write();
send_eof(thd); send_eof(thd);
} }
DBUG_RETURN(ret); DBUG_RETURN(ret);
} }
/* /*
evex_drop_db_events - Drops all events in the selected database evex_drop_db_events - Drops all events in the selected database
thd - Thread thd - Thread
db - ASCIIZ the name of the database db - ASCIIZ the name of the database
...@@ -1449,7 +1452,6 @@ evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer) ...@@ -1449,7 +1452,6 @@ evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer)
spawned and can_spawn() is the right method. spawned and can_spawn() is the right method.
- event_timed::can_spawn() returns false -> being runned ATM - event_timed::can_spawn() returns false -> being runned ATM
just set the flags so it should drop itself. just set the flags so it should drop itself.
*/ */
int int
...@@ -1505,7 +1507,7 @@ evex_drop_db_events(THD *thd, char *db) ...@@ -1505,7 +1507,7 @@ evex_drop_db_events(THD *thd, char *db)
else if (ret == EVEX_KEY_NOT_FOUND) else if (ret == EVEX_KEY_NOT_FOUND)
{ {
sql_print_error("Expected to find event %s.%s of %s on disk-not there.", sql_print_error("Expected to find event %s.%s of %s on disk-not there.",
et->dbname.str, et->name.str, et->definer.str); et->dbname.str, et->name.str, et->definer.str);
} }
et->free_sp(); et->free_sp();
delete et; delete et;
...@@ -1521,7 +1523,7 @@ evex_drop_db_events(THD *thd, char *db) ...@@ -1521,7 +1523,7 @@ evex_drop_db_events(THD *thd, char *db)
} }
DBUG_PRINT("info",("%d elements in the queue", DBUG_PRINT("info",("%d elements in the queue",
evex_queue_num_elements(EVEX_EQ_NAME))); evex_queue_num_elements(EVEX_EQ_NAME)));
evex_queue_delete_element(&EVEX_EQ_NAME, i);// 1 is top evex_queue_delete_element(&EVEX_EQ_NAME, i);// 0 is top
DBUG_PRINT("info",("%d elements in the queue", DBUG_PRINT("info",("%d elements in the queue",
evex_queue_num_elements(EVEX_EQ_NAME))); evex_queue_num_elements(EVEX_EQ_NAME)));
/* /*
...@@ -1598,7 +1600,7 @@ evex_drop_db_events(THD *thd, char *db) ...@@ -1598,7 +1600,7 @@ evex_drop_db_events(THD *thd, char *db)
VOID(pthread_mutex_unlock(&LOCK_event_arrays)); VOID(pthread_mutex_unlock(&LOCK_event_arrays));
end_read_record(&read_record_info); end_read_record(&read_record_info);
thd->version--; // Force close to free memory thd->version--; /* Force close to free memory */
close_thread_tables(thd); close_thread_tables(thd);
......
...@@ -103,6 +103,9 @@ class event_timed ...@@ -103,6 +103,9 @@ class event_timed
TIME starts; TIME starts;
TIME ends; TIME ends;
TIME execute_at; TIME execute_at;
my_bool starts_null;
my_bool ends_null;
my_bool execute_at_null;
longlong expression; longlong expression;
interval_type interval; interval_type interval;
......
...@@ -38,9 +38,9 @@ extern ulong thread_created; ...@@ -38,9 +38,9 @@ extern ulong thread_created;
extern const char *my_localhost; extern const char *my_localhost;
extern pthread_attr_t connection_attrib; extern pthread_attr_t connection_attrib;
pthread_mutex_t LOCK_event_arrays, // mutex for when working with the queue pthread_mutex_t LOCK_event_arrays, // mutex for when working with the queue
LOCK_workers_count, // mutex for when inc/dec uint workers_count LOCK_workers_count, // mutex for when inc/dec uint workers_count
LOCK_evex_running; // mutes for managing bool evex_is_running LOCK_evex_running; // mutes for managing bool evex_is_running
bool evex_is_running= false; bool evex_is_running= false;
...@@ -135,7 +135,7 @@ evex_check_system_tables() ...@@ -135,7 +135,7 @@ evex_check_system_tables()
bool not_used; bool not_used;
Open_tables_state backup; Open_tables_state backup;
// thd is 0x0 during boot of the server. Later it's !=0x0 /* thd is 0x0 during boot of the server. Later it's !=0x0 */
if (!thd) if (!thd)
return; return;
...@@ -151,7 +151,7 @@ evex_check_system_tables() ...@@ -151,7 +151,7 @@ evex_check_system_tables()
else else
{ {
table_check_intact(tables.table, MYSQL_DB_FIELD_COUNT, mysql_db_table_fields, table_check_intact(tables.table, MYSQL_DB_FIELD_COUNT, mysql_db_table_fields,
&mysql_db_table_last_check,ER_CANNOT_LOAD_FROM_TABLE); &mysql_db_table_last_check,ER_CANNOT_LOAD_FROM_TABLE);
close_thread_tables(thd); close_thread_tables(thd);
} }
...@@ -182,7 +182,7 @@ evex_check_system_tables() ...@@ -182,7 +182,7 @@ evex_check_system_tables()
SYNOPSIS SYNOPSIS
init_events() init_events()
NOTES NOTES
Inits the mutexes used by the scheduler. Done at server start. Inits the mutexes used by the scheduler. Done at server start.
*/ */
...@@ -194,7 +194,7 @@ init_events() ...@@ -194,7 +194,7 @@ init_events()
DBUG_ENTER("init_events"); DBUG_ENTER("init_events");
DBUG_PRINT("info",("Starting events main thread")); DBUG_PRINT("info",("Starting events main thread"));
evex_check_system_tables(); evex_check_system_tables();
evex_init_mutexes(); evex_init_mutexes();
...@@ -206,7 +206,7 @@ init_events() ...@@ -206,7 +206,7 @@ init_events()
if (event_executor_running_global_var) if (event_executor_running_global_var)
{ {
#ifndef DBUG_FAULTY_THR #ifndef DBUG_FAULTY_THR
//TODO Andrey: Change the error code returned! /* TODO Andrey: Change the error code returned! */
if (pthread_create(&th, &connection_attrib, event_executor_main,(void*)NULL)) if (pthread_create(&th, &connection_attrib, event_executor_main,(void*)NULL))
DBUG_RETURN(ER_SLAVE_THREAD); DBUG_RETURN(ER_SLAVE_THREAD);
#else #else
...@@ -223,7 +223,7 @@ init_events() ...@@ -223,7 +223,7 @@ init_events()
SYNOPSIS SYNOPSIS
shutdown_events() shutdown_events()
NOTES NOTES
Destroys the mutexes. Destroys the mutexes.
*/ */
...@@ -232,10 +232,10 @@ void ...@@ -232,10 +232,10 @@ void
shutdown_events() shutdown_events()
{ {
DBUG_ENTER("shutdown_events"); DBUG_ENTER("shutdown_events");
if (evex_mutexes_initted) if (evex_mutexes_initted)
{ {
evex_mutexes_initted= FALSE; evex_mutexes_initted= FALSE;
VOID(pthread_mutex_lock(&LOCK_evex_running)); VOID(pthread_mutex_lock(&LOCK_evex_running));
VOID(pthread_mutex_unlock(&LOCK_evex_running)); VOID(pthread_mutex_unlock(&LOCK_evex_running));
...@@ -253,11 +253,11 @@ shutdown_events() ...@@ -253,11 +253,11 @@ shutdown_events()
SYNOPSIS SYNOPSIS
init_event_thread() init_event_thread()
thd - the THD of the thread. Has to be allocated by the caller. thd - the THD of the thread. Has to be allocated by the caller.
NOTES NOTES
1. The host of the thead is my_localhost 1. The host of the thead is my_localhost
2. thd->net is initted with NULL - no communication. 2. thd->net is initted with NULL - no communication.
Returns Returns
0 - OK 0 - OK
-1 - Error -1 - Error
...@@ -304,7 +304,7 @@ init_event_thread(THD* thd) ...@@ -304,7 +304,7 @@ init_event_thread(THD* thd)
/* /*
This function waits till the time next event in the queue should be This function waits till the time next event in the queue should be
executed. executed.
Returns Returns
WAIT_STATUS_READY There is an event to be executed right now WAIT_STATUS_READY There is an event to be executed right now
WAIT_STATUS_EMPTY_QUEUE No events or the last event was dropped. WAIT_STATUS_EMPTY_QUEUE No events or the last event was dropped.
...@@ -329,7 +329,7 @@ executor_wait_till_next_event_exec(THD *thd) ...@@ -329,7 +329,7 @@ executor_wait_till_next_event_exec(THD *thd)
if (!evex_queue_num_elements(EVEX_EQ_NAME)) if (!evex_queue_num_elements(EVEX_EQ_NAME))
{ {
VOID(pthread_mutex_unlock(&LOCK_event_arrays)); VOID(pthread_mutex_unlock(&LOCK_event_arrays));
DBUG_RETURN(1); DBUG_RETURN(WAIT_STATUS_EMPTY_QUEUE);
} }
et= evex_queue_first_element(&EVEX_EQ_NAME, event_timed*); et= evex_queue_first_element(&EVEX_EQ_NAME, event_timed*);
DBUG_ASSERT(et); DBUG_ASSERT(et);
...@@ -339,14 +339,14 @@ executor_wait_till_next_event_exec(THD *thd) ...@@ -339,14 +339,14 @@ executor_wait_till_next_event_exec(THD *thd)
if (et->dropped) if (et->dropped)
et->drop(thd); et->drop(thd);
delete et; delete et;
evex_queue_delete_element(&EVEX_EQ_NAME, 1);// 1 is top evex_queue_delete_element(&EVEX_EQ_NAME, 0);// 0 is top, internally 1
VOID(pthread_mutex_unlock(&LOCK_event_arrays)); VOID(pthread_mutex_unlock(&LOCK_event_arrays));
sql_print_information("Event found disabled, dropping."); sql_print_information("Event found disabled, dropping.");
DBUG_RETURN(1); DBUG_RETURN(1);
} }
DBUG_PRINT("evex main thread",("computing time to sleep till next exec")); DBUG_PRINT("evex main thread",("computing time to sleep till next exec"));
// set the internal clock of thd /* set the internal clock of thd */
thd->end_time(); thd->end_time();
my_tz_UTC->gmt_sec_to_TIME(&time_now, thd->query_start()); my_tz_UTC->gmt_sec_to_TIME(&time_now, thd->query_start());
t2sleep= evex_time_diff(&et->execute_at, &time_now); t2sleep= evex_time_diff(&et->execute_at, &time_now);
...@@ -368,13 +368,13 @@ executor_wait_till_next_event_exec(THD *thd) ...@@ -368,13 +368,13 @@ executor_wait_till_next_event_exec(THD *thd)
} }
} }
int ret= 0; int ret= WAIT_STATUS_READY;
if (!evex_queue_num_elements(EVEX_EQ_NAME)) if (!evex_queue_num_elements(EVEX_EQ_NAME))
ret= 1; ret= WAIT_STATUS_EMPTY_QUEUE;
else if (evex_queue_first_element(&EVEX_EQ_NAME, event_timed*) != et) else if (evex_queue_first_element(&EVEX_EQ_NAME, event_timed*) != et)
ret= 2; ret= WAIT_STATUS_NEW_TOP_EVENT;
if (thd->killed && event_executor_running_global_var) if (thd->killed && event_executor_running_global_var)
ret= 3; ret= WAIT_STATUS_STOP_EXECUTOR;
DBUG_RETURN(ret); DBUG_RETURN(ret);
} }
...@@ -387,8 +387,8 @@ executor_wait_till_next_event_exec(THD *thd) ...@@ -387,8 +387,8 @@ executor_wait_till_next_event_exec(THD *thd)
SYNOPSIS SYNOPSIS
event_executor_main() event_executor_main()
arg - unused arg unused
NOTES NOTES
1. The host of the thead is my_localhost 1. The host of the thead is my_localhost
2. thd->net is initted with NULL - no communication. 2. thd->net is initted with NULL - no communication.
...@@ -404,14 +404,13 @@ event_executor_main(void *arg) ...@@ -404,14 +404,13 @@ event_executor_main(void *arg)
TIME time_now; TIME time_now;
DBUG_ENTER("event_executor_main"); DBUG_ENTER("event_executor_main");
DBUG_PRINT("event_executor_main", ("EVEX thread started")); DBUG_PRINT("event_executor_main", ("EVEX thread started"));
// init memory root /* init memory root */
init_alloc_root(&evex_mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC); init_alloc_root(&evex_mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
// needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff /* needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff*/
my_thread_init(); my_thread_init();
if (sizeof(my_time_t) != sizeof(time_t)) if (sizeof(my_time_t) != sizeof(time_t))
...@@ -422,14 +421,14 @@ event_executor_main(void *arg) ...@@ -422,14 +421,14 @@ event_executor_main(void *arg)
goto err_no_thd; goto err_no_thd;
} }
//TODO Andrey: Check for NULL /* note that contructor of THD uses DBUG_ ! */
if (!(thd = new THD)) // note that contructor of THD uses DBUG_ ! if (!(thd = new THD))
{ {
sql_print_error("SCHEDULER: Cannot create THD for the main thread."); sql_print_error("SCHEDULER: Cannot create THD for the main thread.");
goto err_no_thd; goto err_no_thd;
} }
thd->thread_stack = (char*)&thd; // remember where our stack is thd->thread_stack = (char*)&thd; // remember where our stack is
pthread_detach_this_thread(); pthread_detach_this_thread();
if (init_event_thread(thd)) if (init_event_thread(thd))
...@@ -472,7 +471,7 @@ event_executor_main(void *arg) ...@@ -472,7 +471,7 @@ event_executor_main(void *arg)
{ {
TIME time_now; TIME time_now;
event_timed *et; event_timed *et;
cnt++; cnt++;
DBUG_PRINT("info", ("EVEX External Loop %d thd->k", cnt)); DBUG_PRINT("info", ("EVEX External Loop %d thd->k", cnt));
...@@ -488,7 +487,7 @@ event_executor_main(void *arg) ...@@ -488,7 +487,7 @@ event_executor_main(void *arg)
my_sleep(1000000);// sleep 1s my_sleep(1000000);// sleep 1s
continue; continue;
} }
restart_ticking: restart_ticking:
switch (executor_wait_till_next_event_exec(thd)) { switch (executor_wait_till_next_event_exec(thd)) {
case WAIT_STATUS_READY: // time to execute the event on top case WAIT_STATUS_READY: // time to execute the event on top
...@@ -498,7 +497,7 @@ event_executor_main(void *arg) ...@@ -498,7 +497,7 @@ event_executor_main(void *arg)
DBUG_PRINT("evex main thread",("no more events")); DBUG_PRINT("evex main thread",("no more events"));
continue; continue;
break; break;
case WAIT_STATUS_NEW_TOP_EVENT: // new event on top in the queue case WAIT_STATUS_NEW_TOP_EVENT: // new event on top in the queue
DBUG_PRINT("evex main thread",("restart ticking")); DBUG_PRINT("evex main thread",("restart ticking"));
goto restart_ticking; goto restart_ticking;
case WAIT_STATUS_STOP_EXECUTOR: case WAIT_STATUS_STOP_EXECUTOR:
...@@ -523,8 +522,7 @@ event_executor_main(void *arg) ...@@ -523,8 +522,7 @@ event_executor_main(void *arg)
et= evex_queue_first_element(&EVEX_EQ_NAME, event_timed*); et= evex_queue_first_element(&EVEX_EQ_NAME, event_timed*);
DBUG_PRINT("evex main thread",("got event from the queue")); DBUG_PRINT("evex main thread",("got event from the queue"));
if (et->execute_at.year > 1969 && if (!et->execute_at_null && my_time_compare(&time_now,&et->execute_at) == -1)
my_time_compare(&time_now, &et->execute_at) == -1)
{ {
DBUG_PRINT("evex main thread",("still not the time for execution")); DBUG_PRINT("evex main thread",("still not the time for execution"));
VOID(pthread_mutex_unlock(&LOCK_event_arrays)); VOID(pthread_mutex_unlock(&LOCK_event_arrays));
...@@ -571,8 +569,11 @@ event_executor_main(void *arg) ...@@ -571,8 +569,11 @@ event_executor_main(void *arg)
#else #else
event_executor_worker((void *) et); event_executor_worker((void *) et);
#endif #endif
if ((et->execute_at.year && !et->expression) || /*
TIME_to_ulonglong_datetime(&et->execute_at) == 0) 1. For one-time event : year is > 0 and expression is 0
2. For recurring, expression is != -=> check execute_at_null in this case
*/
if ((et->execute_at.year && !et->expression) || et->execute_at_null)
et->flags |= EVENT_EXEC_NO_MORE; et->flags |= EVENT_EXEC_NO_MORE;
if ((et->flags & EVENT_EXEC_NO_MORE) || et->status == MYSQL_EVENT_DISABLED) if ((et->flags & EVENT_EXEC_NO_MORE) || et->status == MYSQL_EVENT_DISABLED)
...@@ -582,10 +583,10 @@ event_executor_main(void *arg) ...@@ -582,10 +583,10 @@ event_executor_main(void *arg)
} }
DBUG_PRINT("evex main thread",("unlocking")); DBUG_PRINT("evex main thread",("unlocking"));
VOID(pthread_mutex_unlock(&LOCK_event_arrays)); VOID(pthread_mutex_unlock(&LOCK_event_arrays));
}// while }/* while */
finish: finish:
// First manifest that this thread does not work and then destroy /* First manifest that this thread does not work and then destroy */
VOID(pthread_mutex_lock(&LOCK_evex_running)); VOID(pthread_mutex_lock(&LOCK_evex_running));
evex_is_running= false; evex_is_running= false;
evex_main_thread_id= 0; evex_main_thread_id= 0;
...@@ -609,7 +610,7 @@ event_executor_main(void *arg) ...@@ -609,7 +610,7 @@ event_executor_main(void *arg)
break; break;
} }
VOID(pthread_mutex_unlock(&LOCK_workers_count)); VOID(pthread_mutex_unlock(&LOCK_workers_count));
my_sleep(1000000);// 1s my_sleep(1000000);// 1s
} }
/* /*
...@@ -625,9 +626,9 @@ event_executor_main(void *arg) ...@@ -625,9 +626,9 @@ event_executor_main(void *arg)
delete et; delete et;
} }
VOID(pthread_mutex_unlock(&LOCK_event_arrays)); VOID(pthread_mutex_unlock(&LOCK_event_arrays));
// ... then we can thrash the whole queue at once /* ... then we can thrash the whole queue at once */
evex_queue_destroy(&EVEX_EQ_NAME); evex_queue_destroy(&EVEX_EQ_NAME);
thd->proc_info = "Clearing"; thd->proc_info = "Clearing";
DBUG_ASSERT(thd->net.buff != 0); DBUG_ASSERT(thd->net.buff != 0);
net_end(&thd->net); // destructor will not free it, because we are weird net_end(&thd->net); // destructor will not free it, because we are weird
...@@ -655,7 +656,7 @@ event_executor_main(void *arg) ...@@ -655,7 +656,7 @@ event_executor_main(void *arg)
my_thread_end(); my_thread_end();
pthread_exit(0); pthread_exit(0);
#endif #endif
DBUG_RETURN(0);// Can't return anything here DBUG_RETURN(0); // Can't return anything here
} }
...@@ -665,7 +666,7 @@ event_executor_main(void *arg) ...@@ -665,7 +666,7 @@ event_executor_main(void *arg)
SYNOPSIS SYNOPSIS
event_executor_worker() event_executor_worker()
arg - the event_timed object to be processed arg The event_timed object to be processed
*/ */
pthread_handler_t pthread_handler_t
...@@ -682,12 +683,12 @@ event_executor_worker(void *event_void) ...@@ -682,12 +683,12 @@ event_executor_worker(void *event_void)
#ifndef DBUG_FAULTY_THR #ifndef DBUG_FAULTY_THR
my_thread_init(); my_thread_init();
if (!(thd = new THD)) // note that contructor of THD uses DBUG_ ! if (!(thd = new THD)) /* note that contructor of THD uses DBUG_ ! */
{ {
sql_print_error("SCHEDULER: Cannot create a THD structure in an worker."); sql_print_error("SCHEDULER: Cannot create a THD structure in an worker.");
goto err_no_thd; goto err_no_thd;
} }
thd->thread_stack = (char*)&thd; // remember where our stack is thd->thread_stack = (char*)&thd; // remember where our stack is
thd->mem_root= &worker_mem_root; thd->mem_root= &worker_mem_root;
pthread_detach_this_thread(); pthread_detach_this_thread();
...@@ -697,7 +698,7 @@ event_executor_worker(void *event_void) ...@@ -697,7 +698,7 @@ event_executor_worker(void *event_void)
thd->init_for_queries(); thd->init_for_queries();
// make this thread visible it has no vio -> show processlist needs this flag /* make this thread visible it has no vio -> show processlist needs this flag */
thd->system_thread= 1; thd->system_thread= 1;
VOID(pthread_mutex_lock(&LOCK_thread_count)); VOID(pthread_mutex_lock(&LOCK_thread_count));
...@@ -747,7 +748,7 @@ event_executor_worker(void *event_void) ...@@ -747,7 +748,7 @@ event_executor_worker(void *event_void)
DBUG_ASSERT(thd->net.buff != 0); DBUG_ASSERT(thd->net.buff != 0);
net_end(&thd->net); // destructor will not free it, because we are weird net_end(&thd->net); // destructor will not free it, because we are weird
THD_CHECK_SENTRY(thd); THD_CHECK_SENTRY(thd);
VOID(pthread_mutex_lock(&LOCK_thread_count)); VOID(pthread_mutex_lock(&LOCK_thread_count));
THD_CHECK_SENTRY(thd); THD_CHECK_SENTRY(thd);
delete thd; delete thd;
...@@ -778,9 +779,9 @@ event_executor_worker(void *event_void) ...@@ -778,9 +779,9 @@ event_executor_worker(void *event_void)
thd - Thread context. Used for memory allocation in some cases. thd - Thread context. Used for memory allocation in some cases.
RETURNS RETURNS
0 - OK 0 OK
!0 - Error !0 Error
NOTES NOTES
Reports the error to the console Reports the error to the console
*/ */
...@@ -793,7 +794,7 @@ evex_load_events_from_db(THD *thd) ...@@ -793,7 +794,7 @@ evex_load_events_from_db(THD *thd)
MYSQL_LOCK *lock; MYSQL_LOCK *lock;
int ret= -1; int ret= -1;
uint count= 0; uint count= 0;
DBUG_ENTER("evex_load_events_from_db"); DBUG_ENTER("evex_load_events_from_db");
if ((ret= evex_open_event_table(thd, TL_READ, &table))) if ((ret= evex_open_event_table(thd, TL_READ, &table)))
...@@ -828,7 +829,7 @@ evex_load_events_from_db(THD *thd) ...@@ -828,7 +829,7 @@ evex_load_events_from_db(THD *thd)
delete et; delete et;
continue; continue;
} }
DBUG_PRINT("evex_load_events_from_db", DBUG_PRINT("evex_load_events_from_db",
("Event %s loaded from row. Time to compile", et->name.str)); ("Event %s loaded from row. Time to compile", et->name.str));
...@@ -844,8 +845,8 @@ evex_load_events_from_db(THD *thd) ...@@ -844,8 +845,8 @@ evex_load_events_from_db(THD *thd)
default: default:
break; break;
} }
// let's find when to be executed /* let's find when to be executed */
if (et->compute_next_execution_time()) if (et->compute_next_execution_time())
{ {
sql_print_error("SCHEDULER: Error while computing execution time of %s.%s." sql_print_error("SCHEDULER: Error while computing execution time of %s.%s."
...@@ -866,8 +867,9 @@ evex_load_events_from_db(THD *thd) ...@@ -866,8 +867,9 @@ evex_load_events_from_db(THD *thd)
end: end:
VOID(pthread_mutex_unlock(&LOCK_event_arrays)); VOID(pthread_mutex_unlock(&LOCK_event_arrays));
end_read_record(&read_record_info); end_read_record(&read_record_info);
thd->version--; // Force close to free memory /* Force close to free memory */
thd->version--;
close_thread_tables(thd); close_thread_tables(thd);
if (!ret) if (!ret)
...@@ -887,15 +889,15 @@ evex_load_events_from_db(THD *thd) ...@@ -887,15 +889,15 @@ evex_load_events_from_db(THD *thd)
event_executor_worker() event_executor_worker()
thd - Thread context (unused) thd - Thread context (unused)
car - the new value car - the new value
Returns Returns
0 - OK (always) 0 OK (always)
*/ */
bool bool
sys_var_event_executor::update(THD *thd, set_var *var) sys_var_event_executor::update(THD *thd, set_var *var)
{ {
// here start the thread if not running. /* here start the thread if not running. */
DBUG_ENTER("sys_var_event_executor::update"); DBUG_ENTER("sys_var_event_executor::update");
VOID(pthread_mutex_lock(&LOCK_evex_running)); VOID(pthread_mutex_lock(&LOCK_evex_running));
*value= var->save_result.ulong_value; *value= var->save_result.ulong_value;
...@@ -927,12 +929,12 @@ static sql_print_xxx_func sql_print_xxx_handlers[3] = ...@@ -927,12 +929,12 @@ static sql_print_xxx_func sql_print_xxx_handlers[3] =
Prints the stack of infos, warnings, errors from thd to Prints the stack of infos, warnings, errors from thd to
the console so it can be fetched by the logs-into-tables and the console so it can be fetched by the logs-into-tables and
checked later. checked later.
Synopsis Synopsis
evex_print_warnings evex_print_warnings
thd - thread used during the execution of the event thd - thread used during the execution of the event
et - the event itself et - the event itself
Returns Returns
0 - OK (always) 0 - OK (always)
...@@ -940,19 +942,20 @@ static sql_print_xxx_func sql_print_xxx_handlers[3] = ...@@ -940,19 +942,20 @@ static sql_print_xxx_func sql_print_xxx_handlers[3] =
bool bool
evex_print_warnings(THD *thd, event_timed *et) evex_print_warnings(THD *thd, event_timed *et)
{ {
MYSQL_ERROR *err; MYSQL_ERROR *err;
DBUG_ENTER("evex_show_warnings"); DBUG_ENTER("evex_show_warnings");
char msg_buf[1024]; char msg_buf[1024];
char prefix_buf[512]; char prefix_buf[512];
String prefix(prefix_buf, sizeof(prefix_buf), system_charset_info); String prefix(prefix_buf, sizeof(prefix_buf), system_charset_info);
prefix.length(0); prefix.length(0);
List_iterator_fast<MYSQL_ERROR> it(thd->warn_list); List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
while ((err= it++)) while ((err= it++))
{ {
String err_msg(msg_buf, sizeof(msg_buf), system_charset_info); String err_msg(msg_buf, sizeof(msg_buf), system_charset_info);
err_msg.length(0);// set it to 0 or we start adding at the end /* set it to 0 or we start adding at the end. That's the trick ;) */
err_msg.length(0);
if (!prefix.length()) if (!prefix.length())
{ {
prefix.append("SCHEDULER: ["); prefix.append("SCHEDULER: [");
...@@ -966,7 +969,7 @@ evex_print_warnings(THD *thd, event_timed *et) ...@@ -966,7 +969,7 @@ evex_print_warnings(THD *thd, event_timed *et)
append_identifier(thd,&prefix, et->name.str, et->name.length); append_identifier(thd,&prefix, et->name.str, et->name.length);
prefix.append("] ", 2); prefix.append("] ", 2);
} }
err_msg.append(prefix); err_msg.append(prefix);
err_msg.append(err->msg, strlen(err->msg), system_charset_info); err_msg.append(err->msg, strlen(err->msg), system_charset_info);
err_msg.append("]"); err_msg.append("]");
......
...@@ -41,6 +41,7 @@ event_timed::init() ...@@ -41,6 +41,7 @@ event_timed::init()
set_zero_time(&ends, MYSQL_TIMESTAMP_DATETIME); set_zero_time(&ends, MYSQL_TIMESTAMP_DATETIME);
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME); set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
set_zero_time(&last_executed, MYSQL_TIMESTAMP_DATETIME); set_zero_time(&last_executed, MYSQL_TIMESTAMP_DATETIME);
starts_null= ends_null= execute_at_null= TRUE;
definer_user.str= definer_host.str= 0; definer_user.str= definer_host.str= 0;
definer_user.length= definer_host.length= 0; definer_user.length= definer_host.length= 0;
...@@ -115,7 +116,7 @@ event_timed::init_body(THD *thd) ...@@ -115,7 +116,7 @@ event_timed::init_body(THD *thd)
body_begin, thd->lex->ptr)); body_begin, thd->lex->ptr));
body.length= thd->lex->ptr - body_begin; body.length= thd->lex->ptr - body_begin;
// Trim nuls at the end /* Trim nuls at the end */
while (body.length && body_begin[body.length-1] == '\0') while (body.length && body_begin[body.length-1] == '\0')
body.length--; body.length--;
...@@ -157,12 +158,16 @@ event_timed::init_execute_at(THD *thd, Item *expr) ...@@ -157,12 +158,16 @@ event_timed::init_execute_at(THD *thd, Item *expr)
if (expr->fix_fields(thd, &expr)) if (expr->fix_fields(thd, &expr))
DBUG_RETURN(EVEX_PARSE_ERROR); DBUG_RETURN(EVEX_PARSE_ERROR);
/* Let's check whether time is in the past */ /* no starts and/or ends in case of execute_at */
thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp, DBUG_PRINT("info", ("starts_null && ends_null should be 1 is %d",
(starts_null && ends_null)));
DBUG_ASSERT(starts_null && ends_null);
/* let's check whether time is in the past */
thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp,
(my_time_t) thd->query_start()); (my_time_t) thd->query_start());
if ((not_used= expr->get_date(&ltime, TIME_NO_ZERO_DATE))) if ((not_used= expr->get_date(&ltime, TIME_NO_ZERO_DATE)))
DBUG_RETURN(ER_WRONG_VALUE); DBUG_RETURN(ER_WRONG_VALUE);
...@@ -177,7 +182,7 @@ event_timed::init_execute_at(THD *thd, Item *expr) ...@@ -177,7 +182,7 @@ event_timed::init_execute_at(THD *thd, Item *expr)
*/ */
my_tz_UTC->gmt_sec_to_TIME(&ltime, TIME_to_timestamp(thd,&ltime, &not_used)); my_tz_UTC->gmt_sec_to_TIME(&ltime, TIME_to_timestamp(thd,&ltime, &not_used));
execute_at_null= FALSE;
execute_at= ltime; execute_at= ltime;
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -246,14 +251,14 @@ event_timed::init_interval(THD *thd, Item *expr, interval_type new_interval) ...@@ -246,14 +251,14 @@ event_timed::init_interval(THD *thd, Item *expr, interval_type new_interval)
case INTERVAL_DAY_MINUTE: case INTERVAL_DAY_MINUTE:
expression= (interval.day* 24 + interval.hour) * 60 + interval.minute; expression= (interval.day* 24 + interval.hour) * 60 + interval.minute;
break; break;
case INTERVAL_HOUR_SECOND: // day is anyway 0 case INTERVAL_HOUR_SECOND: /* day is anyway 0 */
case INTERVAL_DAY_SECOND: case INTERVAL_DAY_SECOND:
/* DAY_SECOND having problems because of leap seconds? */ /* DAY_SECOND having problems because of leap seconds? */
expression= ((interval.day* 24 + interval.hour) * 60 + interval.minute)*60 expression= ((interval.day* 24 + interval.hour) * 60 + interval.minute)*60
+ interval.second; + interval.second;
break; break;
case INTERVAL_MINUTE_MICROSECOND: // day and hour are 0 case INTERVAL_MINUTE_MICROSECOND: /* day and hour are 0 */
case INTERVAL_HOUR_MICROSECOND:// day is anyway 0 case INTERVAL_HOUR_MICROSECOND: /* day is anyway 0 */
case INTERVAL_DAY_MICROSECOND: case INTERVAL_DAY_MICROSECOND:
DBUG_RETURN(EVEX_MICROSECOND_UNSUP); DBUG_RETURN(EVEX_MICROSECOND_UNSUP);
expression= ((((interval.day*24) + interval.hour)*60+interval.minute)*60 + expression= ((((interval.day*24) + interval.hour)*60+interval.minute)*60 +
...@@ -332,6 +337,7 @@ event_timed::init_starts(THD *thd, Item *new_starts) ...@@ -332,6 +337,7 @@ event_timed::init_starts(THD *thd, Item *new_starts)
my_tz_UTC->gmt_sec_to_TIME(&ltime, TIME_to_timestamp(thd, &ltime, &not_used)); my_tz_UTC->gmt_sec_to_TIME(&ltime, TIME_to_timestamp(thd, &ltime, &not_used));
starts= ltime; starts= ltime;
starts_null= FALSE;
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -361,8 +367,7 @@ event_timed::init_starts(THD *thd, Item *new_starts) ...@@ -361,8 +367,7 @@ event_timed::init_starts(THD *thd, Item *new_starts)
int int
event_timed::init_ends(THD *thd, Item *new_ends) event_timed::init_ends(THD *thd, Item *new_ends)
{ {
TIME ltime; TIME ltime, ltime_now;
my_time_t my_time_tmp;
my_bool not_used; my_bool not_used;
DBUG_ENTER("event_timed::init_ends"); DBUG_ENTER("event_timed::init_ends");
...@@ -370,20 +375,34 @@ event_timed::init_ends(THD *thd, Item *new_ends) ...@@ -370,20 +375,34 @@ event_timed::init_ends(THD *thd, Item *new_ends)
if (new_ends->fix_fields(thd, &new_ends)) if (new_ends->fix_fields(thd, &new_ends))
DBUG_RETURN(EVEX_PARSE_ERROR); DBUG_RETURN(EVEX_PARSE_ERROR);
/* The field was already fixed in init_ends */ DBUG_PRINT("info", ("convert to TIME"));
if ((not_used= new_ends->get_date(&ltime, TIME_NO_ZERO_DATE))) if ((not_used= new_ends->get_date(&ltime, TIME_NO_ZERO_DATE)))
DBUG_RETURN(EVEX_BAD_PARAMS); DBUG_RETURN(EVEX_BAD_PARAMS);
/* /*
This may result in a 1970-01-01 date if ltime is > 2037-xx-xx. This may result in a 1970-01-01 date if ltime is > 2037-xx-xx ?
CONVERT_TZ has similar problem. CONVERT_TZ has similar problem ?
*/ */
DBUG_PRINT("info", ("get the UTC time"));
my_tz_UTC->gmt_sec_to_TIME(&ltime, TIME_to_timestamp(thd, &ltime, &not_used)); my_tz_UTC->gmt_sec_to_TIME(&ltime, TIME_to_timestamp(thd, &ltime, &not_used));
if (starts.year && my_time_compare(&starts, &ltime) != -1) /* Check whether ends is after starts */
DBUG_PRINT("info", ("ENDS after STARTS?"));
if (!starts_null && my_time_compare(&starts, &ltime) != -1)
DBUG_RETURN(EVEX_BAD_PARAMS);
/*
The parser forces starts to be provided but one day STARTS could be
set before NOW() and in this case the following check should be done.
Check whether ENDS is not in the past.
*/
DBUG_PRINT("info", ("ENDS after NOW?"));
my_tz_UTC->gmt_sec_to_TIME(&ltime_now, thd->query_start());
if (my_time_compare(&ltime_now, &ltime) == 1)
DBUG_RETURN(EVEX_BAD_PARAMS); DBUG_RETURN(EVEX_BAD_PARAMS);
ends= ltime; ends= ltime;
ends_null= FALSE;
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -403,7 +422,7 @@ event_timed::init_comment(THD *thd, LEX_STRING *set_comment) ...@@ -403,7 +422,7 @@ event_timed::init_comment(THD *thd, LEX_STRING *set_comment)
DBUG_ENTER("event_timed::init_comment"); DBUG_ENTER("event_timed::init_comment");
comment.str= strmake_root(thd->mem_root, set_comment->str, comment.str= strmake_root(thd->mem_root, set_comment->str,
comment.length= set_comment->length); comment.length= set_comment->length);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -514,32 +533,41 @@ event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table) ...@@ -514,32 +533,41 @@ event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
et->definer_user.str= strmake_root(mem_root, et->definer.str, len); et->definer_user.str= strmake_root(mem_root, et->definer.str, len);
et->definer_user.length= len; et->definer_user.length= len;
len= et->definer.length - len - 1; //1 is because of @ len= et->definer.length - len - 1; //1 is because of @
et->definer_host.str= strmake_root(mem_root, ptr + 1, len);//1: because of @ et->definer_host.str= strmake_root(mem_root, ptr + 1, len);/* 1:because of @*/
et->definer_host.length= len; et->definer_host.length= len;
et->starts_null= table->field[EVEX_FIELD_STARTS]->is_null();
res1= table->field[EVEX_FIELD_STARTS]->get_date(&et->starts,TIME_NO_ZERO_DATE);
res1= table->field[EVEX_FIELD_STARTS]-> et->ends_null= table->field[EVEX_FIELD_ENDS]->is_null();
get_date(&et->starts, TIME_NO_ZERO_DATE); res2= table->field[EVEX_FIELD_ENDS]->get_date(&et->ends, TIME_NO_ZERO_DATE);
res2= table->field[EVEX_FIELD_ENDS]-> if (!table->field[EVEX_FIELD_INTERVAL_EXPR]->is_null())
get_date(&et->ends, TIME_NO_ZERO_DATE); et->expression= table->field[EVEX_FIELD_INTERVAL_EXPR]->val_int();
else
et->expression= table->field[EVEX_FIELD_INTERVAL_EXPR]->val_int(); et->expression= 0;
/* /*
If res1 and res2 are true then both fields are empty. If res1 and res2 are true then both fields are empty.
Hence if EVEX_FIELD_EXECUTE_AT is empty there is an error. Hence if EVEX_FIELD_EXECUTE_AT is empty there is an error.
*/ */
if (res1 && res2 && !et->expression && table->field[EVEX_FIELD_EXECUTE_AT]-> et->execute_at_null= table->field[EVEX_FIELD_EXECUTE_AT]->is_null();
get_date(&et->execute_at, TIME_NO_ZERO_DATE)) DBUG_ASSERT(!(et->starts_null && et->ends_null && !et->expression &&
et->execute_at_null));
if (!et->expression &&
table->field[EVEX_FIELD_EXECUTE_AT]->get_date(&et->execute_at,
TIME_NO_ZERO_DATE))
goto error; goto error;
/* /*
In DB the values start from 1 but enum interval_type starts In DB the values start from 1 but enum interval_type starts
from 0 from 0
*/ */
et->interval= (interval_type) if (!table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->is_null())
et->interval= (interval_type)
((ulonglong) table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->val_int() - 1); ((ulonglong) table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->val_int() - 1);
else
et->interval= (interval_type) 0;
et->modified= table->field[EVEX_FIELD_CREATED]->val_int(); et->modified= table->field[EVEX_FIELD_CREATED]->val_int();
et->created= table->field[EVEX_FIELD_MODIFIED]->val_int(); et->created= table->field[EVEX_FIELD_MODIFIED]->val_int();
...@@ -568,20 +596,20 @@ event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table) ...@@ -568,20 +596,20 @@ event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
#endif #endif
last_executed_changed= false; last_executed_changed= false;
// ToDo : Andrey . Find a way not to allocate ptr on event_mem_root /* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */
if ((ptr= get_field(mem_root, table->field[EVEX_FIELD_STATUS])) == NullS) if ((ptr= get_field(mem_root, table->field[EVEX_FIELD_STATUS])) == NullS)
goto error; goto error;
DBUG_PRINT("load_from_row", ("Event [%s] is [%s]", et->name.str, ptr)); DBUG_PRINT("load_from_row", ("Event [%s] is [%s]", et->name.str, ptr));
et->status= (ptr[0]=='E'? MYSQL_EVENT_ENABLED:MYSQL_EVENT_DISABLED); et->status= (ptr[0]=='E'? MYSQL_EVENT_ENABLED:MYSQL_EVENT_DISABLED);
// ToDo : Andrey . Find a way not to allocate ptr on event_mem_root /* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */
if ((ptr= get_field(mem_root, if ((ptr= get_field(mem_root,
table->field[EVEX_FIELD_ON_COMPLETION])) == NullS) table->field[EVEX_FIELD_ON_COMPLETION])) == NullS)
goto error; goto error;
et->on_completion= (ptr[0]=='D'? MYSQL_EVENT_ON_COMPLETION_DROP: et->on_completion= (ptr[0]=='D'? MYSQL_EVENT_ON_COMPLETION_DROP:
MYSQL_EVENT_ON_COMPLETION_PRESERVE); MYSQL_EVENT_ON_COMPLETION_PRESERVE);
et->comment.str= get_field(mem_root, table->field[EVEX_FIELD_COMMENT]); et->comment.str= get_field(mem_root, table->field[EVEX_FIELD_COMMENT]);
if (et->comment.str != NullS) if (et->comment.str != NullS)
...@@ -698,14 +726,11 @@ event_timed::compute_next_execution_time() ...@@ -698,14 +726,11 @@ event_timed::compute_next_execution_time()
/* Let's check whether it was executed */ /* Let's check whether it was executed */
if (last_executed.year) if (last_executed.year)
{ {
DBUG_PRINT("compute_next_execution_time", DBUG_PRINT("info",("One-time event %s.%s of was already executed",
("One-time event %s was already executed", name.str)); dbname.str, name.str, definer.str));
if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP) dropped= (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP);
{ DBUG_PRINT("info",("One-time event will be dropped=%d.", dropped));
DBUG_PRINT("compute_next_execution_time",
("One-time event will be dropped."));
dropped= true;
}
status= MYSQL_EVENT_DISABLED; status= MYSQL_EVENT_DISABLED;
status_changed= true; status_changed= true;
} }
...@@ -731,11 +756,12 @@ event_timed::compute_next_execution_time() ...@@ -731,11 +756,12 @@ event_timed::compute_next_execution_time()
last_executed.second); last_executed.second);
#endif #endif
/* If time_now is after ends don't execute anymore */ /* if time_now is after ends don't execute anymore */
if (ends.year && (tmp= my_time_compare(&ends, &time_now)) == -1) if (!ends_null && (tmp= my_time_compare(&ends, &time_now)) == -1)
{ {
/* time_now is after ends. don't execute anymore */ /* time_now is after ends. don't execute anymore */
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME); set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
execute_at_null= TRUE;
if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP) if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
dropped= true; dropped= true;
status= MYSQL_EVENT_DISABLED; status= MYSQL_EVENT_DISABLED;
...@@ -749,7 +775,7 @@ event_timed::compute_next_execution_time() ...@@ -749,7 +775,7 @@ event_timed::compute_next_execution_time()
Let's check whether time_now is before starts. Let's check whether time_now is before starts.
If so schedule for starts. If so schedule for starts.
*/ */
if (starts.year && (tmp= my_time_compare(&time_now, &starts)) < 1) if (!starts_null && (tmp= my_time_compare(&time_now, &starts)) < 1)
{ {
if (tmp == 0 && my_time_compare(&starts, &last_executed) == 0) if (tmp == 0 && my_time_compare(&starts, &last_executed) == 0)
{ {
...@@ -765,11 +791,12 @@ event_timed::compute_next_execution_time() ...@@ -765,11 +791,12 @@ event_timed::compute_next_execution_time()
time_now before starts. Scheduling for starts time_now before starts. Scheduling for starts
*/ */
execute_at= starts; execute_at= starts;
execute_at_null= FALSE;
goto ret; goto ret;
} }
} }
if (starts.year && ends.year) if (!starts_null && !ends_null)
{ {
/* /*
Both starts and m_ends are set and time_now is between them (incl.) Both starts and m_ends are set and time_now is between them (incl.)
...@@ -778,7 +805,10 @@ event_timed::compute_next_execution_time() ...@@ -778,7 +805,10 @@ event_timed::compute_next_execution_time()
If not set then schedule for now. If not set then schedule for now.
*/ */
if (!last_executed.year) if (!last_executed.year)
{
execute_at= time_now; execute_at= time_now;
execute_at_null= FALSE;
}
else else
{ {
TIME next_exec; TIME next_exec;
...@@ -791,15 +821,19 @@ event_timed::compute_next_execution_time() ...@@ -791,15 +821,19 @@ event_timed::compute_next_execution_time()
{ {
/* Next execution after ends. No more executions */ /* Next execution after ends. No more executions */
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME); set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
execute_at_null= TRUE;
if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP) if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
dropped= true; dropped= true;
} }
else else
{
execute_at= next_exec; execute_at= next_exec;
execute_at_null= FALSE;
}
} }
goto ret; goto ret;
} }
else if (!starts.year && !ends.year) else if (starts_null && ends_null)
{ {
/* /*
Both starts and m_ends are not set, so we schedule for the next Both starts and m_ends are not set, so we schedule for the next
...@@ -815,11 +849,12 @@ event_timed::compute_next_execution_time() ...@@ -815,11 +849,12 @@ event_timed::compute_next_execution_time()
/* last_executed not set. Schedule the event for now */ /* last_executed not set. Schedule the event for now */
execute_at= time_now; execute_at= time_now;
} }
execute_at_null= FALSE;
} }
else else
{ {
/* Either starts or m_ends is set */ /* either starts or m_ends is set */
if (starts.year) if (!starts_null)
{ {
/* /*
- starts is set. - starts is set.
...@@ -834,6 +869,7 @@ event_timed::compute_next_execution_time() ...@@ -834,6 +869,7 @@ event_timed::compute_next_execution_time()
} }
else else
execute_at= starts; execute_at= starts;
execute_at_null= FALSE;
} }
else else
{ {
...@@ -856,11 +892,15 @@ event_timed::compute_next_execution_time() ...@@ -856,11 +892,15 @@ event_timed::compute_next_execution_time()
if (my_time_compare(&ends, &next_exec) == -1) if (my_time_compare(&ends, &next_exec) == -1)
{ {
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME); set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
execute_at_null= TRUE;
if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP) if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
dropped= true; dropped= true;
} }
else else
{
execute_at= next_exec; execute_at= next_exec;
execute_at_null= FALSE;
}
} }
} }
goto ret; goto ret;
...@@ -890,7 +930,7 @@ event_timed::mark_last_executed(THD *thd) ...@@ -890,7 +930,7 @@ event_timed::mark_last_executed(THD *thd)
thd->end_time(); thd->end_time();
my_tz_UTC->gmt_sec_to_TIME(&time_now, (my_time_t) thd->query_start()); my_tz_UTC->gmt_sec_to_TIME(&time_now, (my_time_t) thd->query_start());
last_executed= time_now; // was execute_at last_executed= time_now; /* was execute_at */
#ifdef ANDREY_0 #ifdef ANDREY_0
last_executed= execute_at; last_executed= execute_at;
#endif #endif
...@@ -1045,7 +1085,7 @@ event_timed::get_create_event(THD *thd, String *buf) ...@@ -1045,7 +1085,7 @@ event_timed::get_create_event(THD *thd, String *buf)
} }
else else
{ {
char dtime_buff[20*2+32];// +32 to make my_snprintf_{8bit|ucs2} happy char dtime_buff[20*2+32];/* +32 to make my_snprintf_{8bit|ucs2} happy */
buf->append(STRING_WITH_LEN("AT '")); buf->append(STRING_WITH_LEN("AT '"));
/* /*
Pass the buffer and the second param tells fills the buffer and Pass the buffer and the second param tells fills the buffer and
...@@ -1324,10 +1364,7 @@ event_timed::compile(THD *thd, MEM_ROOT *mem_root) ...@@ -1324,10 +1364,7 @@ event_timed::compile(THD *thd, MEM_ROOT *mem_root)
sphead= lex.et->sphead; sphead= lex.et->sphead;
sphead->m_db= dbname; sphead->m_db= dbname;
/*
Ccopy also chistics since they will vanish otherwise we get 0x0 pointer
TODO: Handle sql_mode!!
*/
sphead->set_definer(definer.str, definer.length); sphead->set_definer(definer.str, definer.length);
sphead->set_info(0, 0, &lex.sp_chistics, sql_mode); sphead->set_info(0, 0, &lex.sp_chistics, sql_mode);
sphead->optimize(); sphead->optimize();
...@@ -1389,7 +1426,7 @@ extern pthread_attr_t connection_attrib; ...@@ -1389,7 +1426,7 @@ extern pthread_attr_t connection_attrib;
/* /*
Checks whether is possible and forks a thread. Passes self as argument. Checks whether is possible and forks a thread. Passes self as argument.
Returns Returns
EVENT_EXEC_STARTED - OK EVENT_EXEC_STARTED - OK
EVENT_EXEC_ALREADY_EXEC - Thread not forked, already working EVENT_EXEC_ALREADY_EXEC - Thread not forked, already working
...@@ -1460,7 +1497,6 @@ event_timed::spawn_thread_finish(THD *thd) ...@@ -1460,7 +1497,6 @@ event_timed::spawn_thread_finish(THD *thd)
Returns Returns
0 - ok 0 - ok
1 - not locked by this thread 1 - not locked by this thread
*/ */
...@@ -1486,5 +1522,5 @@ event_timed::spawn_unlock(THD *thd) ...@@ -1486,5 +1522,5 @@ event_timed::spawn_unlock(THD *thd)
} }
} }
VOID(pthread_mutex_unlock(&this->LOCK_running)); VOID(pthread_mutex_unlock(&this->LOCK_running));
return ret; return ret;
} }
...@@ -3957,7 +3957,7 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) ...@@ -3957,7 +3957,7 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
sch_table->field[3]->store(et.definer.str, et.definer.length, scs); sch_table->field[3]->store(et.definer.str, et.definer.length, scs);
sch_table->field[4]->store(et.body.str, et.body.length, scs); sch_table->field[4]->store(et.body.str, et.body.length, scs);
// [9] is SQL_MODE /* [9] is SQL_MODE */
{ {
byte *sql_mode_str; byte *sql_mode_str;
ulong sql_mode_len=0; ulong sql_mode_len=0;
...@@ -3972,9 +3972,9 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) ...@@ -3972,9 +3972,9 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
String show_str; String show_str;
//type //type
sch_table->field[5]->store(STRING_WITH_LEN("RECURRING"), scs); sch_table->field[5]->store(STRING_WITH_LEN("RECURRING"), scs);
//execute_at /* execute_at */
sch_table->field[6]->set_null(); sch_table->field[6]->set_null();
//interval_value /* interval_value */
//interval_type //interval_type
if (event_reconstruct_interval_expression(&show_str, et.interval, if (event_reconstruct_interval_expression(&show_str, et.interval,
et.expression)) et.expression))
...@@ -3986,26 +3986,24 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) ...@@ -3986,26 +3986,24 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
LEX_STRING *ival= &interval_type_to_name[et.interval]; LEX_STRING *ival= &interval_type_to_name[et.interval];
sch_table->field[8]->set_notnull(); sch_table->field[8]->set_notnull();
sch_table->field[8]->store(ival->str, ival->length, scs); sch_table->field[8]->store(ival->str, ival->length, scs);
//starts & ends
//starts & ends
sch_table->field[10]->set_notnull(); sch_table->field[10]->set_notnull();
sch_table->field[10]->store_time(&et.starts, MYSQL_TIMESTAMP_DATETIME); sch_table->field[10]->store_time(&et.starts, MYSQL_TIMESTAMP_DATETIME);
sch_table->field[11]->set_notnull();
sch_table->field[11]->store_time(&et.ends, MYSQL_TIMESTAMP_DATETIME); if (!et.ends_null)
{
sch_table->field[11]->set_notnull();
sch_table->field[11]->store_time(&et.ends, MYSQL_TIMESTAMP_DATETIME);
}
} }
else else
{ {
//type //type
sch_table->field[5]->store(STRING_WITH_LEN("ONE TIME"), scs); sch_table->field[5]->store(STRING_WITH_LEN("ONE TIME"), scs);
//execute_at
sch_table->field[6]->set_notnull(); sch_table->field[6]->set_notnull();
sch_table->field[6]->store_time(&et.execute_at, MYSQL_TIMESTAMP_DATETIME); sch_table->field[6]->store_time(&et.execute_at, MYSQL_TIMESTAMP_DATETIME);
//interval
sch_table->field[7]->set_null();
//interval_type
sch_table->field[8]->set_null();
//starts & ends
sch_table->field[10]->set_null();
sch_table->field[11]->set_null();
} }
//status //status
......
...@@ -1476,6 +1476,9 @@ opt_ev_status: /* empty */ { $$= 0; } ...@@ -1476,6 +1476,9 @@ opt_ev_status: /* empty */ { $$= 0; }
; ;
ev_starts: /* empty */ ev_starts: /* empty */
{
Lex->et->init_starts(YYTHD, new Item_func_now_local());
}
| STARTS_SYM expr | STARTS_SYM expr
{ {
LEX *lex= Lex; LEX *lex= Lex;
......
...@@ -2056,59 +2056,94 @@ int ...@@ -2056,59 +2056,94 @@ int
NdbDictionaryImpl::createTable(NdbTableImpl &t) NdbDictionaryImpl::createTable(NdbTableImpl &t)
{ {
DBUG_ENTER("NdbDictionaryImpl::createTable"); DBUG_ENTER("NdbDictionaryImpl::createTable");
// If the a new name has not been set, used the copied name
// if the new name has not been set, use the copied name
if (t.m_newExternalName.empty()) if (t.m_newExternalName.empty())
t.m_newExternalName.assign(t.m_externalName); t.m_newExternalName.assign(t.m_externalName);
// create table
if (m_receiver.createTable(m_ndb, t) != 0) if (m_receiver.createTable(m_ndb, t) != 0)
{ DBUG_RETURN(-1);
Uint32* data = (Uint32*)m_receiver.m_buffer.get_data();
t.m_id = data[0];
t.m_version = data[1];
// update table def from DICT - by-pass cache
NdbTableImpl* t2 =
m_receiver.getTable(t.m_internalName, m_ndb.usingFullyQualifiedNames());
// check if we got back same table
if (t2 == NULL) {
DBUG_PRINT("info", ("table %s dropped by another thread",
t.m_internalName.c_str()));
m_error.code = 283;
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
if (t.m_noOfBlobs == 0) if (t.m_id != t2->m_id || t.m_version != t2->m_version) {
{ DBUG_PRINT("info", ("table %s re-created by another thread",
DBUG_RETURN(0); t.m_internalName.c_str()));
} m_error.code = 283;
// update table def from DICT delete t2;
Ndb_local_table_info *info=
get_local_table_info(t.m_internalName,false);
if (info == NULL) {
m_error.code= 709;
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
if (createBlobTables(t, *(info->m_table_impl)) != 0) {
// auto-increment - use "t" because initial value is not in DICT
{
bool autoIncrement = false;
Uint64 initialValue = 0;
for (Uint32 i = 0; i < t.m_columns.size(); i++) {
const NdbColumnImpl* c = t.m_columns[i];
assert(c != NULL);
if (c->m_autoIncrement) {
if (autoIncrement) {
m_error.code = 4335;
delete t2;
DBUG_RETURN(-1);
}
autoIncrement = true;
initialValue = c->m_autoIncrementInitialValue;
}
}
if (autoIncrement) {
// XXX unlikely race condition - t.m_id may no longer be same table
if (! m_ndb.setTupleIdInNdb(t.m_id, initialValue, false)) {
if (m_ndb.theError.code)
m_error.code = m_ndb.theError.code;
else
m_error.code = 4336;
delete t2;
DBUG_RETURN(-1);
}
}
}
// blob tables - use "t2" to get values set by kernel
if (t2->m_noOfBlobs != 0 && createBlobTables(*t2) != 0) {
int save_code = m_error.code; int save_code = m_error.code;
(void)dropTable(t); (void)dropTable(*t2);
m_error.code= save_code; m_error.code = save_code;
delete t2;
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
// not entered in cache
delete t2;
DBUG_RETURN(0); DBUG_RETURN(0);
} }
int int
NdbDictionaryImpl::createBlobTables(NdbTableImpl& org, NdbTableImpl &t) NdbDictionaryImpl::createBlobTables(NdbTableImpl &t)
{ {
DBUG_ENTER("NdbDictionaryImpl::createBlobTables"); DBUG_ENTER("NdbDictionaryImpl::createBlobTables");
for (unsigned i = 0; i < t.m_columns.size(); i++) { for (unsigned i = 0; i < t.m_columns.size(); i++) {
NdbColumnImpl & c = *t.m_columns[i]; NdbColumnImpl & c = *t.m_columns[i];
NdbColumnImpl & oc = *org.m_columns[i];
if (! c.getBlobType() || c.getPartSize() == 0) if (! c.getBlobType() || c.getPartSize() == 0)
continue; continue;
NdbTableImpl bt; NdbTableImpl bt;
NdbDictionary::Column::StorageType save = c.getStorageType();
c.setStorageType(oc.getStorageType());
NdbBlob::getBlobTable(bt, &t, &c); NdbBlob::getBlobTable(bt, &t, &c);
c.setStorageType(save); if (createTable(bt) != 0) {
if (createTable(bt) != 0)
{
DBUG_RETURN(-1);
}
// Save BLOB table handle
Ndb_local_table_info *info=
get_local_table_info(bt.m_internalName, false);
if (info == 0)
{
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
c.m_blobTable = info->m_table_impl;
} }
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -2292,21 +2327,13 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb, ...@@ -2292,21 +2327,13 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb,
sizeof(tmpTab->TableName), sizeof(tmpTab->TableName),
internalName.c_str()); internalName.c_str());
bool haveAutoIncrement = false;
Uint64 autoIncrementValue = 0;
Uint32 distKeys= 0; Uint32 distKeys= 0;
for(i = 0; i<sz; i++){ for(i = 0; i<sz; i++) {
const NdbColumnImpl * col = impl.m_columns[i]; const NdbColumnImpl * col = impl.m_columns[i];
if(col == 0) if (col == NULL) {
continue; m_error.code = 4272;
if (col->m_autoIncrement) { NdbMem_Free((void*)tmpTab);
if (haveAutoIncrement) { DBUG_RETURN(-1);
m_error.code= 4335;
NdbMem_Free((void*)tmpTab);
DBUG_RETURN(-1);
}
haveAutoIncrement = true;
autoIncrementValue = col->m_autoIncrementInitialValue;
} }
if (col->m_distributionKey) if (col->m_distributionKey)
{ {
...@@ -2570,17 +2597,6 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb, ...@@ -2570,17 +2597,6 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb,
errCodes); errCodes);
} }
if (!ret && !alter && haveAutoIncrement) {
if (!ndb.setAutoIncrementValue(impl.m_externalName.c_str(),
autoIncrementValue)) {
if (ndb.theError.code == 0) {
m_error.code = 4336;
ndb.theError = m_error;
} else
m_error= ndb.theError;
ret = -1; // errorcode set in initialize_autoincrement
}
}
DBUG_RETURN(ret); DBUG_RETURN(ret);
} }
...@@ -2588,12 +2604,12 @@ void ...@@ -2588,12 +2604,12 @@ void
NdbDictInterface::execCREATE_TABLE_CONF(NdbApiSignal * signal, NdbDictInterface::execCREATE_TABLE_CONF(NdbApiSignal * signal,
LinearSectionPtr ptr[3]) LinearSectionPtr ptr[3])
{ {
#if 0
const CreateTableConf* const conf= const CreateTableConf* const conf=
CAST_CONSTPTR(CreateTableConf, signal->getDataPtr()); CAST_CONSTPTR(CreateTableConf, signal->getDataPtr());
Uint32 tableId= conf->tableId; m_buffer.grow(4 * 2); // 2 words
Uint32 tableVersion= conf->tableVersion; Uint32* data = (Uint32*)m_buffer.get_data();
#endif data[0] = conf->tableId;
data[1] = conf->tableVersion;
m_waiter.signal(NO_WAIT); m_waiter.signal(NO_WAIT);
} }
......
...@@ -479,6 +479,7 @@ private: ...@@ -479,6 +479,7 @@ private:
class TransporterFacade * m_transporter; class TransporterFacade * m_transporter;
friend class Ndb; friend class Ndb;
friend class NdbDictionaryImpl;
static void execSignal(void* dictImpl, static void execSignal(void* dictImpl,
class NdbApiSignal* signal, class NdbApiSignal* signal,
struct LinearSectionPtr ptr[3]); struct LinearSectionPtr ptr[3]);
...@@ -540,7 +541,7 @@ public: ...@@ -540,7 +541,7 @@ public:
bool setTransporter(class TransporterFacade * tf); bool setTransporter(class TransporterFacade * tf);
int createTable(NdbTableImpl &t); int createTable(NdbTableImpl &t);
int createBlobTables(NdbTableImpl& org, NdbTableImpl & created); int createBlobTables(NdbTableImpl& t);
int addBlobTables(NdbTableImpl &); int addBlobTables(NdbTableImpl &);
int alterTable(NdbTableImpl &t); int alterTable(NdbTableImpl &t);
int dropTable(const char * name); int dropTable(const char * name);
......
...@@ -596,7 +596,9 @@ ErrorBundle ErrorCodes[] = { ...@@ -596,7 +596,9 @@ ErrorBundle ErrorCodes[] = {
{ 4269, DMEC, IE, "No connection to ndb management server" }, { 4269, DMEC, IE, "No connection to ndb management server" },
{ 4270, DMEC, IE, "Unknown blob error" }, { 4270, DMEC, IE, "Unknown blob error" },
{ 4335, DMEC, AE, "Only one autoincrement column allowed per table. Having a table without primary key uses an autoincremented hidden key, i.e. a table without a primary key can not have an autoincremented column" }, { 4335, DMEC, AE, "Only one autoincrement column allowed per table. Having a table without primary key uses an autoincremented hidden key, i.e. a table without a primary key can not have an autoincremented column" },
{ 4271, DMEC, AE, "Invalid index object, not retrieved via getIndex()" } { 4336, DMEC, AE, "Auto-increment value set below current value" },
{ 4271, DMEC, AE, "Invalid index object, not retrieved via getIndex()" },
{ 4272, DMEC, AE, "Table definition has undefined column" }
}; };
static static
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment