Commit 9a9c64ce authored by ingo@mysql.com's avatar ingo@mysql.com

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

into  mysql.com:/home/mydev/mysql-5.1-bug11527
parents 8efa709f 9d819dff
This diff is collapsed.
#############################################################
# 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;
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;
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;
set global event_scheduler = 1;
alter event e_43 do alter event e_43 do set @a = 4;
......
......@@ -22,12 +22,16 @@ partition_03ndb : Bug#16385
ps_7ndb : dbug assert in RBR mode when executing test suite
rpl_bit_npk : Bug#13418
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_basic : Bug#16228 [IN REVIEW]
rpl_ndb_charset : Bug#17246
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_innodb2ndb : Bugs#17400, 17687, 17701
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_relay_space : Bug#16993
rpl_ndb_multi_update3 : Bug#17400: delete & update of rows in table without pk fails
......
......@@ -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;
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;
set global event_scheduler = 1;
--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
......@@ -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("datetime")},
{NULL, 0}
},
{
{(char *) STRING_WITH_LEN("starts")},
......@@ -343,8 +344,6 @@ event_timed_compare_q(void *vptr, byte* a, byte *b)
RETURNS
0 - OK
1 - Error
*/
int
......@@ -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))
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_STATUS]->store((longlong)et->status);
......@@ -637,20 +636,6 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update)
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)
{
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)
table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->store((longlong)et->interval+1);
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)
{
// fix_fields already called in init_execute_at
table->field[EVEX_FIELD_INTERVAL_EXPR]->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]->store_time(&et->execute_at,
MYSQL_TIMESTAMP_DATETIME);
table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->set_null();
}
else
{
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();
if (et->comment.length)
if (table->field[field_num= EVEX_FIELD_COMMENT]->
store(et->comment.str, et->comment.length, system_charset_info))
if (et->comment.str)
{
if (table->field[field_num= EVEX_FIELD_COMMENT]->store(et->comment.str,
et->comment.length,
system_charset_info))
goto trunc_err;
}
DBUG_RETURN(0);
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);
}
......@@ -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();
// 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)))
goto err;
......@@ -807,6 +813,7 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not,
goto err;
}
#ifdef USE_THIS_CODE_AS_TEMPLATE_WHEN_EVENT_REPLICATION_IS_AGREED
if (mysql_bin_log.is_open())
{
thd->clear_error();
......@@ -814,6 +821,7 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not,
thd->binlog_query(THD::MYSQL_QUERY_TYPE,
thd->query, thd->query_length, FALSE, FALSE);
}
#endif
*rows_affected= 1;
ok:
......@@ -865,7 +873,7 @@ db_update_event(THD *thd, event_timed *et, sp_name *new_name)
goto err;
}
// first look whether we overwrite
/* first look whether we overwrite */
if (new_name)
{
if (!sortcmp_lex_string(et->name, new_name->m_name, system_charset_info) &&
......@@ -894,13 +902,12 @@ db_update_event(THD *thd, event_timed *et, sp_name *new_name)
goto err;
}
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;
// 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)))
goto err;
......@@ -918,7 +925,7 @@ db_update_event(THD *thd, event_timed *et, sp_name *new_name)
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);
DBUG_RETURN(0);
......@@ -995,7 +1002,7 @@ db_find_event(THD *thd, sp_name *name, LEX_STRING *definer, event_timed **ett,
delete et;
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)
close_thread_tables(thd);
*ett= et;
......@@ -1017,7 +1024,6 @@ db_find_event(THD *thd, sp_name *name, LEX_STRING *definer, event_timed **ett,
RETURN VALUE
0 - OK
< 0 - error (in this case underlying functions call my_error()).
*/
static int
......@@ -1036,7 +1042,7 @@ evex_load_and_compile_event(THD * thd, sp_name *spn, LEX_STRING definer,
thd->mem_root= &evex_mem_root;
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);
thd->restore_backup_open_tables_state(&backup);
if (ret)
......@@ -1088,7 +1094,7 @@ evex_load_and_compile_event(THD * thd, sp_name *spn, LEX_STRING definer,
ALTER EVENT.
RETURNS
0 - OK (always)
0 OK (always)
*/
static int
......@@ -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"));
evex_queue_delete_element(&EVEX_EQ_NAME, i);
// ok, we have cleaned
/* ok, we have cleaned */
ret= 0;
goto done;
}
......@@ -1185,7 +1191,7 @@ evex_create_event(THD *thd, event_timed *et, uint create_options,
VOID(pthread_mutex_unlock(&LOCK_evex_running));
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);
}
......@@ -1259,7 +1265,6 @@ evex_update_event(THD *thd, event_timed *et, sp_name *new_name,
et event's name
drop_if_exists if set and the event not existing => warning onto the stack
rows_affected affected number of rows is returned heres
*/
int db_drop_event(THD *thd, event_timed *et, bool drop_if_exists,
......@@ -1362,7 +1367,6 @@ evex_drop_event(THD *thd, event_timed *et, bool drop_if_exists,
RETURNS
0 - OK
1 - Error during writing to the wire
*/
int
......@@ -1413,7 +1417,6 @@ 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(show_str.c_ptr(), show_str.length(), system_charset_info);
ret= protocol->write();
send_eof(thd);
......@@ -1449,7 +1452,6 @@ evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer)
spawned and can_spawn() is the right method.
- event_timed::can_spawn() returns false -> being runned ATM
just set the flags so it should drop itself.
*/
int
......@@ -1521,7 +1523,7 @@ evex_drop_db_events(THD *thd, char *db)
}
DBUG_PRINT("info",("%d elements in the queue",
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",
evex_queue_num_elements(EVEX_EQ_NAME)));
/*
......@@ -1598,7 +1600,7 @@ evex_drop_db_events(THD *thd, char *db)
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
end_read_record(&read_record_info);
thd->version--; // Force close to free memory
thd->version--; /* Force close to free memory */
close_thread_tables(thd);
......
......@@ -103,6 +103,9 @@ class event_timed
TIME starts;
TIME ends;
TIME execute_at;
my_bool starts_null;
my_bool ends_null;
my_bool execute_at_null;
longlong expression;
interval_type interval;
......
......@@ -135,7 +135,7 @@ evex_check_system_tables()
bool not_used;
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)
return;
......@@ -206,7 +206,7 @@ init_events()
if (event_executor_running_global_var)
{
#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))
DBUG_RETURN(ER_SLAVE_THREAD);
#else
......@@ -329,7 +329,7 @@ executor_wait_till_next_event_exec(THD *thd)
if (!evex_queue_num_elements(EVEX_EQ_NAME))
{
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*);
DBUG_ASSERT(et);
......@@ -339,14 +339,14 @@ executor_wait_till_next_event_exec(THD *thd)
if (et->dropped)
et->drop(thd);
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));
sql_print_information("Event found disabled, dropping.");
DBUG_RETURN(1);
}
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();
my_tz_UTC->gmt_sec_to_TIME(&time_now, thd->query_start());
t2sleep= evex_time_diff(&et->execute_at, &time_now);
......@@ -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))
ret= 1;
ret= WAIT_STATUS_EMPTY_QUEUE;
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)
ret= 3;
ret= WAIT_STATUS_STOP_EXECUTOR;
DBUG_RETURN(ret);
}
......@@ -387,7 +387,7 @@ executor_wait_till_next_event_exec(THD *thd)
SYNOPSIS
event_executor_main()
arg - unused
arg unused
NOTES
1. The host of the thead is my_localhost
......@@ -407,11 +407,10 @@ event_executor_main(void *arg)
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);
// 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();
if (sizeof(my_time_t) != sizeof(time_t))
......@@ -422,8 +421,8 @@ event_executor_main(void *arg)
goto err_no_thd;
}
//TODO Andrey: Check for NULL
if (!(thd = new THD)) // note that contructor of THD uses DBUG_ !
/* note that contructor of THD uses DBUG_ ! */
if (!(thd = new THD))
{
sql_print_error("SCHEDULER: Cannot create THD for the main thread.");
goto err_no_thd;
......@@ -523,8 +522,7 @@ event_executor_main(void *arg)
et= evex_queue_first_element(&EVEX_EQ_NAME, event_timed*);
DBUG_PRINT("evex main thread",("got event from the queue"));
if (et->execute_at.year > 1969 &&
my_time_compare(&time_now, &et->execute_at) == -1)
if (!et->execute_at_null && my_time_compare(&time_now,&et->execute_at) == -1)
{
DBUG_PRINT("evex main thread",("still not the time for execution"));
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
......@@ -571,8 +569,11 @@ event_executor_main(void *arg)
#else
event_executor_worker((void *) et);
#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;
if ((et->flags & EVENT_EXEC_NO_MORE) || et->status == MYSQL_EVENT_DISABLED)
......@@ -582,10 +583,10 @@ event_executor_main(void *arg)
}
DBUG_PRINT("evex main thread",("unlocking"));
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
}// while
}/* while */
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));
evex_is_running= false;
evex_main_thread_id= 0;
......@@ -625,7 +626,7 @@ event_executor_main(void *arg)
delete et;
}
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);
thd->proc_info = "Clearing";
......@@ -655,7 +656,7 @@ event_executor_main(void *arg)
my_thread_end();
pthread_exit(0);
#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)
SYNOPSIS
event_executor_worker()
arg - the event_timed object to be processed
arg The event_timed object to be processed
*/
pthread_handler_t
......@@ -682,7 +683,7 @@ event_executor_worker(void *event_void)
#ifndef DBUG_FAULTY_THR
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.");
goto err_no_thd;
......@@ -697,7 +698,7 @@ event_executor_worker(void *event_void)
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;
VOID(pthread_mutex_lock(&LOCK_thread_count));
......@@ -778,8 +779,8 @@ event_executor_worker(void *event_void)
thd - Thread context. Used for memory allocation in some cases.
RETURNS
0 - OK
!0 - Error
0 OK
!0 Error
NOTES
Reports the error to the console
......@@ -845,7 +846,7 @@ evex_load_events_from_db(THD *thd)
break;
}
// let's find when to be executed
/* let's find when to be executed */
if (et->compute_next_execution_time())
{
sql_print_error("SCHEDULER: Error while computing execution time of %s.%s."
......@@ -867,7 +868,8 @@ evex_load_events_from_db(THD *thd)
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
end_read_record(&read_record_info);
thd->version--; // Force close to free memory
/* Force close to free memory */
thd->version--;
close_thread_tables(thd);
if (!ret)
......@@ -889,13 +891,13 @@ evex_load_events_from_db(THD *thd)
car - the new value
Returns
0 - OK (always)
0 OK (always)
*/
bool
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");
VOID(pthread_mutex_lock(&LOCK_evex_running));
*value= var->save_result.ulong_value;
......@@ -952,7 +954,8 @@ evex_print_warnings(THD *thd, event_timed *et)
while ((err= it++))
{
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())
{
prefix.append("SCHEDULER: [");
......
This diff is collapsed.
......@@ -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[4]->store(et.body.str, et.body.length, scs);
// [9] is SQL_MODE
/* [9] is SQL_MODE */
{
byte *sql_mode_str;
ulong sql_mode_len=0;
......@@ -3972,9 +3972,9 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
String show_str;
//type
sch_table->field[5]->store(STRING_WITH_LEN("RECURRING"), scs);
//execute_at
/* execute_at */
sch_table->field[6]->set_null();
//interval_value
/* interval_value */
//interval_type
if (event_reconstruct_interval_expression(&show_str, et.interval,
et.expression))
......@@ -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];
sch_table->field[8]->set_notnull();
sch_table->field[8]->store(ival->str, ival->length, scs);
//starts & ends
sch_table->field[10]->set_notnull();
sch_table->field[10]->store_time(&et.starts, 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
{
//type
sch_table->field[5]->store(STRING_WITH_LEN("ONE TIME"), scs);
//execute_at
sch_table->field[6]->set_notnull();
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
......
......@@ -1476,6 +1476,9 @@ opt_ev_status: /* empty */ { $$= 0; }
;
ev_starts: /* empty */
{
Lex->et->init_starts(YYTHD, new Item_func_now_local());
}
| STARTS_SYM expr
{
LEX *lex= Lex;
......
......@@ -2056,59 +2056,94 @@ int
NdbDictionaryImpl::createTable(NdbTableImpl &t)
{
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())
t.m_newExternalName.assign(t.m_externalName);
// create table
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);
}
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",
t.m_internalName.c_str()));
m_error.code = 283;
delete t2;
DBUG_RETURN(-1);
}
// auto-increment - use "t" because initial value is not in DICT
{
DBUG_RETURN(0);
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);
}
// update table def from DICT
Ndb_local_table_info *info=
get_local_table_info(t.m_internalName,false);
if (info == NULL) {
m_error.code= 709;
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);
}
if (createBlobTables(t, *(info->m_table_impl)) != 0) {
}
}
// blob tables - use "t2" to get values set by kernel
if (t2->m_noOfBlobs != 0 && createBlobTables(*t2) != 0) {
int save_code = m_error.code;
(void)dropTable(t);
m_error.code= save_code;
(void)dropTable(*t2);
m_error.code = save_code;
delete t2;
DBUG_RETURN(-1);
}
// not entered in cache
delete t2;
DBUG_RETURN(0);
}
int
NdbDictionaryImpl::createBlobTables(NdbTableImpl& org, NdbTableImpl &t)
NdbDictionaryImpl::createBlobTables(NdbTableImpl &t)
{
DBUG_ENTER("NdbDictionaryImpl::createBlobTables");
for (unsigned i = 0; i < t.m_columns.size(); i++) {
NdbColumnImpl & c = *t.m_columns[i];
NdbColumnImpl & oc = *org.m_columns[i];
if (! c.getBlobType() || c.getPartSize() == 0)
continue;
NdbTableImpl bt;
NdbDictionary::Column::StorageType save = c.getStorageType();
c.setStorageType(oc.getStorageType());
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);
}
c.m_blobTable = info->m_table_impl;
}
DBUG_RETURN(0);
}
......@@ -2292,22 +2327,14 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb,
sizeof(tmpTab->TableName),
internalName.c_str());
bool haveAutoIncrement = false;
Uint64 autoIncrementValue = 0;
Uint32 distKeys= 0;
for(i = 0; i<sz; i++){
for(i = 0; i<sz; i++) {
const NdbColumnImpl * col = impl.m_columns[i];
if(col == 0)
continue;
if (col->m_autoIncrement) {
if (haveAutoIncrement) {
m_error.code= 4335;
if (col == NULL) {
m_error.code = 4272;
NdbMem_Free((void*)tmpTab);
DBUG_RETURN(-1);
}
haveAutoIncrement = true;
autoIncrementValue = col->m_autoIncrementInitialValue;
}
if (col->m_distributionKey)
{
distKeys++;
......@@ -2570,17 +2597,6 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb,
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);
}
......@@ -2588,12 +2604,12 @@ void
NdbDictInterface::execCREATE_TABLE_CONF(NdbApiSignal * signal,
LinearSectionPtr ptr[3])
{
#if 0
const CreateTableConf* const conf=
CAST_CONSTPTR(CreateTableConf, signal->getDataPtr());
Uint32 tableId= conf->tableId;
Uint32 tableVersion= conf->tableVersion;
#endif
m_buffer.grow(4 * 2); // 2 words
Uint32* data = (Uint32*)m_buffer.get_data();
data[0] = conf->tableId;
data[1] = conf->tableVersion;
m_waiter.signal(NO_WAIT);
}
......
......@@ -479,6 +479,7 @@ private:
class TransporterFacade * m_transporter;
friend class Ndb;
friend class NdbDictionaryImpl;
static void execSignal(void* dictImpl,
class NdbApiSignal* signal,
struct LinearSectionPtr ptr[3]);
......@@ -540,7 +541,7 @@ public:
bool setTransporter(class TransporterFacade * tf);
int createTable(NdbTableImpl &t);
int createBlobTables(NdbTableImpl& org, NdbTableImpl & created);
int createBlobTables(NdbTableImpl& t);
int addBlobTables(NdbTableImpl &);
int alterTable(NdbTableImpl &t);
int dropTable(const char * name);
......
......@@ -596,7 +596,9 @@ ErrorBundle ErrorCodes[] = {
{ 4269, DMEC, IE, "No connection to ndb management server" },
{ 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" },
{ 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
......
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