Merge bk-internal.mysql.com:/home/bk/mysql-5.1
into bodhi.local:/opt/local/work/mysql-5.1-runtime include/my_global.h: Auto merged mysql-test/mysql-test-run.pl: Auto merged mysql-test/r/events_scheduling.result: Auto merged BitKeeper/deleted/.del-init_db.sql~a77d572c39d5a1f8: Auto merged BitKeeper/deleted/.del-mysql_create_system_tables.sh: Auto merged mysql-test/r/query_cache.result: Auto merged mysql-test/r/view.result: Auto merged mysql-test/t/events_scheduling.test: Auto merged mysql-test/t/grant_cache.test: Auto merged mysql-test/t/query_cache.test: Auto merged mysql-test/t/view.test: Auto merged scripts/mysql_system_tables_fix.sql: Auto merged sql/event_db_repository.cc: Auto merged sql/event_queue.cc: Auto merged sql/field.cc: Auto merged sql/handler.cc: Auto merged sql/handler.h: Auto merged sql/item.cc: Auto merged sql/item.h: Auto merged sql/item_func.cc: Auto merged sql/item_subselect.cc: Auto merged sql/log_event.cc: Auto merged sql/mysql_priv.h: Auto merged sql/mysqld.cc: Auto merged sql/set_var.cc: Auto merged sql/sp.cc: Auto merged sql/sp_head.cc: Auto merged sql/sp_head.h: Auto merged sql/sql_base.cc: Auto merged sql/sql_class.cc: Auto merged sql/sql_class.h: Auto merged sql/sql_help.cc: Auto merged sql/sql_lex.cc: Auto merged sql/sql_lex.h: Auto merged sql/sql_parse.cc: Auto merged sql/sql_prepare.cc: Auto merged sql/sql_select.cc: Auto merged sql/sql_show.cc: Auto merged sql/sql_table.cc: Auto merged sql/sql_yacc.yy: Auto merged sql/table.cc: Auto merged sql/share/errmsg.txt: Auto merged sql/tztime.cc: Auto merged storage/innobase/handler/ha_innodb.cc: Auto merged storage/myisam/ha_myisam.cc: Auto merged storage/myisam/ha_myisam.h: Auto merged mysql-test/r/skip_grants.result: Manualmerge. mysql-test/r/sp.result: Manualmerge. mysql-test/t/skip_grants.test: Manualmerge. mysql-test/t/sp.test: Manualmerge. sql/event_data_objects.cc: Manualmerge.
This commit is contained in:
commit
e9bb08ac0c
@ -1431,6 +1431,8 @@ static uint dump_events_for_db(char *db)
|
||||
strcpy(delimiter, ";");
|
||||
if (mysql_num_rows(event_list_res) > 0)
|
||||
{
|
||||
fprintf(sql_file, "/*!50106 SET @save_time_zone= @@TIME_ZONE */ ;\n");
|
||||
|
||||
while ((event_list_row= mysql_fetch_row(event_list_res)) != NULL)
|
||||
{
|
||||
event_name= quote_name(event_list_row[1], name_buff, 0);
|
||||
@ -1447,13 +1449,13 @@ static uint dump_events_for_db(char *db)
|
||||
if the user has EXECUTE privilege he can see event names, but not the
|
||||
event body!
|
||||
*/
|
||||
if (strlen(row[2]) != 0)
|
||||
if (strlen(row[3]) != 0)
|
||||
{
|
||||
if (opt_drop)
|
||||
fprintf(sql_file, "/*!50106 DROP EVENT IF EXISTS %s */%s\n",
|
||||
event_name, delimiter);
|
||||
|
||||
delimit_test= create_delimiter(row[2], delimiter, sizeof(delimiter));
|
||||
delimit_test= create_delimiter(row[3], delimiter, sizeof(delimiter));
|
||||
if (delimit_test == NULL) {
|
||||
fprintf(stderr, "%s: Warning: Can't dump event '%s'\n",
|
||||
event_name, my_progname);
|
||||
@ -1461,11 +1463,15 @@ static uint dump_events_for_db(char *db)
|
||||
}
|
||||
|
||||
fprintf(sql_file, "DELIMITER %s\n", delimiter);
|
||||
fprintf(sql_file, "/*!50106 %s */ %s\n", row[2], delimiter);
|
||||
fprintf(sql_file, "/*!50106 SET TIME_ZONE= '%s' */ %s\n",
|
||||
row[2], delimiter);
|
||||
fprintf(sql_file, "/*!50106 %s */ %s\n", row[3], delimiter);
|
||||
}
|
||||
} /* end of event printing */
|
||||
} /* end of list of events */
|
||||
fprintf(sql_file, "DELIMITER ;\n");
|
||||
fprintf(sql_file, "/*!50106 SET TIME_ZONE= @save_time_zone */ ;\n");
|
||||
|
||||
mysql_free_result(event_res);
|
||||
}
|
||||
mysql_free_result(event_list_res);
|
||||
|
@ -1496,4 +1496,10 @@ do { doubleget_union _tmp; \
|
||||
#include <new>
|
||||
#endif
|
||||
|
||||
/* Length of decimal number represented by INT32. */
|
||||
#define MY_INT32_NUM_DECIMAL_DIGITS 11
|
||||
|
||||
/* Length of decimal number represented by INT64. */
|
||||
#define MY_INT64_NUM_DECIMAL_DIGITS 21
|
||||
|
||||
#endif /* my_global_h */
|
||||
|
@ -822,7 +822,7 @@ int Protocol::begin_dataset()
|
||||
remove last row of current recordset
|
||||
|
||||
SYNOPSIS
|
||||
Protocol_simple::remove_last_row()
|
||||
Protocol_text::remove_last_row()
|
||||
|
||||
NOTES
|
||||
does the loop from the beginning of the current recordset to
|
||||
@ -830,12 +830,12 @@ int Protocol::begin_dataset()
|
||||
Not supposed to be frequently called.
|
||||
*/
|
||||
|
||||
void Protocol_simple::remove_last_row()
|
||||
void Protocol_text::remove_last_row()
|
||||
{
|
||||
MYSQL_DATA *data= thd->cur_data;
|
||||
MYSQL_ROWS **last_row_hook= &data->data;
|
||||
uint count= data->rows;
|
||||
DBUG_ENTER("Protocol_simple::remove_last_row");
|
||||
DBUG_ENTER("Protocol_text::remove_last_row");
|
||||
while (--count)
|
||||
last_row_hook= &(*last_row_hook)->next;
|
||||
|
||||
@ -964,7 +964,7 @@ bool Protocol::write()
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Protocol_prep::write()
|
||||
bool Protocol_binary::write()
|
||||
{
|
||||
MYSQL_ROWS *cur;
|
||||
MYSQL_DATA *data= thd->cur_data;
|
||||
@ -1031,7 +1031,7 @@ void net_send_error_packet(THD *thd, uint sql_errno, const char *err)
|
||||
}
|
||||
|
||||
|
||||
void Protocol_simple::prepare_for_resend()
|
||||
void Protocol_text::prepare_for_resend()
|
||||
{
|
||||
MYSQL_ROWS *cur;
|
||||
MYSQL_DATA *data= thd->cur_data;
|
||||
@ -1056,7 +1056,7 @@ void Protocol_simple::prepare_for_resend()
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
bool Protocol_simple::store_null()
|
||||
bool Protocol_text::store_null()
|
||||
{
|
||||
*(next_field++)= NULL;
|
||||
++next_mysql_field;
|
||||
|
@ -1,7 +1,4 @@
|
||||
-- require r/have_query_cache.require
|
||||
# As PS are not cached we disable them to ensure the we get the right number
|
||||
# of query cache hits
|
||||
-- disable_ps_protocol
|
||||
disable_query_log;
|
||||
show variables like "have_query_cache";
|
||||
enable_query_log;
|
||||
|
@ -11,13 +11,28 @@
|
||||
# SELECT c = 3 FROM t;
|
||||
# --source include/wait_condition.inc
|
||||
#
|
||||
# OR
|
||||
#
|
||||
# let $wait_timeout= 60; # Override default 30 seconds with 60.
|
||||
# let $wait_condition=
|
||||
# SELECT c = 3 FROM t;
|
||||
# --source include/wait_condition.inc
|
||||
#
|
||||
# EXAMPLE
|
||||
# events_bugs.test
|
||||
# events_bugs.test, events_time_zone.test
|
||||
#
|
||||
|
||||
--disable_query_log
|
||||
|
||||
let $wait_counter= 300;
|
||||
if ($wait_timeout)
|
||||
{
|
||||
let $wait_counter= `SELECT $wait_timeout * 10`;
|
||||
}
|
||||
# Reset $wait_timeout so that its value won't be used on subsequent
|
||||
# calls, and default will be used instead.
|
||||
let $wait_timeout= 0;
|
||||
|
||||
while ($wait_counter)
|
||||
{
|
||||
let $success= `$wait_condition`;
|
||||
|
@ -902,7 +902,7 @@ sub command_line_setup () {
|
||||
# --------------------------------------------------------------------------
|
||||
if ( $opt_with_ndbcluster and !$opt_bench)
|
||||
{
|
||||
mtr_error("Can only use --with-ndbcluster togheter with --bench");
|
||||
mtr_error("Can only use --with-ndbcluster together with --bench");
|
||||
}
|
||||
|
||||
if ( $opt_ndbconnectstring )
|
||||
|
@ -118,81 +118,81 @@ drop table t_event3;
|
||||
set names utf8;
|
||||
CREATE EVENT root6 ON SCHEDULE EVERY '10:20' MINUTE_SECOND ON COMPLETION PRESERVE ENABLE COMMENT 'some comment' DO select 1;
|
||||
SHOW CREATE EVENT root6;
|
||||
Event sql_mode Create Event
|
||||
root6 CREATE EVENT `root6` ON SCHEDULE EVERY '10:20' MINUTE_SECOND ON COMPLETION PRESERVE ENABLE COMMENT 'some comment' DO select 1
|
||||
Event sql_mode time_zone Create Event
|
||||
root6 SYSTEM CREATE EVENT `root6` ON SCHEDULE EVERY '10:20' MINUTE_SECOND STARTS '#' ON COMPLETION PRESERVE ENABLE COMMENT 'some comment' DO select 1
|
||||
create event root7 on schedule every 2 year do select 1;
|
||||
SHOW CREATE EVENT root7;
|
||||
Event sql_mode Create Event
|
||||
root7 CREATE EVENT `root7` ON SCHEDULE EVERY 2 YEAR ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
Event sql_mode time_zone Create Event
|
||||
root7 SYSTEM CREATE EVENT `root7` ON SCHEDULE EVERY 2 YEAR STARTS '#' ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
create event root8 on schedule every '2:5' year_month do select 1;
|
||||
SHOW CREATE EVENT root8;
|
||||
Event sql_mode Create Event
|
||||
root8 CREATE EVENT `root8` ON SCHEDULE EVERY '2-5' YEAR_MONTH ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
Event sql_mode time_zone Create Event
|
||||
root8 SYSTEM CREATE EVENT `root8` ON SCHEDULE EVERY '2-5' YEAR_MONTH STARTS '#' ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
create event root8_1 on schedule every '2:15' year_month do select 1;
|
||||
SHOW CREATE EVENT root8_1;
|
||||
Event sql_mode Create Event
|
||||
root8_1 CREATE EVENT `root8_1` ON SCHEDULE EVERY '3-3' YEAR_MONTH ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
Event sql_mode time_zone Create Event
|
||||
root8_1 SYSTEM CREATE EVENT `root8_1` ON SCHEDULE EVERY '3-3' YEAR_MONTH STARTS '#' ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
create event root9 on schedule every 2 week ON COMPLETION PRESERVE DISABLE COMMENT 'коментар на кирилица' do select 1;
|
||||
SHOW CREATE EVENT root9;
|
||||
Event sql_mode Create Event
|
||||
root9 CREATE EVENT `root9` ON SCHEDULE EVERY 2 WEEK ON COMPLETION PRESERVE DISABLE COMMENT 'коментар на кирилица' DO select 1
|
||||
Event sql_mode time_zone Create Event
|
||||
root9 SYSTEM CREATE EVENT `root9` ON SCHEDULE EVERY 2 WEEK STARTS '#' ON COMPLETION PRESERVE DISABLE COMMENT 'коментар на кирилица' DO select 1
|
||||
create event root10 on schedule every '20:5' day_hour do select 1;
|
||||
SHOW CREATE EVENT root10;
|
||||
Event sql_mode Create Event
|
||||
root10 CREATE EVENT `root10` ON SCHEDULE EVERY '20 5' DAY_HOUR ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
Event sql_mode time_zone Create Event
|
||||
root10 SYSTEM CREATE EVENT `root10` ON SCHEDULE EVERY '20 5' DAY_HOUR STARTS '#' ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
create event root11 on schedule every '20:25' day_hour do select 1;
|
||||
SHOW CREATE EVENT root11;
|
||||
Event sql_mode Create Event
|
||||
root11 CREATE EVENT `root11` ON SCHEDULE EVERY '21 1' DAY_HOUR ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
Event sql_mode time_zone Create Event
|
||||
root11 SYSTEM CREATE EVENT `root11` ON SCHEDULE EVERY '21 1' DAY_HOUR STARTS '#' ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
create event root12 on schedule every '20:25' hour_minute do select 1;
|
||||
SHOW CREATE EVENT root12;
|
||||
Event sql_mode Create Event
|
||||
root12 CREATE EVENT `root12` ON SCHEDULE EVERY '20:25' HOUR_MINUTE ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
Event sql_mode time_zone Create Event
|
||||
root12 SYSTEM CREATE EVENT `root12` ON SCHEDULE EVERY '20:25' HOUR_MINUTE STARTS '#' ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
create event root13 on schedule every '25:25' hour_minute do select 1;
|
||||
SHOW CREATE EVENT root13;
|
||||
Event sql_mode Create Event
|
||||
root13 CREATE EVENT `root13` ON SCHEDULE EVERY '25:25' HOUR_MINUTE ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
Event sql_mode time_zone Create Event
|
||||
root13 SYSTEM CREATE EVENT `root13` ON SCHEDULE EVERY '25:25' HOUR_MINUTE STARTS '#' ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
create event root13_1 on schedule every '11:65' hour_minute do select 1;
|
||||
SHOW CREATE EVENT root13_1;
|
||||
Event sql_mode Create Event
|
||||
root13_1 CREATE EVENT `root13_1` ON SCHEDULE EVERY '12:5' HOUR_MINUTE ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
Event sql_mode time_zone Create Event
|
||||
root13_1 SYSTEM CREATE EVENT `root13_1` ON SCHEDULE EVERY '12:5' HOUR_MINUTE STARTS '#' ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
create event root14 on schedule every '35:35' minute_second do select 1;
|
||||
SHOW CREATE EVENT root14;
|
||||
Event sql_mode Create Event
|
||||
root14 CREATE EVENT `root14` ON SCHEDULE EVERY '35:35' MINUTE_SECOND ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
Event sql_mode time_zone Create Event
|
||||
root14 SYSTEM CREATE EVENT `root14` ON SCHEDULE EVERY '35:35' MINUTE_SECOND STARTS '#' ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
create event root15 on schedule every '35:66' minute_second do select 1;
|
||||
SHOW CREATE EVENT root15;
|
||||
Event sql_mode Create Event
|
||||
root15 CREATE EVENT `root15` ON SCHEDULE EVERY '36:6' MINUTE_SECOND ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
Event sql_mode time_zone Create Event
|
||||
root15 SYSTEM CREATE EVENT `root15` ON SCHEDULE EVERY '36:6' MINUTE_SECOND STARTS '#' ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
create event root16 on schedule every '35:56' day_minute do select 1;
|
||||
SHOW CREATE EVENT root16;
|
||||
Event sql_mode Create Event
|
||||
root16 CREATE EVENT `root16` ON SCHEDULE EVERY '1 11:56' DAY_MINUTE ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
Event sql_mode time_zone Create Event
|
||||
root16 SYSTEM CREATE EVENT `root16` ON SCHEDULE EVERY '1 11:56' DAY_MINUTE STARTS '#' ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
create event root17 on schedule every '35:12:45' day_minute do select 1;
|
||||
SHOW CREATE EVENT root17;
|
||||
Event sql_mode Create Event
|
||||
root17 CREATE EVENT `root17` ON SCHEDULE EVERY '35 12:45' DAY_MINUTE ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
Event sql_mode time_zone Create Event
|
||||
root17 SYSTEM CREATE EVENT `root17` ON SCHEDULE EVERY '35 12:45' DAY_MINUTE STARTS '#' ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
create event root17_1 on schedule every '35:25:65' day_minute do select 1;
|
||||
SHOW CREATE EVENT root17_1;
|
||||
Event sql_mode Create Event
|
||||
root17_1 CREATE EVENT `root17_1` ON SCHEDULE EVERY '36 2:5' DAY_MINUTE ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
Event sql_mode time_zone Create Event
|
||||
root17_1 SYSTEM CREATE EVENT `root17_1` ON SCHEDULE EVERY '36 2:5' DAY_MINUTE STARTS '#' ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
create event root18 on schedule every '35:12:45' hour_second do select 1;
|
||||
SHOW CREATE EVENT root18;
|
||||
Event sql_mode Create Event
|
||||
root18 CREATE EVENT `root18` ON SCHEDULE EVERY '35:12:45' HOUR_SECOND ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
Event sql_mode time_zone Create Event
|
||||
root18 SYSTEM CREATE EVENT `root18` ON SCHEDULE EVERY '35:12:45' HOUR_SECOND STARTS '#' ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
create event root19 on schedule every '15:59:85' hour_second do select 1;
|
||||
SHOW CREATE EVENT root19;
|
||||
Event sql_mode Create Event
|
||||
root19 CREATE EVENT `root19` ON SCHEDULE EVERY '16:0:25' HOUR_SECOND ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
Event sql_mode time_zone Create Event
|
||||
root19 SYSTEM CREATE EVENT `root19` ON SCHEDULE EVERY '16:0:25' HOUR_SECOND STARTS '#' ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
create event root20 on schedule every '50:20:12:45' day_second do select 1;
|
||||
SHOW CREATE EVENT root20;
|
||||
Event sql_mode Create Event
|
||||
root20 CREATE EVENT `root20` ON SCHEDULE EVERY '50 20:12:45' DAY_SECOND ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
Event sql_mode time_zone Create Event
|
||||
root20 SYSTEM CREATE EVENT `root20` ON SCHEDULE EVERY '50 20:12:45' DAY_SECOND STARTS '#' ON COMPLETION NOT PRESERVE ENABLE DO select 1
|
||||
set names cp1251;
|
||||
create event ðóóò21 on schedule every '50:23:59:95' day_second COMMENT 'òîâà å 1251 êîìåíòàð' do select 1;
|
||||
SHOW CREATE EVENT ðóóò21;
|
||||
Event sql_mode Create Event
|
||||
ðóóò21 CREATE EVENT `ðóóò21` ON SCHEDULE EVERY '51 0:0:35' DAY_SECOND ON COMPLETION NOT PRESERVE ENABLE COMMENT 'òîâà å 1251 êîìåíòàð' DO select 1
|
||||
Event sql_mode time_zone Create Event
|
||||
ðóóò21 SYSTEM CREATE EVENT `ðóóò21` ON SCHEDULE EVERY '51 0:0:35' DAY_SECOND STARTS '#' ON COMPLETION NOT PRESERVE ENABLE COMMENT 'òîâà å 1251 êîìåíòàð' DO select 1
|
||||
insert into mysql.event (db, name, body, definer, interval_value, interval_field) values (database(), "root22", "select 1", user(), 100, "SECOND_MICROSECOND");
|
||||
show create event root22;
|
||||
ERROR 42000: This version of MySQL doesn't yet support 'MICROSECOND'
|
||||
@ -225,18 +225,18 @@ drop event
|
||||
set names latin1;
|
||||
CREATE EVENT intact_check ON SCHEDULE EVERY 10 HOUR DO SELECT "nothing";
|
||||
SHOW EVENTS;
|
||||
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
|
||||
events_test intact_check root@localhost RECURRING NULL 10 HOUR # # ENABLED
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
events_test intact_check root@localhost SYSTEM RECURRING NULL 10 # # NULL ENABLED
|
||||
ALTER TABLE mysql.event ADD dummy INT FIRST;
|
||||
SHOW EVENTS;
|
||||
ERROR HY000: Column count of mysql.event is wrong. Expected 16, found 17. Table probably corrupted
|
||||
ERROR HY000: Column count of mysql.event is wrong. Expected 17, found 18. Table probably corrupted
|
||||
ALTER TABLE mysql.event DROP dummy, ADD dummy2 VARCHAR(64) FIRST;
|
||||
SHOW EVENTS;
|
||||
ERROR HY000: Column count of mysql.event is wrong. Expected 16, found 17. Table probably corrupted
|
||||
ERROR HY000: Column count of mysql.event is wrong. Expected 17, found 18. Table probably corrupted
|
||||
ALTER TABLE mysql.event DROP dummy2;
|
||||
SHOW EVENTS;
|
||||
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
|
||||
events_test intact_check root@localhost RECURRING NULL 10 HOUR # # ENABLED
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
events_test intact_check root@localhost SYSTEM RECURRING NULL 10 # # NULL ENABLED
|
||||
CREATE TABLE event_like LIKE mysql.event;
|
||||
INSERT INTO event_like SELECT * FROM mysql.event;
|
||||
ALTER TABLE mysql.event MODIFY db char(64) character set cp1251 default '';
|
||||
@ -262,6 +262,7 @@ event CREATE TABLE `event` (
|
||||
`on_completion` enum('DROP','PRESERVE') NOT NULL DEFAULT 'DROP',
|
||||
`sql_mode` set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION','NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB','NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40','ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER','HIGH_NOT_PRECEDENCE') NOT NULL DEFAULT '',
|
||||
`comment` char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '',
|
||||
`time_zone` char(64) CHARACTER SET latin1 NOT NULL DEFAULT 'SYSTEM',
|
||||
PRIMARY KEY (`db`,`name`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Events'
|
||||
SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
|
||||
@ -269,8 +270,8 @@ ERROR HY000: Cannot load from mysql.event. Table probably corrupted. See error l
|
||||
ALTER TABLE mysql.event MODIFY db char(64) character set utf8 collate utf8_bin default '';
|
||||
"This should work"
|
||||
SHOW EVENTS;
|
||||
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
|
||||
events_test intact_check root@localhost RECURRING NULL 10 HOUR # # ENABLED
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
events_test intact_check root@localhost SYSTEM RECURRING NULL 10 # # NULL ENABLED
|
||||
ALTER TABLE mysql.event MODIFY db char(64) character set cp1251 default '';
|
||||
SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
|
||||
ERROR HY000: Cannot load from mysql.event. Table probably corrupted. See error log.
|
||||
@ -279,14 +280,14 @@ SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
|
||||
ERROR HY000: Cannot load from mysql.event. Table probably corrupted. See error log.
|
||||
ALTER TABLE mysql.event DROP comment, DROP starts;
|
||||
SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
|
||||
ERROR HY000: Column count of mysql.event is wrong. Expected 16, found 14. Table probably corrupted
|
||||
ERROR HY000: Column count of mysql.event is wrong. Expected 17, found 15. Table probably corrupted
|
||||
DROP TABLE mysql.event;
|
||||
CREATE TABLE mysql.event like event_like;
|
||||
INSERT INTO mysql.event SELECT * FROM event_like;
|
||||
DROP TABLE event_like;
|
||||
SHOW EVENTS;
|
||||
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
|
||||
events_test intact_check root@localhost RECURRING NULL 10 HOUR # # ENABLED
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
events_test intact_check root@localhost SYSTEM RECURRING NULL 10 # # NULL ENABLED
|
||||
DROP EVENT intact_check;
|
||||
create event e_26 on schedule at '2017-01-01 00:00:00' disable do set @a = 5;
|
||||
select db, name, body, definer, convert_tz(execute_at, 'UTC', 'SYSTEM'), on_completion from mysql.event;
|
||||
@ -399,5 +400,5 @@ ERROR 42000: Incorrect database name 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
SHOW EVENTS FROM ``;
|
||||
ERROR 42000: Incorrect database name ''
|
||||
SHOW EVENTS FROM `events\\test`;
|
||||
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
drop database events_test;
|
||||
|
@ -25,9 +25,12 @@ ERROR HY000: Incorrect STARTS value: '99990101000000'
|
||||
create event e_55 on schedule every 10 minute ends 99990101000000 do drop table t;
|
||||
ERROR HY000: ENDS is either invalid or before STARTS
|
||||
create event e_55 on schedule at 10000101000000 do drop table t;
|
||||
ERROR HY000: Activation (AT) time is in the past
|
||||
ERROR HY000: Incorrect AT value: '10000101000000'
|
||||
create event e_55 on schedule at 20000101000000 do drop table t;
|
||||
ERROR HY000: Activation (AT) time is in the past
|
||||
Warnings:
|
||||
Note 1584 Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. Event has not been created
|
||||
show events;
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
create event e_55 on schedule at 20200101000000 starts 10000101000000 do drop table t;
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'starts 10000101000000 do drop table t' at line 1
|
||||
create event e_55 on schedule at 20200101000000 ends 10000101000000 do drop table t;
|
||||
|
@ -2,8 +2,8 @@ CREATE DATABASE IF NOT EXISTS events_test;
|
||||
use events_test;
|
||||
CREATE EVENT one_event ON SCHEDULE EVERY 10 SECOND DO SELECT 123;
|
||||
SHOW EVENTS;
|
||||
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
|
||||
events_test one_event root@localhost RECURRING NULL 10 SECOND # # ENABLED
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
events_test one_event root@localhost SYSTEM RECURRING NULL 10 # # NULL ENABLED
|
||||
SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_DEFINITION, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT FROM INFORMATION_SCHEMA.EVENTS ORDER BY EVENT_SCHEMA, EVENT_NAME;
|
||||
EVENT_CATALOG EVENT_SCHEMA EVENT_NAME DEFINER EVENT_BODY EVENT_DEFINITION EVENT_TYPE EXECUTE_AT INTERVAL_VALUE INTERVAL_FIELD STATUS ON_COMPLETION EVENT_COMMENT
|
||||
NULL events_test one_event root@localhost SQL SELECT 123 RECURRING NULL 10 SECOND ENABLED NOT PRESERVE
|
||||
@ -29,8 +29,8 @@ ERROR 42000: Access denied for user 'ev_test'@'localhost' to database 'events_te
|
||||
USE events_test;
|
||||
"We should see one event";
|
||||
SHOW EVENTS;
|
||||
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
|
||||
events_test one_event root@localhost RECURRING NULL 10 SECOND # # ENABLED
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
events_test one_event root@localhost SYSTEM RECURRING NULL 10 # # NULL ENABLED
|
||||
SELECT CONCAT("Let's create some new events from the name of ", USER());
|
||||
CONCAT("Let's create some new events from the name of ", USER())
|
||||
Let's create some new events from the name of ev_test@localhost
|
||||
@ -40,18 +40,18 @@ CREATE EVENT two_event ON SCHEDULE EVERY 20 SECOND ON COMPLETION NOT PRESERVE CO
|
||||
CREATE EVENT three_event ON SCHEDULE EVERY 20 SECOND ON COMPLETION PRESERVE COMMENT "three event" DO SELECT 123;
|
||||
"Now we should see 3 events:";
|
||||
SHOW EVENTS;
|
||||
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
|
||||
events_test one_event root@localhost RECURRING NULL 10 SECOND # # ENABLED
|
||||
events_test three_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
|
||||
events_test two_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
events_test one_event root@localhost SYSTEM RECURRING NULL 10 # # NULL ENABLED
|
||||
events_test three_event ev_test@localhost SYSTEM RECURRING NULL 20 # # NULL ENABLED
|
||||
events_test two_event ev_test@localhost SYSTEM RECURRING NULL 20 # # NULL ENABLED
|
||||
"This should show us only 2 events:";
|
||||
SHOW EVENTS LIKE 't%event';
|
||||
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
|
||||
events_test three_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
|
||||
events_test two_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
events_test three_event ev_test@localhost SYSTEM RECURRING NULL 20 # # NULL ENABLED
|
||||
events_test two_event ev_test@localhost SYSTEM RECURRING NULL 20 # # NULL ENABLED
|
||||
"This should show us no events:";
|
||||
SHOW EVENTS FROM test LIKE '%';
|
||||
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
GRANT EVENT ON events_test2.* TO ev_test@localhost;
|
||||
USE events_test2;
|
||||
CREATE EVENT four_event ON SCHEDULE EVERY 20 SECOND DO SELECT 42;
|
||||
|
@ -7,6 +7,6 @@ create event abc2 on schedule every 1 second do insert into execution_log value(
|
||||
create event abc3 on schedule every 1 second do insert into execution_log value('abc3');
|
||||
select name from execution_log;
|
||||
name
|
||||
insert into mysql.event values ('db1','bad','select 42','root@localhost',NULL,1000,'MICROSECOND','2006-05-05 17:39:11','2006-05-05 17:39:20','2016-05-05 15:39:24','2016-05-05 15:39:11',NULL,'ENABLED','DROP','','comment1');
|
||||
insert into mysql.event values ('db1','bad2','sect','root@localhost',NULL,1000,'SECOND','2006-05-05 17:39:11','2006-05-05 17:39:20','2016-05-05 15:39:24','2016-05-05 15:39:11',NULL,'ENABLED','DROP','','comment2');
|
||||
insert into mysql.event values ('db1','bad','select 42','root@localhost',NULL,1000,'MICROSECOND','2006-05-05 17:39:11','2006-05-05 17:39:20','2016-05-05 15:39:24','2016-05-05 15:39:11',NULL,'ENABLED','DROP','','comment1','SYSTEM');
|
||||
insert into mysql.event values ('db1','bad2','sect','root@localhost',NULL,1000,'SECOND','2006-05-05 17:39:11','2006-05-05 17:39:20','2016-05-05 15:39:24','2016-05-05 15:39:11',NULL,'ENABLED','DROP','','comment2','SYSTEM');
|
||||
"Now we restart the server"
|
||||
|
291
mysql-test/r/events_time_zone.result
Normal file
291
mysql-test/r/events_time_zone.result
Normal file
@ -0,0 +1,291 @@
|
||||
DROP DATABASE IF EXISTS mysqltest_db1;
|
||||
CREATE DATABASE mysqltest_db1;
|
||||
USE mysqltest_db1;
|
||||
SET GLOBAL EVENT_SCHEDULER= OFF;
|
||||
SET @save_time_zone= @@TIME_ZONE;
|
||||
SET TIME_ZONE= '+00:00';
|
||||
SET TIMESTAMP= UNIX_TIMESTAMP('2005-12-31 23:58:59');
|
||||
CREATE EVENT e1 ON SCHEDULE EVERY 1 DAY DO SELECT 1;
|
||||
SHOW EVENTS;
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
mysqltest_db1 e1 root@localhost +00:00 RECURRING NULL 1 DAY 2005-12-31 23:58:59 NULL ENABLED
|
||||
SET TIME_ZONE= '-01:00';
|
||||
ALTER EVENT e1 ON SCHEDULE EVERY 1 DAY STARTS '2000-01-01 00:00:00';
|
||||
SHOW EVENTS;
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
mysqltest_db1 e1 root@localhost -01:00 RECURRING NULL 1 DAY 2000-01-01 00:00:00 NULL ENABLED
|
||||
SET TIME_ZONE= '+02:00';
|
||||
ALTER EVENT e1 ON SCHEDULE AT '2000-01-02 00:00:00'
|
||||
ON COMPLETION PRESERVE DISABLE;
|
||||
SHOW EVENTS;
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
mysqltest_db1 e1 root@localhost +02:00 ONE TIME 2000-01-02 00:00:00 NULL NULL NULL NULL DISABLED
|
||||
SET TIME_ZONE= '-03:00';
|
||||
ALTER EVENT e1 ON SCHEDULE EVERY 1 DAY ENDS '2030-01-03 00:00:00'
|
||||
ON COMPLETION PRESERVE DISABLE;
|
||||
SHOW EVENTS;
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
mysqltest_db1 e1 root@localhost -03:00 RECURRING NULL 1 DAY 2005-12-31 20:58:59 2030-01-03 00:00:00 DISABLED
|
||||
SET TIME_ZONE= '+04:00';
|
||||
ALTER EVENT e1 DO SELECT 2;
|
||||
SHOW EVENTS;
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
mysqltest_db1 e1 root@localhost -03:00 RECURRING NULL 1 DAY 2005-12-31 20:58:59 2030-01-03 00:00:00 ENABLED
|
||||
DROP EVENT e1;
|
||||
SET TIME_ZONE='+05:00';
|
||||
CREATE EVENT e1 ON SCHEDULE EVERY 1 DAY STARTS '2006-01-01 00:00:00' DO
|
||||
SELECT 1;
|
||||
SET TIMESTAMP= @@TIMESTAMP + 1;
|
||||
SET TIME_ZONE='-05:00';
|
||||
CREATE EVENT e2 ON SCHEDULE EVERY 1 DAY STARTS '2006-01-01 00:00:00' DO
|
||||
SELECT 1;
|
||||
SET TIMESTAMP= @@TIMESTAMP + 1;
|
||||
SET TIME_ZONE='+00:00';
|
||||
CREATE EVENT e3 ON SCHEDULE EVERY 1 DAY STARTS '2006-01-01 00:00:00' DO
|
||||
SELECT 1;
|
||||
SELECT * FROM INFORMATION_SCHEMA.EVENTS;
|
||||
EVENT_CATALOG EVENT_SCHEMA EVENT_NAME DEFINER TIME_ZONE EVENT_BODY EVENT_DEFINITION EVENT_TYPE EXECUTE_AT INTERVAL_VALUE INTERVAL_FIELD SQL_MODE STARTS ENDS STATUS ON_COMPLETION CREATED LAST_ALTERED LAST_EXECUTED EVENT_COMMENT
|
||||
NULL mysqltest_db1 e1 root@localhost +05:00 SQL SELECT 1 RECURRING NULL 1 DAY 2006-01-01 00:00:00 NULL ENABLED NOT PRESERVE 2005-12-31 23:58:59 2005-12-31 23:58:59 NULL
|
||||
NULL mysqltest_db1 e2 root@localhost -05:00 SQL SELECT 1 RECURRING NULL 1 DAY 2006-01-01 00:00:00 NULL ENABLED NOT PRESERVE 2005-12-31 23:59:00 2005-12-31 23:59:00 NULL
|
||||
NULL mysqltest_db1 e3 root@localhost +00:00 SQL SELECT 1 RECURRING NULL 1 DAY 2006-01-01 00:00:00 NULL ENABLED NOT PRESERVE 2005-12-31 23:59:01 2005-12-31 23:59:01 NULL
|
||||
SHOW EVENTS;
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
mysqltest_db1 e1 root@localhost +05:00 RECURRING NULL 1 DAY 2006-01-01 00:00:00 NULL ENABLED
|
||||
mysqltest_db1 e2 root@localhost -05:00 RECURRING NULL 1 DAY 2006-01-01 00:00:00 NULL ENABLED
|
||||
mysqltest_db1 e3 root@localhost +00:00 RECURRING NULL 1 DAY 2006-01-01 00:00:00 NULL ENABLED
|
||||
SHOW CREATE EVENT e1;
|
||||
Event sql_mode time_zone Create Event
|
||||
e1 +05:00 CREATE EVENT `e1` ON SCHEDULE EVERY 1 DAY STARTS '2006-01-01 00:00:00' ON COMPLETION NOT PRESERVE ENABLE DO SELECT 1
|
||||
SHOW CREATE EVENT e2;
|
||||
Event sql_mode time_zone Create Event
|
||||
e2 -05:00 CREATE EVENT `e2` ON SCHEDULE EVERY 1 DAY STARTS '2006-01-01 00:00:00' ON COMPLETION NOT PRESERVE ENABLE DO SELECT 1
|
||||
SHOW CREATE EVENT e3;
|
||||
Event sql_mode time_zone Create Event
|
||||
e3 +00:00 CREATE EVENT `e3` ON SCHEDULE EVERY 1 DAY STARTS '2006-01-01 00:00:00' ON COMPLETION NOT PRESERVE ENABLE DO SELECT 1
|
||||
The following should fail, and nothing should be altered.
|
||||
ALTER EVENT e1 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00'
|
||||
ENDS '1999-01-02 00:00:00';
|
||||
ERROR HY000: Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. Event has not been altered
|
||||
ALTER EVENT e1 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00'
|
||||
ENDS '1999-01-02 00:00:00' DISABLE;
|
||||
ERROR HY000: Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. Event has not been altered
|
||||
The following should give warnings, and nothing should be created.
|
||||
CREATE EVENT e4 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00'
|
||||
ENDS '1999-01-02 00:00:00'
|
||||
DO
|
||||
SELECT 1;
|
||||
Warnings:
|
||||
Note 1584 Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. Event has not been created
|
||||
CREATE EVENT e4 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00'
|
||||
ENDS '1999-01-02 00:00:00' DISABLE
|
||||
DO
|
||||
SELECT 1;
|
||||
Warnings:
|
||||
Note 1584 Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. Event has not been created
|
||||
CREATE EVENT e4 ON SCHEDULE AT '1999-01-01 00:00:00' DO
|
||||
SELECT 1;
|
||||
Warnings:
|
||||
Note 1584 Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. Event has not been created
|
||||
CREATE EVENT e4 ON SCHEDULE AT '1999-01-01 00:00:00' DISABLE
|
||||
DO
|
||||
SELECT 1;
|
||||
Warnings:
|
||||
Note 1584 Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. Event has not been created
|
||||
SHOW EVENTS;
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
mysqltest_db1 e1 root@localhost +05:00 RECURRING NULL 1 DAY 2006-01-01 00:00:00 NULL ENABLED
|
||||
mysqltest_db1 e2 root@localhost -05:00 RECURRING NULL 1 DAY 2006-01-01 00:00:00 NULL ENABLED
|
||||
mysqltest_db1 e3 root@localhost +00:00 RECURRING NULL 1 DAY 2006-01-01 00:00:00 NULL ENABLED
|
||||
The following should succeed giving a warning.
|
||||
ALTER EVENT e1 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00'
|
||||
ENDS '1999-01-02 00:00:00' ON COMPLETION PRESERVE;
|
||||
Warnings:
|
||||
Note 1533 Event execution time is in the past. Event has been disabled
|
||||
CREATE EVENT e4 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00'
|
||||
ENDS '1999-01-02 00:00:00' ON COMPLETION PRESERVE
|
||||
DO
|
||||
SELECT 1;
|
||||
Warnings:
|
||||
Note 1533 Event execution time is in the past. Event has been disabled
|
||||
CREATE EVENT e5 ON SCHEDULE AT '1999-01-01 00:00:00'
|
||||
ON COMPLETION PRESERVE
|
||||
DO
|
||||
SELECT 1;
|
||||
Warnings:
|
||||
Note 1533 Event execution time is in the past. Event has been disabled
|
||||
The following should succeed without warnings.
|
||||
ALTER EVENT e2 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00';
|
||||
ALTER EVENT e3 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00'
|
||||
ENDS '1999-01-02 00:00:00' ON COMPLETION PRESERVE DISABLE;
|
||||
CREATE EVENT e6 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00' DO
|
||||
SELECT 1;
|
||||
CREATE EVENT e7 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00'
|
||||
ENDS '1999-01-02 00:00:00' ON COMPLETION PRESERVE DISABLE
|
||||
DO
|
||||
SELECT 1;
|
||||
CREATE EVENT e8 ON SCHEDULE AT '1999-01-01 00:00:00'
|
||||
ON COMPLETION PRESERVE DISABLE
|
||||
DO
|
||||
SELECT 1;
|
||||
SHOW EVENTS;
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
mysqltest_db1 e1 root@localhost +00:00 RECURRING NULL 1 HOUR 1999-01-01 00:00:00 1999-01-02 00:00:00 DISABLED
|
||||
mysqltest_db1 e2 root@localhost +00:00 RECURRING NULL 1 HOUR 1999-01-01 00:00:00 NULL ENABLED
|
||||
mysqltest_db1 e3 root@localhost +00:00 RECURRING NULL 1 HOUR 1999-01-01 00:00:00 1999-01-02 00:00:00 DISABLED
|
||||
mysqltest_db1 e4 root@localhost +00:00 RECURRING NULL 1 HOUR 1999-01-01 00:00:00 1999-01-02 00:00:00 DISABLED
|
||||
mysqltest_db1 e5 root@localhost +00:00 ONE TIME 1999-01-01 00:00:00 NULL NULL NULL NULL DISABLED
|
||||
mysqltest_db1 e6 root@localhost +00:00 RECURRING NULL 1 HOUR 1999-01-01 00:00:00 NULL ENABLED
|
||||
mysqltest_db1 e7 root@localhost +00:00 RECURRING NULL 1 HOUR 1999-01-01 00:00:00 1999-01-02 00:00:00 DISABLED
|
||||
mysqltest_db1 e8 root@localhost +00:00 ONE TIME 1999-01-01 00:00:00 NULL NULL NULL NULL DISABLED
|
||||
DROP EVENT e8;
|
||||
DROP EVENT e7;
|
||||
DROP EVENT e6;
|
||||
DROP EVENT e5;
|
||||
DROP EVENT e4;
|
||||
DROP EVENT e3;
|
||||
DROP EVENT e2;
|
||||
DROP EVENT e1;
|
||||
CREATE TABLE t_step (step INT);
|
||||
INSERT INTO t_step VALUES (@step);
|
||||
CREATE FUNCTION round_to_step(i INT, n INT) RETURNS INT
|
||||
BEGIN
|
||||
DECLARE step INT;
|
||||
SELECT * INTO step FROM t_step;
|
||||
# We add 0.1 as a protection from inexact division.
|
||||
RETURN FLOOR((i % (step * n) + 0.1) / step);
|
||||
END//
|
||||
SET @step3= @step * 3;
|
||||
SET @step6= @step * 6;
|
||||
SET @unix_time= @unix_time - @unix_time % @step6;
|
||||
INSERT INTO mysql.time_zone VALUES (NULL, 'N');
|
||||
SET @tzid= LAST_INSERT_ID();
|
||||
INSERT INTO mysql.time_zone_transition_type
|
||||
VALUES (@tzid, 0, 0, 0, 'b16420_0');
|
||||
INSERT INTO mysql.time_zone_transition_type
|
||||
VALUES (@tzid, 1, @step3 - @step, 1, 'b16420_1');
|
||||
INSERT INTO mysql.time_zone_name VALUES ('bug16420', @tzid);
|
||||
CREATE TABLE t1 (count INT, unix_time INT, local_time INT, comment CHAR(80));
|
||||
CREATE TABLE t2 (count INT);
|
||||
INSERT INTO t2 VALUES (1);
|
||||
CREATE FUNCTION f1(comment CHAR(80)) RETURNS INT
|
||||
BEGIN
|
||||
DECLARE orig_tz CHAR(64);
|
||||
DECLARE unix_time INT;
|
||||
DECLARE local_now DATETIME;
|
||||
DECLARE utc_now DATETIME;
|
||||
DECLARE local_time INT;
|
||||
SET unix_time= UNIX_TIMESTAMP();
|
||||
SET local_now= FROM_UNIXTIME(unix_time);
|
||||
SET orig_tz= @@TIME_ZONE;
|
||||
SET TIME_ZONE = '+00:00';
|
||||
SET utc_now= FROM_UNIXTIME(unix_time);
|
||||
SET TIME_ZONE= orig_tz;
|
||||
SET local_time = unix_time + TIMESTAMPDIFF(SECOND, utc_now, local_now);
|
||||
SET unix_time= round_to_step(unix_time, 6);
|
||||
SET local_time= round_to_step(local_time, 6);
|
||||
INSERT INTO t1 VALUES ((SELECT count FROM t2),
|
||||
unix_time, local_time, comment);
|
||||
RETURN 0;
|
||||
END//
|
||||
SET TIME_ZONE= '+00:00';
|
||||
CREATE EVENT e1 ON SCHEDULE EVERY @step SECOND
|
||||
STARTS FROM_UNIXTIME(@unix_time) DO SELECT f1("<e1>");
|
||||
SET TIME_ZONE= 'bug16420';
|
||||
CREATE EVENT e2 ON SCHEDULE EVERY @step SECOND
|
||||
STARTS FROM_UNIXTIME(@unix_time) DO SELECT f1("<e2>");
|
||||
SET GLOBAL EVENT_SCHEDULER= ON;
|
||||
SELECT SLEEP(@step / 2);
|
||||
SLEEP(@step / 2)
|
||||
0
|
||||
SET GLOBAL EVENT_SCHEDULER= OFF;
|
||||
SELECT * FROM t1 ORDER BY count, comment;
|
||||
count unix_time local_time comment
|
||||
1 1 1 <e1>
|
||||
1 1 3 <e2>
|
||||
1 1 3 e2 should be executed
|
||||
2 2 2 <e1>
|
||||
2 2 4 <e2>
|
||||
2 2 4 e2 should be executed
|
||||
3 3 3 <e1>
|
||||
3 3 3 Second pass after backward -2 step shift, e2 should not be executed
|
||||
4 4 4 <e1>
|
||||
4 4 4 Second pass after backward -2 step shift, e2 should not be executed
|
||||
5 5 5 <e1>
|
||||
5 5 5 <e2>
|
||||
5 5 5 e2 should be executed
|
||||
6 0 0 <e1>
|
||||
6 0 2 <e2>
|
||||
6 0 2 Forward +2 step shift, local 0, 1 are skipped, e2 should be executed
|
||||
7 1 1 <e1>
|
||||
7 1 3 <e2>
|
||||
7 1 3 e2 should be executed
|
||||
SET TIME_ZONE= @save_time_zone;
|
||||
DROP EVENT e2;
|
||||
DROP EVENT e1;
|
||||
DROP FUNCTION f1;
|
||||
DROP TABLE t1, t2;
|
||||
DELETE FROM mysql.time_zone_name WHERE time_zone_id = @tzid;
|
||||
DELETE FROM mysql.time_zone_transition_type WHERE time_zone_id = @tzid;
|
||||
DELETE FROM mysql.time_zone_transition WHERE time_zone_id = @tzid;
|
||||
DELETE FROM mysql.time_zone WHERE time_zone_id = @tzid;
|
||||
SET TIME_ZONE= '+00:00';
|
||||
CREATE TABLE t1 (event CHAR(2), dt DATE, offset INT);
|
||||
INSERT INTO mysql.time_zone VALUES (NULL, 'N');
|
||||
SET @tzid= LAST_INSERT_ID();
|
||||
SET @now= UNIX_TIMESTAMP();
|
||||
SET @offset_month_01= UNIX_TIMESTAMP('2030-01-31 12:00:00') - @now;
|
||||
SET @offset_month_02= UNIX_TIMESTAMP('2030-02-28 12:00:00') - @now - 5*@step;
|
||||
SET @offset_month_03= UNIX_TIMESTAMP('2030-03-31 12:00:00') - @now - 5*@step;
|
||||
SET @offset_month_04= UNIX_TIMESTAMP('2030-04-30 12:00:00') - @now - 13*@step;
|
||||
INSERT INTO mysql.time_zone_transition_type
|
||||
VALUES (@tzid, 0, @offset_month_01, 0, 'b16420_0');
|
||||
INSERT INTO mysql.time_zone_transition_type
|
||||
VALUES (@tzid, 1, @offset_month_02, 1, 'b16420_1');
|
||||
INSERT INTO mysql.time_zone_transition_type
|
||||
VALUES (@tzid, 2, @offset_month_03, 1, 'b16420_2');
|
||||
INSERT INTO mysql.time_zone_transition_type
|
||||
VALUES (@tzid, 3, @offset_month_04, 1, 'b16420_3');
|
||||
INSERT INTO mysql.time_zone_transition
|
||||
VALUES (@tzid, @now, 0);
|
||||
INSERT INTO mysql.time_zone_transition
|
||||
VALUES (@tzid, @now + 3 * @step, 1);
|
||||
INSERT INTO mysql.time_zone_transition
|
||||
VALUES (@tzid, @now + 7 * @step, 2);
|
||||
INSERT INTO mysql.time_zone_transition
|
||||
VALUES (@tzid, @now + 12 * @step, 3);
|
||||
INSERT INTO mysql.time_zone_name VALUES ('bug16420_2', @tzid);
|
||||
SET TIME_ZONE= 'bug16420_2';
|
||||
SET GLOBAL EVENT_SCHEDULER= ON;
|
||||
SET GLOBAL EVENT_SCHEDULER= OFF;
|
||||
Below we should see the following:
|
||||
- On Jan 31 only e2 is executed, because we started later than
|
||||
e1 should have been executed. Offset of e2 is 0 because of
|
||||
the late start, not 1.
|
||||
- The next execution is on Feb 28 (last day of Feb). Both events
|
||||
are executed in their times, offsets are -1 and 1.
|
||||
- The next time is Mar 31. Because the time of event
|
||||
execution was skipped over, events are executed right away,
|
||||
offsets are 2 and 2.
|
||||
- The next time is Apr 30. Events are again executed in their
|
||||
appointed times, offsets are -1 and 1.
|
||||
SELECT * FROM t1 ORDER BY dt, event;
|
||||
event dt offset
|
||||
e2 2030-01-31 0
|
||||
e1 2030-02-28 -1
|
||||
e2 2030-02-28 1
|
||||
e1 2030-03-31 2
|
||||
e2 2030-03-31 2
|
||||
e1 2030-04-30 -1
|
||||
e2 2030-04-30 1
|
||||
DROP EVENT e2;
|
||||
DROP EVENT e1;
|
||||
DROP TABLE t1;
|
||||
SET TIME_ZONE= @save_time_zone;
|
||||
DELETE FROM mysql.time_zone_name WHERE time_zone_id = @tzid;
|
||||
DELETE FROM mysql.time_zone_transition_type WHERE time_zone_id = @tzid;
|
||||
DELETE FROM mysql.time_zone_transition WHERE time_zone_id = @tzid;
|
||||
DELETE FROM mysql.time_zone WHERE time_zone_id = @tzid;
|
||||
DROP FUNCTION round_to_step;
|
||||
DROP TABLE t_step;
|
||||
DROP DATABASE mysqltest_db1;
|
||||
End of 5.1 tests.
|
@ -257,3 +257,12 @@ delete from mysql.help_relation where help_keyword_id=@keyword1_id and help_topi
|
||||
delete from mysql.help_relation where help_keyword_id=@keyword2_id and help_topic_id=@topic1_id;
|
||||
delete from mysql.help_relation where help_keyword_id=@keyword3_id and help_topic_id=@topic3_id;
|
||||
delete from mysql.help_relation where help_keyword_id=@keyword3_id and help_topic_id=@topic4_id;
|
||||
End of 4.1 tests.
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1 (i INT);
|
||||
LOCK TABLES t1 WRITE;
|
||||
HELP no_such_topic;
|
||||
name is_it_category
|
||||
UNLOCK TABLES;
|
||||
DROP TABLE t1;
|
||||
End of 5.1 tests.
|
||||
|
@ -68,6 +68,7 @@ ERROR HY000: Table 't2' was locked with a READ lock and can't be updated
|
||||
delete t2 from t1,t2 where t1.a=t2.a;
|
||||
ERROR HY000: Table 't2' was locked with a READ lock and can't be updated
|
||||
drop table t1,t2;
|
||||
End of 4.1 tests.
|
||||
drop table if exists t1;
|
||||
create table t1 (a int);
|
||||
lock table t1 write;
|
||||
@ -75,3 +76,23 @@ flush tables with read lock;
|
||||
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
|
||||
unlock tables;
|
||||
drop table t1;
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1 (i INT);
|
||||
LOCK TABLES mysql.time_zone READ, mysql.proc READ, t1 READ;
|
||||
UNLOCK TABLES;
|
||||
LOCK TABLES mysql.time_zone READ, mysql.proc READ, t1 WRITE;
|
||||
UNLOCK TABLES;
|
||||
LOCK TABLES mysql.time_zone READ, mysql.proc READ;
|
||||
UNLOCK TABLES;
|
||||
LOCK TABLES mysql.time_zone WRITE, mysql.proc WRITE;
|
||||
UNLOCK TABLES;
|
||||
LOCK TABLES mysql.time_zone READ, mysql.proc WRITE, t1 READ;
|
||||
ERROR HY000: You can't combine write-locking of system tables with other tables or lock types
|
||||
LOCK TABLES mysql.time_zone WRITE, mysql.proc WRITE, t1 READ;
|
||||
ERROR HY000: You can't combine write-locking of system tables with other tables or lock types
|
||||
LOCK TABLES mysql.time_zone WRITE, mysql.proc WRITE, t1 WRITE;
|
||||
ERROR HY000: You can't combine write-locking of system tables with other tables or lock types
|
||||
LOCK TABLES mysql.time_zone READ, mysql.proc WRITE;
|
||||
ERROR HY000: You can't combine write-locking of system tables with other tables or lock types
|
||||
DROP TABLE t1;
|
||||
End of 5.1 tests.
|
||||
|
@ -3440,35 +3440,35 @@ use first;
|
||||
set time_zone = 'UTC';
|
||||
create event ee1 on schedule at '2035-12-31 20:01:23' do set @a=5;
|
||||
show events;
|
||||
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
|
||||
first ee1 root@localhost ONE TIME 2035-12-31 20:01:23 NULL NULL NULL NULL ENABLED
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
first ee1 root@localhost UTC ONE TIME 2035-12-31 20:01:23 NULL NULL NULL NULL ENABLED
|
||||
show create event ee1;
|
||||
Event sql_mode Create Event
|
||||
ee1 CREATE EVENT `ee1` ON SCHEDULE AT '2035-12-31 20:01:23' ON COMPLETION NOT PRESERVE ENABLE DO set @a=5
|
||||
Event sql_mode time_zone Create Event
|
||||
ee1 UTC CREATE EVENT `ee1` ON SCHEDULE AT '2035-12-31 20:01:23' ON COMPLETION NOT PRESERVE ENABLE DO set @a=5
|
||||
drop database first;
|
||||
create database second;
|
||||
use second;
|
||||
show events;
|
||||
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
|
||||
second ee1 root@localhost ONE TIME 2035-12-31 20:01:23 NULL NULL NULL NULL ENABLED
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
second ee1 root@localhost UTC ONE TIME 2035-12-31 20:01:23 NULL NULL NULL NULL ENABLED
|
||||
show create event ee1;
|
||||
Event sql_mode Create Event
|
||||
ee1 NO_AUTO_VALUE_ON_ZERO CREATE EVENT `ee1` ON SCHEDULE AT '2035-12-31 20:01:23' ON COMPLETION NOT PRESERVE ENABLE DO set @a=5
|
||||
Event sql_mode time_zone Create Event
|
||||
ee1 NO_AUTO_VALUE_ON_ZERO UTC CREATE EVENT `ee1` ON SCHEDULE AT '2035-12-31 20:01:23' ON COMPLETION NOT PRESERVE ENABLE DO set @a=5
|
||||
create event ee2 on schedule at '2018-12-31 21:01:23' do set @a=5;
|
||||
create event ee3 on schedule at '2030-12-31 22:01:23' do set @a=5;
|
||||
show events;
|
||||
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
|
||||
second ee1 root@localhost ONE TIME 2035-12-31 20:01:23 NULL NULL NULL NULL ENABLED
|
||||
second ee2 root@localhost ONE TIME 2018-12-31 21:01:23 NULL NULL NULL NULL ENABLED
|
||||
second ee3 root@localhost ONE TIME 2030-12-31 22:01:23 NULL NULL NULL NULL ENABLED
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
second ee1 root@localhost UTC ONE TIME 2035-12-31 20:01:23 NULL NULL NULL NULL ENABLED
|
||||
second ee2 root@localhost UTC ONE TIME 2018-12-31 21:01:23 NULL NULL NULL NULL ENABLED
|
||||
second ee3 root@localhost UTC ONE TIME 2030-12-31 22:01:23 NULL NULL NULL NULL ENABLED
|
||||
drop database second;
|
||||
create database third;
|
||||
use third;
|
||||
show events;
|
||||
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
|
||||
third ee1 root@localhost ONE TIME 2035-12-31 20:01:23 NULL NULL NULL NULL ENABLED
|
||||
third ee2 root@localhost ONE TIME 2018-12-31 21:01:23 NULL NULL NULL NULL ENABLED
|
||||
third ee3 root@localhost ONE TIME 2030-12-31 22:01:23 NULL NULL NULL NULL ENABLED
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
third ee1 root@localhost UTC ONE TIME 2035-12-31 20:01:23 NULL NULL NULL NULL ENABLED
|
||||
third ee2 root@localhost UTC ONE TIME 2018-12-31 21:01:23 NULL NULL NULL NULL ENABLED
|
||||
third ee3 root@localhost UTC ONE TIME 2030-12-31 22:01:23 NULL NULL NULL NULL ENABLED
|
||||
drop database third;
|
||||
set time_zone = 'SYSTEM';
|
||||
use test;
|
||||
|
@ -1968,11 +1968,11 @@ prepare abc from "show master logs";
|
||||
deallocate prepare abc;
|
||||
create procedure proc_1() show events;
|
||||
call proc_1();
|
||||
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
call proc_1();
|
||||
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
call proc_1();
|
||||
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
drop procedure proc_1;
|
||||
create function func_1() returns int begin show events; return 1; end|
|
||||
ERROR 0A000: Not allowed to return a result set from a function
|
||||
@ -1982,11 +1982,11 @@ drop function func_1;
|
||||
ERROR 42000: FUNCTION test.func_1 does not exist
|
||||
prepare abc from "show events";
|
||||
execute abc;
|
||||
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
execute abc;
|
||||
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
execute abc;
|
||||
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status
|
||||
deallocate prepare abc;
|
||||
drop procedure if exists a;
|
||||
create procedure a() select 42;
|
||||
@ -2488,3 +2488,40 @@ execute stmt2 using @to_format, @dec;
|
||||
format(?, ?)
|
||||
10,000.00
|
||||
deallocate prepare stmt2;
|
||||
DROP TABLE IF EXISTS t1, t2;
|
||||
CREATE TABLE t1 (i INT);
|
||||
INSERT INTO t1 VALUES (1);
|
||||
CREATE TABLE t2 (i INT);
|
||||
INSERT INTO t2 VALUES (2);
|
||||
LOCK TABLE t1 READ, t2 WRITE;
|
||||
PREPARE stmt1 FROM "SELECT i FROM t1";
|
||||
PREPARE stmt2 FROM "INSERT INTO t2 (i) VALUES (3)";
|
||||
EXECUTE stmt1;
|
||||
i
|
||||
1
|
||||
EXECUTE stmt2;
|
||||
SELECT * FROM t2;
|
||||
i
|
||||
2
|
||||
UNLOCK TABLES;
|
||||
SELECT * FROM t2;
|
||||
i
|
||||
2
|
||||
3
|
||||
ALTER TABLE t1 ADD COLUMN j INT;
|
||||
ALTER TABLE t2 ADD COLUMN j INT;
|
||||
INSERT INTO t1 VALUES (4, 5);
|
||||
INSERT INTO t2 VALUES (4, 5);
|
||||
EXECUTE stmt1;
|
||||
i
|
||||
1
|
||||
4
|
||||
EXECUTE stmt2;
|
||||
SELECT * FROM t2;
|
||||
i j
|
||||
2 NULL
|
||||
3 NULL
|
||||
4 5
|
||||
3 NULL
|
||||
DROP TABLE t1, t2;
|
||||
End of 5.1 tests.
|
||||
|
@ -1325,4 +1325,27 @@ start transaction;
|
||||
insert into t1(c1) select c1 from v1;
|
||||
drop table t1, t2, t3;
|
||||
drop view v1;
|
||||
create table t1(c1 int);
|
||||
insert into t1 values(1),(10),(100);
|
||||
select * from t1;
|
||||
c1
|
||||
1
|
||||
10
|
||||
100
|
||||
select * from t1;
|
||||
c1
|
||||
1
|
||||
10
|
||||
100
|
||||
select * from t1;
|
||||
c1
|
||||
1
|
||||
10
|
||||
100
|
||||
select * from t1;
|
||||
c1
|
||||
1
|
||||
10
|
||||
100
|
||||
drop table t1;
|
||||
set global query_cache_size=0;
|
||||
|
204
mysql-test/r/query_cache_sql_prepare.result
Normal file
204
mysql-test/r/query_cache_sql_prepare.result
Normal file
@ -0,0 +1,204 @@
|
||||
set global query_cache_size=100000;
|
||||
flush status;
|
||||
create table t1(c1 int);
|
||||
insert into t1 values(1),(10),(100);
|
||||
prepare stmt1 from "select * from t1 where c1=10";
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 0
|
||||
execute stmt1;
|
||||
c1
|
||||
10
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 0
|
||||
execute stmt1;
|
||||
c1
|
||||
10
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 1
|
||||
execute stmt1;
|
||||
c1
|
||||
10
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 2
|
||||
prepare stmt2 from "select * from t1 where c1=10";
|
||||
execute stmt2;
|
||||
c1
|
||||
10
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 3
|
||||
execute stmt2;
|
||||
c1
|
||||
10
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 4
|
||||
execute stmt2;
|
||||
c1
|
||||
10
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 5
|
||||
prepare stmt3 from "select * from t1 where c1=10";
|
||||
execute stmt3;
|
||||
c1
|
||||
10
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 6
|
||||
execute stmt3;
|
||||
c1
|
||||
10
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 7
|
||||
execute stmt3;
|
||||
c1
|
||||
10
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 8
|
||||
select * from t1 where c1=10;
|
||||
c1
|
||||
10
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 9
|
||||
flush tables;
|
||||
execute stmt1;
|
||||
c1
|
||||
10
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 9
|
||||
select * from t1 where c1=10;
|
||||
c1
|
||||
10
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 10
|
||||
prepare stmt1 from "select * from t1 where c1=?";
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 10
|
||||
set @a=1;
|
||||
execute stmt1 using @a;
|
||||
c1
|
||||
1
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 10
|
||||
set @a=100;
|
||||
execute stmt1 using @a;
|
||||
c1
|
||||
100
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 10
|
||||
set @a=10;
|
||||
execute stmt1 using @a;
|
||||
c1
|
||||
10
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 10
|
||||
prepare stmt1 from "select * from t1 where c1=10";
|
||||
set global query_cache_size=0;
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 10
|
||||
execute stmt1;
|
||||
c1
|
||||
10
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 10
|
||||
execute stmt1;
|
||||
c1
|
||||
10
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 10
|
||||
execute stmt1;
|
||||
c1
|
||||
10
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 10
|
||||
set global query_cache_size=100000;
|
||||
execute stmt1;
|
||||
c1
|
||||
10
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 10
|
||||
execute stmt1;
|
||||
c1
|
||||
10
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 11
|
||||
execute stmt1;
|
||||
c1
|
||||
10
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 12
|
||||
set global query_cache_size=0;
|
||||
prepare stmt1 from "select * from t1 where c1=10";
|
||||
set global query_cache_size=100000;
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 12
|
||||
execute stmt1;
|
||||
c1
|
||||
10
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 12
|
||||
execute stmt1;
|
||||
c1
|
||||
10
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 12
|
||||
execute stmt1;
|
||||
c1
|
||||
10
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 12
|
||||
set global query_cache_size=0;
|
||||
prepare stmt1 from "select * from t1 where c1=?";
|
||||
set global query_cache_size=100000;
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 12
|
||||
set @a=1;
|
||||
execute stmt1 using @a;
|
||||
c1
|
||||
1
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 12
|
||||
set @a=100;
|
||||
execute stmt1 using @a;
|
||||
c1
|
||||
100
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 12
|
||||
set @a=10;
|
||||
execute stmt1 using @a;
|
||||
c1
|
||||
10
|
||||
show status like 'Qcache_hits';
|
||||
Variable_name Value
|
||||
Qcache_hits 12
|
||||
drop table t1;
|
||||
set global query_cache_size=0;
|
||||
flush status;
|
@ -58,6 +58,8 @@ DROP PROCEDURE p3;
|
||||
DROP FUNCTION f1;
|
||||
DROP FUNCTION f2;
|
||||
DROP FUNCTION f3;
|
||||
set global event_scheduler=1;
|
||||
ERROR HY000: The MySQL server is running with the --event-scheduler=DISABLED or --skip-grant-tables option so it cannot execute this statement
|
||||
select count(*) from information_schema.COLUMN_PRIVILEGES;
|
||||
count(*)
|
||||
0
|
||||
|
@ -292,9 +292,9 @@ call p()|
|
||||
unlock tables|
|
||||
drop procedure p|
|
||||
lock tables t1 read, mysql.proc write|
|
||||
ERROR HY000: You can't combine write-locking of system 'mysql.proc' table with other tables
|
||||
ERROR HY000: You can't combine write-locking of system tables with other tables or lock types
|
||||
lock tables mysql.proc write, mysql.user write|
|
||||
ERROR HY000: You can't combine write-locking of system 'mysql.proc' table with other tables
|
||||
ERROR HY000: You can't combine write-locking of system tables with other tables or lock types
|
||||
lock tables t1 read, mysql.proc read|
|
||||
unlock tables|
|
||||
lock tables mysql.proc write|
|
||||
@ -1414,3 +1414,55 @@ ERROR 42000: This version of MySQL doesn't yet support 'return value collation'
|
||||
create function bug20701() returns varchar(25) return "test";
|
||||
drop function bug20701;
|
||||
End of 5.1 tests
|
||||
create procedure proc_26503_error_1()
|
||||
begin
|
||||
retry:
|
||||
repeat
|
||||
begin
|
||||
declare continue handler for sqlexception
|
||||
begin
|
||||
iterate retry;
|
||||
end
|
||||
select "do something";
|
||||
end
|
||||
until true end repeat retry;
|
||||
end//
|
||||
ERROR 42000: ITERATE with no matching label: retry
|
||||
create procedure proc_26503_error_2()
|
||||
begin
|
||||
retry:
|
||||
repeat
|
||||
begin
|
||||
declare continue handler for sqlexception
|
||||
iterate retry;
|
||||
select "do something";
|
||||
end
|
||||
until true end repeat retry;
|
||||
end//
|
||||
ERROR 42000: ITERATE with no matching label: retry
|
||||
create procedure proc_26503_error_3()
|
||||
begin
|
||||
retry:
|
||||
repeat
|
||||
begin
|
||||
declare continue handler for sqlexception
|
||||
begin
|
||||
leave retry;
|
||||
end
|
||||
select "do something";
|
||||
end
|
||||
until true end repeat retry;
|
||||
end//
|
||||
ERROR 42000: LEAVE with no matching label: retry
|
||||
create procedure proc_26503_error_4()
|
||||
begin
|
||||
retry:
|
||||
repeat
|
||||
begin
|
||||
declare continue handler for sqlexception
|
||||
leave retry;
|
||||
select "do something";
|
||||
end
|
||||
until true end repeat retry;
|
||||
end//
|
||||
ERROR 42000: LEAVE with no matching label: retry
|
||||
|
@ -5617,6 +5617,32 @@ Called B
|
||||
Called B
|
||||
drop procedure proc_21462_a|
|
||||
drop procedure proc_21462_b|
|
||||
DROP PROCEDURE IF EXISTS p1|
|
||||
DROP VIEW IF EXISTS v1, v2|
|
||||
DROP TABLE IF EXISTS t3, t4|
|
||||
CREATE TABLE t3 (t3_id INT)|
|
||||
INSERT INTO t3 VALUES (0)|
|
||||
INSERT INTO t3 VALUES (1)|
|
||||
CREATE TABLE t4 (t4_id INT)|
|
||||
INSERT INTO t4 VALUES (2)|
|
||||
CREATE VIEW v1 AS
|
||||
SELECT t3.t3_id, t4.t4_id
|
||||
FROM t3 JOIN t4 ON t3.t3_id = 0|
|
||||
CREATE VIEW v2 AS
|
||||
SELECT t3.t3_id AS t3_id_1, v1.t3_id AS t3_id_2, v1.t4_id
|
||||
FROM t3 LEFT JOIN v1 ON t3.t3_id = 0|
|
||||
CREATE PROCEDURE p1() SELECT * FROM v2|
|
||||
CALL p1()|
|
||||
t3_id_1 t3_id_2 t4_id
|
||||
0 0 2
|
||||
1 NULL NULL
|
||||
CALL p1()|
|
||||
t3_id_1 t3_id_2 t4_id
|
||||
0 0 2
|
||||
1 NULL NULL
|
||||
DROP PROCEDURE p1|
|
||||
DROP VIEW v1, v2|
|
||||
DROP TABLE t3, t4|
|
||||
End of 5.0 tests
|
||||
Begin of 5.1 tests
|
||||
drop function if exists pi;
|
||||
@ -5857,6 +5883,171 @@ func_8407_b()
|
||||
1500
|
||||
drop function func_8407_a|
|
||||
drop function func_8407_b|
|
||||
drop table if exists table_26503|
|
||||
drop procedure if exists proc_26503_ok_1|
|
||||
drop procedure if exists proc_26503_ok_2|
|
||||
drop procedure if exists proc_26503_ok_3|
|
||||
drop procedure if exists proc_26503_ok_4|
|
||||
create table table_26503(a int unique)|
|
||||
create procedure proc_26503_ok_1(v int)
|
||||
begin
|
||||
declare i int default 5;
|
||||
declare continue handler for sqlexception
|
||||
begin
|
||||
select 'caught something';
|
||||
retry:
|
||||
while i > 0 do
|
||||
begin
|
||||
set i = i - 1;
|
||||
select 'looping', i;
|
||||
iterate retry;
|
||||
select 'dead code';
|
||||
end;
|
||||
end while retry;
|
||||
select 'leaving handler';
|
||||
end;
|
||||
select 'do something';
|
||||
insert into table_26503 values (v);
|
||||
select 'do something again';
|
||||
insert into table_26503 values (v);
|
||||
end|
|
||||
create procedure proc_26503_ok_2(v int)
|
||||
begin
|
||||
declare i int default 5;
|
||||
declare continue handler for sqlexception
|
||||
begin
|
||||
select 'caught something';
|
||||
retry:
|
||||
while i > 0 do
|
||||
begin
|
||||
set i = i - 1;
|
||||
select 'looping', i;
|
||||
leave retry;
|
||||
select 'dead code';
|
||||
end;
|
||||
end while;
|
||||
select 'leaving handler';
|
||||
end;
|
||||
select 'do something';
|
||||
insert into table_26503 values (v);
|
||||
select 'do something again';
|
||||
insert into table_26503 values (v);
|
||||
end|
|
||||
create procedure proc_26503_ok_3(v int)
|
||||
begin
|
||||
declare i int default 5;
|
||||
retry:
|
||||
begin
|
||||
declare continue handler for sqlexception
|
||||
begin
|
||||
select 'caught something';
|
||||
retry:
|
||||
while i > 0 do
|
||||
begin
|
||||
set i = i - 1;
|
||||
select 'looping', i;
|
||||
iterate retry;
|
||||
select 'dead code';
|
||||
end;
|
||||
end while retry;
|
||||
select 'leaving handler';
|
||||
end;
|
||||
select 'do something';
|
||||
insert into table_26503 values (v);
|
||||
select 'do something again';
|
||||
insert into table_26503 values (v);
|
||||
end;
|
||||
end|
|
||||
create procedure proc_26503_ok_4(v int)
|
||||
begin
|
||||
declare i int default 5;
|
||||
retry:
|
||||
begin
|
||||
declare continue handler for sqlexception
|
||||
begin
|
||||
select 'caught something';
|
||||
retry:
|
||||
while i > 0 do
|
||||
begin
|
||||
set i = i - 1;
|
||||
select 'looping', i;
|
||||
leave retry;
|
||||
select 'dead code';
|
||||
end;
|
||||
end while;
|
||||
select 'leaving handler';
|
||||
end;
|
||||
select 'do something';
|
||||
insert into table_26503 values (v);
|
||||
select 'do something again';
|
||||
insert into table_26503 values (v);
|
||||
end;
|
||||
end|
|
||||
call proc_26503_ok_1(1)|
|
||||
do something
|
||||
do something
|
||||
do something again
|
||||
do something again
|
||||
caught something
|
||||
caught something
|
||||
looping i
|
||||
looping 4
|
||||
looping i
|
||||
looping 3
|
||||
looping i
|
||||
looping 2
|
||||
looping i
|
||||
looping 1
|
||||
looping i
|
||||
looping 0
|
||||
leaving handler
|
||||
leaving handler
|
||||
call proc_26503_ok_2(2)|
|
||||
do something
|
||||
do something
|
||||
do something again
|
||||
do something again
|
||||
caught something
|
||||
caught something
|
||||
looping i
|
||||
looping 4
|
||||
leaving handler
|
||||
leaving handler
|
||||
call proc_26503_ok_3(3)|
|
||||
do something
|
||||
do something
|
||||
do something again
|
||||
do something again
|
||||
caught something
|
||||
caught something
|
||||
looping i
|
||||
looping 4
|
||||
looping i
|
||||
looping 3
|
||||
looping i
|
||||
looping 2
|
||||
looping i
|
||||
looping 1
|
||||
looping i
|
||||
looping 0
|
||||
leaving handler
|
||||
leaving handler
|
||||
call proc_26503_ok_4(4)|
|
||||
do something
|
||||
do something
|
||||
do something again
|
||||
do something again
|
||||
caught something
|
||||
caught something
|
||||
looping i
|
||||
looping 4
|
||||
leaving handler
|
||||
leaving handler
|
||||
drop table table_26503|
|
||||
drop procedure proc_26503_ok_1|
|
||||
drop procedure proc_26503_ok_2|
|
||||
drop procedure proc_26503_ok_3|
|
||||
drop procedure proc_26503_ok_4|
|
||||
DROP FUNCTION IF EXISTS bug25373|
|
||||
CREATE FUNCTION bug25373(p1 INTEGER) RETURNS INTEGER
|
||||
LANGUAGE SQL DETERMINISTIC
|
||||
|
@ -224,6 +224,7 @@ event CREATE TABLE `event` (
|
||||
`on_completion` enum('DROP','PRESERVE') NOT NULL DEFAULT 'DROP',
|
||||
`sql_mode` set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION','NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB','NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40','ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER','HIGH_NOT_PRECEDENCE') NOT NULL DEFAULT '',
|
||||
`comment` char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '',
|
||||
`time_zone` char(64) CHARACTER SET latin1 NOT NULL DEFAULT 'SYSTEM',
|
||||
PRIMARY KEY (`db`,`name`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Events'
|
||||
show create table general_log;
|
||||
|
@ -285,3 +285,14 @@ ldt ldt2
|
||||
drop table t1;
|
||||
drop function f1;
|
||||
SET GLOBAL log_bin_trust_function_creators = 0;
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1 (t TIMESTAMP);
|
||||
INSERT INTO t1 VALUES (NULL), (NULL);
|
||||
LOCK TABLES t1 WRITE;
|
||||
SELECT CONVERT_TZ(NOW(), 'UTC', 'Europe/Moscow') IS NULL;
|
||||
CONVERT_TZ(NOW(), 'UTC', 'Europe/Moscow') IS NULL
|
||||
0
|
||||
UPDATE t1 SET t = CONVERT_TZ(t, 'UTC', 'Europe/Moscow');
|
||||
UNLOCK TABLES;
|
||||
DROP TABLE t1;
|
||||
End of 5.1 tests
|
||||
|
@ -900,6 +900,7 @@ drop view v1;
|
||||
drop table t1;
|
||||
create table t1 (col1 int);
|
||||
create table t2 (col1 int);
|
||||
create table t3 (col1 datetime not null);
|
||||
create view v1 as select * from t1;
|
||||
create view v2 as select * from v1;
|
||||
create view v3 as select v2.col1 from v2,t2 where v2.col1 = t2.col1;
|
||||
@ -1004,8 +1005,8 @@ ERROR HY000: The definition of table 'v2' prevents operation INSERT on table 'v3
|
||||
insert into v3 (col1) values ((select CONVERT_TZ('20050101000000','UTC','MET') from v2));
|
||||
ERROR HY000: The definition of table 'v2' prevents operation INSERT on table 'v3'.
|
||||
insert into v3 (col1) values ((select CONVERT_TZ('20050101000000','UTC','MET') from t2));
|
||||
insert into mysql.time_zone values ('', (select CONVERT_TZ('20050101000000','UTC','MET') from t2));
|
||||
ERROR 23000: Column 'Use_leap_seconds' cannot be null
|
||||
insert into t3 values ((select CONVERT_TZ('20050101000000','UTC','MET') from t2));
|
||||
ERROR 23000: Column 'col1' cannot be null
|
||||
create algorithm=temptable view v4 as select * from t1;
|
||||
insert into t1 values (1),(2),(3);
|
||||
insert into t1 (col1) values ((select max(col1) from v4));
|
||||
@ -1017,7 +1018,7 @@ NULL
|
||||
3
|
||||
3
|
||||
drop view v4,v3,v2,v1;
|
||||
drop table t1,t2;
|
||||
drop table t1,t2,t3;
|
||||
create table t1 (s1 int);
|
||||
create view v1 as select * from t1;
|
||||
handler v1 open as xx;
|
||||
@ -3320,3 +3321,38 @@ DROP TABLE `t-2`;
|
||||
DROP VIEW `v-2`;
|
||||
DROP DATABASE `d-1`;
|
||||
USE test;
|
||||
DROP VIEW IF EXISTS v1;
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1 (i INT);
|
||||
CREATE VIEW v1 AS SELECT * FROM t1;
|
||||
ALTER VIEW v1 AS SELECT * FROM t1;
|
||||
SHOW CREATE VIEW v1;
|
||||
View Create View
|
||||
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i` from `t1`
|
||||
ALTER DEFINER=no_such@user_1 VIEW v1 AS SELECT * FROM t1;
|
||||
Warnings:
|
||||
Note 1449 There is no 'no_such'@'user_1' registered
|
||||
SHOW CREATE VIEW v1;
|
||||
View Create View
|
||||
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`no_such`@`user_1` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i` from `t1`
|
||||
Warnings:
|
||||
Note 1449 There is no 'no_such'@'user_1' registered
|
||||
ALTER ALGORITHM=MERGE VIEW v1 AS SELECT * FROM t1;
|
||||
Warnings:
|
||||
Note 1449 There is no 'no_such'@'user_1' registered
|
||||
SHOW CREATE VIEW v1;
|
||||
View Create View
|
||||
v1 CREATE ALGORITHM=MERGE DEFINER=`no_such`@`user_1` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i` from `t1`
|
||||
Warnings:
|
||||
Note 1449 There is no 'no_such'@'user_1' registered
|
||||
ALTER ALGORITHM=TEMPTABLE DEFINER=no_such@user_2 VIEW v1 AS SELECT * FROM t1;
|
||||
Warnings:
|
||||
Note 1449 There is no 'no_such'@'user_2' registered
|
||||
SHOW CREATE VIEW v1;
|
||||
View Create View
|
||||
v1 CREATE ALGORITHM=TEMPTABLE DEFINER=`no_such`@`user_2` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i` from `t1`
|
||||
Warnings:
|
||||
Note 1449 There is no 'no_such'@'user_2' registered
|
||||
DROP VIEW v1;
|
||||
DROP TABLE t1;
|
||||
End of 5.1 tests.
|
||||
|
@ -122,43 +122,62 @@ set names utf8;
|
||||
# SHOW CREATE EVENT test begin
|
||||
#
|
||||
CREATE EVENT root6 ON SCHEDULE EVERY '10:20' MINUTE_SECOND ON COMPLETION PRESERVE ENABLE COMMENT 'some comment' DO select 1;
|
||||
--replace_regex /STARTS '[^']+'/STARTS '#'/
|
||||
SHOW CREATE EVENT root6;
|
||||
create event root7 on schedule every 2 year do select 1;
|
||||
--replace_regex /STARTS '[^']+'/STARTS '#'/
|
||||
SHOW CREATE EVENT root7;
|
||||
create event root8 on schedule every '2:5' year_month do select 1;
|
||||
--replace_regex /STARTS '[^']+'/STARTS '#'/
|
||||
SHOW CREATE EVENT root8;
|
||||
create event root8_1 on schedule every '2:15' year_month do select 1;
|
||||
--replace_regex /STARTS '[^']+'/STARTS '#'/
|
||||
SHOW CREATE EVENT root8_1;
|
||||
create event root9 on schedule every 2 week ON COMPLETION PRESERVE DISABLE COMMENT 'коментар на кирилица' do select 1;
|
||||
--replace_regex /STARTS '[^']+'/STARTS '#'/
|
||||
SHOW CREATE EVENT root9;
|
||||
create event root10 on schedule every '20:5' day_hour do select 1;
|
||||
--replace_regex /STARTS '[^']+'/STARTS '#'/
|
||||
SHOW CREATE EVENT root10;
|
||||
create event root11 on schedule every '20:25' day_hour do select 1;
|
||||
--replace_regex /STARTS '[^']+'/STARTS '#'/
|
||||
SHOW CREATE EVENT root11;
|
||||
create event root12 on schedule every '20:25' hour_minute do select 1;
|
||||
--replace_regex /STARTS '[^']+'/STARTS '#'/
|
||||
SHOW CREATE EVENT root12;
|
||||
create event root13 on schedule every '25:25' hour_minute do select 1;
|
||||
--replace_regex /STARTS '[^']+'/STARTS '#'/
|
||||
SHOW CREATE EVENT root13;
|
||||
create event root13_1 on schedule every '11:65' hour_minute do select 1;
|
||||
--replace_regex /STARTS '[^']+'/STARTS '#'/
|
||||
SHOW CREATE EVENT root13_1;
|
||||
create event root14 on schedule every '35:35' minute_second do select 1;
|
||||
--replace_regex /STARTS '[^']+'/STARTS '#'/
|
||||
SHOW CREATE EVENT root14;
|
||||
create event root15 on schedule every '35:66' minute_second do select 1;
|
||||
--replace_regex /STARTS '[^']+'/STARTS '#'/
|
||||
SHOW CREATE EVENT root15;
|
||||
create event root16 on schedule every '35:56' day_minute do select 1;
|
||||
--replace_regex /STARTS '[^']+'/STARTS '#'/
|
||||
SHOW CREATE EVENT root16;
|
||||
create event root17 on schedule every '35:12:45' day_minute do select 1;
|
||||
--replace_regex /STARTS '[^']+'/STARTS '#'/
|
||||
SHOW CREATE EVENT root17;
|
||||
create event root17_1 on schedule every '35:25:65' day_minute do select 1;
|
||||
--replace_regex /STARTS '[^']+'/STARTS '#'/
|
||||
SHOW CREATE EVENT root17_1;
|
||||
create event root18 on schedule every '35:12:45' hour_second do select 1;
|
||||
--replace_regex /STARTS '[^']+'/STARTS '#'/
|
||||
SHOW CREATE EVENT root18;
|
||||
create event root19 on schedule every '15:59:85' hour_second do select 1;
|
||||
--replace_regex /STARTS '[^']+'/STARTS '#'/
|
||||
SHOW CREATE EVENT root19;
|
||||
create event root20 on schedule every '50:20:12:45' day_second do select 1;
|
||||
--replace_regex /STARTS '[^']+'/STARTS '#'/
|
||||
SHOW CREATE EVENT root20;
|
||||
set names cp1251;
|
||||
create event ðóóò21 on schedule every '50:23:59:95' day_second COMMENT 'òîâà å 1251 êîìåíòàð' do select 1;
|
||||
--replace_regex /STARTS '[^']+'/STARTS '#'/
|
||||
SHOW CREATE EVENT ðóóò21;
|
||||
insert into mysql.event (db, name, body, definer, interval_value, interval_field) values (database(), "root22", "select 1", user(), 100, "SECOND_MICROSECOND");
|
||||
--error ER_NOT_SUPPORTED_YET
|
||||
|
@ -45,10 +45,17 @@ create event e_55 on schedule at 99990101000000 do drop table t;
|
||||
create event e_55 on schedule every 10 hour starts 99990101000000 do drop table t;
|
||||
--error ER_EVENT_ENDS_BEFORE_STARTS
|
||||
create event e_55 on schedule every 10 minute ends 99990101000000 do drop table t;
|
||||
--error ER_EVENT_EXEC_TIME_IN_THE_PAST
|
||||
--error ER_WRONG_VALUE
|
||||
create event e_55 on schedule at 10000101000000 do drop table t;
|
||||
--error ER_EVENT_EXEC_TIME_IN_THE_PAST
|
||||
|
||||
# For the purpose of backup we allow times in the past. Here, no
|
||||
# error will be given, but the event won't be created. One may think
|
||||
# of that as if the event was created, then it turned out it's in the
|
||||
# past, so it was dropped because of implicit ON COMPLETION NOT
|
||||
# PRESERVE.
|
||||
create event e_55 on schedule at 20000101000000 do drop table t;
|
||||
show events;
|
||||
|
||||
--error ER_PARSE_ERROR
|
||||
create event e_55 on schedule at 20200101000000 starts 10000101000000 do drop table t;
|
||||
--error ER_PARSE_ERROR
|
||||
|
@ -14,6 +14,6 @@ create event abc3 on schedule every 1 second do insert into execution_log value(
|
||||
--sleep 1.5
|
||||
select name from execution_log;
|
||||
|
||||
insert into mysql.event values ('db1','bad','select 42','root@localhost',NULL,1000,'MICROSECOND','2006-05-05 17:39:11','2006-05-05 17:39:20','2016-05-05 15:39:24','2016-05-05 15:39:11',NULL,'ENABLED','DROP','','comment1');
|
||||
insert into mysql.event values ('db1','bad2','sect','root@localhost',NULL,1000,'SECOND','2006-05-05 17:39:11','2006-05-05 17:39:20','2016-05-05 15:39:24','2016-05-05 15:39:11',NULL,'ENABLED','DROP','','comment2');
|
||||
insert into mysql.event values ('db1','bad','select 42','root@localhost',NULL,1000,'MICROSECOND','2006-05-05 17:39:11','2006-05-05 17:39:20','2016-05-05 15:39:24','2016-05-05 15:39:11',NULL,'ENABLED','DROP','','comment1','SYSTEM');
|
||||
insert into mysql.event values ('db1','bad2','sect','root@localhost',NULL,1000,'SECOND','2006-05-05 17:39:11','2006-05-05 17:39:20','2016-05-05 15:39:24','2016-05-05 15:39:11',NULL,'ENABLED','DROP','','comment2','SYSTEM');
|
||||
--echo "Now we restart the server"
|
||||
|
463
mysql-test/t/events_time_zone.test
Normal file
463
mysql-test/t/events_time_zone.test
Normal file
@ -0,0 +1,463 @@
|
||||
# This test case is sensitive to execution timing. You may control
|
||||
# this sensitivity by the parameter below. Small values will result
|
||||
# in fast but more unstable execution, large values will improve
|
||||
# stability at the cost of speed. Basically, N is a number of seconds
|
||||
# to wait for operation to complete. Should be positive. Test runs
|
||||
# about 25*N seconds (it sleeps most of the time, so CPU speed is not
|
||||
# relevant).
|
||||
let $N = 5;
|
||||
|
||||
--source include/big_test.inc
|
||||
|
||||
|
||||
--disable_warnings
|
||||
DROP DATABASE IF EXISTS mysqltest_db1;
|
||||
--enable_warnings
|
||||
|
||||
CREATE DATABASE mysqltest_db1;
|
||||
|
||||
let $old_db= `SELECT DATABASE()`;
|
||||
USE mysqltest_db1;
|
||||
|
||||
SET GLOBAL EVENT_SCHEDULER= OFF;
|
||||
|
||||
|
||||
#
|
||||
# BUG#16420: Events: timestamps become UTC
|
||||
# BUG#26429: SHOW CREATE EVENT is incorrect for an event that
|
||||
# STARTS NOW()
|
||||
# BUG#26431: Impossible to re-create an event from backup if its
|
||||
# STARTS clause is in the past
|
||||
# WL#3698: Events: execution in local time zone
|
||||
#
|
||||
|
||||
SET @save_time_zone= @@TIME_ZONE;
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
# We will use a separate connection because SET TIMESTAMP will stop
|
||||
# the clock in that connection.
|
||||
|
||||
connect (conn1, localhost, root, , mysqltest_db1);
|
||||
|
||||
SET TIME_ZONE= '+00:00';
|
||||
SET TIMESTAMP= UNIX_TIMESTAMP('2005-12-31 23:58:59');
|
||||
|
||||
|
||||
# Test when event time zone is updated on ALTER EVENT.
|
||||
#
|
||||
|
||||
CREATE EVENT e1 ON SCHEDULE EVERY 1 DAY DO SELECT 1;
|
||||
SHOW EVENTS;
|
||||
|
||||
# Test storing and updating of the event time zone.
|
||||
#
|
||||
SET TIME_ZONE= '-01:00';
|
||||
ALTER EVENT e1 ON SCHEDULE EVERY 1 DAY STARTS '2000-01-01 00:00:00';
|
||||
SHOW EVENTS;
|
||||
|
||||
# This will update event time zone.
|
||||
SET TIME_ZONE= '+02:00';
|
||||
ALTER EVENT e1 ON SCHEDULE AT '2000-01-02 00:00:00'
|
||||
ON COMPLETION PRESERVE DISABLE;
|
||||
SHOW EVENTS;
|
||||
|
||||
# This will update event time zone.
|
||||
SET TIME_ZONE= '-03:00';
|
||||
ALTER EVENT e1 ON SCHEDULE EVERY 1 DAY ENDS '2030-01-03 00:00:00'
|
||||
ON COMPLETION PRESERVE DISABLE;
|
||||
SHOW EVENTS;
|
||||
|
||||
# This will not update event time zone, as no time is being adjusted.
|
||||
SET TIME_ZONE= '+04:00';
|
||||
ALTER EVENT e1 DO SELECT 2;
|
||||
SHOW EVENTS;
|
||||
|
||||
DROP EVENT e1;
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
# Create some events.
|
||||
SET TIME_ZONE='+05:00';
|
||||
CREATE EVENT e1 ON SCHEDULE EVERY 1 DAY STARTS '2006-01-01 00:00:00' DO
|
||||
SELECT 1;
|
||||
|
||||
SET TIMESTAMP= @@TIMESTAMP + 1;
|
||||
|
||||
SET TIME_ZONE='-05:00';
|
||||
CREATE EVENT e2 ON SCHEDULE EVERY 1 DAY STARTS '2006-01-01 00:00:00' DO
|
||||
SELECT 1;
|
||||
|
||||
SET TIMESTAMP= @@TIMESTAMP + 1;
|
||||
|
||||
SET TIME_ZONE='+00:00';
|
||||
CREATE EVENT e3 ON SCHEDULE EVERY 1 DAY STARTS '2006-01-01 00:00:00' DO
|
||||
SELECT 1;
|
||||
|
||||
|
||||
# Test INFORMATION_SCHEMA.EVENTS.
|
||||
#
|
||||
|
||||
SELECT * FROM INFORMATION_SCHEMA.EVENTS;
|
||||
|
||||
|
||||
# Test SHOW EVENTS.
|
||||
#
|
||||
|
||||
SHOW EVENTS;
|
||||
|
||||
|
||||
# Test SHOW CREATE EVENT.
|
||||
#
|
||||
|
||||
SHOW CREATE EVENT e1;
|
||||
SHOW CREATE EVENT e2;
|
||||
SHOW CREATE EVENT e3;
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
# Test times in the past.
|
||||
#
|
||||
|
||||
--echo The following should fail, and nothing should be altered.
|
||||
|
||||
--error ER_EVENT_CANNOT_ALTER_IN_THE_PAST
|
||||
ALTER EVENT e1 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00'
|
||||
ENDS '1999-01-02 00:00:00';
|
||||
|
||||
--error ER_EVENT_CANNOT_ALTER_IN_THE_PAST
|
||||
ALTER EVENT e1 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00'
|
||||
ENDS '1999-01-02 00:00:00' DISABLE;
|
||||
|
||||
--echo The following should give warnings, and nothing should be created.
|
||||
|
||||
CREATE EVENT e4 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00'
|
||||
ENDS '1999-01-02 00:00:00'
|
||||
DO
|
||||
SELECT 1;
|
||||
|
||||
CREATE EVENT e4 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00'
|
||||
ENDS '1999-01-02 00:00:00' DISABLE
|
||||
DO
|
||||
SELECT 1;
|
||||
|
||||
CREATE EVENT e4 ON SCHEDULE AT '1999-01-01 00:00:00' DO
|
||||
SELECT 1;
|
||||
|
||||
CREATE EVENT e4 ON SCHEDULE AT '1999-01-01 00:00:00' DISABLE
|
||||
DO
|
||||
SELECT 1;
|
||||
|
||||
SHOW EVENTS;
|
||||
|
||||
--echo The following should succeed giving a warning.
|
||||
|
||||
ALTER EVENT e1 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00'
|
||||
ENDS '1999-01-02 00:00:00' ON COMPLETION PRESERVE;
|
||||
|
||||
CREATE EVENT e4 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00'
|
||||
ENDS '1999-01-02 00:00:00' ON COMPLETION PRESERVE
|
||||
DO
|
||||
SELECT 1;
|
||||
|
||||
CREATE EVENT e5 ON SCHEDULE AT '1999-01-01 00:00:00'
|
||||
ON COMPLETION PRESERVE
|
||||
DO
|
||||
SELECT 1;
|
||||
|
||||
--echo The following should succeed without warnings.
|
||||
|
||||
ALTER EVENT e2 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00';
|
||||
|
||||
ALTER EVENT e3 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00'
|
||||
ENDS '1999-01-02 00:00:00' ON COMPLETION PRESERVE DISABLE;
|
||||
|
||||
CREATE EVENT e6 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00' DO
|
||||
SELECT 1;
|
||||
|
||||
CREATE EVENT e7 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00'
|
||||
ENDS '1999-01-02 00:00:00' ON COMPLETION PRESERVE DISABLE
|
||||
DO
|
||||
SELECT 1;
|
||||
|
||||
CREATE EVENT e8 ON SCHEDULE AT '1999-01-01 00:00:00'
|
||||
ON COMPLETION PRESERVE DISABLE
|
||||
DO
|
||||
SELECT 1;
|
||||
|
||||
SHOW EVENTS;
|
||||
|
||||
|
||||
DROP EVENT e8;
|
||||
DROP EVENT e7;
|
||||
DROP EVENT e6;
|
||||
DROP EVENT e5;
|
||||
DROP EVENT e4;
|
||||
DROP EVENT e3;
|
||||
DROP EVENT e2;
|
||||
DROP EVENT e1;
|
||||
|
||||
|
||||
disconnect conn1;
|
||||
connection default;
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
# Create rounding function.
|
||||
|
||||
# Disable query log to hide actual value of $N.
|
||||
--disable_query_log
|
||||
eval SET @step= $N;
|
||||
--enable_query_log
|
||||
|
||||
# Since we are working in a separate database, we may use any names we
|
||||
# like.
|
||||
CREATE TABLE t_step (step INT);
|
||||
INSERT INTO t_step VALUES (@step);
|
||||
|
||||
# We can't use @variables in function, because it will be called from
|
||||
# the event thread, and 'eval' doesn't work for multi-statements, so
|
||||
# we can't interpolate $variables either, hence we fetch the step
|
||||
# value from the table.
|
||||
delimiter //;
|
||||
CREATE FUNCTION round_to_step(i INT, n INT) RETURNS INT
|
||||
BEGIN
|
||||
DECLARE step INT;
|
||||
|
||||
SELECT * INTO step FROM t_step;
|
||||
|
||||
# We add 0.1 as a protection from inexact division.
|
||||
RETURN FLOOR((i % (step * n) + 0.1) / step);
|
||||
END//
|
||||
delimiter ;//
|
||||
|
||||
|
||||
# Test time computations wrt Daylight Saving Time shifts. We also
|
||||
# test here that the event operates in its time zone (see what NOW()
|
||||
# returns).
|
||||
#
|
||||
|
||||
# Create a fake time zone with time transitions every 3*$N second.
|
||||
|
||||
SET @step3= @step * 3;
|
||||
SET @step6= @step * 6;
|
||||
|
||||
# Disable query log to hide current time.
|
||||
--disable_query_log
|
||||
SET @unix_time= UNIX_TIMESTAMP() - 1;
|
||||
--enable_query_log
|
||||
|
||||
SET @unix_time= @unix_time - @unix_time % @step6;
|
||||
|
||||
INSERT INTO mysql.time_zone VALUES (NULL, 'N');
|
||||
SET @tzid= LAST_INSERT_ID();
|
||||
INSERT INTO mysql.time_zone_transition_type
|
||||
VALUES (@tzid, 0, 0, 0, 'b16420_0');
|
||||
INSERT INTO mysql.time_zone_transition_type
|
||||
VALUES (@tzid, 1, @step3 - @step, 1, 'b16420_1');
|
||||
|
||||
let $transition_unix_time= `SELECT @unix_time`;
|
||||
let $count= 30;
|
||||
--disable_query_log
|
||||
while ($count)
|
||||
{
|
||||
eval INSERT INTO mysql.time_zone_transition
|
||||
VALUES (@tzid, $transition_unix_time,
|
||||
$transition_unix_time % @step6 = 0);
|
||||
let $transition_unix_time= `SELECT $transition_unix_time + @step3`;
|
||||
dec $count;
|
||||
}
|
||||
--enable_query_log
|
||||
INSERT INTO mysql.time_zone_name VALUES ('bug16420', @tzid);
|
||||
|
||||
CREATE TABLE t1 (count INT, unix_time INT, local_time INT, comment CHAR(80));
|
||||
CREATE TABLE t2 (count INT);
|
||||
INSERT INTO t2 VALUES (1);
|
||||
|
||||
delimiter //;
|
||||
CREATE FUNCTION f1(comment CHAR(80)) RETURNS INT
|
||||
BEGIN
|
||||
DECLARE orig_tz CHAR(64);
|
||||
DECLARE unix_time INT;
|
||||
DECLARE local_now DATETIME;
|
||||
DECLARE utc_now DATETIME;
|
||||
DECLARE local_time INT;
|
||||
|
||||
SET unix_time= UNIX_TIMESTAMP();
|
||||
SET local_now= FROM_UNIXTIME(unix_time);
|
||||
SET orig_tz= @@TIME_ZONE;
|
||||
SET TIME_ZONE = '+00:00';
|
||||
SET utc_now= FROM_UNIXTIME(unix_time);
|
||||
SET TIME_ZONE= orig_tz;
|
||||
SET local_time = unix_time + TIMESTAMPDIFF(SECOND, utc_now, local_now);
|
||||
|
||||
SET unix_time= round_to_step(unix_time, 6);
|
||||
SET local_time= round_to_step(local_time, 6);
|
||||
|
||||
INSERT INTO t1 VALUES ((SELECT count FROM t2),
|
||||
unix_time, local_time, comment);
|
||||
RETURN 0;
|
||||
END//
|
||||
delimiter ;//
|
||||
|
||||
SET TIME_ZONE= '+00:00';
|
||||
CREATE EVENT e1 ON SCHEDULE EVERY @step SECOND
|
||||
STARTS FROM_UNIXTIME(@unix_time) DO SELECT f1("<e1>");
|
||||
|
||||
SET TIME_ZONE= 'bug16420';
|
||||
CREATE EVENT e2 ON SCHEDULE EVERY @step SECOND
|
||||
STARTS FROM_UNIXTIME(@unix_time) DO SELECT f1("<e2>");
|
||||
|
||||
# We want to start at the beginning of the DST cycle, so we wait
|
||||
# untill current time divides by @step6.
|
||||
let $wait_timeout= `SELECT @step6 + 1`;
|
||||
let $wait_condition= SELECT UNIX_TIMESTAMP() % @step6 = @step6 - 1;
|
||||
--source include/wait_condition.inc
|
||||
# The second wait is needed because after the first wait we may end up
|
||||
# on the ending edge of a second. Second wait will bring us to the
|
||||
# beginning edge.
|
||||
let $wait_timeout= `SELECT @step + 1`;
|
||||
let $wait_condition= SELECT UNIX_TIMESTAMP() % @step6 = 0;
|
||||
--source include/wait_condition.inc
|
||||
|
||||
# Note that after the scheduler is enabled, the event will be
|
||||
# scheduled only for the next second.
|
||||
SET GLOBAL EVENT_SCHEDULER= ON;
|
||||
|
||||
# We want to run after the events are executed.
|
||||
SELECT SLEEP(@step / 2);
|
||||
|
||||
let $count= 7;
|
||||
--disable_query_log
|
||||
--disable_result_log
|
||||
while ($count)
|
||||
{
|
||||
SELECT SLEEP(@step);
|
||||
|
||||
eval SELECT CASE $count
|
||||
WHEN 5 THEN f1(CONCAT("Second pass after backward -2 step shift,",
|
||||
" e2 should not be executed"))
|
||||
WHEN 4 THEN f1(CONCAT("Second pass after backward -2 step shift,",
|
||||
" e2 should not be executed"))
|
||||
WHEN 2 THEN f1(CONCAT("Forward +2 step shift, local 0, 1 are skipped,",
|
||||
" e2 should be executed"))
|
||||
ELSE f1("e2 should be executed")
|
||||
END;
|
||||
UPDATE t2 SET count= count + 1;
|
||||
|
||||
dec $count;
|
||||
}
|
||||
--enable_result_log
|
||||
--enable_query_log
|
||||
|
||||
SET GLOBAL EVENT_SCHEDULER= OFF;
|
||||
|
||||
SELECT * FROM t1 ORDER BY count, comment;
|
||||
|
||||
SET TIME_ZONE= @save_time_zone;
|
||||
|
||||
DROP EVENT e2;
|
||||
DROP EVENT e1;
|
||||
DROP FUNCTION f1;
|
||||
DROP TABLE t1, t2;
|
||||
|
||||
DELETE FROM mysql.time_zone_name WHERE time_zone_id = @tzid;
|
||||
DELETE FROM mysql.time_zone_transition_type WHERE time_zone_id = @tzid;
|
||||
DELETE FROM mysql.time_zone_transition WHERE time_zone_id = @tzid;
|
||||
DELETE FROM mysql.time_zone WHERE time_zone_id = @tzid;
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
# Test MONTH interval.
|
||||
#
|
||||
|
||||
SET TIME_ZONE= '+00:00';
|
||||
|
||||
CREATE TABLE t1 (event CHAR(2), dt DATE, offset INT);
|
||||
|
||||
INSERT INTO mysql.time_zone VALUES (NULL, 'N');
|
||||
SET @tzid= LAST_INSERT_ID();
|
||||
|
||||
SET @now= UNIX_TIMESTAMP();
|
||||
SET @offset_month_01= UNIX_TIMESTAMP('2030-01-31 12:00:00') - @now;
|
||||
SET @offset_month_02= UNIX_TIMESTAMP('2030-02-28 12:00:00') - @now - 5*@step;
|
||||
SET @offset_month_03= UNIX_TIMESTAMP('2030-03-31 12:00:00') - @now - 5*@step;
|
||||
SET @offset_month_04= UNIX_TIMESTAMP('2030-04-30 12:00:00') - @now - 13*@step;
|
||||
|
||||
INSERT INTO mysql.time_zone_transition_type
|
||||
VALUES (@tzid, 0, @offset_month_01, 0, 'b16420_0');
|
||||
INSERT INTO mysql.time_zone_transition_type
|
||||
VALUES (@tzid, 1, @offset_month_02, 1, 'b16420_1');
|
||||
INSERT INTO mysql.time_zone_transition_type
|
||||
VALUES (@tzid, 2, @offset_month_03, 1, 'b16420_2');
|
||||
INSERT INTO mysql.time_zone_transition_type
|
||||
VALUES (@tzid, 3, @offset_month_04, 1, 'b16420_3');
|
||||
INSERT INTO mysql.time_zone_transition
|
||||
VALUES (@tzid, @now, 0);
|
||||
INSERT INTO mysql.time_zone_transition
|
||||
VALUES (@tzid, @now + 3 * @step, 1);
|
||||
INSERT INTO mysql.time_zone_transition
|
||||
VALUES (@tzid, @now + 7 * @step, 2);
|
||||
INSERT INTO mysql.time_zone_transition
|
||||
VALUES (@tzid, @now + 12 * @step, 3);
|
||||
# We have to user a new time zone name, because 'bug16420' has been
|
||||
# cached already.
|
||||
INSERT INTO mysql.time_zone_name VALUES ('bug16420_2', @tzid);
|
||||
|
||||
SET TIME_ZONE= 'bug16420_2';
|
||||
|
||||
SET GLOBAL EVENT_SCHEDULER= ON;
|
||||
|
||||
let $now= `SELECT @now`;
|
||||
--disable_query_log
|
||||
eval CREATE EVENT e1 ON SCHEDULE EVERY 1 MONTH
|
||||
STARTS FROM_UNIXTIME($now - @step) DO
|
||||
INSERT INTO t1 VALUES
|
||||
("e1", NOW(), round_to_step(UNIX_TIMESTAMP() - $now, 4) - 1);
|
||||
eval CREATE EVENT e2 ON SCHEDULE EVERY 1 MONTH
|
||||
STARTS FROM_UNIXTIME($now + @step) DO
|
||||
INSERT INTO t1 VALUES
|
||||
("e2", NOW(), round_to_step(UNIX_TIMESTAMP() - $now, 4) - 1);
|
||||
--enable_query_log
|
||||
|
||||
let $wait_timeout= `SELECT 16 * @step`;
|
||||
let $wait_condition= SELECT COUNT(*) = 7 FROM t1;
|
||||
--source include/wait_condition.inc
|
||||
|
||||
SET GLOBAL EVENT_SCHEDULER= OFF;
|
||||
|
||||
--echo Below we should see the following:
|
||||
--echo - On Jan 31 only e2 is executed, because we started later than
|
||||
--echo e1 should have been executed. Offset of e2 is 0 because of
|
||||
--echo the late start, not 1.
|
||||
--echo - The next execution is on Feb 28 (last day of Feb). Both events
|
||||
--echo are executed in their times, offsets are -1 and 1.
|
||||
--echo - The next time is Mar 31. Because the time of event
|
||||
--echo execution was skipped over, events are executed right away,
|
||||
--echo offsets are 2 and 2.
|
||||
--echo - The next time is Apr 30. Events are again executed in their
|
||||
--echo appointed times, offsets are -1 and 1.
|
||||
SELECT * FROM t1 ORDER BY dt, event;
|
||||
|
||||
DROP EVENT e2;
|
||||
DROP EVENT e1;
|
||||
DROP TABLE t1;
|
||||
|
||||
SET TIME_ZONE= @save_time_zone;
|
||||
|
||||
DELETE FROM mysql.time_zone_name WHERE time_zone_id = @tzid;
|
||||
DELETE FROM mysql.time_zone_transition_type WHERE time_zone_id = @tzid;
|
||||
DELETE FROM mysql.time_zone_transition WHERE time_zone_id = @tzid;
|
||||
DELETE FROM mysql.time_zone WHERE time_zone_id = @tzid;
|
||||
|
||||
DROP FUNCTION round_to_step;
|
||||
DROP TABLE t_step;
|
||||
|
||||
|
||||
DROP DATABASE mysqltest_db1;
|
||||
--disable_query_log
|
||||
eval USE $old_db;
|
||||
--enable_query_log
|
||||
|
||||
|
||||
--echo End of 5.1 tests.
|
@ -1,6 +1,8 @@
|
||||
# Grant tests not performed with embedded server
|
||||
-- source include/not_embedded.inc
|
||||
-- source include/have_query_cache.inc
|
||||
# See at the end of the test why we disable the ps protocol (*)
|
||||
-- disable_ps_protocol
|
||||
|
||||
--source include/add_anonymous_users.inc
|
||||
|
||||
@ -157,3 +159,27 @@ set GLOBAL query_cache_size=default;
|
||||
|
||||
|
||||
# End of 4.1 tests
|
||||
|
||||
# (*) Why we disable the ps protocol: because in normal protocol,
|
||||
# a SELECT failing due to insufficient privileges increments
|
||||
# Qcache_not_cached, while in ps-protocol, no.
|
||||
# In detail: in normal protocol,
|
||||
# the "access denied" errors on SELECT are issued at (stack trace):
|
||||
# mysql_parse/mysql_execute_command/execute_sqlcom_select/handle_select/
|
||||
# mysql_select/JOIN::prepare/setup_wild/insert_fields/
|
||||
# check_grant_all_columns/my_error/my_message_sql, which then calls
|
||||
# push_warning/query_cache_abort: at this moment,
|
||||
# query_cache_store_query() has been called, so query exists in cache,
|
||||
# so thd->net.query_cache_query!=NULL, so query_cache_abort() removes
|
||||
# the query from cache, which causes a query_cache.refused++ (thus,
|
||||
# a Qcache_not_cached++).
|
||||
# While in ps-protocol, the error is issued at prepare time;
|
||||
# for this mysql_test_select() is called, not execute_sqlcom_select()
|
||||
# (and that also leads to JOIN::prepare/etc). Thus, as
|
||||
# query_cache_store_query() has not been called,
|
||||
# thd->net.query_cache_query==NULL, so query_cache_abort() does nothing:
|
||||
# Qcache_not_cached is not incremented.
|
||||
# As this test prints Qcache_not_cached after SELECT failures,
|
||||
# we cannot enable this test in ps-protocol.
|
||||
|
||||
--enable_ps_protocol
|
||||
|
@ -114,4 +114,25 @@ delete from mysql.help_relation where help_keyword_id=@keyword2_id and help_topi
|
||||
delete from mysql.help_relation where help_keyword_id=@keyword3_id and help_topic_id=@topic3_id;
|
||||
delete from mysql.help_relation where help_keyword_id=@keyword3_id and help_topic_id=@topic4_id;
|
||||
|
||||
# End of 4.1 tests
|
||||
--echo End of 4.1 tests.
|
||||
|
||||
#
|
||||
# Test that we can use HELP even under LOCK TABLES. See bug#9953:
|
||||
# CONVERT_TZ requires mysql.time_zone_name to be locked.
|
||||
#
|
||||
--disable_warnings
|
||||
DROP TABLE IF EXISTS t1;
|
||||
--enable_warnings
|
||||
|
||||
CREATE TABLE t1 (i INT);
|
||||
|
||||
LOCK TABLES t1 WRITE;
|
||||
|
||||
HELP no_such_topic;
|
||||
|
||||
UNLOCK TABLES;
|
||||
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo End of 5.1 tests.
|
||||
|
@ -92,7 +92,8 @@ delete from t2 using t1,t2 where t1.a=t2.a;
|
||||
delete t2 from t1,t2 where t1.a=t2.a;
|
||||
drop table t1,t2;
|
||||
|
||||
# End of 4.1 tests
|
||||
--echo End of 4.1 tests.
|
||||
|
||||
|
||||
#
|
||||
# Bug#18884 "lock table + global read lock = crash"
|
||||
@ -108,3 +109,44 @@ flush tables with read lock;
|
||||
unlock tables;
|
||||
drop table t1;
|
||||
|
||||
|
||||
#
|
||||
# Test LOCK TABLE on system tables. See bug#9953: CONVERT_TZ requires
|
||||
# mysql.time_zone_name to be locked.
|
||||
#
|
||||
--disable_warnings
|
||||
DROP TABLE IF EXISTS t1;
|
||||
--enable_warnings
|
||||
|
||||
CREATE TABLE t1 (i INT);
|
||||
|
||||
LOCK TABLES mysql.time_zone READ, mysql.proc READ, t1 READ;
|
||||
UNLOCK TABLES;
|
||||
|
||||
LOCK TABLES mysql.time_zone READ, mysql.proc READ, t1 WRITE;
|
||||
UNLOCK TABLES;
|
||||
|
||||
LOCK TABLES mysql.time_zone READ, mysql.proc READ;
|
||||
UNLOCK TABLES;
|
||||
|
||||
LOCK TABLES mysql.time_zone WRITE, mysql.proc WRITE;
|
||||
UNLOCK TABLES;
|
||||
|
||||
# If at least one system table is locked for WRITE, then all other
|
||||
# tables should be system tables locked also for WRITE.
|
||||
--error ER_WRONG_LOCK_OF_SYSTEM_TABLE
|
||||
LOCK TABLES mysql.time_zone READ, mysql.proc WRITE, t1 READ;
|
||||
|
||||
--error ER_WRONG_LOCK_OF_SYSTEM_TABLE
|
||||
LOCK TABLES mysql.time_zone WRITE, mysql.proc WRITE, t1 READ;
|
||||
|
||||
--error ER_WRONG_LOCK_OF_SYSTEM_TABLE
|
||||
LOCK TABLES mysql.time_zone WRITE, mysql.proc WRITE, t1 WRITE;
|
||||
|
||||
--error ER_WRONG_LOCK_OF_SYSTEM_TABLE
|
||||
LOCK TABLES mysql.time_zone READ, mysql.proc WRITE;
|
||||
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo End of 5.1 tests.
|
||||
|
@ -36,7 +36,11 @@ insert into t1 value (2);
|
||||
insert into t2 value (3);
|
||||
select * from t1;
|
||||
# Run the check query once to load it into qc on server1
|
||||
# See at the end of this test why we need to disable ps-protocol for
|
||||
# this query (*)
|
||||
--disable_ps_protocol
|
||||
select a != 3 from t1;
|
||||
--enable_ps_protocol
|
||||
select * from t2;
|
||||
show status like "Qcache_queries_in_cache";
|
||||
show status like "Qcache_inserts";
|
||||
@ -93,3 +97,30 @@ set GLOBAL query_cache_size=0;
|
||||
set GLOBAL ndb_cache_check_time=0;
|
||||
reset query cache;
|
||||
flush status;
|
||||
|
||||
# (*) Why we need to execute the query in non-ps mode.
|
||||
# The principle of this test is: two mysqlds connected to one cluster,
|
||||
# both using their query cache. Queries are cached in server1
|
||||
# ("select a!=3 from t1", "select * from t1"),
|
||||
# table t1 is modified in server2, we want to see that this invalidates
|
||||
# the query cache of server1. Invalidation with NDB works like this:
|
||||
# when a query is found in the query cache, NDB is asked if the tables
|
||||
# have changed. In this test, ha_ndbcluster calls NDB every millisecond
|
||||
# to collect change information about tables.
|
||||
# Due to this millisecond delay, there is need for a loop ("while...")
|
||||
# in this test, which waits until a query1 ("select a!=3 from t1") is
|
||||
# invalidated (which is equivalent to it returning
|
||||
# up-to-date results), and then expects query2 ("select * from t1")
|
||||
# to have been invalidated (see up-to-date results).
|
||||
# But when enabling --ps-protocol in this test, the logic breaks,
|
||||
# because query1 is still done via mysql_real_query() (see mysqltest.c:
|
||||
# eval_expr() always uses mysql_real_query()). So, query1 returning
|
||||
# up-to-date results is not a sign of it being invalidated in the cache,
|
||||
# because it was NOT in the cache ("select a!=3 from t1" on line 39
|
||||
# was done with prep stmts, while `select a!=3 from t1` is not,
|
||||
# thus the second does not see the first in the cache). Thus, we may run
|
||||
# query2 when cache still has not been invalidated.
|
||||
# The solution is to make the initial "select a!=3 from t1" run
|
||||
# as a normal query, this repairs the broken logic.
|
||||
# But note, "select * from t1" is still using prepared statements
|
||||
# which was the goal of this test with --ps-protocol.
|
||||
|
@ -2516,3 +2516,60 @@ set @to_format="10000";
|
||||
execute stmt2 using @to_format, @dec;
|
||||
deallocate prepare stmt2;
|
||||
|
||||
|
||||
#
|
||||
# BUG#18326: Do not lock table for writing during prepare of statement
|
||||
#
|
||||
--disable_warnings
|
||||
DROP TABLE IF EXISTS t1, t2;
|
||||
--enable_warnings
|
||||
|
||||
CREATE TABLE t1 (i INT);
|
||||
INSERT INTO t1 VALUES (1);
|
||||
CREATE TABLE t2 (i INT);
|
||||
INSERT INTO t2 VALUES (2);
|
||||
|
||||
LOCK TABLE t1 READ, t2 WRITE;
|
||||
|
||||
connect (conn1, localhost, root, , );
|
||||
|
||||
# Prepare never acquires the lock, and thus should not block.
|
||||
PREPARE stmt1 FROM "SELECT i FROM t1";
|
||||
PREPARE stmt2 FROM "INSERT INTO t2 (i) VALUES (3)";
|
||||
|
||||
# This should not block because READ lock on t1 is shared.
|
||||
EXECUTE stmt1;
|
||||
|
||||
# This should block because WRITE lock on t2 is exclusive.
|
||||
send EXECUTE stmt2;
|
||||
|
||||
connection default;
|
||||
|
||||
SELECT * FROM t2;
|
||||
UNLOCK TABLES;
|
||||
let $wait_condition= SELECT COUNT(*) = 2 FROM t2;
|
||||
--source include/wait_condition.inc
|
||||
SELECT * FROM t2;
|
||||
|
||||
# DDL and DML works even if some client have a prepared statement
|
||||
# referencing the table.
|
||||
ALTER TABLE t1 ADD COLUMN j INT;
|
||||
ALTER TABLE t2 ADD COLUMN j INT;
|
||||
INSERT INTO t1 VALUES (4, 5);
|
||||
INSERT INTO t2 VALUES (4, 5);
|
||||
|
||||
connection conn1;
|
||||
|
||||
reap;
|
||||
EXECUTE stmt1;
|
||||
EXECUTE stmt2;
|
||||
SELECT * FROM t2;
|
||||
|
||||
disconnect conn1;
|
||||
|
||||
connection default;
|
||||
|
||||
DROP TABLE t1, t2;
|
||||
|
||||
|
||||
--echo End of 5.1 tests.
|
||||
|
@ -907,4 +907,24 @@ start transaction;
|
||||
insert into t1(c1) select c1 from v1;
|
||||
drop table t1, t2, t3;
|
||||
drop view v1;
|
||||
|
||||
|
||||
#
|
||||
# If running with --ps-protocol:
|
||||
# see if a query from the text protocol is served with results cached
|
||||
# from a query which used the binary (which would be wrong, results
|
||||
# are in different formats); if that happens, the results will
|
||||
# be incorrect and the test will fail.
|
||||
#
|
||||
|
||||
create table t1(c1 int);
|
||||
insert into t1 values(1),(10),(100);
|
||||
select * from t1;
|
||||
-- disable_ps_protocol
|
||||
select * from t1;
|
||||
select * from t1;
|
||||
-- enable_ps_protocol
|
||||
select * from t1;
|
||||
drop table t1;
|
||||
|
||||
set global query_cache_size=0;
|
||||
|
144
mysql-test/t/query_cache_sql_prepare.test
Normal file
144
mysql-test/t/query_cache_sql_prepare.test
Normal file
@ -0,0 +1,144 @@
|
||||
# This is to see how statements prepared via the PREPARE SQL command
|
||||
# go into the query cache: if using parameters they cannot; if not
|
||||
# using parameters they can.
|
||||
# Query cache is abbreviated as "QC"
|
||||
|
||||
-- source include/have_query_cache.inc
|
||||
|
||||
connect (con1,127.0.0.1,root,,test,$MASTER_MYPORT,);
|
||||
connection default;
|
||||
|
||||
set global query_cache_size=100000;
|
||||
flush status;
|
||||
create table t1(c1 int);
|
||||
insert into t1 values(1),(10),(100);
|
||||
|
||||
# Prepared statements has no parameters, query caching should happen
|
||||
prepare stmt1 from "select * from t1 where c1=10";
|
||||
show status like 'Qcache_hits';
|
||||
execute stmt1;
|
||||
show status like 'Qcache_hits';
|
||||
execute stmt1;
|
||||
show status like 'Qcache_hits';
|
||||
execute stmt1;
|
||||
show status like 'Qcache_hits';
|
||||
# Another prepared statement (same text, same connection), should hit the QC
|
||||
prepare stmt2 from "select * from t1 where c1=10";
|
||||
execute stmt2;
|
||||
show status like 'Qcache_hits';
|
||||
execute stmt2;
|
||||
show status like 'Qcache_hits';
|
||||
execute stmt2;
|
||||
show status like 'Qcache_hits';
|
||||
# Another prepared statement (same text, other connection), should hit the QC
|
||||
connection con1;
|
||||
prepare stmt3 from "select * from t1 where c1=10";
|
||||
execute stmt3;
|
||||
show status like 'Qcache_hits';
|
||||
execute stmt3;
|
||||
show status like 'Qcache_hits';
|
||||
execute stmt3;
|
||||
show status like 'Qcache_hits';
|
||||
connection default;
|
||||
# A non-prepared statement (same text, same connection), should hit
|
||||
# the QC (as it uses the text protocol like SQL EXECUTE).
|
||||
# But if it uses the binary protocol, it will not hit. So we make sure
|
||||
# that it uses the text protocol:
|
||||
-- disable_ps_protocol
|
||||
select * from t1 where c1=10;
|
||||
show status like 'Qcache_hits';
|
||||
# A non-prepared statement (same text, other connection), should hit
|
||||
# the QC. To test that it hits the result of SQL EXECUTE, we need to
|
||||
# empty/repopulate the QC (to remove the result from the non-prepared
|
||||
# SELECT just above).
|
||||
flush tables;
|
||||
execute stmt1;
|
||||
show status like 'Qcache_hits';
|
||||
connection con1;
|
||||
select * from t1 where c1=10;
|
||||
show status like 'Qcache_hits';
|
||||
-- enable_ps_protocol
|
||||
connection default;
|
||||
|
||||
# Prepared statement has parameters, query caching should not happen
|
||||
prepare stmt1 from "select * from t1 where c1=?";
|
||||
show status like 'Qcache_hits';
|
||||
set @a=1;
|
||||
execute stmt1 using @a;
|
||||
show status like 'Qcache_hits';
|
||||
set @a=100;
|
||||
execute stmt1 using @a;
|
||||
show status like 'Qcache_hits';
|
||||
set @a=10;
|
||||
execute stmt1 using @a;
|
||||
show status like 'Qcache_hits';
|
||||
|
||||
# See if enabling/disabling the query cache between PREPARE and
|
||||
# EXECUTE is an issue; the expected result is that the query cache
|
||||
# will not be used.
|
||||
# Indeed, decision to read/write the query cache is taken at PREPARE
|
||||
# time, so if the query cache was disabled at PREPARE time then no
|
||||
# execution of the statement will read/write the query cache.
|
||||
# If the query cache was enabled at PREPARE time, but disabled at
|
||||
# EXECUTE time, at EXECUTE time the query cache internal functions do
|
||||
# nothing so again the query cache is not read/written. But if the
|
||||
# query cache is re-enabled before another execution then that
|
||||
# execution will read/write the query cache.
|
||||
|
||||
# QC is enabled at PREPARE
|
||||
prepare stmt1 from "select * from t1 where c1=10";
|
||||
# then QC is disabled at EXECUTE
|
||||
set global query_cache_size=0;
|
||||
show status like 'Qcache_hits';
|
||||
execute stmt1;
|
||||
show status like 'Qcache_hits';
|
||||
execute stmt1;
|
||||
show status like 'Qcache_hits';
|
||||
execute stmt1;
|
||||
show status like 'Qcache_hits';
|
||||
# then QC is re-enabled for more EXECUTE.
|
||||
set global query_cache_size=100000;
|
||||
# Note that this execution will not hit results from the
|
||||
# beginning of the test (because QC has been emptied meanwhile by
|
||||
# setting its size to 0).
|
||||
execute stmt1;
|
||||
show status like 'Qcache_hits';
|
||||
execute stmt1;
|
||||
show status like 'Qcache_hits';
|
||||
execute stmt1;
|
||||
show status like 'Qcache_hits';
|
||||
|
||||
# QC is disabled at PREPARE
|
||||
set global query_cache_size=0;
|
||||
prepare stmt1 from "select * from t1 where c1=10";
|
||||
# then QC is enabled at EXECUTE
|
||||
set global query_cache_size=100000;
|
||||
show status like 'Qcache_hits';
|
||||
execute stmt1;
|
||||
show status like 'Qcache_hits';
|
||||
execute stmt1;
|
||||
show status like 'Qcache_hits';
|
||||
execute stmt1;
|
||||
show status like 'Qcache_hits';
|
||||
|
||||
# QC is disabled at PREPARE
|
||||
set global query_cache_size=0;
|
||||
prepare stmt1 from "select * from t1 where c1=?";
|
||||
# then QC is enabled at EXECUTE
|
||||
set global query_cache_size=100000;
|
||||
show status like 'Qcache_hits';
|
||||
set @a=1;
|
||||
execute stmt1 using @a;
|
||||
show status like 'Qcache_hits';
|
||||
set @a=100;
|
||||
execute stmt1 using @a;
|
||||
show status like 'Qcache_hits';
|
||||
set @a=10;
|
||||
execute stmt1 using @a;
|
||||
show status like 'Qcache_hits';
|
||||
|
||||
|
||||
drop table t1;
|
||||
|
||||
set global query_cache_size=0;
|
||||
flush status; # reset Qcache status variables for next tests
|
@ -109,6 +109,12 @@ DROP FUNCTION f1;
|
||||
DROP FUNCTION f2;
|
||||
DROP FUNCTION f3;
|
||||
|
||||
#
|
||||
# Bug #26807 "set global event_scheduler=1" and --skip-grant-tables crashes server
|
||||
#
|
||||
--error ER_OPTION_PREVENTS_STATEMENT
|
||||
set global event_scheduler=1;
|
||||
|
||||
#
|
||||
# Bug#26285 Selecting information_schema crahes server
|
||||
#
|
||||
|
@ -2067,6 +2067,74 @@ drop function bug20701;
|
||||
--echo End of 5.1 tests
|
||||
|
||||
|
||||
#
|
||||
# Bug#26503 (Illegal SQL exception handler code causes the server to crash)
|
||||
#
|
||||
|
||||
delimiter //;
|
||||
|
||||
--error ER_SP_LILABEL_MISMATCH
|
||||
create procedure proc_26503_error_1()
|
||||
begin
|
||||
retry:
|
||||
repeat
|
||||
begin
|
||||
declare continue handler for sqlexception
|
||||
begin
|
||||
iterate retry;
|
||||
end
|
||||
|
||||
select "do something";
|
||||
end
|
||||
until true end repeat retry;
|
||||
end//
|
||||
|
||||
--error ER_SP_LILABEL_MISMATCH
|
||||
create procedure proc_26503_error_2()
|
||||
begin
|
||||
retry:
|
||||
repeat
|
||||
begin
|
||||
declare continue handler for sqlexception
|
||||
iterate retry;
|
||||
|
||||
select "do something";
|
||||
end
|
||||
until true end repeat retry;
|
||||
end//
|
||||
|
||||
--error ER_SP_LILABEL_MISMATCH
|
||||
create procedure proc_26503_error_3()
|
||||
begin
|
||||
retry:
|
||||
repeat
|
||||
begin
|
||||
declare continue handler for sqlexception
|
||||
begin
|
||||
leave retry;
|
||||
end
|
||||
|
||||
select "do something";
|
||||
end
|
||||
until true end repeat retry;
|
||||
end//
|
||||
|
||||
--error ER_SP_LILABEL_MISMATCH
|
||||
create procedure proc_26503_error_4()
|
||||
begin
|
||||
retry:
|
||||
repeat
|
||||
begin
|
||||
declare continue handler for sqlexception
|
||||
leave retry;
|
||||
|
||||
select "do something";
|
||||
end
|
||||
until true end repeat retry;
|
||||
end//
|
||||
|
||||
delimiter ;//
|
||||
|
||||
#
|
||||
# BUG#NNNN: New bug synopsis
|
||||
#
|
||||
|
@ -6564,6 +6564,46 @@ call proc_21462_b(1)|
|
||||
drop procedure proc_21462_a|
|
||||
drop procedure proc_21462_b|
|
||||
|
||||
|
||||
#
|
||||
# BUG#20492: Subsequent calls to stored procedure yeild incorrect
|
||||
# result if join is used
|
||||
#
|
||||
# Optimized ON expression in join wasn't properly saved for reuse.
|
||||
#
|
||||
--disable_warnings
|
||||
DROP PROCEDURE IF EXISTS p1|
|
||||
DROP VIEW IF EXISTS v1, v2|
|
||||
DROP TABLE IF EXISTS t3, t4|
|
||||
--enable_warnings
|
||||
|
||||
CREATE TABLE t3 (t3_id INT)|
|
||||
|
||||
INSERT INTO t3 VALUES (0)|
|
||||
INSERT INTO t3 VALUES (1)|
|
||||
|
||||
CREATE TABLE t4 (t4_id INT)|
|
||||
|
||||
INSERT INTO t4 VALUES (2)|
|
||||
|
||||
CREATE VIEW v1 AS
|
||||
SELECT t3.t3_id, t4.t4_id
|
||||
FROM t3 JOIN t4 ON t3.t3_id = 0|
|
||||
|
||||
CREATE VIEW v2 AS
|
||||
SELECT t3.t3_id AS t3_id_1, v1.t3_id AS t3_id_2, v1.t4_id
|
||||
FROM t3 LEFT JOIN v1 ON t3.t3_id = 0|
|
||||
|
||||
CREATE PROCEDURE p1() SELECT * FROM v2|
|
||||
|
||||
# Results should not differ.
|
||||
CALL p1()|
|
||||
CALL p1()|
|
||||
|
||||
DROP PROCEDURE p1|
|
||||
DROP VIEW v1, v2|
|
||||
DROP TABLE t3, t4|
|
||||
|
||||
--echo End of 5.0 tests
|
||||
|
||||
--echo Begin of 5.1 tests
|
||||
@ -6827,6 +6867,141 @@ select func_8407_b()|
|
||||
drop function func_8407_a|
|
||||
drop function func_8407_b|
|
||||
|
||||
#
|
||||
# Bug#26503 (Illegal SQL exception handler code causes the server to crash)
|
||||
#
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists table_26503|
|
||||
drop procedure if exists proc_26503_ok_1|
|
||||
drop procedure if exists proc_26503_ok_2|
|
||||
drop procedure if exists proc_26503_ok_3|
|
||||
drop procedure if exists proc_26503_ok_4|
|
||||
--enable_warnings
|
||||
|
||||
create table table_26503(a int unique)|
|
||||
|
||||
create procedure proc_26503_ok_1(v int)
|
||||
begin
|
||||
declare i int default 5;
|
||||
|
||||
declare continue handler for sqlexception
|
||||
begin
|
||||
select 'caught something';
|
||||
retry:
|
||||
while i > 0 do
|
||||
begin
|
||||
set i = i - 1;
|
||||
select 'looping', i;
|
||||
iterate retry;
|
||||
select 'dead code';
|
||||
end;
|
||||
end while retry;
|
||||
select 'leaving handler';
|
||||
end;
|
||||
|
||||
select 'do something';
|
||||
insert into table_26503 values (v);
|
||||
select 'do something again';
|
||||
insert into table_26503 values (v);
|
||||
end|
|
||||
|
||||
create procedure proc_26503_ok_2(v int)
|
||||
begin
|
||||
declare i int default 5;
|
||||
|
||||
declare continue handler for sqlexception
|
||||
begin
|
||||
select 'caught something';
|
||||
retry:
|
||||
while i > 0 do
|
||||
begin
|
||||
set i = i - 1;
|
||||
select 'looping', i;
|
||||
leave retry;
|
||||
select 'dead code';
|
||||
end;
|
||||
end while;
|
||||
select 'leaving handler';
|
||||
end;
|
||||
|
||||
select 'do something';
|
||||
insert into table_26503 values (v);
|
||||
select 'do something again';
|
||||
insert into table_26503 values (v);
|
||||
end|
|
||||
|
||||
## The outer retry label should not prevent using the inner label.
|
||||
|
||||
create procedure proc_26503_ok_3(v int)
|
||||
begin
|
||||
declare i int default 5;
|
||||
|
||||
retry:
|
||||
begin
|
||||
declare continue handler for sqlexception
|
||||
begin
|
||||
select 'caught something';
|
||||
retry:
|
||||
while i > 0 do
|
||||
begin
|
||||
set i = i - 1;
|
||||
select 'looping', i;
|
||||
iterate retry;
|
||||
select 'dead code';
|
||||
end;
|
||||
end while retry;
|
||||
select 'leaving handler';
|
||||
end;
|
||||
|
||||
select 'do something';
|
||||
insert into table_26503 values (v);
|
||||
select 'do something again';
|
||||
insert into table_26503 values (v);
|
||||
end;
|
||||
end|
|
||||
|
||||
## The outer retry label should not prevent using the inner label.
|
||||
|
||||
create procedure proc_26503_ok_4(v int)
|
||||
begin
|
||||
declare i int default 5;
|
||||
|
||||
retry:
|
||||
begin
|
||||
declare continue handler for sqlexception
|
||||
begin
|
||||
select 'caught something';
|
||||
retry:
|
||||
while i > 0 do
|
||||
begin
|
||||
set i = i - 1;
|
||||
select 'looping', i;
|
||||
leave retry;
|
||||
select 'dead code';
|
||||
end;
|
||||
end while;
|
||||
select 'leaving handler';
|
||||
end;
|
||||
|
||||
select 'do something';
|
||||
insert into table_26503 values (v);
|
||||
select 'do something again';
|
||||
insert into table_26503 values (v);
|
||||
end;
|
||||
end|
|
||||
|
||||
call proc_26503_ok_1(1)|
|
||||
call proc_26503_ok_2(2)|
|
||||
call proc_26503_ok_3(3)|
|
||||
call proc_26503_ok_4(4)|
|
||||
|
||||
drop table table_26503|
|
||||
drop procedure proc_26503_ok_1|
|
||||
drop procedure proc_26503_ok_2|
|
||||
drop procedure proc_26503_ok_3|
|
||||
drop procedure proc_26503_ok_4|
|
||||
|
||||
#
|
||||
# Bug#25373: Stored functions wasn't compared correctly which leads to a wrong
|
||||
# result.
|
||||
|
@ -246,3 +246,31 @@ drop function f1;
|
||||
SET GLOBAL log_bin_trust_function_creators = 0;
|
||||
|
||||
# End of 5.0 tests
|
||||
|
||||
|
||||
#
|
||||
# BUG#9953: CONVERT_TZ requires mysql.time_zone_name to be locked
|
||||
# BUG#19339: CONVERT_TZ(): overly aggressive in locking time_zone_name
|
||||
# table
|
||||
#
|
||||
--disable_warnings
|
||||
DROP TABLE IF EXISTS t1;
|
||||
--enable_warnings
|
||||
|
||||
CREATE TABLE t1 (t TIMESTAMP);
|
||||
INSERT INTO t1 VALUES (NULL), (NULL);
|
||||
|
||||
LOCK TABLES t1 WRITE;
|
||||
|
||||
# The following two queries should not return error that time zone
|
||||
# tables aren't locked. We use IS NULL below to supress timestamp
|
||||
# result.
|
||||
SELECT CONVERT_TZ(NOW(), 'UTC', 'Europe/Moscow') IS NULL;
|
||||
UPDATE t1 SET t = CONVERT_TZ(t, 'UTC', 'Europe/Moscow');
|
||||
|
||||
UNLOCK TABLES;
|
||||
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo End of 5.1 tests
|
||||
|
@ -832,6 +832,7 @@ drop table t1;
|
||||
#
|
||||
create table t1 (col1 int);
|
||||
create table t2 (col1 int);
|
||||
create table t3 (col1 datetime not null);
|
||||
create view v1 as select * from t1;
|
||||
create view v2 as select * from v1;
|
||||
create view v3 as select v2.col1 from v2,t2 where v2.col1 = t2.col1;
|
||||
@ -938,7 +939,7 @@ insert into v3 (col1) values ((select max(col1) from v2));
|
||||
insert into v3 (col1) values ((select CONVERT_TZ('20050101000000','UTC','MET') from v2));
|
||||
insert into v3 (col1) values ((select CONVERT_TZ('20050101000000','UTC','MET') from t2));
|
||||
-- error 1048
|
||||
insert into mysql.time_zone values ('', (select CONVERT_TZ('20050101000000','UTC','MET') from t2));
|
||||
insert into t3 values ((select CONVERT_TZ('20050101000000','UTC','MET') from t2));
|
||||
# temporary table algorithm view should be equal to subquery in the from clause
|
||||
create algorithm=temptable view v4 as select * from t1;
|
||||
insert into t1 values (1),(2),(3);
|
||||
@ -946,7 +947,7 @@ insert into t1 (col1) values ((select max(col1) from v4));
|
||||
select * from t1;
|
||||
|
||||
drop view v4,v3,v2,v1;
|
||||
drop table t1,t2;
|
||||
drop table t1,t2,t3;
|
||||
|
||||
#
|
||||
# HANDLER with VIEW
|
||||
@ -3214,3 +3215,30 @@ DROP TABLE `t-2`;
|
||||
DROP VIEW `v-2`;
|
||||
DROP DATABASE `d-1`;
|
||||
USE test;
|
||||
|
||||
|
||||
#
|
||||
# Test that ALTER VIEW accepts DEFINER and ALGORITHM, see bug#16425.
|
||||
#
|
||||
--disable_warnings
|
||||
DROP VIEW IF EXISTS v1;
|
||||
DROP TABLE IF EXISTS t1;
|
||||
--enable_warnings
|
||||
|
||||
CREATE TABLE t1 (i INT);
|
||||
CREATE VIEW v1 AS SELECT * FROM t1;
|
||||
|
||||
ALTER VIEW v1 AS SELECT * FROM t1;
|
||||
SHOW CREATE VIEW v1;
|
||||
ALTER DEFINER=no_such@user_1 VIEW v1 AS SELECT * FROM t1;
|
||||
SHOW CREATE VIEW v1;
|
||||
ALTER ALGORITHM=MERGE VIEW v1 AS SELECT * FROM t1;
|
||||
SHOW CREATE VIEW v1;
|
||||
ALTER ALGORITHM=TEMPTABLE DEFINER=no_such@user_2 VIEW v1 AS SELECT * FROM t1;
|
||||
SHOW CREATE VIEW v1;
|
||||
|
||||
DROP VIEW v1;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo End of 5.1 tests.
|
||||
|
@ -483,6 +483,7 @@ CREATE TABLE event (
|
||||
'HIGH_NOT_PRECEDENCE'
|
||||
) DEFAULT '' NOT NULL,
|
||||
comment char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
|
||||
time_zone char(64) CHARACTER SET latin1 NOT NULL DEFAULT 'SYSTEM',
|
||||
PRIMARY KEY (db,name)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT 'Events';
|
||||
|
||||
@ -534,10 +535,12 @@ ALTER TABLE event ADD sql_mode
|
||||
'NO_AUTO_CREATE_USER',
|
||||
'HIGH_NOT_PRECEDENCE'
|
||||
) DEFAULT '' NOT NULL AFTER on_completion;
|
||||
|
||||
UPDATE user SET Event_priv=Super_priv WHERE @hadEventPriv = 0;
|
||||
ALTER TABLE event MODIFY name char(64) CHARACTER SET utf8 NOT NULL default '';
|
||||
|
||||
ALTER TABLE event ADD COLUMN time_zone char(64) CHARACTER SET latin1
|
||||
NOT NULL DEFAULT 'SYSTEM' AFTER comment;
|
||||
|
||||
#
|
||||
# TRIGGER privilege
|
||||
#
|
||||
|
@ -101,7 +101,7 @@ Event_parse_data::new_instance(THD *thd)
|
||||
*/
|
||||
|
||||
Event_parse_data::Event_parse_data()
|
||||
:on_completion(ON_COMPLETION_DROP), status(ENABLED),
|
||||
:on_completion(ON_COMPLETION_DROP), status(ENABLED), do_not_create(FALSE),
|
||||
item_starts(NULL), item_ends(NULL), item_execute_at(NULL),
|
||||
starts_null(TRUE), ends_null(TRUE), execute_at_null(TRUE),
|
||||
item_expression(NULL), expression(0)
|
||||
@ -109,9 +109,7 @@ Event_parse_data::Event_parse_data()
|
||||
DBUG_ENTER("Event_parse_data::Event_parse_data");
|
||||
|
||||
/* Actually in the parser STARTS is always set */
|
||||
set_zero_time(&starts, MYSQL_TIMESTAMP_DATETIME);
|
||||
set_zero_time(&ends, MYSQL_TIMESTAMP_DATETIME);
|
||||
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
|
||||
starts= ends= execute_at= 0;
|
||||
|
||||
body.str= comment.str= NULL;
|
||||
body.length= comment.length= 0;
|
||||
@ -223,6 +221,55 @@ Event_parse_data::init_body(THD *thd)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This function is called on CREATE EVENT or ALTER EVENT. When either
|
||||
ENDS or AT is in the past, we are trying to create an event that
|
||||
will never be executed. If it has ON COMPLETION NOT PRESERVE
|
||||
(default), then it would normally be dropped already, so on CREATE
|
||||
EVENT we give a warning, and do not create anyting. On ALTER EVENT
|
||||
we give a error, and do not change the event.
|
||||
|
||||
If the event has ON COMPLETION PRESERVE, then we see if the event is
|
||||
created or altered to the ENABLED (default) state. If so, then we
|
||||
give a warning, and change the state to DISABLED.
|
||||
|
||||
Otherwise it is a valid event in ON COMPLETION PRESERVE DISABLE
|
||||
state.
|
||||
*/
|
||||
|
||||
void
|
||||
Event_parse_data::check_if_in_the_past(THD *thd, my_time_t ltime_utc)
|
||||
{
|
||||
if (ltime_utc >= (my_time_t) thd->query_start())
|
||||
return;
|
||||
|
||||
if (on_completion == ON_COMPLETION_DROP)
|
||||
{
|
||||
switch (thd->lex->sql_command) {
|
||||
case SQLCOM_CREATE_EVENT:
|
||||
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
||||
ER_EVENT_CANNOT_CREATE_IN_THE_PAST,
|
||||
ER(ER_EVENT_CANNOT_CREATE_IN_THE_PAST));
|
||||
break;
|
||||
case SQLCOM_ALTER_EVENT:
|
||||
my_error(ER_EVENT_CANNOT_ALTER_IN_THE_PAST, MYF(0));
|
||||
break;
|
||||
default:
|
||||
DBUG_ASSERT(0);
|
||||
}
|
||||
|
||||
do_not_create= TRUE;
|
||||
}
|
||||
else if (status == ENABLED)
|
||||
{
|
||||
status= DISABLED;
|
||||
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
||||
ER_EVENT_EXEC_TIME_IN_THE_PAST,
|
||||
ER(ER_EVENT_EXEC_TIME_IN_THE_PAST));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Sets time for execution for one-time event.
|
||||
|
||||
@ -240,8 +287,7 @@ Event_parse_data::init_execute_at(THD *thd)
|
||||
{
|
||||
my_bool not_used;
|
||||
TIME ltime;
|
||||
my_time_t t;
|
||||
TIME time_tmp;
|
||||
my_time_t ltime_utc;
|
||||
|
||||
DBUG_ENTER("Event_parse_data::init_execute_at");
|
||||
|
||||
@ -256,35 +302,20 @@ Event_parse_data::init_execute_at(THD *thd)
|
||||
(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());
|
||||
|
||||
if ((not_used= item_execute_at->get_date(<ime, TIME_NO_ZERO_DATE)))
|
||||
goto wrong_value;
|
||||
|
||||
if (TIME_to_ulonglong_datetime(<ime) <
|
||||
TIME_to_ulonglong_datetime(&time_tmp))
|
||||
{
|
||||
my_error(ER_EVENT_EXEC_TIME_IN_THE_PAST, MYF(0));
|
||||
DBUG_RETURN(ER_WRONG_VALUE);
|
||||
}
|
||||
|
||||
/*
|
||||
This may result in a 1970-01-01 date if ltime is > 2037-xx-xx.
|
||||
CONVERT_TZ has similar problem.
|
||||
mysql_priv.h currently lists
|
||||
#define TIMESTAMP_MAX_YEAR 2038 (see TIME_to_timestamp())
|
||||
*/
|
||||
my_tz_UTC->gmt_sec_to_TIME(<ime,t=TIME_to_timestamp(thd,<ime,¬_used));
|
||||
if (!t)
|
||||
ltime_utc= TIME_to_timestamp(thd,<ime,¬_used);
|
||||
if (!ltime_utc)
|
||||
{
|
||||
DBUG_PRINT("error", ("Execute AT after year 2037"));
|
||||
goto wrong_value;
|
||||
}
|
||||
|
||||
check_if_in_the_past(thd, ltime_utc);
|
||||
|
||||
execute_at_null= FALSE;
|
||||
execute_at= ltime;
|
||||
execute_at= ltime_utc;
|
||||
DBUG_RETURN(0);
|
||||
|
||||
wrong_value:
|
||||
@ -424,8 +455,8 @@ int
|
||||
Event_parse_data::init_starts(THD *thd)
|
||||
{
|
||||
my_bool not_used;
|
||||
TIME ltime, time_tmp;
|
||||
my_time_t t;
|
||||
TIME ltime;
|
||||
my_time_t ltime_utc;
|
||||
|
||||
DBUG_ENTER("Event_parse_data::init_starts");
|
||||
if (!item_starts)
|
||||
@ -437,36 +468,15 @@ Event_parse_data::init_starts(THD *thd)
|
||||
if ((not_used= item_starts->get_date(<ime, TIME_NO_ZERO_DATE)))
|
||||
goto wrong_value;
|
||||
|
||||
/*
|
||||
Let's check whether time is in the past.
|
||||
Note: This call is not post year 2038 safe. That's because
|
||||
thd->query_start() is of time_t, while gmt_sec_to_TIME()
|
||||
wants my_time_t. In the case time_t is larger than my_time_t
|
||||
an overflow might happen and events subsystem will not work as
|
||||
expected.
|
||||
*/
|
||||
thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp,
|
||||
(my_time_t) thd->query_start());
|
||||
ltime_utc= TIME_to_timestamp(thd, <ime, ¬_used);
|
||||
if (!ltime_utc)
|
||||
goto wrong_value;
|
||||
|
||||
DBUG_PRINT("info",("now: %ld starts: %ld",
|
||||
(long) TIME_to_ulonglong_datetime(&time_tmp),
|
||||
(long) TIME_to_ulonglong_datetime(<ime)));
|
||||
if (TIME_to_ulonglong_datetime(<ime) <
|
||||
TIME_to_ulonglong_datetime(&time_tmp))
|
||||
goto wrong_value;
|
||||
(long) thd->query_start(), (long) ltime_utc));
|
||||
|
||||
/*
|
||||
Again, after 2038 this code won't work. As
|
||||
mysql_priv.h currently lists
|
||||
#define TIMESTAMP_MAX_YEAR 2038 (see TIME_to_timestamp())
|
||||
*/
|
||||
my_tz_UTC->gmt_sec_to_TIME(<ime,t=TIME_to_timestamp(thd, <ime,
|
||||
¬_used));
|
||||
if (!t)
|
||||
goto wrong_value;
|
||||
|
||||
starts= ltime;
|
||||
starts_null= FALSE;
|
||||
starts= ltime_utc;
|
||||
DBUG_RETURN(0);
|
||||
|
||||
wrong_value:
|
||||
@ -498,9 +508,9 @@ wrong_value:
|
||||
int
|
||||
Event_parse_data::init_ends(THD *thd)
|
||||
{
|
||||
TIME ltime, ltime_now;
|
||||
my_bool not_used;
|
||||
my_time_t t;
|
||||
TIME ltime;
|
||||
my_time_t ltime_utc;
|
||||
|
||||
DBUG_ENTER("Event_parse_data::init_ends");
|
||||
if (!item_ends)
|
||||
@ -513,34 +523,19 @@ Event_parse_data::init_ends(THD *thd)
|
||||
if ((not_used= item_ends->get_date(<ime, TIME_NO_ZERO_DATE)))
|
||||
goto error_bad_params;
|
||||
|
||||
/*
|
||||
Again, after 2038 this code won't work. As
|
||||
mysql_priv.h currently lists
|
||||
#define TIMESTAMP_MAX_YEAR 2038 (see TIME_to_timestamp())
|
||||
*/
|
||||
DBUG_PRINT("info", ("get the UTC time"));
|
||||
my_tz_UTC->gmt_sec_to_TIME(<ime,t=TIME_to_timestamp(thd, <ime,
|
||||
¬_used));
|
||||
if (!t)
|
||||
ltime_utc= TIME_to_timestamp(thd, <ime, ¬_used);
|
||||
if (!ltime_utc)
|
||||
goto error_bad_params;
|
||||
|
||||
/* Check whether ends is after starts */
|
||||
DBUG_PRINT("info", ("ENDS after STARTS?"));
|
||||
if (!starts_null && my_time_compare(&starts, <ime) != -1)
|
||||
if (!starts_null && starts >= ltime_utc)
|
||||
goto error_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(<ime_now, (my_time_t)thd->query_start());
|
||||
if (my_time_compare(<ime_now, <ime) == 1)
|
||||
goto error_bad_params;
|
||||
check_if_in_the_past(thd, ltime_utc);
|
||||
|
||||
ends= ltime;
|
||||
ends_null= FALSE;
|
||||
ends= ltime_utc;
|
||||
DBUG_RETURN(0);
|
||||
|
||||
error_bad_params:
|
||||
@ -656,6 +651,7 @@ Event_basic::Event_basic()
|
||||
init_alloc_root(&mem_root, 256, 512);
|
||||
dbname.str= name.str= NULL;
|
||||
dbname.length= name.length= 0;
|
||||
time_zone= NULL;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@ -716,6 +712,16 @@ Event_basic::load_string_fields(Field **fields, ...)
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Event_basic::load_time_zone(THD *thd, const LEX_STRING tz_name)
|
||||
{
|
||||
String str(tz_name.str, &my_charset_latin1);
|
||||
time_zone= my_tz_find(thd, &str);
|
||||
|
||||
return (time_zone == NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Constructor
|
||||
|
||||
@ -730,10 +736,7 @@ Event_queue_element::Event_queue_element():
|
||||
{
|
||||
DBUG_ENTER("Event_queue_element::Event_queue_element");
|
||||
|
||||
set_zero_time(&starts, MYSQL_TIMESTAMP_DATETIME);
|
||||
set_zero_time(&ends, MYSQL_TIMESTAMP_DATETIME);
|
||||
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
|
||||
set_zero_time(&last_executed, MYSQL_TIMESTAMP_DATETIME);
|
||||
starts= ends= execute_at= last_executed= 0;
|
||||
starts_null= ends_null= execute_at_null= TRUE;
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
@ -833,7 +836,7 @@ Event_timed::init()
|
||||
Loads an event's body from a row from mysql.event
|
||||
|
||||
SYNOPSIS
|
||||
Event_job_data::load_from_row(MEM_ROOT *mem_root, TABLE *table)
|
||||
Event_job_data::load_from_row(THD *thd, TABLE *table)
|
||||
|
||||
RETURN VALUE
|
||||
0 OK
|
||||
@ -846,7 +849,7 @@ Event_timed::init()
|
||||
*/
|
||||
|
||||
int
|
||||
Event_job_data::load_from_row(TABLE *table)
|
||||
Event_job_data::load_from_row(THD *thd, TABLE *table)
|
||||
{
|
||||
char *ptr;
|
||||
uint len;
|
||||
@ -858,9 +861,12 @@ Event_job_data::load_from_row(TABLE *table)
|
||||
if (table->s->fields != ET_FIELD_COUNT)
|
||||
goto error;
|
||||
|
||||
LEX_STRING tz_name;
|
||||
load_string_fields(table->field, ET_FIELD_DB, &dbname, ET_FIELD_NAME, &name,
|
||||
ET_FIELD_BODY, &body, ET_FIELD_DEFINER, &definer,
|
||||
ET_FIELD_COUNT);
|
||||
ET_FIELD_TIME_ZONE, &tz_name, ET_FIELD_COUNT);
|
||||
if (load_time_zone(thd, tz_name))
|
||||
goto error;
|
||||
|
||||
ptr= strchr(definer.str, '@');
|
||||
|
||||
@ -887,7 +893,7 @@ error:
|
||||
Loads an event from a row from mysql.event
|
||||
|
||||
SYNOPSIS
|
||||
Event_queue_element::load_from_row(MEM_ROOT *mem_root, TABLE *table)
|
||||
Event_queue_element::load_from_row(THD *thd, TABLE *table)
|
||||
|
||||
RETURN VALUE
|
||||
0 OK
|
||||
@ -900,10 +906,10 @@ error:
|
||||
*/
|
||||
|
||||
int
|
||||
Event_queue_element::load_from_row(TABLE *table)
|
||||
Event_queue_element::load_from_row(THD *thd, TABLE *table)
|
||||
{
|
||||
char *ptr;
|
||||
bool res1, res2;
|
||||
TIME time;
|
||||
|
||||
DBUG_ENTER("Event_queue_element::load_from_row");
|
||||
|
||||
@ -913,29 +919,44 @@ Event_queue_element::load_from_row(TABLE *table)
|
||||
if (table->s->fields != ET_FIELD_COUNT)
|
||||
goto error;
|
||||
|
||||
LEX_STRING tz_name;
|
||||
load_string_fields(table->field, ET_FIELD_DB, &dbname, ET_FIELD_NAME, &name,
|
||||
ET_FIELD_DEFINER, &definer, ET_FIELD_COUNT);
|
||||
ET_FIELD_DEFINER, &definer,
|
||||
ET_FIELD_TIME_ZONE, &tz_name, ET_FIELD_COUNT);
|
||||
if (load_time_zone(thd, tz_name))
|
||||
goto error;
|
||||
|
||||
starts_null= table->field[ET_FIELD_STARTS]->is_null();
|
||||
res1= table->field[ET_FIELD_STARTS]->get_date(&starts, TIME_NO_ZERO_DATE);
|
||||
if (!starts_null)
|
||||
{
|
||||
table->field[ET_FIELD_STARTS]->get_date(&time, TIME_NO_ZERO_DATE);
|
||||
starts= sec_since_epoch_TIME(&time);
|
||||
}
|
||||
|
||||
ends_null= table->field[ET_FIELD_ENDS]->is_null();
|
||||
res2= table->field[ET_FIELD_ENDS]->get_date(&ends, TIME_NO_ZERO_DATE);
|
||||
if (!ends_null)
|
||||
{
|
||||
table->field[ET_FIELD_ENDS]->get_date(&time, TIME_NO_ZERO_DATE);
|
||||
ends= sec_since_epoch_TIME(&time);
|
||||
}
|
||||
|
||||
if (!table->field[ET_FIELD_INTERVAL_EXPR]->is_null())
|
||||
expression= table->field[ET_FIELD_INTERVAL_EXPR]->val_int();
|
||||
else
|
||||
expression= 0;
|
||||
/*
|
||||
If res1 and res2 are TRUE then both fields are empty.
|
||||
If neigher STARTS and ENDS is set, then both fields are empty.
|
||||
Hence, if ET_FIELD_EXECUTE_AT is empty there is an error.
|
||||
*/
|
||||
execute_at_null= table->field[ET_FIELD_EXECUTE_AT]->is_null();
|
||||
DBUG_ASSERT(!(starts_null && ends_null && !expression && execute_at_null));
|
||||
if (!expression &&
|
||||
table->field[ET_FIELD_EXECUTE_AT]->get_date(&execute_at,
|
||||
TIME_NO_ZERO_DATE))
|
||||
goto error;
|
||||
if (!expression && !execute_at_null)
|
||||
{
|
||||
if (table->field[ET_FIELD_EXECUTE_AT]->get_date(&time,
|
||||
TIME_NO_ZERO_DATE))
|
||||
goto error;
|
||||
execute_at= sec_since_epoch_TIME(&time);
|
||||
}
|
||||
|
||||
/*
|
||||
We load the interval type from disk as string and then map it to
|
||||
@ -962,11 +983,14 @@ Event_queue_element::load_from_row(TABLE *table)
|
||||
interval= (interval_type) i;
|
||||
}
|
||||
|
||||
table->field[ET_FIELD_LAST_EXECUTED]->get_date(&last_executed,
|
||||
TIME_NO_ZERO_DATE);
|
||||
if (!table->field[ET_FIELD_LAST_EXECUTED]->is_null())
|
||||
{
|
||||
table->field[ET_FIELD_LAST_EXECUTED]->get_date(&time,
|
||||
TIME_NO_ZERO_DATE);
|
||||
last_executed= sec_since_epoch_TIME(&time);
|
||||
}
|
||||
last_executed_changed= FALSE;
|
||||
|
||||
|
||||
if ((ptr= get_field(&mem_root, table->field[ET_FIELD_STATUS])) == NullS)
|
||||
goto error;
|
||||
|
||||
@ -992,7 +1016,7 @@ error:
|
||||
Loads an event from a row from mysql.event
|
||||
|
||||
SYNOPSIS
|
||||
Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
|
||||
Event_timed::load_from_row(THD *thd, TABLE *table)
|
||||
|
||||
RETURN VALUE
|
||||
0 OK
|
||||
@ -1005,14 +1029,14 @@ error:
|
||||
*/
|
||||
|
||||
int
|
||||
Event_timed::load_from_row(TABLE *table)
|
||||
Event_timed::load_from_row(THD *thd, TABLE *table)
|
||||
{
|
||||
char *ptr;
|
||||
uint len;
|
||||
|
||||
DBUG_ENTER("Event_timed::load_from_row");
|
||||
|
||||
if (Event_queue_element::load_from_row(table))
|
||||
if (Event_queue_element::load_from_row(thd, table))
|
||||
goto error;
|
||||
|
||||
load_string_fields(table->field, ET_FIELD_BODY, &body, ET_FIELD_COUNT);
|
||||
@ -1048,11 +1072,30 @@ error:
|
||||
|
||||
|
||||
/*
|
||||
Computes the sum of a timestamp plus interval. Presumed is that at least one
|
||||
previous execution has occured.
|
||||
add_interval() adds a specified interval to time 'ltime' in time
|
||||
zone 'time_zone', and returns the result converted to the number of
|
||||
seconds since epoch (aka Unix time; in UTC time zone). Zero result
|
||||
means an error.
|
||||
*/
|
||||
static
|
||||
my_time_t
|
||||
add_interval(TIME *ltime, const Time_zone *time_zone,
|
||||
interval_type scale, INTERVAL interval)
|
||||
{
|
||||
if (date_add_interval(ltime, scale, interval))
|
||||
return 0;
|
||||
|
||||
my_bool not_used;
|
||||
return time_zone->TIME_to_gmt_sec(ltime, ¬_used);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Computes the sum of a timestamp plus interval.
|
||||
|
||||
SYNOPSIS
|
||||
get_next_time(TIME *start, int interval_value, interval_type interval)
|
||||
get_next_time()
|
||||
time_zone event time zone
|
||||
next the sum
|
||||
start add interval_value to this time
|
||||
time_now current time
|
||||
@ -1069,26 +1112,19 @@ error:
|
||||
seconds as resolution for computation.
|
||||
2) In all other cases - MONTH, QUARTER, YEAR we use MONTH as resolution
|
||||
and PERIOD_DIFF()'s implementation
|
||||
3) We get the difference between time_now and `start`, then divide it
|
||||
by the months, respectively seconds and round up. Then we multiply
|
||||
monts/seconds by the rounded value and add it to `start` -> we get
|
||||
the next execution time.
|
||||
*/
|
||||
|
||||
static
|
||||
bool get_next_time(TIME *next, TIME *start, TIME *time_now, TIME *last_exec,
|
||||
bool get_next_time(const Time_zone *time_zone, my_time_t *next,
|
||||
my_time_t start, my_time_t time_now,
|
||||
int i_value, interval_type i_type)
|
||||
{
|
||||
bool ret;
|
||||
INTERVAL interval;
|
||||
TIME tmp;
|
||||
longlong months=0, seconds=0;
|
||||
DBUG_ENTER("get_next_time");
|
||||
DBUG_PRINT("enter", ("start: %lu now: %lu",
|
||||
(long) TIME_to_ulonglong_datetime(start),
|
||||
(long) TIME_to_ulonglong_datetime(time_now)));
|
||||
DBUG_PRINT("enter", ("start: %lu now: %lu", (long) start, (long) time_now));
|
||||
|
||||
bzero(&interval, sizeof(interval));
|
||||
DBUG_ASSERT(start <= time_now);
|
||||
|
||||
longlong months=0, seconds=0;
|
||||
|
||||
switch (i_type) {
|
||||
case INTERVAL_YEAR:
|
||||
@ -1135,84 +1171,151 @@ bool get_next_time(TIME *next, TIME *start, TIME *time_now, TIME *last_exec,
|
||||
DBUG_ASSERT(0);
|
||||
}
|
||||
DBUG_PRINT("info", ("seconds: %ld months: %ld", (long) seconds, (long) months));
|
||||
|
||||
TIME local_start;
|
||||
TIME local_now;
|
||||
|
||||
/* Convert times from UTC to local. */
|
||||
{
|
||||
time_zone->gmt_sec_to_TIME(&local_start, start);
|
||||
time_zone->gmt_sec_to_TIME(&local_now, time_now);
|
||||
}
|
||||
|
||||
INTERVAL interval;
|
||||
bzero(&interval, sizeof(interval));
|
||||
my_time_t next_time= 0;
|
||||
|
||||
if (seconds)
|
||||
{
|
||||
longlong seconds_diff;
|
||||
long microsec_diff;
|
||||
|
||||
if (calc_time_diff(time_now, start, 1, &seconds_diff, µsec_diff))
|
||||
bool negative= calc_time_diff(&local_now, &local_start, 1,
|
||||
&seconds_diff, µsec_diff);
|
||||
if (!negative)
|
||||
{
|
||||
DBUG_PRINT("error", ("negative difference"));
|
||||
DBUG_ASSERT(0);
|
||||
/*
|
||||
The formula below returns the interval that, when added to
|
||||
local_start, will always give the time in the future.
|
||||
*/
|
||||
interval.second= seconds_diff - seconds_diff % seconds + seconds;
|
||||
next_time= add_interval(&local_start, time_zone,
|
||||
INTERVAL_SECOND, interval);
|
||||
if (next_time == 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (next_time <= time_now)
|
||||
{
|
||||
/*
|
||||
If 'negative' is true above, then 'next_time == 0', and
|
||||
'next_time <= time_now' is also true. If negative is false,
|
||||
then next_time was set, but perhaps to the value that is less
|
||||
then time_now. See below for elaboration.
|
||||
*/
|
||||
DBUG_ASSERT(negative || next_time > 0);
|
||||
|
||||
/*
|
||||
If local_now < local_start, i.e. STARTS time is in the future
|
||||
according to the local time (it always in the past according
|
||||
to UTC---this is a prerequisite of this function), then
|
||||
STARTS is almost always in the past according to the local
|
||||
time too. However, in the time zone that has backward
|
||||
Daylight Saving Time shift, the following may happen: suppose
|
||||
we have a backward DST shift at certain date after 2:59:59,
|
||||
i.e. local time goes 1:59:59, 2:00:00, ... , 2:59:59, (shift
|
||||
here) 2:00:00 (again), ... , 2:59:59 (again), 3:00:00, ... .
|
||||
Now suppose the time has passed the first 2:59:59, has been
|
||||
shifted backward, and now is (the second) 2:20:00. The user
|
||||
does CREATE EVENT with STARTS 'current-date 2:40:00'. Local
|
||||
time 2:40:00 from create statement is treated by time
|
||||
functions as the first such time, so according to UTC it comes
|
||||
before the second 2:20:00. But according to local time it is
|
||||
obviously in the future, so we end up in this branch.
|
||||
|
||||
Since we are in the second pass through 2:00:00--2:59:59, and
|
||||
any local time form this interval is treated by system
|
||||
functions as the time from the first pass, we have to find the
|
||||
time for the next execution that is past the DST-affected
|
||||
interval (past the second 2:59:59 for our example,
|
||||
i.e. starting from 3:00:00). We do this in the loop until the
|
||||
local time is mapped onto future UTC time. 'start' time is in
|
||||
the past, so we may use 'do { } while' here, and add the first
|
||||
interval right away.
|
||||
|
||||
Alternatively, it could be that local_now >= local_start. Now
|
||||
for the example above imagine we do CREATE EVENT with STARTS
|
||||
'current-date 2:10:00'. Local start 2:10 is in the past (now
|
||||
is local 2:20), so we add an interval, and get next execution
|
||||
time, say, 2:40. It is in the future according to local time,
|
||||
but, again, since we are in the second pass through
|
||||
2:00:00--2:59:59, 2:40 will be converted into UTC time in the
|
||||
past. So we will end up in this branch again, and may add
|
||||
intervals in a 'do { } while' loop.
|
||||
|
||||
Note that for any given event we may end up here only if event
|
||||
next execution time will map to the time interval that is
|
||||
passed twice, and only if the server was started during the
|
||||
second pass, or the event is being created during the second
|
||||
pass. After that, we never will get here (unless we again
|
||||
start the server during the second pass). In other words,
|
||||
such a condition is extremely rare.
|
||||
*/
|
||||
interval.second= seconds;
|
||||
do
|
||||
{
|
||||
next_time= add_interval(&local_start, time_zone,
|
||||
INTERVAL_SECOND, interval);
|
||||
if (next_time == 0)
|
||||
goto done;
|
||||
}
|
||||
while (next_time <= time_now);
|
||||
}
|
||||
uint multiplier= (uint) (seconds_diff / seconds);
|
||||
/*
|
||||
Increase the multiplier is the modulus is not zero to make round up.
|
||||
Or if time_now==start then we should not execute the same
|
||||
event two times for the same time
|
||||
get the next exec if the modulus is not
|
||||
*/
|
||||
DBUG_PRINT("info", ("multiplier: %d", multiplier));
|
||||
if (seconds_diff % seconds || (!seconds_diff && last_exec->year) ||
|
||||
TIME_to_ulonglong_datetime(time_now) ==
|
||||
TIME_to_ulonglong_datetime(last_exec))
|
||||
++multiplier;
|
||||
interval.second= seconds * multiplier;
|
||||
DBUG_PRINT("info", ("multiplier: %lu interval.second: %lu", (ulong) multiplier,
|
||||
(ulong) interval.second));
|
||||
tmp= *start;
|
||||
if (!(ret= date_add_interval(&tmp, INTERVAL_SECOND, interval)))
|
||||
*next= tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* PRESUMED is that at least one execution took already place */
|
||||
int diff_months= (time_now->year - start->year)*12 +
|
||||
(time_now->month - start->month);
|
||||
long diff_months= (long) (local_now.year - local_start.year)*12 +
|
||||
(local_now.month - local_start.month);
|
||||
/*
|
||||
Note: If diff_months is 0 that means we are in the same month as the
|
||||
last execution which is also the first execution.
|
||||
*/
|
||||
/*
|
||||
First we try with the smaller if not then + 1, because if we try with
|
||||
directly with +1 we will be after the current date but it could be that
|
||||
we will be 1 month ahead, so 2 steps are necessary.
|
||||
*/
|
||||
interval.month= (ulong) ((diff_months / months)*months);
|
||||
/*
|
||||
Check if the same month as last_exec (always set - prerequisite)
|
||||
An event happens at most once per month so there is no way to
|
||||
schedule it two times for the current month. This saves us from two
|
||||
calls to date_add_interval() if the event was just executed. But if
|
||||
the scheduler is started and there was at least 1 scheduled date
|
||||
skipped this one does not help and two calls to date_add_interval()
|
||||
will be done, which is a bit more expensive but compared to the
|
||||
rareness of the case is neglectable.
|
||||
*/
|
||||
if (time_now->year == last_exec->year &&
|
||||
time_now->month == last_exec->month)
|
||||
interval.month+= (ulong) months;
|
||||
Unlike for seconds above, the formula below returns the interval
|
||||
that, when added to the local_start, will give the time in the
|
||||
past, or somewhere in the current month. We are interested in
|
||||
the latter case, to see if this time has already passed, or is
|
||||
yet to come this month.
|
||||
|
||||
tmp= *start;
|
||||
if ((ret= date_add_interval(&tmp, INTERVAL_MONTH, interval)))
|
||||
Note that the time is guaranteed to be in the past unless
|
||||
(diff_months % months == 0), but no good optimization is
|
||||
possible here, because (diff_months % months == 0) is what will
|
||||
happen most of the time, as get_next_time() will be called right
|
||||
after the execution of the event. We could pass last_executed
|
||||
time to this function, and see if the execution has already
|
||||
happened this month, but for that we will have to convert
|
||||
last_executed from seconds since epoch to local broken-down
|
||||
time, and this will greatly reduce the effect of the
|
||||
optimization. So instead we keep the code simple and clean.
|
||||
*/
|
||||
interval.month= (ulong) (diff_months - diff_months % months);
|
||||
next_time= add_interval(&local_start, time_zone,
|
||||
INTERVAL_MONTH, interval);
|
||||
if (next_time == 0)
|
||||
goto done;
|
||||
|
||||
/* If `tmp` is still before time_now just add one more time the interval */
|
||||
if (my_time_compare(&tmp, time_now) == -1)
|
||||
{
|
||||
interval.month+= (ulong) months;
|
||||
tmp= *start;
|
||||
if ((ret= date_add_interval(&tmp, INTERVAL_MONTH, interval)))
|
||||
if (next_time <= time_now)
|
||||
{
|
||||
interval.month= (ulong) months;
|
||||
next_time= add_interval(&local_start, time_zone,
|
||||
INTERVAL_MONTH, interval);
|
||||
if (next_time == 0)
|
||||
goto done;
|
||||
}
|
||||
*next= tmp;
|
||||
/* assert on that the next is after now */
|
||||
DBUG_ASSERT(1==my_time_compare(next, time_now));
|
||||
}
|
||||
|
||||
DBUG_ASSERT(time_now < next_time);
|
||||
|
||||
*next= next_time;
|
||||
|
||||
done:
|
||||
DBUG_PRINT("info", ("next: %lu", (long) TIME_to_ulonglong_datetime(next)));
|
||||
DBUG_RETURN(ret);
|
||||
DBUG_PRINT("info", ("next_time: %ld", (long) next_time));
|
||||
DBUG_RETURN(next_time == 0);
|
||||
}
|
||||
|
||||
|
||||
@ -1227,20 +1330,17 @@ done:
|
||||
TRUE Error
|
||||
|
||||
NOTES
|
||||
The time is set in execute_at, if no more executions the latter is set to
|
||||
0000-00-00.
|
||||
The time is set in execute_at, if no more executions the latter is
|
||||
set to 0.
|
||||
*/
|
||||
|
||||
bool
|
||||
Event_queue_element::compute_next_execution_time()
|
||||
{
|
||||
TIME time_now;
|
||||
int tmp;
|
||||
my_time_t time_now;
|
||||
DBUG_ENTER("Event_queue_element::compute_next_execution_time");
|
||||
DBUG_PRINT("enter", ("starts: %lu ends: %lu last_executed: %lu this: 0x%lx",
|
||||
(long) TIME_to_ulonglong_datetime(&starts),
|
||||
(long) TIME_to_ulonglong_datetime(&ends),
|
||||
(long) TIME_to_ulonglong_datetime(&last_executed),
|
||||
(long) starts, (long) ends, (long) last_executed,
|
||||
(long) this));
|
||||
|
||||
if (status == Event_queue_element::DISABLED)
|
||||
@ -1253,7 +1353,7 @@ Event_queue_element::compute_next_execution_time()
|
||||
if (!expression)
|
||||
{
|
||||
/* Let's check whether it was executed */
|
||||
if (last_executed.year)
|
||||
if (last_executed)
|
||||
{
|
||||
DBUG_PRINT("info",("One-time event %s.%s of was already executed",
|
||||
dbname.str, name.str));
|
||||
@ -1266,17 +1366,16 @@ Event_queue_element::compute_next_execution_time()
|
||||
goto ret;
|
||||
}
|
||||
|
||||
my_tz_UTC->gmt_sec_to_TIME(&time_now, (my_time_t)current_thd->query_start());
|
||||
time_now= current_thd->query_start();
|
||||
|
||||
DBUG_PRINT("info",("NOW: [%lu]",
|
||||
(ulong) TIME_to_ulonglong_datetime(&time_now)));
|
||||
DBUG_PRINT("info",("NOW: [%lu]", (ulong) time_now));
|
||||
|
||||
/* if time_now is after ends don't execute anymore */
|
||||
if (!ends_null && (tmp= my_time_compare(&ends, &time_now)) == -1)
|
||||
if (!ends_null && ends < time_now)
|
||||
{
|
||||
DBUG_PRINT("info", ("NOW after ENDS, don't execute anymore"));
|
||||
/* time_now is after ends. don't execute anymore */
|
||||
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
|
||||
execute_at= 0;
|
||||
execute_at_null= TRUE;
|
||||
if (on_completion == Event_queue_element::ON_COMPLETION_DROP)
|
||||
dropped= TRUE;
|
||||
@ -1293,12 +1392,11 @@ Event_queue_element::compute_next_execution_time()
|
||||
Let's check whether time_now is before starts.
|
||||
If so schedule for starts.
|
||||
*/
|
||||
if (!starts_null && (tmp= my_time_compare(&time_now, &starts)) < 1)
|
||||
if (!starts_null && time_now <= starts)
|
||||
{
|
||||
if (tmp == 0 && my_time_compare(&starts, &last_executed) == 0)
|
||||
if (time_now == starts && starts == last_executed)
|
||||
{
|
||||
/*
|
||||
time_now = starts = last_executed
|
||||
do nothing or we will schedule for second time execution at starts.
|
||||
*/
|
||||
}
|
||||
@ -1324,26 +1422,25 @@ Event_queue_element::compute_next_execution_time()
|
||||
If not set then schedule for now.
|
||||
*/
|
||||
DBUG_PRINT("info", ("Both STARTS & ENDS are set"));
|
||||
if (!last_executed.year)
|
||||
if (!last_executed)
|
||||
{
|
||||
DBUG_PRINT("info", ("Not executed so far."));
|
||||
}
|
||||
|
||||
{
|
||||
TIME next_exec;
|
||||
my_time_t next_exec;
|
||||
|
||||
if (get_next_time(&next_exec, &starts, &time_now,
|
||||
last_executed.year? &last_executed:&starts,
|
||||
if (get_next_time(time_zone, &next_exec, starts, time_now,
|
||||
(int) expression, interval))
|
||||
goto err;
|
||||
|
||||
/* There was previous execution */
|
||||
if (my_time_compare(&ends, &next_exec) == -1)
|
||||
if (ends < next_exec)
|
||||
{
|
||||
DBUG_PRINT("info", ("Next execution of %s after ENDS. Stop executing.",
|
||||
name.str));
|
||||
/* Next execution after ends. No more executions */
|
||||
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
|
||||
execute_at= 0;
|
||||
execute_at_null= TRUE;
|
||||
if (on_completion == Event_queue_element::ON_COMPLETION_DROP)
|
||||
dropped= TRUE;
|
||||
@ -1352,8 +1449,7 @@ Event_queue_element::compute_next_execution_time()
|
||||
}
|
||||
else
|
||||
{
|
||||
DBUG_PRINT("info",("Next[%lu]",
|
||||
(ulong) TIME_to_ulonglong_datetime(&next_exec)));
|
||||
DBUG_PRINT("info",("Next[%lu]", (ulong) next_exec));
|
||||
execute_at= next_exec;
|
||||
execute_at_null= FALSE;
|
||||
}
|
||||
@ -1368,15 +1464,14 @@ Event_queue_element::compute_next_execution_time()
|
||||
Both starts and m_ends are not set, so we schedule for the next
|
||||
based on last_executed.
|
||||
*/
|
||||
if (last_executed.year)
|
||||
if (last_executed)
|
||||
{
|
||||
TIME next_exec;
|
||||
if (get_next_time(&next_exec, &starts, &time_now, &last_executed,
|
||||
my_time_t next_exec;
|
||||
if (get_next_time(time_zone, &next_exec, starts, time_now,
|
||||
(int) expression, interval))
|
||||
goto err;
|
||||
execute_at= next_exec;
|
||||
DBUG_PRINT("info",("Next[%lu]",
|
||||
(ulong) TIME_to_ulonglong_datetime(&next_exec)));
|
||||
DBUG_PRINT("info",("Next[%lu]", (ulong) next_exec));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1398,20 +1493,18 @@ Event_queue_element::compute_next_execution_time()
|
||||
Hence schedule for starts + m_expression in case last_executed
|
||||
is not set, otherwise to last_executed + m_expression
|
||||
*/
|
||||
if (!last_executed.year)
|
||||
if (!last_executed)
|
||||
{
|
||||
DBUG_PRINT("info", ("Not executed so far."));
|
||||
}
|
||||
|
||||
{
|
||||
TIME next_exec;
|
||||
if (get_next_time(&next_exec, &starts, &time_now,
|
||||
last_executed.year? &last_executed:&starts,
|
||||
my_time_t next_exec;
|
||||
if (get_next_time(time_zone, &next_exec, starts, time_now,
|
||||
(int) expression, interval))
|
||||
goto err;
|
||||
execute_at= next_exec;
|
||||
DBUG_PRINT("info",("Next[%lu]",
|
||||
(ulong) TIME_to_ulonglong_datetime(&next_exec)));
|
||||
DBUG_PRINT("info",("Next[%lu]", (ulong) next_exec));
|
||||
}
|
||||
execute_at_null= FALSE;
|
||||
}
|
||||
@ -1426,20 +1519,20 @@ Event_queue_element::compute_next_execution_time()
|
||||
If last_executed is not set then schedule for now
|
||||
*/
|
||||
|
||||
if (!last_executed.year)
|
||||
if (!last_executed)
|
||||
execute_at= time_now;
|
||||
else
|
||||
{
|
||||
TIME next_exec;
|
||||
my_time_t next_exec;
|
||||
|
||||
if (get_next_time(&next_exec, &starts, &time_now, &last_executed,
|
||||
if (get_next_time(time_zone, &next_exec, starts, time_now,
|
||||
(int) expression, interval))
|
||||
goto err;
|
||||
|
||||
if (my_time_compare(&ends, &next_exec) == -1)
|
||||
if (ends < next_exec)
|
||||
{
|
||||
DBUG_PRINT("info", ("Next execution after ENDS. Stop executing."));
|
||||
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
|
||||
execute_at= 0;
|
||||
execute_at_null= TRUE;
|
||||
status= Event_queue_element::DISABLED;
|
||||
status_changed= TRUE;
|
||||
@ -1448,8 +1541,7 @@ Event_queue_element::compute_next_execution_time()
|
||||
}
|
||||
else
|
||||
{
|
||||
DBUG_PRINT("info", ("Next[%lu]",
|
||||
(ulong) TIME_to_ulonglong_datetime(&next_exec)));
|
||||
DBUG_PRINT("info", ("Next[%lu]", (ulong) next_exec));
|
||||
execute_at= next_exec;
|
||||
execute_at_null= FALSE;
|
||||
}
|
||||
@ -1458,8 +1550,7 @@ Event_queue_element::compute_next_execution_time()
|
||||
goto ret;
|
||||
}
|
||||
ret:
|
||||
DBUG_PRINT("info", ("ret: 0 execute_at: %lu",
|
||||
(long) TIME_to_ulonglong_datetime(&execute_at)));
|
||||
DBUG_PRINT("info", ("ret: 0 execute_at: %lu", (long) execute_at));
|
||||
DBUG_RETURN(FALSE);
|
||||
err:
|
||||
DBUG_PRINT("info", ("ret=1"));
|
||||
@ -1479,12 +1570,9 @@ err:
|
||||
void
|
||||
Event_queue_element::mark_last_executed(THD *thd)
|
||||
{
|
||||
TIME time_now;
|
||||
|
||||
thd->end_time();
|
||||
my_tz_UTC->gmt_sec_to_TIME(&time_now, (my_time_t) thd->query_start());
|
||||
|
||||
last_executed= time_now; /* was execute_at */
|
||||
last_executed= thd->query_start();
|
||||
last_executed_changed= TRUE;
|
||||
|
||||
execution_count++;
|
||||
@ -1538,8 +1626,11 @@ Event_queue_element::update_timing_fields(THD *thd)
|
||||
|
||||
if (last_executed_changed)
|
||||
{
|
||||
TIME time;
|
||||
my_tz_UTC->gmt_sec_to_TIME(&time, last_executed);
|
||||
|
||||
fields[ET_FIELD_LAST_EXECUTED]->set_notnull();
|
||||
fields[ET_FIELD_LAST_EXECUTED]->store_time(&last_executed,
|
||||
fields[ET_FIELD_LAST_EXECUTED]->store_time(&time,
|
||||
MYSQL_TIMESTAMP_DATETIME);
|
||||
last_executed_changed= FALSE;
|
||||
}
|
||||
@ -1561,6 +1652,26 @@ done:
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void
|
||||
append_datetime(String *buf, Time_zone *time_zone, my_time_t secs,
|
||||
const char *name, uint len)
|
||||
{
|
||||
char dtime_buff[20*2+32];/* +32 to make my_snprintf_{8bit|ucs2} happy */
|
||||
buf->append(STRING_WITH_LEN(" "));
|
||||
buf->append(name, len);
|
||||
buf->append(STRING_WITH_LEN(" '"));
|
||||
/*
|
||||
Pass the buffer and the second param tells fills the buffer and
|
||||
returns the number of chars to copy.
|
||||
*/
|
||||
TIME time;
|
||||
time_zone->gmt_sec_to_TIME(&time, secs);
|
||||
buf->append(dtime_buff, my_datetime_to_str(&time, dtime_buff));
|
||||
buf->append(STRING_WITH_LEN("'"));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Get SHOW CREATE EVENT as string
|
||||
|
||||
@ -1600,17 +1711,17 @@ Event_timed::get_create_event(THD *thd, String *buf)
|
||||
buf->append(' ');
|
||||
LEX_STRING *ival= &interval_type_to_name[interval];
|
||||
buf->append(ival->str, ival->length);
|
||||
|
||||
if (!starts_null)
|
||||
append_datetime(buf, time_zone, starts, STRING_WITH_LEN("STARTS"));
|
||||
|
||||
if (!ends_null)
|
||||
append_datetime(buf, time_zone, ends, STRING_WITH_LEN("ENDS"));
|
||||
}
|
||||
else
|
||||
{
|
||||
char dtime_buff[20*2+32];/* +32 to make my_snprintf_{8bit|ucs2} happy */
|
||||
buf->append(STRING_WITH_LEN(" ON SCHEDULE AT '"));
|
||||
/*
|
||||
Pass the buffer and the second param tells fills the buffer and
|
||||
returns the number of chars to copy.
|
||||
*/
|
||||
buf->append(dtime_buff, my_datetime_to_str(&execute_at, dtime_buff));
|
||||
buf->append(STRING_WITH_LEN("'"));
|
||||
append_datetime(buf, time_zone, execute_at,
|
||||
STRING_WITH_LEN("ON SCHEDULE AT"));
|
||||
}
|
||||
|
||||
if (on_completion == Event_timed::ON_COMPLETION_DROP)
|
||||
@ -1654,6 +1765,7 @@ int
|
||||
Event_job_data::get_fake_create_event(THD *thd, String *buf)
|
||||
{
|
||||
DBUG_ENTER("Event_job_data::get_create_event");
|
||||
/* FIXME: "EVERY 3337 HOUR" is asking for trouble. */
|
||||
buf->append(STRING_WITH_LEN("CREATE EVENT anonymous ON SCHEDULE "
|
||||
"EVERY 3337 HOUR DO "));
|
||||
buf->append(body.str, body.length);
|
||||
@ -1705,6 +1817,9 @@ Event_job_data::execute(THD *thd)
|
||||
sphead->m_flags|= sp_head::LOG_SLOW_STATEMENTS;
|
||||
sphead->m_flags|= sp_head::LOG_GENERAL_LOG;
|
||||
|
||||
/* Execute the event in its time zone. */
|
||||
thd->variables.time_zone= time_zone;
|
||||
|
||||
ret= sphead->execute_procedure(thd, &empty_item_list);
|
||||
}
|
||||
else
|
||||
|
@ -58,15 +58,20 @@ public:
|
||||
LEX_STRING name;
|
||||
LEX_STRING definer;// combination of user and host
|
||||
|
||||
Time_zone *time_zone;
|
||||
|
||||
Event_basic();
|
||||
virtual ~Event_basic();
|
||||
|
||||
virtual int
|
||||
load_from_row(TABLE *table) = 0;
|
||||
load_from_row(THD *thd, TABLE *table) = 0;
|
||||
|
||||
protected:
|
||||
bool
|
||||
load_string_fields(Field **fields, ...);
|
||||
|
||||
bool
|
||||
load_time_zone(THD *thd, const LEX_STRING tz_name);
|
||||
};
|
||||
|
||||
|
||||
@ -92,11 +97,11 @@ public:
|
||||
|
||||
enum enum_on_completion on_completion;
|
||||
enum enum_status status;
|
||||
TIME last_executed;
|
||||
|
||||
TIME execute_at;
|
||||
TIME starts;
|
||||
TIME ends;
|
||||
my_time_t last_executed;
|
||||
my_time_t execute_at;
|
||||
my_time_t starts;
|
||||
my_time_t ends;
|
||||
my_bool starts_null;
|
||||
my_bool ends_null;
|
||||
my_bool execute_at_null;
|
||||
@ -112,7 +117,7 @@ public:
|
||||
virtual ~Event_queue_element();
|
||||
|
||||
virtual int
|
||||
load_from_row(TABLE *table);
|
||||
load_from_row(THD *thd, TABLE *table);
|
||||
|
||||
bool
|
||||
compute_next_execution_time();
|
||||
@ -168,7 +173,7 @@ public:
|
||||
init();
|
||||
|
||||
virtual int
|
||||
load_from_row(TABLE *table);
|
||||
load_from_row(THD *thd, TABLE *table);
|
||||
|
||||
int
|
||||
get_create_event(THD *thd, String *buf);
|
||||
@ -192,7 +197,7 @@ public:
|
||||
virtual ~Event_job_data();
|
||||
|
||||
virtual int
|
||||
load_from_row(TABLE *table);
|
||||
load_from_row(THD *thd, TABLE *table);
|
||||
|
||||
int
|
||||
execute(THD *thd);
|
||||
@ -224,6 +229,11 @@ public:
|
||||
};
|
||||
enum enum_on_completion on_completion;
|
||||
enum enum_status status;
|
||||
/*
|
||||
do_not_create will be set if STARTS time is in the past and
|
||||
on_completion == ON_COMPLETION_DROP.
|
||||
*/
|
||||
bool do_not_create;
|
||||
|
||||
const uchar *body_begin;
|
||||
|
||||
@ -237,9 +247,9 @@ public:
|
||||
Item* item_ends;
|
||||
Item* item_execute_at;
|
||||
|
||||
TIME starts;
|
||||
TIME ends;
|
||||
TIME execute_at;
|
||||
my_time_t starts;
|
||||
my_time_t ends;
|
||||
my_time_t execute_at;
|
||||
my_bool starts_null;
|
||||
my_bool ends_null;
|
||||
my_bool execute_at_null;
|
||||
@ -284,6 +294,9 @@ private:
|
||||
void
|
||||
report_bad_value(const char *item_name, Item *bad_item);
|
||||
|
||||
void
|
||||
check_if_in_the_past(THD *thd, my_time_t ltime_utc);
|
||||
|
||||
Event_parse_data(const Event_parse_data &); /* Prevent use of these */
|
||||
void operator=(Event_parse_data &);
|
||||
};
|
||||
|
@ -118,6 +118,11 @@ const TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] =
|
||||
{ C_STRING_WITH_LEN("comment") },
|
||||
{ C_STRING_WITH_LEN("char(64)") },
|
||||
{ C_STRING_WITH_LEN("utf8") }
|
||||
},
|
||||
{
|
||||
{ C_STRING_WITH_LEN("time_zone") },
|
||||
{ C_STRING_WITH_LEN("char(64)") },
|
||||
{ C_STRING_WITH_LEN("latin1") }
|
||||
}
|
||||
};
|
||||
|
||||
@ -183,6 +188,14 @@ mysql_event_fill_row(THD *thd, TABLE *table, Event_parse_data *et,
|
||||
|
||||
if (et->expression)
|
||||
{
|
||||
const String *tz_name= thd->variables.time_zone->get_name();
|
||||
if (!is_update || !et->starts_null)
|
||||
{
|
||||
fields[ET_FIELD_TIME_ZONE]->set_notnull();
|
||||
fields[ET_FIELD_TIME_ZONE]->store(tz_name->ptr(), tz_name->length(),
|
||||
tz_name->charset());
|
||||
}
|
||||
|
||||
fields[ET_FIELD_INTERVAL_EXPR]->set_notnull();
|
||||
fields[ET_FIELD_INTERVAL_EXPR]->store((longlong)et->expression, TRUE);
|
||||
|
||||
@ -197,26 +210,40 @@ mysql_event_fill_row(THD *thd, TABLE *table, Event_parse_data *et,
|
||||
|
||||
if (!et->starts_null)
|
||||
{
|
||||
TIME time;
|
||||
my_tz_UTC->gmt_sec_to_TIME(&time, et->starts);
|
||||
|
||||
fields[ET_FIELD_STARTS]->set_notnull();
|
||||
fields[ET_FIELD_STARTS]->store_time(&et->starts, MYSQL_TIMESTAMP_DATETIME);
|
||||
fields[ET_FIELD_STARTS]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
|
||||
}
|
||||
|
||||
if (!et->ends_null)
|
||||
{
|
||||
TIME time;
|
||||
my_tz_UTC->gmt_sec_to_TIME(&time, et->ends);
|
||||
|
||||
fields[ET_FIELD_ENDS]->set_notnull();
|
||||
fields[ET_FIELD_ENDS]->store_time(&et->ends, MYSQL_TIMESTAMP_DATETIME);
|
||||
fields[ET_FIELD_ENDS]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
|
||||
}
|
||||
}
|
||||
else if (et->execute_at.year)
|
||||
else if (et->execute_at)
|
||||
{
|
||||
const String *tz_name= thd->variables.time_zone->get_name();
|
||||
fields[ET_FIELD_TIME_ZONE]->set_notnull();
|
||||
fields[ET_FIELD_TIME_ZONE]->store(tz_name->ptr(), tz_name->length(),
|
||||
tz_name->charset());
|
||||
|
||||
fields[ET_FIELD_INTERVAL_EXPR]->set_null();
|
||||
fields[ET_FIELD_TRANSIENT_INTERVAL]->set_null();
|
||||
fields[ET_FIELD_STARTS]->set_null();
|
||||
fields[ET_FIELD_ENDS]->set_null();
|
||||
|
||||
TIME time;
|
||||
my_tz_UTC->gmt_sec_to_TIME(&time, et->execute_at);
|
||||
|
||||
fields[ET_FIELD_EXECUTE_AT]->set_notnull();
|
||||
fields[ET_FIELD_EXECUTE_AT]->
|
||||
store_time(&et->execute_at, MYSQL_TIMESTAMP_DATETIME);
|
||||
store_time(&time, MYSQL_TIMESTAMP_DATETIME);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -527,6 +554,8 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data,
|
||||
|
||||
if (check_parse_params(thd, parse_data))
|
||||
goto err;
|
||||
if (parse_data->do_not_create)
|
||||
goto ok;
|
||||
|
||||
DBUG_PRINT("info", ("open mysql.event for update"));
|
||||
if (open_event_table(thd, TL_WRITE, &table))
|
||||
@ -587,7 +616,7 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data,
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!(parse_data->expression) && !(parse_data->execute_at.year))
|
||||
if (!(parse_data->expression) && !(parse_data->execute_at))
|
||||
{
|
||||
DBUG_PRINT("error", ("neither expression nor execute_at are set!"));
|
||||
my_error(ER_EVENT_NEITHER_M_EXPR_NOR_M_AT, MYF(0));
|
||||
@ -664,7 +693,7 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data,
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (check_parse_params(thd, parse_data))
|
||||
if (check_parse_params(thd, parse_data) || parse_data->do_not_create)
|
||||
goto err;
|
||||
|
||||
DBUG_PRINT("info", ("dbname: %s", parse_data->dbname.str));
|
||||
@ -963,7 +992,7 @@ Event_db_repository::load_named_event(THD *thd, LEX_STRING dbname,
|
||||
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
|
||||
else if ((ret= find_named_event(thd, dbname, name, table)))
|
||||
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
|
||||
else if ((ret= etn->load_from_row(table)))
|
||||
else if ((ret= etn->load_from_row(thd, table)))
|
||||
my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "event");
|
||||
|
||||
if (table)
|
||||
|
@ -35,6 +35,7 @@ enum enum_events_table_field
|
||||
ET_FIELD_ON_COMPLETION,
|
||||
ET_FIELD_SQL_MODE,
|
||||
ET_FIELD_COMMENT,
|
||||
ET_FIELD_TIME_ZONE,
|
||||
ET_FIELD_COUNT /* a cool trick to count the number of fields :) */
|
||||
};
|
||||
|
||||
|
@ -65,8 +65,10 @@ struct event_queue_param
|
||||
static int
|
||||
event_queue_element_compare_q(void *vptr, byte* a, byte *b)
|
||||
{
|
||||
return my_time_compare(&((Event_queue_element *)a)->execute_at,
|
||||
&((Event_queue_element *)b)->execute_at);
|
||||
my_time_t lhs = ((Event_queue_element *)a)->execute_at;
|
||||
my_time_t rhs = ((Event_queue_element *)b)->execute_at;
|
||||
|
||||
return (lhs < rhs ? -1 : (lhs > rhs ? 1 : 0));
|
||||
}
|
||||
|
||||
|
||||
@ -84,7 +86,7 @@ Event_queue::Event_queue()
|
||||
{
|
||||
mutex_last_unlocked_in_func= mutex_last_locked_in_func=
|
||||
mutex_last_attempted_lock_in_func= "";
|
||||
set_zero_time(&next_activation_at, MYSQL_TIMESTAMP_DATETIME);
|
||||
next_activation_at= 0;
|
||||
}
|
||||
|
||||
|
||||
@ -497,15 +499,11 @@ Event_queue::dbug_dump_queue(time_t now)
|
||||
DBUG_PRINT("info", ("exec_at: %lu starts: %lu ends: %lu execs_so_far: %u "
|
||||
"expr: %ld et.exec_at: %ld now: %ld "
|
||||
"(et.exec_at - now): %d if: %d",
|
||||
(long) TIME_to_ulonglong_datetime(&et->execute_at),
|
||||
(long) TIME_to_ulonglong_datetime(&et->starts),
|
||||
(long) TIME_to_ulonglong_datetime(&et->ends),
|
||||
et->execution_count,
|
||||
(long) et->expression,
|
||||
(long) (sec_since_epoch_TIME(&et->execute_at)),
|
||||
(long) now,
|
||||
(int) (sec_since_epoch_TIME(&et->execute_at) - now),
|
||||
sec_since_epoch_TIME(&et->execute_at) <= now));
|
||||
(long) et->execute_at, (long) et->starts,
|
||||
(long) et->ends, et->execution_count,
|
||||
(long) et->expression, (long) et->execute_at,
|
||||
(long) now, (int) (et->execute_at - now),
|
||||
et->execute_at <= now));
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
#endif
|
||||
@ -534,7 +532,6 @@ Event_queue::get_top_for_execution_if_time(THD *thd,
|
||||
Event_queue_element_for_exec **event_name)
|
||||
{
|
||||
bool ret= FALSE;
|
||||
struct timespec top_time;
|
||||
*event_name= NULL;
|
||||
DBUG_ENTER("Event_queue::get_top_for_execution_if_time");
|
||||
|
||||
@ -553,7 +550,7 @@ Event_queue::get_top_for_execution_if_time(THD *thd,
|
||||
if (!queue.elements)
|
||||
{
|
||||
/* There are no events in the queue */
|
||||
set_zero_time(&next_activation_at, MYSQL_TIMESTAMP_DATETIME);
|
||||
next_activation_at= 0;
|
||||
|
||||
/* Wait on condition until signaled. Release LOCK_queue while waiting. */
|
||||
cond_wait(thd, NULL, queue_empty_msg, SCHED_FUNC, __LINE__);
|
||||
@ -565,16 +562,15 @@ Event_queue::get_top_for_execution_if_time(THD *thd,
|
||||
|
||||
thd->end_time(); /* Get current time */
|
||||
|
||||
time_t seconds_to_next_event=
|
||||
sec_since_epoch_TIME(&top->execute_at) - thd->query_start();
|
||||
next_activation_at= top->execute_at;
|
||||
if (seconds_to_next_event > 0)
|
||||
if (next_activation_at > thd->query_start())
|
||||
{
|
||||
/*
|
||||
Not yet time for top event, wait on condition with
|
||||
time or until signaled. Release LOCK_queue while waiting.
|
||||
*/
|
||||
set_timespec(top_time, seconds_to_next_event);
|
||||
struct timespec top_time;
|
||||
set_timespec(top_time, next_activation_at - thd->query_start());
|
||||
cond_wait(thd, &top_time, queue_wait_msg, SCHED_FUNC, __LINE__);
|
||||
|
||||
continue;
|
||||
@ -752,10 +748,11 @@ Event_queue::dump_internal_status()
|
||||
printf("Last lock attempt at: %s:%u\n", mutex_last_attempted_lock_in_func,
|
||||
mutex_last_attempted_lock_at_line);
|
||||
printf("WOC : %s\n", waiting_on_cond? "YES":"NO");
|
||||
|
||||
TIME time;
|
||||
my_tz_UTC->gmt_sec_to_TIME(&time, next_activation_at);
|
||||
printf("Next activation : %04d-%02d-%02d %02d:%02d:%02d\n",
|
||||
next_activation_at.year, next_activation_at.month,
|
||||
next_activation_at.day, next_activation_at.hour,
|
||||
next_activation_at.minute, next_activation_at.second);
|
||||
time.year, time.month, time.day, time.hour, time.minute, time.second);
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ protected:
|
||||
/* The sorted queue with the Event_queue_element objects */
|
||||
QUEUE queue;
|
||||
|
||||
TIME next_activation_at;
|
||||
my_time_t next_activation_at;
|
||||
|
||||
uint mutex_last_locked_at_line;
|
||||
uint mutex_last_unlocked_at_line;
|
||||
|
@ -574,6 +574,14 @@ Event_scheduler::execute_top(THD *thd, Event_queue_element_for_exec *event_name)
|
||||
DBUG_PRINT("info", ("Event %s@%s ready for start",
|
||||
event_name->dbname.str, event_name->name.str));
|
||||
|
||||
/*
|
||||
TODO: should use thread pool here, preferably with an upper limit
|
||||
on number of threads: if too many events are scheduled for the
|
||||
same time, starting all of them at once won't help them run truly
|
||||
in parallel (because of the great amount of synchronization), so
|
||||
we may as well execute them in sequence, keeping concurrency at a
|
||||
reasonable level.
|
||||
*/
|
||||
/* Major failure */
|
||||
if ((res= pthread_create(&th, &connection_attrib, event_worker_thread,
|
||||
event_name)))
|
||||
|
@ -326,7 +326,8 @@ Events::create_event(THD *thd, Event_parse_data *parse_data, bool if_not_exists)
|
||||
|
||||
pthread_mutex_lock(&LOCK_event_metadata);
|
||||
/* On error conditions my_error() is called so no need to handle here */
|
||||
if (!(ret= db_repository->create_event(thd, parse_data, if_not_exists)))
|
||||
if (!(ret= db_repository->create_event(thd, parse_data, if_not_exists)) &&
|
||||
!parse_data->do_not_create)
|
||||
{
|
||||
Event_queue_element *new_element;
|
||||
|
||||
@ -527,6 +528,10 @@ Events::show_create_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
|
||||
|
||||
field_list.push_back(new Item_empty_string("sql_mode", sql_mode_len));
|
||||
|
||||
const String *tz_name= et->time_zone->get_name();
|
||||
field_list.push_back(new Item_empty_string("time_zone",
|
||||
tz_name->length()));
|
||||
|
||||
field_list.push_back(new Item_empty_string("Create Event",
|
||||
show_str.length()));
|
||||
|
||||
@ -539,6 +544,8 @@ Events::show_create_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
|
||||
|
||||
protocol->store((char*) sql_mode_str, sql_mode_len, scs);
|
||||
|
||||
protocol->store((char*) tz_name->ptr(), tz_name->length(), scs);
|
||||
|
||||
protocol->store(show_str.c_ptr(), show_str.length(), scs);
|
||||
ret= protocol->write();
|
||||
send_eof(thd);
|
||||
@ -942,7 +949,7 @@ Events::load_events_from_db(THD *thd)
|
||||
}
|
||||
DBUG_PRINT("info", ("Loading event from row."));
|
||||
|
||||
if ((ret= et->load_from_row(table)))
|
||||
if ((ret= et->load_from_row(thd, table)))
|
||||
{
|
||||
sql_print_error("SCHEDULER: Error while loading from mysql.event. "
|
||||
"Table probably corrupted");
|
||||
@ -967,7 +974,7 @@ Events::load_events_from_db(THD *thd)
|
||||
Event_job_data temp_job_data;
|
||||
DBUG_PRINT("info", ("Event %s loaded from row. ", et->name.str));
|
||||
|
||||
temp_job_data.load_from_row(table);
|
||||
temp_job_data.load_from_row(thd, table);
|
||||
|
||||
/*
|
||||
We load only on scheduler root just to check whether the body
|
||||
|
@ -1208,13 +1208,13 @@ String *Field::val_int_as_str(String *val_buffer, my_bool unsigned_val)
|
||||
{
|
||||
ASSERT_COLUMN_MARKED_FOR_READ;
|
||||
CHARSET_INFO *cs= &my_charset_bin;
|
||||
uint length= 21;
|
||||
uint length;
|
||||
longlong value= val_int();
|
||||
|
||||
if (val_buffer->alloc(length))
|
||||
if (val_buffer->alloc(MY_INT64_NUM_DECIMAL_DIGITS))
|
||||
return 0;
|
||||
length= (uint) (*cs->cset->longlong10_to_str)(cs, (char*) val_buffer->ptr(),
|
||||
length,
|
||||
MY_INT64_NUM_DECIMAL_DIGITS,
|
||||
unsigned_val ? 10 : -10,
|
||||
value);
|
||||
val_buffer->length(length);
|
||||
|
@ -1143,9 +1143,9 @@ bool mysql_xa_recover(THD *thd)
|
||||
XID_STATE *xs;
|
||||
DBUG_ENTER("mysql_xa_recover");
|
||||
|
||||
field_list.push_back(new Item_int("formatID",0,11));
|
||||
field_list.push_back(new Item_int("gtrid_length",0,11));
|
||||
field_list.push_back(new Item_int("bqual_length",0,11));
|
||||
field_list.push_back(new Item_int("formatID", 0, MY_INT32_NUM_DECIMAL_DIGITS));
|
||||
field_list.push_back(new Item_int("gtrid_length", 0, MY_INT32_NUM_DECIMAL_DIGITS));
|
||||
field_list.push_back(new Item_int("bqual_length", 0, MY_INT32_NUM_DECIMAL_DIGITS));
|
||||
field_list.push_back(new Item_empty_string("data",XIDDATASIZE));
|
||||
|
||||
if (protocol->send_fields(&field_list,
|
||||
|
@ -986,7 +986,11 @@ public:
|
||||
check_if_locking_is_allowed()
|
||||
thd Handler of the thread, trying to lock the table
|
||||
table Table handler to check
|
||||
count Number of locks already granted to the table
|
||||
count Total number of tables to be locked
|
||||
current Index of the current table in the list of the tables
|
||||
to be locked.
|
||||
system_count Pointer to the counter of system tables seen thus
|
||||
far.
|
||||
called_by_privileged_thread TRUE if called from a logger THD
|
||||
(general_log_thd or slow_log_thd)
|
||||
or by a privileged thread, which
|
||||
@ -1005,7 +1009,8 @@ public:
|
||||
*/
|
||||
virtual bool check_if_locking_is_allowed(uint sql_command,
|
||||
ulong type, TABLE *table,
|
||||
uint count,
|
||||
uint count, uint current,
|
||||
uint *system_count,
|
||||
bool called_by_privileged_thread)
|
||||
{
|
||||
return TRUE;
|
||||
|
@ -148,7 +148,7 @@ void
|
||||
Hybrid_type_traits_integer::fix_length_and_dec(Item *item, Item *arg) const
|
||||
{
|
||||
item->decimals= 0;
|
||||
item->max_length= 21;
|
||||
item->max_length= MY_INT64_NUM_DECIMAL_DIGITS;
|
||||
item->unsigned_flag= 0;
|
||||
}
|
||||
|
||||
@ -2525,7 +2525,7 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry)
|
||||
item_result_type= REAL_RESULT;
|
||||
break;
|
||||
case INT_RESULT:
|
||||
set_int(*(longlong*)entry->value, 21);
|
||||
set_int(*(longlong*)entry->value, MY_INT64_NUM_DECIMAL_DIGITS);
|
||||
item_type= Item::INT_ITEM;
|
||||
item_result_type= INT_RESULT;
|
||||
break;
|
||||
@ -6676,7 +6676,7 @@ uint32 Item_type_holder::display_length(Item *item)
|
||||
case MYSQL_TYPE_SHORT:
|
||||
return 6;
|
||||
case MYSQL_TYPE_LONG:
|
||||
return 11;
|
||||
return MY_INT32_NUM_DECIMAL_DIGITS;
|
||||
case MYSQL_TYPE_FLOAT:
|
||||
return 25;
|
||||
case MYSQL_TYPE_DOUBLE:
|
||||
|
@ -1592,11 +1592,14 @@ class Item_int :public Item_num
|
||||
{
|
||||
public:
|
||||
longlong value;
|
||||
Item_int(int32 i,uint length=11) :value((longlong) i)
|
||||
Item_int(int32 i,uint length= MY_INT32_NUM_DECIMAL_DIGITS)
|
||||
:value((longlong) i)
|
||||
{ max_length=length; fixed= 1; }
|
||||
Item_int(longlong i,uint length=21) :value(i)
|
||||
Item_int(longlong i,uint length= MY_INT64_NUM_DECIMAL_DIGITS)
|
||||
:value(i)
|
||||
{ max_length=length; fixed= 1; }
|
||||
Item_int(ulonglong i, uint length= 21) :value((longlong)i)
|
||||
Item_int(ulonglong i, uint length= MY_INT64_NUM_DECIMAL_DIGITS)
|
||||
:value((longlong)i)
|
||||
{ max_length=length; fixed= 1; unsigned_flag= 1; }
|
||||
Item_int(const char *str_arg,longlong i,uint length) :value(i)
|
||||
{ max_length=length; name=(char*) str_arg; fixed= 1; }
|
||||
|
@ -2877,9 +2877,6 @@ Create_func_convert_tz Create_func_convert_tz::s_singleton;
|
||||
Item*
|
||||
Create_func_convert_tz::create(THD *thd, Item *arg1, Item *arg2, Item *arg3)
|
||||
{
|
||||
if (thd->lex->add_time_zone_tables_to_query_tables(thd))
|
||||
return NULL;
|
||||
|
||||
return new (thd->mem_root) Item_func_convert_tz(arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
|
@ -435,7 +435,7 @@ Field *Item_func::tmp_table_field(TABLE *table)
|
||||
|
||||
switch (result_type()) {
|
||||
case INT_RESULT:
|
||||
if (max_length > 11)
|
||||
if (max_length > MY_INT32_NUM_DECIMAL_DIGITS)
|
||||
field= new Field_longlong(max_length, maybe_null, name, unsigned_flag);
|
||||
else
|
||||
field= new Field_long(max_length, maybe_null, name, unsigned_flag);
|
||||
@ -2338,7 +2338,8 @@ longlong Item_func_coercibility::val_int()
|
||||
|
||||
void Item_func_locate::fix_length_and_dec()
|
||||
{
|
||||
maybe_null=0; max_length=11;
|
||||
maybe_null= 0;
|
||||
max_length= MY_INT32_NUM_DECIMAL_DIGITS;
|
||||
agg_arg_charsets(cmp_collation, args, 2, MY_COLL_CMP_CONV, 1);
|
||||
}
|
||||
|
||||
|
@ -1080,7 +1080,8 @@ Item_in_subselect::single_value_transformer(JOIN *join,
|
||||
Item *having= item, *orig_item= item;
|
||||
select_lex->item_list.empty();
|
||||
select_lex->item_list.push_back(new Item_int("Not_used",
|
||||
(longlong) 1, 21));
|
||||
(longlong) 1,
|
||||
MY_INT64_NUM_DECIMAL_DIGITS));
|
||||
select_lex->ref_pointer_array[0]= select_lex->item_list.head();
|
||||
|
||||
item= func->create(expr, item);
|
||||
|
@ -1927,19 +1927,6 @@ void Item_func_convert_tz::fix_length_and_dec()
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Item_func_convert_tz::fix_fields(THD *thd_arg, Item **ref)
|
||||
{
|
||||
String str;
|
||||
if (Item_date_func::fix_fields(thd_arg, ref))
|
||||
return TRUE;
|
||||
|
||||
tz_tables= thd_arg->lex->time_zone_tables_used;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
String *Item_func_convert_tz::val_str(String *str)
|
||||
{
|
||||
TIME time_tmp;
|
||||
@ -1974,16 +1961,17 @@ bool Item_func_convert_tz::get_date(TIME *ltime,
|
||||
{
|
||||
my_time_t my_time_tmp;
|
||||
String str;
|
||||
THD *thd= current_thd;
|
||||
|
||||
if (!from_tz_cached)
|
||||
{
|
||||
from_tz= my_tz_find(args[1]->val_str(&str), tz_tables);
|
||||
from_tz= my_tz_find(thd, args[1]->val_str(&str));
|
||||
from_tz_cached= args[1]->const_item();
|
||||
}
|
||||
|
||||
if (!to_tz_cached)
|
||||
{
|
||||
to_tz= my_tz_find(args[2]->val_str(&str), tz_tables);
|
||||
to_tz= my_tz_find(thd, args[2]->val_str(&str));
|
||||
to_tz_cached= args[2]->const_item();
|
||||
}
|
||||
|
||||
|
@ -641,8 +641,6 @@ class Time_zone;
|
||||
*/
|
||||
class Item_func_convert_tz :public Item_date_func
|
||||
{
|
||||
/* Cached pointer to list of pre-opened time zone tables. */
|
||||
TABLE_LIST *tz_tables;
|
||||
/*
|
||||
If time zone parameters are constants we are caching objects that
|
||||
represent them (we use separate from_tz_cached/to_tz_cached members
|
||||
@ -658,7 +656,6 @@ class Item_func_convert_tz :public Item_date_func
|
||||
double val_real() { return (double) val_int(); }
|
||||
String *val_str(String *str);
|
||||
const char *func_name() const { return "convert_tz"; }
|
||||
bool fix_fields(THD *, Item **);
|
||||
void fix_length_and_dec();
|
||||
bool get_date(TIME *res, uint fuzzy_date);
|
||||
void cleanup();
|
||||
|
@ -692,6 +692,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
|
||||
|
||||
DBUG_PRINT("info", ("count %d", count));
|
||||
*write_lock_used=0;
|
||||
uint system_count= 0;
|
||||
for (i=tables=lock_count=0 ; i < count ; i++)
|
||||
{
|
||||
if (table_ptr[i]->s->tmp_table != TMP_TABLE)
|
||||
@ -705,7 +706,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
|
||||
*/
|
||||
if (!table_ptr[i]-> file->
|
||||
check_if_locking_is_allowed(thd->lex->sql_command, thd->lex->type,
|
||||
table_ptr[i], count,
|
||||
table_ptr[i], count, i, &system_count,
|
||||
(thd == logger.get_general_log_thd()) ||
|
||||
(thd == logger.get_slow_log_thd()) ||
|
||||
(thd == logger.get_privileged_thread())))
|
||||
|
@ -642,12 +642,13 @@ int Log_event::net_send(Protocol *protocol, const char* log_name, my_off_t pos)
|
||||
void Log_event::init_show_field_list(List<Item>* field_list)
|
||||
{
|
||||
field_list->push_back(new Item_empty_string("Log_name", 20));
|
||||
field_list->push_back(new Item_return_int("Pos", 11,
|
||||
field_list->push_back(new Item_return_int("Pos", MY_INT32_NUM_DECIMAL_DIGITS,
|
||||
MYSQL_TYPE_LONGLONG));
|
||||
field_list->push_back(new Item_empty_string("Event_type", 20));
|
||||
field_list->push_back(new Item_return_int("Server_id", 10,
|
||||
MYSQL_TYPE_LONG));
|
||||
field_list->push_back(new Item_return_int("End_log_pos", 11,
|
||||
field_list->push_back(new Item_return_int("End_log_pos",
|
||||
MY_INT32_NUM_DECIMAL_DIGITS,
|
||||
MYSQL_TYPE_LONGLONG));
|
||||
field_list->push_back(new Item_empty_string("Info", 20));
|
||||
}
|
||||
@ -2006,8 +2007,7 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli,
|
||||
if (time_zone_len)
|
||||
{
|
||||
String tmp(time_zone_str, time_zone_len, &my_charset_bin);
|
||||
if (!(thd->variables.time_zone=
|
||||
my_tz_find_with_opening_tz_tables(thd, &tmp)))
|
||||
if (!(thd->variables.time_zone= my_tz_find(thd, &tmp)))
|
||||
{
|
||||
my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), tmp.c_ptr());
|
||||
thd->variables.time_zone= global_system_variables.time_zone;
|
||||
|
@ -646,6 +646,7 @@ struct Query_cache_query_flags
|
||||
{
|
||||
unsigned int client_long_flag:1;
|
||||
unsigned int client_protocol_41:1;
|
||||
unsigned int result_in_binary_protocol:1;
|
||||
unsigned int more_results_exists:1;
|
||||
unsigned int pkt_nr;
|
||||
uint character_set_client_num;
|
||||
@ -672,6 +673,11 @@ struct Query_cache_query_flags
|
||||
query_cache.send_result_to_client(A, B, C)
|
||||
#define query_cache_invalidate_by_MyISAM_filename_ref \
|
||||
&query_cache_invalidate_by_MyISAM_filename
|
||||
/* note the "maybe": it's a read without mutex */
|
||||
#define query_cache_maybe_disabled(T) \
|
||||
(T->variables.query_cache_type == 0 || query_cache.query_cache_size == 0)
|
||||
#define query_cache_is_cacheable_query(L) \
|
||||
(((L)->sql_command == SQLCOM_SELECT) && (L)->safe_to_cache_query)
|
||||
#else
|
||||
#define QUERY_CACHE_FLAGS_SIZE 0
|
||||
#define query_cache_store_query(A, B)
|
||||
@ -688,6 +694,8 @@ struct Query_cache_query_flags
|
||||
#define query_cache_abort(A)
|
||||
#define query_cache_end_of_result(A)
|
||||
#define query_cache_invalidate_by_MyISAM_filename_ref NULL
|
||||
#define query_cache_maybe_disabled(T) 1
|
||||
#define query_cache_is_cacheable_query(L) 0
|
||||
#endif /*HAVE_QUERY_CACHE*/
|
||||
|
||||
/*
|
||||
@ -1429,6 +1437,12 @@ int abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt);
|
||||
void close_open_tables_and_downgrade(ALTER_PARTITION_PARAM_TYPE *lpt);
|
||||
void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table);
|
||||
|
||||
/* Functions to work with system tables. */
|
||||
bool open_system_tables_for_read(THD *thd, TABLE_LIST *table_list,
|
||||
Open_tables_state *backup);
|
||||
void close_system_tables(THD *thd, Open_tables_state *backup);
|
||||
TABLE *open_system_table_for_update(THD *thd, TABLE_LIST *one_table);
|
||||
|
||||
bool close_cached_tables(THD *thd, bool wait_for_refresh, TABLE_LIST *tables, bool have_lock = FALSE);
|
||||
void copy_field_from_tmp_record(Field *field,int offset);
|
||||
bool fill_record(THD *thd, Field **field, List<Item> &values,
|
||||
|
@ -3805,6 +3805,7 @@ we force server id to 2, but this MySQL server will not act as a slave.");
|
||||
udf_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
init_status_vars();
|
||||
if (opt_bootstrap) /* If running with bootstrap, do not start replication. */
|
||||
opt_skip_slave_start= 1;
|
||||
@ -3851,6 +3852,10 @@ we force server id to 2, but this MySQL server will not act as a slave.");
|
||||
if (Events::get_instance()->init())
|
||||
unireg_abort(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
Events::opt_event_scheduler = Events::EVENTS_DISABLED;
|
||||
}
|
||||
|
||||
/* Signal threads waiting for server to be started */
|
||||
pthread_mutex_lock(&LOCK_server_started);
|
||||
|
@ -35,7 +35,7 @@ static void write_eof_packet(THD *thd, NET *net);
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
bool Protocol::net_store_data(const char *from, uint length)
|
||||
#else
|
||||
bool Protocol_prep::net_store_data(const char *from, uint length)
|
||||
bool Protocol_binary::net_store_data(const char *from, uint length)
|
||||
#endif
|
||||
{
|
||||
ulong packet_length=packet->length();
|
||||
@ -557,7 +557,7 @@ bool Protocol::send_fields(List<Item> *list, uint flags)
|
||||
Item *item;
|
||||
char buff[80];
|
||||
String tmp((char*) buff,sizeof(buff),&my_charset_bin);
|
||||
Protocol_simple prot(thd);
|
||||
Protocol_text prot(thd);
|
||||
String *local_packet= prot.storage_packet();
|
||||
CHARSET_INFO *thd_charset= thd->variables.character_set_results;
|
||||
DBUG_ENTER("send_fields");
|
||||
@ -760,7 +760,7 @@ bool Protocol::store(I_List<i_string>* str_list)
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
void Protocol_simple::prepare_for_resend()
|
||||
void Protocol_text::prepare_for_resend()
|
||||
{
|
||||
packet->length(0);
|
||||
#ifndef DBUG_OFF
|
||||
@ -768,7 +768,7 @@ void Protocol_simple::prepare_for_resend()
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Protocol_simple::store_null()
|
||||
bool Protocol_text::store_null()
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
field_pos++;
|
||||
@ -801,7 +801,7 @@ bool Protocol::store_string_aux(const char *from, uint length,
|
||||
}
|
||||
|
||||
|
||||
bool Protocol_simple::store(const char *from, uint length,
|
||||
bool Protocol_text::store(const char *from, uint length,
|
||||
CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
@ -817,8 +817,8 @@ bool Protocol_simple::store(const char *from, uint length,
|
||||
}
|
||||
|
||||
|
||||
bool Protocol_simple::store(const char *from, uint length,
|
||||
CHARSET_INFO *fromcs)
|
||||
bool Protocol_text::store(const char *from, uint length,
|
||||
CHARSET_INFO *fromcs)
|
||||
{
|
||||
CHARSET_INFO *tocs= this->thd->variables.character_set_results;
|
||||
#ifndef DBUG_OFF
|
||||
@ -834,7 +834,7 @@ bool Protocol_simple::store(const char *from, uint length,
|
||||
}
|
||||
|
||||
|
||||
bool Protocol_simple::store_tiny(longlong from)
|
||||
bool Protocol_text::store_tiny(longlong from)
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_TINY);
|
||||
@ -846,7 +846,7 @@ bool Protocol_simple::store_tiny(longlong from)
|
||||
}
|
||||
|
||||
|
||||
bool Protocol_simple::store_short(longlong from)
|
||||
bool Protocol_text::store_short(longlong from)
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
DBUG_ASSERT(field_types == 0 ||
|
||||
@ -860,7 +860,7 @@ bool Protocol_simple::store_short(longlong from)
|
||||
}
|
||||
|
||||
|
||||
bool Protocol_simple::store_long(longlong from)
|
||||
bool Protocol_text::store_long(longlong from)
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
DBUG_ASSERT(field_types == 0 ||
|
||||
@ -874,7 +874,7 @@ bool Protocol_simple::store_long(longlong from)
|
||||
}
|
||||
|
||||
|
||||
bool Protocol_simple::store_longlong(longlong from, bool unsigned_flag)
|
||||
bool Protocol_text::store_longlong(longlong from, bool unsigned_flag)
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
DBUG_ASSERT(field_types == 0 ||
|
||||
@ -889,7 +889,7 @@ bool Protocol_simple::store_longlong(longlong from, bool unsigned_flag)
|
||||
}
|
||||
|
||||
|
||||
bool Protocol_simple::store_decimal(const my_decimal *d)
|
||||
bool Protocol_text::store_decimal(const my_decimal *d)
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
DBUG_ASSERT(field_types == 0 ||
|
||||
@ -903,7 +903,7 @@ bool Protocol_simple::store_decimal(const my_decimal *d)
|
||||
}
|
||||
|
||||
|
||||
bool Protocol_simple::store(float from, uint32 decimals, String *buffer)
|
||||
bool Protocol_text::store(float from, uint32 decimals, String *buffer)
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
DBUG_ASSERT(field_types == 0 ||
|
||||
@ -915,7 +915,7 @@ bool Protocol_simple::store(float from, uint32 decimals, String *buffer)
|
||||
}
|
||||
|
||||
|
||||
bool Protocol_simple::store(double from, uint32 decimals, String *buffer)
|
||||
bool Protocol_text::store(double from, uint32 decimals, String *buffer)
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
DBUG_ASSERT(field_types == 0 ||
|
||||
@ -927,7 +927,7 @@ bool Protocol_simple::store(double from, uint32 decimals, String *buffer)
|
||||
}
|
||||
|
||||
|
||||
bool Protocol_simple::store(Field *field)
|
||||
bool Protocol_text::store(Field *field)
|
||||
{
|
||||
if (field->is_null())
|
||||
return store_null();
|
||||
@ -961,7 +961,7 @@ bool Protocol_simple::store(Field *field)
|
||||
*/
|
||||
|
||||
|
||||
bool Protocol_simple::store(TIME *tm)
|
||||
bool Protocol_text::store(TIME *tm)
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
DBUG_ASSERT(field_types == 0 ||
|
||||
@ -984,7 +984,7 @@ bool Protocol_simple::store(TIME *tm)
|
||||
}
|
||||
|
||||
|
||||
bool Protocol_simple::store_date(TIME *tm)
|
||||
bool Protocol_text::store_date(TIME *tm)
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
DBUG_ASSERT(field_types == 0 ||
|
||||
@ -1003,7 +1003,7 @@ bool Protocol_simple::store_date(TIME *tm)
|
||||
we support 0-6 decimals for time.
|
||||
*/
|
||||
|
||||
bool Protocol_simple::store_time(TIME *tm)
|
||||
bool Protocol_text::store_time(TIME *tm)
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
DBUG_ASSERT(field_types == 0 ||
|
||||
@ -1043,7 +1043,7 @@ bool Protocol_simple::store_time(TIME *tm)
|
||||
[..]..[[length]data] data
|
||||
****************************************************************************/
|
||||
|
||||
bool Protocol_prep::prepare_for_send(List<Item> *item_list)
|
||||
bool Protocol_binary::prepare_for_send(List<Item> *item_list)
|
||||
{
|
||||
Protocol::prepare_for_send(item_list);
|
||||
bit_fields= (field_count+9)/8;
|
||||
@ -1054,7 +1054,7 @@ bool Protocol_prep::prepare_for_send(List<Item> *item_list)
|
||||
}
|
||||
|
||||
|
||||
void Protocol_prep::prepare_for_resend()
|
||||
void Protocol_binary::prepare_for_resend()
|
||||
{
|
||||
packet->length(bit_fields+1);
|
||||
bzero((char*) packet->ptr(), 1+bit_fields);
|
||||
@ -1062,21 +1062,22 @@ void Protocol_prep::prepare_for_resend()
|
||||
}
|
||||
|
||||
|
||||
bool Protocol_prep::store(const char *from, uint length, CHARSET_INFO *fromcs)
|
||||
bool Protocol_binary::store(const char *from, uint length,
|
||||
CHARSET_INFO *fromcs)
|
||||
{
|
||||
CHARSET_INFO *tocs= thd->variables.character_set_results;
|
||||
field_pos++;
|
||||
return store_string_aux(from, length, fromcs, tocs);
|
||||
}
|
||||
|
||||
bool Protocol_prep::store(const char *from,uint length,
|
||||
CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
|
||||
bool Protocol_binary::store(const char *from,uint length,
|
||||
CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
|
||||
{
|
||||
field_pos++;
|
||||
return store_string_aux(from, length, fromcs, tocs);
|
||||
}
|
||||
|
||||
bool Protocol_prep::store_null()
|
||||
bool Protocol_binary::store_null()
|
||||
{
|
||||
uint offset= (field_pos+2)/8+1, bit= (1 << ((field_pos+2) & 7));
|
||||
/* Room for this as it's allocated in prepare_for_send */
|
||||
@ -1087,7 +1088,7 @@ bool Protocol_prep::store_null()
|
||||
}
|
||||
|
||||
|
||||
bool Protocol_prep::store_tiny(longlong from)
|
||||
bool Protocol_binary::store_tiny(longlong from)
|
||||
{
|
||||
char buff[1];
|
||||
field_pos++;
|
||||
@ -1096,7 +1097,7 @@ bool Protocol_prep::store_tiny(longlong from)
|
||||
}
|
||||
|
||||
|
||||
bool Protocol_prep::store_short(longlong from)
|
||||
bool Protocol_binary::store_short(longlong from)
|
||||
{
|
||||
field_pos++;
|
||||
char *to= packet->prep_append(2, PACKET_BUFFER_EXTRA_ALLOC);
|
||||
@ -1107,7 +1108,7 @@ bool Protocol_prep::store_short(longlong from)
|
||||
}
|
||||
|
||||
|
||||
bool Protocol_prep::store_long(longlong from)
|
||||
bool Protocol_binary::store_long(longlong from)
|
||||
{
|
||||
field_pos++;
|
||||
char *to= packet->prep_append(4, PACKET_BUFFER_EXTRA_ALLOC);
|
||||
@ -1118,7 +1119,7 @@ bool Protocol_prep::store_long(longlong from)
|
||||
}
|
||||
|
||||
|
||||
bool Protocol_prep::store_longlong(longlong from, bool unsigned_flag)
|
||||
bool Protocol_binary::store_longlong(longlong from, bool unsigned_flag)
|
||||
{
|
||||
field_pos++;
|
||||
char *to= packet->prep_append(8, PACKET_BUFFER_EXTRA_ALLOC);
|
||||
@ -1128,7 +1129,7 @@ bool Protocol_prep::store_longlong(longlong from, bool unsigned_flag)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Protocol_prep::store_decimal(const my_decimal *d)
|
||||
bool Protocol_binary::store_decimal(const my_decimal *d)
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
DBUG_ASSERT(field_types == 0 ||
|
||||
@ -1141,7 +1142,7 @@ bool Protocol_prep::store_decimal(const my_decimal *d)
|
||||
return store(str.ptr(), str.length(), str.charset());
|
||||
}
|
||||
|
||||
bool Protocol_prep::store(float from, uint32 decimals, String *buffer)
|
||||
bool Protocol_binary::store(float from, uint32 decimals, String *buffer)
|
||||
{
|
||||
field_pos++;
|
||||
char *to= packet->prep_append(4, PACKET_BUFFER_EXTRA_ALLOC);
|
||||
@ -1152,7 +1153,7 @@ bool Protocol_prep::store(float from, uint32 decimals, String *buffer)
|
||||
}
|
||||
|
||||
|
||||
bool Protocol_prep::store(double from, uint32 decimals, String *buffer)
|
||||
bool Protocol_binary::store(double from, uint32 decimals, String *buffer)
|
||||
{
|
||||
field_pos++;
|
||||
char *to= packet->prep_append(8, PACKET_BUFFER_EXTRA_ALLOC);
|
||||
@ -1163,7 +1164,7 @@ bool Protocol_prep::store(double from, uint32 decimals, String *buffer)
|
||||
}
|
||||
|
||||
|
||||
bool Protocol_prep::store(Field *field)
|
||||
bool Protocol_binary::store(Field *field)
|
||||
{
|
||||
/*
|
||||
We should not increment field_pos here as send_binary() will call another
|
||||
@ -1175,7 +1176,7 @@ bool Protocol_prep::store(Field *field)
|
||||
}
|
||||
|
||||
|
||||
bool Protocol_prep::store(TIME *tm)
|
||||
bool Protocol_binary::store(TIME *tm)
|
||||
{
|
||||
char buff[12],*pos;
|
||||
uint length;
|
||||
@ -1201,15 +1202,15 @@ bool Protocol_prep::store(TIME *tm)
|
||||
return packet->append(buff, length+1, PACKET_BUFFER_EXTRA_ALLOC);
|
||||
}
|
||||
|
||||
bool Protocol_prep::store_date(TIME *tm)
|
||||
bool Protocol_binary::store_date(TIME *tm)
|
||||
{
|
||||
tm->hour= tm->minute= tm->second=0;
|
||||
tm->second_part= 0;
|
||||
return Protocol_prep::store(tm);
|
||||
return Protocol_binary::store(tm);
|
||||
}
|
||||
|
||||
|
||||
bool Protocol_prep::store_time(TIME *tm)
|
||||
bool Protocol_binary::store_time(TIME *tm)
|
||||
{
|
||||
char buff[13], *pos;
|
||||
uint length;
|
||||
|
@ -98,16 +98,25 @@ public:
|
||||
#else
|
||||
void remove_last_row() {}
|
||||
#endif
|
||||
enum enum_protocol_type
|
||||
{
|
||||
PROTOCOL_TEXT= 0, PROTOCOL_BINARY= 1
|
||||
/*
|
||||
before adding here or change the values, consider that it is cast to a
|
||||
bit in sql_cache.cc.
|
||||
*/
|
||||
};
|
||||
virtual enum enum_protocol_type type()= 0;
|
||||
};
|
||||
|
||||
|
||||
/* Class used for the old (MySQL 4.0 protocol) */
|
||||
|
||||
class Protocol_simple :public Protocol
|
||||
class Protocol_text :public Protocol
|
||||
{
|
||||
public:
|
||||
Protocol_simple() {}
|
||||
Protocol_simple(THD *thd_arg) :Protocol(thd_arg) {}
|
||||
Protocol_text() {}
|
||||
Protocol_text(THD *thd_arg) :Protocol(thd_arg) {}
|
||||
virtual void prepare_for_resend();
|
||||
virtual bool store_null();
|
||||
virtual bool store_tiny(longlong from);
|
||||
@ -127,16 +136,17 @@ public:
|
||||
#ifdef EMBEDDED_LIBRARY
|
||||
void remove_last_row();
|
||||
#endif
|
||||
virtual enum enum_protocol_type type() { return PROTOCOL_TEXT; };
|
||||
};
|
||||
|
||||
|
||||
class Protocol_prep :public Protocol
|
||||
class Protocol_binary :public Protocol
|
||||
{
|
||||
private:
|
||||
uint bit_fields;
|
||||
public:
|
||||
Protocol_prep() {}
|
||||
Protocol_prep(THD *thd_arg) :Protocol(thd_arg) {}
|
||||
Protocol_binary() {}
|
||||
Protocol_binary(THD *thd_arg) :Protocol(thd_arg) {}
|
||||
virtual bool prepare_for_send(List<Item> *item_list);
|
||||
virtual void prepare_for_resend();
|
||||
#ifdef EMBEDDED_LIBRARY
|
||||
@ -158,6 +168,7 @@ public:
|
||||
virtual bool store(float nr, uint32 decimals, String *buffer);
|
||||
virtual bool store(double from, uint32 decimals, String *buffer);
|
||||
virtual bool store(Field *field);
|
||||
virtual enum enum_protocol_type type() { return PROTOCOL_BINARY; };
|
||||
};
|
||||
|
||||
void send_warning(THD *thd, uint sql_errno, const char *err=0);
|
||||
|
@ -2750,8 +2750,8 @@ int set_var_collation_client::update(THD *thd)
|
||||
thd->variables.character_set_results= character_set_results;
|
||||
thd->variables.collation_connection= collation_connection;
|
||||
thd->update_charset();
|
||||
thd->protocol_simple.init(thd);
|
||||
thd->protocol_prep.init(thd);
|
||||
thd->protocol_text.init(thd);
|
||||
thd->protocol_binary.init(thd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2880,8 +2880,7 @@ bool sys_var_thd_time_zone::check(THD *thd, set_var *var)
|
||||
String str(buff, sizeof(buff), &my_charset_latin1);
|
||||
String *res= var->value->val_str(&str);
|
||||
|
||||
if (!(var->save_result.time_zone=
|
||||
my_tz_find(res, thd->lex->time_zone_tables_used)))
|
||||
if (!(var->save_result.time_zone= my_tz_find(thd, res)))
|
||||
{
|
||||
my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), res ? res->c_ptr() : "NULL");
|
||||
return 1;
|
||||
@ -2942,8 +2941,7 @@ void sys_var_thd_time_zone::set_default(THD *thd, enum_var_type type)
|
||||
We are guaranteed to find this time zone since its existence
|
||||
is checked during start-up.
|
||||
*/
|
||||
global_system_variables.time_zone=
|
||||
my_tz_find(&str, thd->lex->time_zone_tables_used);
|
||||
global_system_variables.time_zone= my_tz_find(thd, &str);
|
||||
}
|
||||
else
|
||||
global_system_variables.time_zone= my_tz_SYSTEM;
|
||||
@ -4013,7 +4011,7 @@ sys_var_event_scheduler::update(THD *thd, set_var *var)
|
||||
DBUG_ENTER("sys_var_event_scheduler::update");
|
||||
if (Events::opt_event_scheduler == Events::EVENTS_DISABLED)
|
||||
{
|
||||
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--event-scheduler=DISABLED");
|
||||
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--event-scheduler=DISABLED or --skip-grant-tables");
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
|
@ -5518,8 +5518,7 @@ ER_M_BIGGER_THAN_D 42000 S1009
|
||||
eng "For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column '%-.64s')."
|
||||
ger "Für FLOAT(M,D), DOUBLE(M,D) oder DECIMAL(M,D) muss M >= D sein (Feld '%-.64s')"
|
||||
ER_WRONG_LOCK_OF_SYSTEM_TABLE
|
||||
eng "You can't combine write-locking of system '%-.64s.%-.64s' table with other tables"
|
||||
ger "Sie können Schreibsperren auf der Systemtabelle '%-.64s.%-.64s' nicht mit anderen Tabellen kombinieren"
|
||||
eng "You can't combine write-locking of system tables with other tables or lock types"
|
||||
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
|
||||
eng "Unable to connect to foreign data source: %.64s"
|
||||
ger "Kann nicht mit Fremddatenquelle verbinden: %.64s"
|
||||
@ -5874,8 +5873,7 @@ ER_EVENT_ENDS_BEFORE_STARTS
|
||||
eng "ENDS is either invalid or before STARTS"
|
||||
ger "ENDS ist entweder ungültig oder liegt vor STARTS"
|
||||
ER_EVENT_EXEC_TIME_IN_THE_PAST
|
||||
eng "Activation (AT) time is in the past"
|
||||
ger "Aktivierungszeit (AT) liegt in der Vergangenheit"
|
||||
eng "Event execution time is in the past. Event has been disabled"
|
||||
ER_EVENT_OPEN_TABLE_FAILED
|
||||
eng "Failed to open mysql.event"
|
||||
ger "Öffnen von mysql.event fehlgeschlagen"
|
||||
@ -6053,3 +6051,7 @@ ER_DUP_ENTRY_WITH_KEY_NAME 23000 S1009
|
||||
ER_BINLOG_PURGE_EMFILE
|
||||
eng "Too many files opened, please execute the command again"
|
||||
ger "Zu viele offene Dateien, bitte führen Sie den Befehl noch einmal aus"
|
||||
ER_EVENT_CANNOT_CREATE_IN_THE_PAST
|
||||
eng "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. Event has not been created"
|
||||
ER_EVENT_CANNOT_ALTER_IN_THE_PAST
|
||||
eng "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. Event has not been altered"
|
||||
|
88
sql/sp.cc
88
sql/sp.cc
@ -68,24 +68,6 @@ enum
|
||||
#define SP_DEFAULT_ACCESS_MAPPING SP_CONTAINS_SQL
|
||||
|
||||
|
||||
/*
|
||||
Close mysql.proc, opened with open_proc_table_for_read().
|
||||
|
||||
SYNOPSIS
|
||||
close_proc_table()
|
||||
thd Thread context
|
||||
backup Pointer to Open_tables_state instance which holds
|
||||
information about tables which were open before we
|
||||
decided to access mysql.proc.
|
||||
*/
|
||||
|
||||
void close_proc_table(THD *thd, Open_tables_state *backup)
|
||||
{
|
||||
close_thread_tables(thd);
|
||||
thd->restore_backup_open_tables_state(backup);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Open the mysql.proc table for read.
|
||||
|
||||
@ -96,13 +78,6 @@ void close_proc_table(THD *thd, Open_tables_state *backup)
|
||||
currently open tables will be saved, and from which will be
|
||||
restored when we will end work with mysql.proc.
|
||||
|
||||
NOTES
|
||||
Thanks to restrictions which we put on opening and locking of
|
||||
this table for writing, we can open and lock it for reading
|
||||
even when we already have some other tables open and locked.
|
||||
One must call close_proc_table() to close table opened with
|
||||
this call.
|
||||
|
||||
RETURN
|
||||
0 Error
|
||||
# Pointer to TABLE object of mysql.proc
|
||||
@ -110,38 +85,18 @@ void close_proc_table(THD *thd, Open_tables_state *backup)
|
||||
|
||||
TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup)
|
||||
{
|
||||
TABLE_LIST tables;
|
||||
TABLE *table;
|
||||
bool not_used;
|
||||
DBUG_ENTER("open_proc_table");
|
||||
DBUG_ENTER("open_proc_table_for_read");
|
||||
|
||||
thd->reset_n_backup_open_tables_state(backup);
|
||||
TABLE_LIST table;
|
||||
bzero((char*) &table, sizeof(table));
|
||||
table.db= (char*) "mysql";
|
||||
table.table_name= table.alias= (char*)"proc";
|
||||
table.lock_type= TL_READ;
|
||||
|
||||
bzero((char*) &tables, sizeof(tables));
|
||||
tables.db= (char*) "mysql";
|
||||
tables.table_name= tables.alias= (char*)"proc";
|
||||
if (!(table= open_table(thd, &tables, thd->mem_root, ¬_used,
|
||||
MYSQL_LOCK_IGNORE_FLUSH)))
|
||||
{
|
||||
thd->restore_backup_open_tables_state(backup);
|
||||
if (!open_system_tables_for_read(thd, &table, backup))
|
||||
DBUG_RETURN(table.table);
|
||||
else
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
table->use_all_columns();
|
||||
|
||||
DBUG_ASSERT(table->s->system_table);
|
||||
|
||||
table->reginfo.lock_type= TL_READ;
|
||||
/*
|
||||
We have to ensure we are not blocked by a flush tables, as this
|
||||
could lead to a deadlock if we have other tables opened.
|
||||
*/
|
||||
if (!(thd->lock= mysql_lock_tables(thd, &table, 1,
|
||||
MYSQL_LOCK_IGNORE_FLUSH, ¬_used)))
|
||||
{
|
||||
close_proc_table(thd, backup);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
DBUG_RETURN(table);
|
||||
}
|
||||
|
||||
|
||||
@ -162,20 +117,15 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup)
|
||||
|
||||
static TABLE *open_proc_table_for_update(THD *thd)
|
||||
{
|
||||
TABLE_LIST tables;
|
||||
TABLE *table;
|
||||
DBUG_ENTER("open_proc_table");
|
||||
DBUG_ENTER("open_proc_table_for_update");
|
||||
|
||||
bzero((char*) &tables, sizeof(tables));
|
||||
tables.db= (char*) "mysql";
|
||||
tables.table_name= tables.alias= (char*)"proc";
|
||||
tables.lock_type= TL_WRITE;
|
||||
TABLE_LIST table;
|
||||
bzero((char*) &table, sizeof(table));
|
||||
table.db= (char*) "mysql";
|
||||
table.table_name= table.alias= (char*)"proc";
|
||||
table.lock_type= TL_WRITE;
|
||||
|
||||
table= open_ltable(thd, &tables, TL_WRITE);
|
||||
if (table)
|
||||
table->use_all_columns();
|
||||
|
||||
DBUG_RETURN(table);
|
||||
DBUG_RETURN(open_system_table_for_update(thd, &table));
|
||||
}
|
||||
|
||||
|
||||
@ -363,7 +313,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
|
||||
chistics.comment.str= ptr;
|
||||
chistics.comment.length= length;
|
||||
|
||||
close_proc_table(thd, &open_tables_state_backup);
|
||||
close_system_tables(thd, &open_tables_state_backup);
|
||||
table= 0;
|
||||
|
||||
ret= db_load_routine(thd, type, name, sphp,
|
||||
@ -372,7 +322,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
|
||||
|
||||
done:
|
||||
if (table)
|
||||
close_proc_table(thd, &open_tables_state_backup);
|
||||
close_system_tables(thd, &open_tables_state_backup);
|
||||
DBUG_RETURN(ret);
|
||||
}
|
||||
|
||||
@ -1146,7 +1096,7 @@ sp_routine_exists_in_table(THD *thd, int type, sp_name *name)
|
||||
{
|
||||
if ((ret= db_find_routine_aux(thd, type, name, table)) != SP_OK)
|
||||
ret= SP_KEY_NOT_FOUND;
|
||||
close_proc_table(thd, &open_tables_state_backup);
|
||||
close_system_tables(thd, &open_tables_state_backup);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
1
sql/sp.h
1
sql/sp.h
@ -100,7 +100,6 @@ extern "C" byte* sp_sroutine_key(const byte *ptr, uint *plen, my_bool first);
|
||||
we already have some tables open and locked.
|
||||
*/
|
||||
TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup);
|
||||
void close_proc_table(THD *thd, Open_tables_state *backup);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -490,7 +490,7 @@ sp_head::init(LEX *lex)
|
||||
{
|
||||
DBUG_ENTER("sp_head::init");
|
||||
|
||||
lex->spcont= m_pcont= new sp_pcontext(NULL);
|
||||
lex->spcont= m_pcont= new sp_pcontext();
|
||||
|
||||
/*
|
||||
Altough trg_table_fields list is used only in triggers we init for all
|
||||
@ -1117,7 +1117,7 @@ sp_head::execute(THD *thd)
|
||||
case SP_HANDLER_CONTINUE:
|
||||
thd->restore_active_arena(&execute_arena, &backup_arena);
|
||||
thd->set_n_backup_active_arena(&execute_arena, &backup_arena);
|
||||
ctx->push_hstack(ip);
|
||||
ctx->push_hstack(i->get_cont_dest());
|
||||
// Fall through
|
||||
default:
|
||||
ip= hip;
|
||||
@ -2449,7 +2449,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
|
||||
reinit_stmt_before_use(thd, m_lex);
|
||||
|
||||
if (open_tables)
|
||||
res= instr->exec_open_and_lock_tables(thd, m_lex->query_tables, nextp);
|
||||
res= instr->exec_open_and_lock_tables(thd, m_lex->query_tables);
|
||||
|
||||
if (!res)
|
||||
{
|
||||
@ -2501,8 +2501,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
|
||||
sp_instr class functions
|
||||
*/
|
||||
|
||||
int sp_instr::exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables,
|
||||
uint *nextp)
|
||||
int sp_instr::exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables)
|
||||
{
|
||||
int result;
|
||||
|
||||
@ -2512,19 +2511,16 @@ int sp_instr::exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables,
|
||||
*/
|
||||
if (check_table_access(thd, SELECT_ACL, tables, 0)
|
||||
|| open_and_lock_tables(thd, tables))
|
||||
{
|
||||
get_cont_dest(nextp);
|
||||
result= -1;
|
||||
}
|
||||
else
|
||||
result= 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void sp_instr::get_cont_dest(uint *nextp)
|
||||
uint sp_instr::get_cont_dest()
|
||||
{
|
||||
*nextp= m_ip+1;
|
||||
return (m_ip+1);
|
||||
}
|
||||
|
||||
|
||||
@ -2717,9 +2713,9 @@ sp_instr_set_trigger_field::print(String *str)
|
||||
sp_instr_opt_meta
|
||||
*/
|
||||
|
||||
void sp_instr_opt_meta::get_cont_dest(uint *nextp)
|
||||
uint sp_instr_opt_meta::get_cont_dest()
|
||||
{
|
||||
*nextp= m_cont_dest;
|
||||
return m_cont_dest;
|
||||
}
|
||||
|
||||
|
||||
@ -2811,7 +2807,6 @@ sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp)
|
||||
if (! it)
|
||||
{
|
||||
res= -1;
|
||||
*nextp = m_cont_dest;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -3380,7 +3375,6 @@ sp_instr_set_case_expr::exec_core(THD *thd, uint *nextp)
|
||||
spcont->clear_handler();
|
||||
thd->spcont= spcont;
|
||||
}
|
||||
*nextp= m_cont_dest; /* For continue handler */
|
||||
}
|
||||
else
|
||||
*nextp= m_ip+1;
|
||||
|
@ -107,8 +107,6 @@ public:
|
||||
/* Possible values of m_flags */
|
||||
enum {
|
||||
HAS_RETURN= 1, // For FUNCTIONs only: is set if has RETURN
|
||||
IN_SIMPLE_CASE= 2, // Is set if parsing a simple CASE
|
||||
IN_HANDLER= 4, // Is set if the parser is in a handler body
|
||||
MULTI_RESULTS= 8, // Is set if a procedure with SELECT(s)
|
||||
CONTAINS_DYNAMIC_SQL= 16, // Is set if a procedure with PREPARE/EXECUTE
|
||||
IS_INVOKED= 32, // Is set if this sp_head is being used
|
||||
@ -468,13 +466,15 @@ public:
|
||||
thd Thread handle
|
||||
nextp OUT index of the next instruction to execute. (For most
|
||||
instructions this will be the instruction following this
|
||||
one).
|
||||
|
||||
RETURN
|
||||
0 on success,
|
||||
other if some error occured
|
||||
one). Note that this parameter is undefined in case of
|
||||
errors, use get_cont_dest() to find the continuation
|
||||
instruction for CONTINUE error handlers.
|
||||
|
||||
RETURN
|
||||
0 on success,
|
||||
other if some error occurred
|
||||
*/
|
||||
|
||||
|
||||
virtual int execute(THD *thd, uint *nextp) = 0;
|
||||
|
||||
/**
|
||||
@ -482,22 +482,17 @@ public:
|
||||
Open and lock the tables used by this statement, as a pre-requisite
|
||||
to execute the core logic of this instruction with
|
||||
<code>exec_core()</code>.
|
||||
If this statement fails, the next instruction to execute is also returned.
|
||||
This is useful when a user defined SQL continue handler needs to be
|
||||
executed.
|
||||
@param thd the current thread
|
||||
@param tables the list of tables to open and lock
|
||||
@param nextp the continuation instruction, returned to the caller if this
|
||||
method fails.
|
||||
@return zero on success, non zero on failure.
|
||||
*/
|
||||
int exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables, uint *nextp);
|
||||
int exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables);
|
||||
|
||||
/**
|
||||
Get the continuation destination of this instruction.
|
||||
@param nextp the continuation destination (output)
|
||||
@return the continuation destination
|
||||
*/
|
||||
virtual void get_cont_dest(uint *nextp);
|
||||
virtual uint get_cont_dest();
|
||||
|
||||
/*
|
||||
Execute core function of instruction after all preparations (e.g.
|
||||
@ -763,7 +758,7 @@ public:
|
||||
virtual void set_destination(uint old_dest, uint new_dest)
|
||||
= 0;
|
||||
|
||||
virtual void get_cont_dest(uint *nextp);
|
||||
virtual uint get_cont_dest();
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -25,6 +25,11 @@
|
||||
#include "sp_pcontext.h"
|
||||
#include "sp_head.h"
|
||||
|
||||
/* Initial size for the dynamic arrays in sp_pcontext */
|
||||
#define PCONTEXT_ARRAY_INIT_ALLOC 16
|
||||
/* Increment size for the dynamic arrays in sp_pcontext */
|
||||
#define PCONTEXT_ARRAY_INCREMENT_ALLOC 8
|
||||
|
||||
/*
|
||||
Sanity check for SQLSTATEs. Will not check if it's really an existing
|
||||
state (there are just too many), but will check length and bad characters.
|
||||
@ -49,28 +54,61 @@ sp_cond_check(LEX_STRING *sqlstate)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
sp_pcontext::sp_pcontext(sp_pcontext *prev)
|
||||
:Sql_alloc(), m_max_var_index(0), m_max_cursor_index(0), m_max_handler_index(0),
|
||||
m_context_handlers(0), m_parent(prev), m_pboundary(0)
|
||||
sp_pcontext::sp_pcontext()
|
||||
: Sql_alloc(),
|
||||
m_max_var_index(0), m_max_cursor_index(0), m_max_handler_index(0),
|
||||
m_context_handlers(0), m_parent(NULL), m_pboundary(0),
|
||||
m_label_scope(LABEL_DEFAULT_SCOPE)
|
||||
{
|
||||
VOID(my_init_dynamic_array(&m_vars, sizeof(sp_variable_t *), 16, 8));
|
||||
VOID(my_init_dynamic_array(&m_case_expr_id_lst, sizeof(int), 16, 8));
|
||||
VOID(my_init_dynamic_array(&m_conds, sizeof(sp_cond_type_t *), 16, 8));
|
||||
VOID(my_init_dynamic_array(&m_cursors, sizeof(LEX_STRING), 16, 8));
|
||||
VOID(my_init_dynamic_array(&m_handlers, sizeof(sp_cond_type_t *), 16, 8));
|
||||
VOID(my_init_dynamic_array(&m_vars, sizeof(sp_variable_t *),
|
||||
PCONTEXT_ARRAY_INIT_ALLOC,
|
||||
PCONTEXT_ARRAY_INCREMENT_ALLOC));
|
||||
VOID(my_init_dynamic_array(&m_case_expr_id_lst, sizeof(int),
|
||||
PCONTEXT_ARRAY_INIT_ALLOC,
|
||||
PCONTEXT_ARRAY_INCREMENT_ALLOC));
|
||||
VOID(my_init_dynamic_array(&m_conds, sizeof(sp_cond_type_t *),
|
||||
PCONTEXT_ARRAY_INIT_ALLOC,
|
||||
PCONTEXT_ARRAY_INCREMENT_ALLOC));
|
||||
VOID(my_init_dynamic_array(&m_cursors, sizeof(LEX_STRING),
|
||||
PCONTEXT_ARRAY_INIT_ALLOC,
|
||||
PCONTEXT_ARRAY_INCREMENT_ALLOC));
|
||||
VOID(my_init_dynamic_array(&m_handlers, sizeof(sp_cond_type_t *),
|
||||
PCONTEXT_ARRAY_INIT_ALLOC,
|
||||
PCONTEXT_ARRAY_INCREMENT_ALLOC));
|
||||
m_label.empty();
|
||||
m_children.empty();
|
||||
if (!prev)
|
||||
{
|
||||
m_var_offset= m_cursor_offset= 0;
|
||||
m_num_case_exprs= 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_var_offset= prev->m_var_offset + prev->m_max_var_index;
|
||||
m_cursor_offset= prev->current_cursor_count();
|
||||
m_num_case_exprs= prev->get_num_case_exprs();
|
||||
}
|
||||
|
||||
m_var_offset= m_cursor_offset= 0;
|
||||
m_num_case_exprs= 0;
|
||||
}
|
||||
|
||||
sp_pcontext::sp_pcontext(sp_pcontext *prev, label_scope_type label_scope)
|
||||
: Sql_alloc(),
|
||||
m_max_var_index(0), m_max_cursor_index(0), m_max_handler_index(0),
|
||||
m_context_handlers(0), m_parent(prev), m_pboundary(0),
|
||||
m_label_scope(label_scope)
|
||||
{
|
||||
VOID(my_init_dynamic_array(&m_vars, sizeof(sp_variable_t *),
|
||||
PCONTEXT_ARRAY_INIT_ALLOC,
|
||||
PCONTEXT_ARRAY_INCREMENT_ALLOC));
|
||||
VOID(my_init_dynamic_array(&m_case_expr_id_lst, sizeof(int),
|
||||
PCONTEXT_ARRAY_INIT_ALLOC,
|
||||
PCONTEXT_ARRAY_INCREMENT_ALLOC));
|
||||
VOID(my_init_dynamic_array(&m_conds, sizeof(sp_cond_type_t *),
|
||||
PCONTEXT_ARRAY_INIT_ALLOC,
|
||||
PCONTEXT_ARRAY_INCREMENT_ALLOC));
|
||||
VOID(my_init_dynamic_array(&m_cursors, sizeof(LEX_STRING),
|
||||
PCONTEXT_ARRAY_INIT_ALLOC,
|
||||
PCONTEXT_ARRAY_INCREMENT_ALLOC));
|
||||
VOID(my_init_dynamic_array(&m_handlers, sizeof(sp_cond_type_t *),
|
||||
PCONTEXT_ARRAY_INIT_ALLOC,
|
||||
PCONTEXT_ARRAY_INCREMENT_ALLOC));
|
||||
m_label.empty();
|
||||
m_children.empty();
|
||||
|
||||
m_var_offset= prev->m_var_offset + prev->m_max_var_index;
|
||||
m_cursor_offset= prev->current_cursor_count();
|
||||
m_num_case_exprs= prev->get_num_case_exprs();
|
||||
}
|
||||
|
||||
void
|
||||
@ -92,9 +130,9 @@ sp_pcontext::destroy()
|
||||
}
|
||||
|
||||
sp_pcontext *
|
||||
sp_pcontext::push_context()
|
||||
sp_pcontext::push_context(label_scope_type label_scope)
|
||||
{
|
||||
sp_pcontext *child= new sp_pcontext(this);
|
||||
sp_pcontext *child= new sp_pcontext(this, label_scope);
|
||||
|
||||
if (child)
|
||||
m_children.push_back(child);
|
||||
@ -257,7 +295,15 @@ sp_pcontext::find_label(char *name)
|
||||
if (my_strcasecmp(system_charset_info, name, lab->name) == 0)
|
||||
return lab;
|
||||
|
||||
if (m_parent)
|
||||
/*
|
||||
Note about exception handlers.
|
||||
See SQL:2003 SQL/PSM (ISO/IEC 9075-4:2003),
|
||||
section 13.1 <compound statement>,
|
||||
syntax rule 4.
|
||||
In short, a DECLARE HANDLER block can not refer
|
||||
to labels from the parent context, as they are out of scope.
|
||||
*/
|
||||
if (m_parent && (m_label_scope == LABEL_DEFAULT_SCOPE))
|
||||
return m_parent->find_label(name);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -88,16 +88,33 @@ typedef struct sp_cond
|
||||
sp_cond_type_t *val;
|
||||
} sp_cond_t;
|
||||
|
||||
/**
|
||||
The scope of a label in Stored Procedures,
|
||||
for name resolution of labels in a parsing context.
|
||||
*/
|
||||
enum label_scope_type
|
||||
{
|
||||
/**
|
||||
The labels declared in a parent context are in scope.
|
||||
*/
|
||||
LABEL_DEFAULT_SCOPE,
|
||||
/**
|
||||
The labels declared in a parent context are not in scope.
|
||||
*/
|
||||
LABEL_HANDLER_SCOPE
|
||||
};
|
||||
|
||||
/*
|
||||
The parse-time context, used to keep track on declared variables/parameters,
|
||||
/**
|
||||
The parse-time context, used to keep track of declared variables/parameters,
|
||||
conditions, handlers, cursors and labels, during parsing.
|
||||
sp_contexts are organized as a tree, with one object for each begin-end
|
||||
block, plus a root-context for the parameters.
|
||||
block, one object for each exception handler,
|
||||
plus a root-context for the parameters.
|
||||
This is used during parsing for looking up defined names (e.g. declared
|
||||
variables and visible labels), for error checking, and to calculate offsets
|
||||
to be used at runtime. (During execution variable values, active handlers
|
||||
and cursors, etc, are referred to by an index in a stack.)
|
||||
Parsing contexts for exception handlers limit the visibility of labels.
|
||||
The pcontext tree is also kept during execution and is used for error
|
||||
checking (e.g. correct number of parameters), and in the future, used by
|
||||
the debugger.
|
||||
@ -105,21 +122,30 @@ typedef struct sp_cond
|
||||
|
||||
class sp_pcontext : public Sql_alloc
|
||||
{
|
||||
sp_pcontext(const sp_pcontext &); /* Prevent use of these */
|
||||
void operator=(sp_pcontext &);
|
||||
public:
|
||||
|
||||
public:
|
||||
|
||||
sp_pcontext(sp_pcontext *prev);
|
||||
/**
|
||||
Constructor.
|
||||
Builds a parsing context root node.
|
||||
*/
|
||||
sp_pcontext();
|
||||
|
||||
// Free memory
|
||||
void
|
||||
destroy();
|
||||
|
||||
/**
|
||||
Create and push a new context in the tree.
|
||||
@param label_scope label scope for the new parsing context
|
||||
@return the node created
|
||||
*/
|
||||
sp_pcontext *
|
||||
push_context();
|
||||
push_context(label_scope_type label_scope);
|
||||
|
||||
// Returns the previous context, not the one we pop
|
||||
/**
|
||||
Pop a node from the parsing context tree.
|
||||
@return the parent node
|
||||
*/
|
||||
sp_pcontext *
|
||||
pop_context();
|
||||
|
||||
@ -363,6 +389,13 @@ class sp_pcontext : public Sql_alloc
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
Constructor for a tree node.
|
||||
@param prev the parent parsing context
|
||||
@param label_scope label_scope for this parsing context
|
||||
*/
|
||||
sp_pcontext(sp_pcontext *prev, label_scope_type label_scope);
|
||||
|
||||
/*
|
||||
m_max_var_index -- number of variables (including all types of arguments)
|
||||
in this context including all children contexts.
|
||||
@ -416,6 +449,14 @@ private:
|
||||
|
||||
List<sp_pcontext> m_children; // Children contexts, used for destruction
|
||||
|
||||
/**
|
||||
Scope of labels for this parsing context.
|
||||
*/
|
||||
label_scope_type m_label_scope;
|
||||
|
||||
private:
|
||||
sp_pcontext(const sp_pcontext &); /* Prevent use of these */
|
||||
void operator=(sp_pcontext &);
|
||||
}; // class sp_pcontext : public Sql_alloc
|
||||
|
||||
|
||||
|
122
sql/sql_base.cc
122
sql/sql_base.cc
@ -5503,7 +5503,8 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
|
||||
|
||||
Item_int do not need fix_fields() because it is basic constant.
|
||||
*/
|
||||
it.replace(new Item_int("Not_used", (longlong) 1, 21));
|
||||
it.replace(new Item_int("Not_used", (longlong) 1,
|
||||
MY_INT64_NUM_DECIMAL_DIGITS));
|
||||
}
|
||||
else if (insert_fields(thd, ((Item_field*) item)->context,
|
||||
((Item_field*) item)->db_name,
|
||||
@ -6878,3 +6879,122 @@ has_two_write_locked_tables_with_auto_increment(TABLE_LIST *tables)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Open and lock system tables for read.
|
||||
|
||||
SYNOPSIS
|
||||
open_system_tables_for_read()
|
||||
thd Thread context.
|
||||
table_list List of tables to open.
|
||||
backup Pointer to Open_tables_state instance where
|
||||
information about currently open tables will be
|
||||
saved, and from which will be restored when we will
|
||||
end work with system tables.
|
||||
|
||||
NOTES
|
||||
Thanks to restrictions which we put on opening and locking of
|
||||
system tables for writing, we can open and lock them for reading
|
||||
even when we already have some other tables open and locked. One
|
||||
must call close_system_tables() to close systems tables opened
|
||||
with this call.
|
||||
|
||||
RETURN
|
||||
FALSE Success
|
||||
TRUE Error
|
||||
*/
|
||||
|
||||
bool
|
||||
open_system_tables_for_read(THD *thd, TABLE_LIST *table_list,
|
||||
Open_tables_state *backup)
|
||||
{
|
||||
DBUG_ENTER("open_system_tables_for_read");
|
||||
|
||||
thd->reset_n_backup_open_tables_state(backup);
|
||||
|
||||
uint count= 0;
|
||||
bool not_used;
|
||||
for (TABLE_LIST *tables= table_list; tables; tables= tables->next_global)
|
||||
{
|
||||
TABLE *table= open_table(thd, tables, thd->mem_root, ¬_used,
|
||||
MYSQL_LOCK_IGNORE_FLUSH);
|
||||
if (!table)
|
||||
goto error;
|
||||
|
||||
DBUG_ASSERT(table->s->system_table);
|
||||
|
||||
table->use_all_columns();
|
||||
table->reginfo.lock_type= tables->lock_type;
|
||||
tables->table= table;
|
||||
count++;
|
||||
}
|
||||
|
||||
{
|
||||
TABLE **list= (TABLE**) thd->alloc(sizeof(TABLE*) * count);
|
||||
TABLE **ptr= list;
|
||||
for (TABLE_LIST *tables= table_list; tables; tables= tables->next_global)
|
||||
*(ptr++)= tables->table;
|
||||
|
||||
thd->lock= mysql_lock_tables(thd, list, count,
|
||||
MYSQL_LOCK_IGNORE_FLUSH, ¬_used);
|
||||
}
|
||||
if (thd->lock)
|
||||
DBUG_RETURN(FALSE);
|
||||
|
||||
error:
|
||||
close_system_tables(thd, backup);
|
||||
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Close system tables, opened with open_system_tables_for_read().
|
||||
|
||||
SYNOPSIS
|
||||
close_system_tables()
|
||||
thd Thread context
|
||||
backup Pointer to Open_tables_state instance which holds
|
||||
information about tables which were open before we
|
||||
decided to access system tables.
|
||||
*/
|
||||
|
||||
void
|
||||
close_system_tables(THD *thd, Open_tables_state *backup)
|
||||
{
|
||||
close_thread_tables(thd);
|
||||
thd->restore_backup_open_tables_state(backup);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Open and lock one system table for update.
|
||||
|
||||
SYNOPSIS
|
||||
open_system_table_for_update()
|
||||
thd Thread context.
|
||||
one_table Table to open.
|
||||
|
||||
NOTES
|
||||
Table opened with this call should closed using close_thread_tables().
|
||||
|
||||
RETURN
|
||||
0 Error
|
||||
# Pointer to TABLE object of system table
|
||||
*/
|
||||
|
||||
TABLE *
|
||||
open_system_table_for_update(THD *thd, TABLE_LIST *one_table)
|
||||
{
|
||||
DBUG_ENTER("open_system_table_for_update");
|
||||
|
||||
TABLE *table= open_ltable(thd, one_table, one_table->lock_type);
|
||||
if (table)
|
||||
{
|
||||
DBUG_ASSERT(table->s->system_table);
|
||||
table->use_all_columns();
|
||||
}
|
||||
|
||||
DBUG_RETURN(table);
|
||||
}
|
||||
|
@ -844,6 +844,12 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
|
||||
flags.client_long_flag= test(thd->client_capabilities & CLIENT_LONG_FLAG);
|
||||
flags.client_protocol_41= test(thd->client_capabilities &
|
||||
CLIENT_PROTOCOL_41);
|
||||
/*
|
||||
Protocol influences result format, so statement results in the binary
|
||||
protocol (COM_EXECUTE) cannot be served to statements asking for results
|
||||
in the text protocol (COM_QUERY) and vice-versa.
|
||||
*/
|
||||
flags.result_in_binary_protocol= (unsigned int) thd->protocol->type();
|
||||
flags.more_results_exists= test(thd->server_status &
|
||||
SERVER_MORE_RESULTS_EXISTS);
|
||||
flags.pkt_nr= net->pkt_nr;
|
||||
@ -861,11 +867,13 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
|
||||
flags.max_sort_length= thd->variables.max_sort_length;
|
||||
flags.lc_time_names= thd->variables.lc_time_names;
|
||||
flags.group_concat_max_len= thd->variables.group_concat_max_len;
|
||||
DBUG_PRINT("qcache", ("long %d, 4.1: %d, more results %d, pkt_nr: %d, \
|
||||
DBUG_PRINT("qcache", ("\
|
||||
long %d, 4.1: %d, bin_proto: %d, more results %d, pkt_nr: %d, \
|
||||
CS client: %u, CS result: %u, CS conn: %u, limit: %lu, TZ: 0x%lx, \
|
||||
sql mode: 0x%lx, sort len: %lu, conncat len: %lu",
|
||||
(int)flags.client_long_flag,
|
||||
(int)flags.client_protocol_41,
|
||||
(int)flags.result_in_binary_protocol,
|
||||
(int)flags.more_results_exists,
|
||||
flags.pkt_nr,
|
||||
flags.character_set_client_num,
|
||||
@ -1089,6 +1097,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
|
||||
flags.client_long_flag= test(thd->client_capabilities & CLIENT_LONG_FLAG);
|
||||
flags.client_protocol_41= test(thd->client_capabilities &
|
||||
CLIENT_PROTOCOL_41);
|
||||
flags.result_in_binary_protocol= (unsigned int)thd->protocol->type();
|
||||
flags.more_results_exists= test(thd->server_status &
|
||||
SERVER_MORE_RESULTS_EXISTS);
|
||||
flags.pkt_nr= thd->net.pkt_nr;
|
||||
@ -1104,11 +1113,13 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
|
||||
flags.max_sort_length= thd->variables.max_sort_length;
|
||||
flags.group_concat_max_len= thd->variables.group_concat_max_len;
|
||||
flags.lc_time_names= thd->variables.lc_time_names;
|
||||
DBUG_PRINT("qcache", ("long %d, 4.1: %d, more results %d, pkt_nr: %d, \
|
||||
DBUG_PRINT("qcache", ("\
|
||||
long %d, 4.1: %d, bin_proto: %d, more results %d, pkt_nr: %d, \
|
||||
CS client: %u, CS result: %u, CS conn: %u, limit: %lu, TZ: 0x%lx, \
|
||||
sql mode: 0x%lx, sort len: %lu, conncat len: %lu",
|
||||
(int)flags.client_long_flag,
|
||||
(int)flags.client_protocol_41,
|
||||
(int)flags.result_in_binary_protocol,
|
||||
(int)flags.more_results_exists,
|
||||
flags.pkt_nr,
|
||||
flags.character_set_client_num,
|
||||
@ -3048,11 +3059,10 @@ Query_cache::is_cacheable(THD *thd, uint32 query_len, char *query, LEX *lex,
|
||||
TABLE_COUNTER_TYPE table_count;
|
||||
DBUG_ENTER("Query_cache::is_cacheable");
|
||||
|
||||
if (lex->sql_command == SQLCOM_SELECT &&
|
||||
if (query_cache_is_cacheable_query(lex) &&
|
||||
(thd->variables.query_cache_type == 1 ||
|
||||
(thd->variables.query_cache_type == 2 && (lex->select_lex.options &
|
||||
OPTION_TO_QUERY_CACHE))) &&
|
||||
lex->safe_to_cache_query)
|
||||
OPTION_TO_QUERY_CACHE))))
|
||||
{
|
||||
DBUG_PRINT("qcache", ("options: %lx %lx type: %u",
|
||||
(long) OPTION_TO_QUERY_CACHE,
|
||||
|
@ -303,9 +303,9 @@ THD::THD()
|
||||
bzero((char*) &user_var_events, sizeof(user_var_events));
|
||||
|
||||
/* Protocol */
|
||||
protocol= &protocol_simple; // Default protocol
|
||||
protocol_simple.init(this);
|
||||
protocol_prep.init(this);
|
||||
protocol= &protocol_text; // Default protocol
|
||||
protocol_text.init(this);
|
||||
protocol_binary.init(this);
|
||||
|
||||
tablespace_op=FALSE;
|
||||
tmp= sql_rnd_with_mutex();
|
||||
|
@ -910,8 +910,8 @@ public:
|
||||
NET net; // client connection descriptor
|
||||
MEM_ROOT warn_root; // For warnings and errors
|
||||
Protocol *protocol; // Current protocol
|
||||
Protocol_simple protocol_simple; // Normal protocol
|
||||
Protocol_prep protocol_prep; // Binary protocol
|
||||
Protocol_text protocol_text; // Normal protocol
|
||||
Protocol_binary protocol_binary; // Binary protocol
|
||||
HASH user_vars; // hash for user variables
|
||||
String packet; // dynamic buffer for network I/O
|
||||
String convert_buffer; // buffer for charset conversions
|
||||
|
@ -654,8 +654,9 @@ bool mysqld_help(THD *thd, const char *mask)
|
||||
tables[3].lock_type= TL_READ;
|
||||
tables[0].db= tables[1].db= tables[2].db= tables[3].db= (char*) "mysql";
|
||||
|
||||
if (open_and_lock_tables(thd, tables))
|
||||
goto error;
|
||||
Open_tables_state open_tables_state_backup;
|
||||
if (open_system_tables_for_read(thd, tables, &open_tables_state_backup))
|
||||
goto error2;
|
||||
|
||||
/*
|
||||
Init tables and fields to be usable from items
|
||||
@ -780,8 +781,13 @@ bool mysqld_help(THD *thd, const char *mask)
|
||||
}
|
||||
send_eof(thd);
|
||||
|
||||
close_system_tables(thd, &open_tables_state_backup);
|
||||
DBUG_RETURN(FALSE);
|
||||
|
||||
error:
|
||||
close_system_tables(thd, &open_tables_state_backup);
|
||||
|
||||
error2:
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
|
@ -169,7 +169,6 @@ void lex_start(THD *thd, const uchar *buf, uint length)
|
||||
lex->lock_option= TL_READ;
|
||||
lex->found_semicolon= 0;
|
||||
lex->safe_to_cache_query= 1;
|
||||
lex->time_zone_tables_used= 0;
|
||||
lex->leaf_tables_insert= 0;
|
||||
lex->parsing_options.reset();
|
||||
lex->empty_field_list_on_rset= 0;
|
||||
@ -2086,31 +2085,6 @@ void st_lex::first_lists_tables_same()
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Add implicitly used time zone description tables to global table list
|
||||
(if needed).
|
||||
|
||||
SYNOPSYS
|
||||
st_lex::add_time_zone_tables_to_query_tables()
|
||||
thd - pointer to current thread context
|
||||
|
||||
RETURN VALUE
|
||||
TRUE - error
|
||||
FALSE - success
|
||||
*/
|
||||
|
||||
bool st_lex::add_time_zone_tables_to_query_tables(THD *thd_arg)
|
||||
{
|
||||
/* We should not add these tables twice */
|
||||
if (!time_zone_tables_used)
|
||||
{
|
||||
time_zone_tables_used= my_tz_get_table_list(thd_arg, &query_tables_last);
|
||||
if (time_zone_tables_used == &fake_time_zone_tables_list)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
Link table back that was unlinked with unlink_first_table()
|
||||
|
||||
@ -2180,7 +2154,6 @@ void st_lex::cleanup_after_one_table_open()
|
||||
/* remove underlying units (units of VIEW) subtree */
|
||||
select_lex.cut_subtree();
|
||||
}
|
||||
time_zone_tables_used= 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1155,11 +1155,6 @@ typedef struct st_lex : public Query_tables_list
|
||||
bool prepared_stmt_code_is_varref;
|
||||
/* Names of user variables holding parameters (in EXECUTE) */
|
||||
List<LEX_STRING> prepared_stmt_params;
|
||||
/*
|
||||
Points to part of global table list which contains time zone tables
|
||||
implicitly used by the statement.
|
||||
*/
|
||||
TABLE_LIST *time_zone_tables_used;
|
||||
sp_head *sphead;
|
||||
sp_name *spname;
|
||||
bool sp_lex_in_use; /* Keep track on lex usage in SPs for error handling */
|
||||
@ -1246,7 +1241,6 @@ typedef struct st_lex : public Query_tables_list
|
||||
TABLE_LIST *unlink_first_table(bool *link_to_local);
|
||||
void link_first_table_back(TABLE_LIST *first, bool link_to_local);
|
||||
void first_lists_tables_same();
|
||||
bool add_time_zone_tables_to_query_tables(THD *thd);
|
||||
|
||||
bool can_be_merged();
|
||||
bool can_use_merged();
|
||||
|
@ -1689,8 +1689,7 @@ mysql_execute_command(THD *thd)
|
||||
Don't reset warnings when executing a stored routine.
|
||||
*/
|
||||
if ((all_tables || &lex->select_lex != lex->all_selects_list ||
|
||||
lex->sroutines.records) && !thd->spcont ||
|
||||
lex->time_zone_tables_used)
|
||||
lex->sroutines.records) && !thd->spcont)
|
||||
mysql_reset_errors(thd, 0);
|
||||
|
||||
#ifdef HAVE_REPLICATION
|
||||
@ -4739,9 +4738,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
|
||||
*/
|
||||
tables->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
|
||||
if (tables->derived || tables->schema_table ||
|
||||
(tables->table && (int)tables->table->s->tmp_table) ||
|
||||
my_tz_check_n_skip_implicit_tables(&tables,
|
||||
thd->lex->time_zone_tables_used))
|
||||
(tables->table && (int)tables->table->s->tmp_table))
|
||||
continue;
|
||||
thd->security_ctx= sctx;
|
||||
if ((sctx->master_access & want_access) ==
|
||||
@ -6503,14 +6500,12 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
|
||||
/*
|
||||
Is there tables of subqueries?
|
||||
*/
|
||||
if (&lex->select_lex != lex->all_selects_list || lex->time_zone_tables_used)
|
||||
if (&lex->select_lex != lex->all_selects_list)
|
||||
{
|
||||
DBUG_PRINT("info",("Checking sub query list"));
|
||||
for (table= tables; table; table= table->next_global)
|
||||
{
|
||||
if (!my_tz_check_n_skip_implicit_tables(&table,
|
||||
lex->time_zone_tables_used) &&
|
||||
!table->table_in_first_from_clause)
|
||||
if (!table->table_in_first_from_clause)
|
||||
{
|
||||
if (check_access(thd, SELECT_ACL, table->db,
|
||||
&table->grant.privilege, 0, 0,
|
||||
|
@ -34,6 +34,12 @@ When one prepares a statement:
|
||||
[Params meta info (stubs only for now)] (if Param_count > 0)
|
||||
[Columns meta info] (if Column_count > 0)
|
||||
|
||||
During prepare the tables used in a statement are opened, but no
|
||||
locks are acquired. Table opening will block any DDL during the
|
||||
operation, and we do not need any locks as we neither read nor
|
||||
modify any data during prepare. Tables are closed after prepare
|
||||
finishes.
|
||||
|
||||
When one executes a statement:
|
||||
|
||||
- Server gets the command 'COM_STMT_EXECUTE' to execute the
|
||||
@ -53,6 +59,10 @@ When one executes a statement:
|
||||
- Execute the query without re-parsing and send back the results
|
||||
to client
|
||||
|
||||
During execution of prepared statement tables are opened and locked
|
||||
the same way they would for normal (non-prepared) statement
|
||||
execution. Tables are unlocked and closed after the execution.
|
||||
|
||||
When one supplies long data for a placeholder:
|
||||
|
||||
- Server gets the long data in pieces with command type
|
||||
@ -83,11 +93,11 @@ When one supplies long data for a placeholder:
|
||||
|
||||
/* A result class used to send cursor rows using the binary protocol. */
|
||||
|
||||
class Select_fetch_protocol_prep: public select_send
|
||||
class Select_fetch_protocol_binary: public select_send
|
||||
{
|
||||
Protocol_prep protocol;
|
||||
Protocol_binary protocol;
|
||||
public:
|
||||
Select_fetch_protocol_prep(THD *thd);
|
||||
Select_fetch_protocol_binary(THD *thd);
|
||||
virtual bool send_fields(List<Item> &list, uint flags);
|
||||
virtual bool send_data(List<Item> &items);
|
||||
virtual bool send_eof();
|
||||
@ -115,7 +125,7 @@ public:
|
||||
};
|
||||
|
||||
THD *thd;
|
||||
Select_fetch_protocol_prep result;
|
||||
Select_fetch_protocol_binary result;
|
||||
Protocol *protocol;
|
||||
Item_param **param_array;
|
||||
uint param_count;
|
||||
@ -237,9 +247,9 @@ static bool send_prep_stmt(Prepared_statement *stmt, uint columns)
|
||||
*/
|
||||
DBUG_RETURN(my_net_write(net, buff, sizeof(buff)) ||
|
||||
(stmt->param_count &&
|
||||
stmt->thd->protocol_simple.send_fields((List<Item> *)
|
||||
&stmt->lex->param_list,
|
||||
Protocol::SEND_EOF)));
|
||||
stmt->thd->protocol_text.send_fields((List<Item> *)
|
||||
&stmt->lex->param_list,
|
||||
Protocol::SEND_EOF)));
|
||||
}
|
||||
#else
|
||||
static bool send_prep_stmt(Prepared_statement *stmt,
|
||||
@ -681,7 +691,7 @@ static void setup_one_conversion_function(THD *thd, Item_param *param,
|
||||
and generate a valid query for logging.
|
||||
|
||||
NOTES
|
||||
This function, along with other _withlog functions is called when one of
|
||||
This function, along with other _with_log functions is called when one of
|
||||
binary, slow or general logs is open. Logging of prepared statements in
|
||||
all cases is performed by means of conventional queries: if parameter
|
||||
data was supplied from C API, each placeholder in the query is
|
||||
@ -705,9 +715,9 @@ static void setup_one_conversion_function(THD *thd, Item_param *param,
|
||||
0 if success, 1 otherwise
|
||||
*/
|
||||
|
||||
static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array,
|
||||
uchar *read_pos, uchar *data_end,
|
||||
String *query)
|
||||
static bool insert_params_with_log(Prepared_statement *stmt, uchar *null_array,
|
||||
uchar *read_pos, uchar *data_end,
|
||||
String *query)
|
||||
{
|
||||
THD *thd= stmt->thd;
|
||||
Item_param **begin= stmt->param_array;
|
||||
@ -715,7 +725,7 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array,
|
||||
uint32 length= 0;
|
||||
String str;
|
||||
const String *res;
|
||||
DBUG_ENTER("insert_params_withlog");
|
||||
DBUG_ENTER("insert_params_with_log");
|
||||
|
||||
if (query->copy(stmt->query, stmt->query_length, default_charset_info))
|
||||
DBUG_RETURN(1);
|
||||
@ -859,7 +869,8 @@ static bool emb_insert_params(Prepared_statement *stmt, String *expanded_query)
|
||||
}
|
||||
|
||||
|
||||
static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query)
|
||||
static bool emb_insert_params_with_log(Prepared_statement *stmt,
|
||||
String *query)
|
||||
{
|
||||
THD *thd= stmt->thd;
|
||||
Item_param **it= stmt->param_array;
|
||||
@ -870,7 +881,7 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query)
|
||||
const String *res;
|
||||
uint32 length= 0;
|
||||
|
||||
DBUG_ENTER("emb_insert_params_withlog");
|
||||
DBUG_ENTER("emb_insert_params_with_log");
|
||||
|
||||
if (query->copy(stmt->query, stmt->query_length, default_charset_info))
|
||||
DBUG_RETURN(1);
|
||||
@ -1129,32 +1140,20 @@ static int mysql_test_update(Prepared_statement *stmt,
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
uint want_privilege;
|
||||
#endif
|
||||
bool need_reopen;
|
||||
DBUG_ENTER("mysql_test_update");
|
||||
|
||||
if (update_precheck(thd, table_list))
|
||||
if (update_precheck(thd, table_list) ||
|
||||
open_tables(thd, &table_list, &table_count, 0))
|
||||
goto error;
|
||||
|
||||
for ( ; ; )
|
||||
if (table_list->multitable_view)
|
||||
{
|
||||
if (open_tables(thd, &table_list, &table_count, 0))
|
||||
goto error;
|
||||
|
||||
if (table_list->multitable_view)
|
||||
{
|
||||
DBUG_ASSERT(table_list->view != 0);
|
||||
DBUG_PRINT("info", ("Switch to multi-update"));
|
||||
/* pass counter value */
|
||||
thd->lex->table_count= table_count;
|
||||
/* convert to multiupdate */
|
||||
DBUG_RETURN(2);
|
||||
}
|
||||
|
||||
if (!lock_tables(thd, table_list, table_count, &need_reopen))
|
||||
break;
|
||||
if (!need_reopen)
|
||||
goto error;
|
||||
close_tables_for_reopen(thd, &table_list);
|
||||
DBUG_ASSERT(table_list->view != 0);
|
||||
DBUG_PRINT("info", ("Switch to multi-update"));
|
||||
/* pass counter value */
|
||||
thd->lex->table_count= table_count;
|
||||
/* convert to multiupdate */
|
||||
DBUG_RETURN(2);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1221,7 +1220,7 @@ static bool mysql_test_delete(Prepared_statement *stmt,
|
||||
DBUG_ENTER("mysql_test_delete");
|
||||
|
||||
if (delete_precheck(thd, table_list) ||
|
||||
open_and_lock_tables(thd, table_list))
|
||||
open_normal_and_derived_tables(thd, table_list, 0))
|
||||
goto error;
|
||||
|
||||
if (!table_list->table)
|
||||
@ -1280,7 +1279,7 @@ static int mysql_test_select(Prepared_statement *stmt,
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (open_and_lock_tables(thd, tables))
|
||||
if (open_normal_and_derived_tables(thd, tables, 0))
|
||||
goto error;
|
||||
|
||||
thd->used_tables= 0; // Updated by setup_fields
|
||||
@ -1341,7 +1340,7 @@ static bool mysql_test_do_fields(Prepared_statement *stmt,
|
||||
if (tables && check_table_access(thd, SELECT_ACL, tables, 0))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
if (open_and_lock_tables(thd, tables))
|
||||
if (open_normal_and_derived_tables(thd, tables, 0))
|
||||
DBUG_RETURN(TRUE);
|
||||
DBUG_RETURN(setup_fields(thd, 0, *values, MARK_COLUMNS_NONE, 0, 0));
|
||||
}
|
||||
@ -1371,7 +1370,7 @@ static bool mysql_test_set_fields(Prepared_statement *stmt,
|
||||
set_var_base *var;
|
||||
|
||||
if (tables && check_table_access(thd, SELECT_ACL, tables, 0) ||
|
||||
open_and_lock_tables(thd, tables))
|
||||
open_normal_and_derived_tables(thd, tables, 0))
|
||||
goto error;
|
||||
|
||||
while ((var= it++))
|
||||
@ -1397,7 +1396,7 @@ error:
|
||||
NOTE
|
||||
This function won't directly open tables used in select. They should
|
||||
be opened either by calling function (and in this case you probably
|
||||
should use select_like_stmt_test_with_open_n_lock()) or by
|
||||
should use select_like_stmt_test_with_open()) or by
|
||||
"specific_prepare" call (like this happens in case of multi-update).
|
||||
|
||||
RETURN VALUE
|
||||
@ -1425,14 +1424,14 @@ static bool select_like_stmt_test(Prepared_statement *stmt,
|
||||
}
|
||||
|
||||
/*
|
||||
Check internal SELECT of the prepared command (with opening and
|
||||
locking of used tables).
|
||||
Check internal SELECT of the prepared command (with opening of used
|
||||
tables).
|
||||
|
||||
SYNOPSIS
|
||||
select_like_stmt_test_with_open_n_lock()
|
||||
select_like_stmt_test_with_open()
|
||||
stmt prepared statement
|
||||
tables list of tables to be opened and locked
|
||||
before calling specific_prepare function
|
||||
tables list of tables to be opened before calling
|
||||
specific_prepare function
|
||||
specific_prepare function of command specific prepare
|
||||
setup_tables_done_option options to be passed to LEX::unit.prepare()
|
||||
|
||||
@ -1442,19 +1441,20 @@ static bool select_like_stmt_test(Prepared_statement *stmt,
|
||||
*/
|
||||
|
||||
static bool
|
||||
select_like_stmt_test_with_open_n_lock(Prepared_statement *stmt,
|
||||
TABLE_LIST *tables,
|
||||
bool (*specific_prepare)(THD *thd),
|
||||
ulong setup_tables_done_option)
|
||||
select_like_stmt_test_with_open(Prepared_statement *stmt,
|
||||
TABLE_LIST *tables,
|
||||
bool (*specific_prepare)(THD *thd),
|
||||
ulong setup_tables_done_option)
|
||||
{
|
||||
DBUG_ENTER("select_like_stmt_test_with_open_n_lock");
|
||||
DBUG_ENTER("select_like_stmt_test_with_open");
|
||||
|
||||
/*
|
||||
We should not call LEX::unit.cleanup() after this open_and_lock_tables()
|
||||
call because we don't allow prepared EXPLAIN yet so derived tables will
|
||||
clean up after themself.
|
||||
We should not call LEX::unit.cleanup() after this
|
||||
open_normal_and_derived_tables() call because we don't allow
|
||||
prepared EXPLAIN yet so derived tables will clean up after
|
||||
themself.
|
||||
*/
|
||||
if (open_and_lock_tables(stmt->thd, tables))
|
||||
if (open_normal_and_derived_tables(stmt->thd, tables, 0))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
DBUG_RETURN(select_like_stmt_test(stmt, specific_prepare,
|
||||
@ -1493,7 +1493,7 @@ static bool mysql_test_create_table(Prepared_statement *stmt)
|
||||
if (select_lex->item_list.elements)
|
||||
{
|
||||
select_lex->context.resolve_in_select_list= TRUE;
|
||||
res= select_like_stmt_test_with_open_n_lock(stmt, tables, 0, 0);
|
||||
res= select_like_stmt_test_with_open(stmt, tables, 0, 0);
|
||||
}
|
||||
|
||||
/* put tables back for PS rexecuting */
|
||||
@ -1553,9 +1553,9 @@ static bool mysql_test_multidelete(Prepared_statement *stmt,
|
||||
}
|
||||
|
||||
if (multi_delete_precheck(stmt->thd, tables) ||
|
||||
select_like_stmt_test_with_open_n_lock(stmt, tables,
|
||||
&mysql_multi_delete_prepare,
|
||||
OPTION_SETUP_TABLES_DONE))
|
||||
select_like_stmt_test_with_open(stmt, tables,
|
||||
&mysql_multi_delete_prepare,
|
||||
OPTION_SETUP_TABLES_DONE))
|
||||
goto error;
|
||||
if (!tables->table)
|
||||
{
|
||||
@ -1571,15 +1571,16 @@ error:
|
||||
|
||||
/*
|
||||
Wrapper for mysql_insert_select_prepare, to make change of local tables
|
||||
after open_and_lock_tables() call.
|
||||
after open_normal_and_derived_tables() call.
|
||||
|
||||
SYNOPSIS
|
||||
mysql_insert_select_prepare_tester()
|
||||
thd thread handle
|
||||
|
||||
NOTE
|
||||
We need to remove the first local table after open_and_lock_tables,
|
||||
because mysql_handle_derived uses local tables lists.
|
||||
We need to remove the first local table after
|
||||
open_normal_and_derived_tables(), because mysql_handle_derived
|
||||
uses local tables lists.
|
||||
*/
|
||||
|
||||
static bool mysql_insert_select_prepare_tester(THD *thd)
|
||||
@ -1631,9 +1632,9 @@ static bool mysql_test_insert_select(Prepared_statement *stmt,
|
||||
DBUG_ASSERT(first_local_table != 0);
|
||||
|
||||
res=
|
||||
select_like_stmt_test_with_open_n_lock(stmt, tables,
|
||||
&mysql_insert_select_prepare_tester,
|
||||
OPTION_SETUP_TABLES_DONE);
|
||||
select_like_stmt_test_with_open(stmt, tables,
|
||||
&mysql_insert_select_prepare_tester,
|
||||
OPTION_SETUP_TABLES_DONE);
|
||||
/* revert changes made by mysql_insert_select_prepare_tester */
|
||||
lex->select_lex.table_list.first= (byte*) first_local_table;
|
||||
return res;
|
||||
@ -1889,7 +1890,7 @@ void mysql_stmt_prepare(THD *thd, const char *packet, uint packet_length)
|
||||
/* First of all clear possible warnings from the previous command */
|
||||
mysql_reset_thd_for_next_command(thd);
|
||||
|
||||
if (! (stmt= new Prepared_statement(thd, &thd->protocol_prep)))
|
||||
if (! (stmt= new Prepared_statement(thd, &thd->protocol_binary)))
|
||||
DBUG_VOID_RETURN; /* out of memory: error is set in Sql_alloc */
|
||||
|
||||
if (thd->stmt_map.insert(thd, stmt))
|
||||
@ -2061,8 +2062,8 @@ void mysql_sql_stmt_prepare(THD *thd)
|
||||
const char *query;
|
||||
uint query_len;
|
||||
DBUG_ENTER("mysql_sql_stmt_prepare");
|
||||
DBUG_ASSERT(thd->protocol == &thd->protocol_simple);
|
||||
LINT_INIT(query_len);
|
||||
DBUG_ASSERT(thd->protocol == &thd->protocol_text);
|
||||
|
||||
if ((stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name)))
|
||||
{
|
||||
@ -2075,7 +2076,7 @@ void mysql_sql_stmt_prepare(THD *thd)
|
||||
}
|
||||
|
||||
if (! (query= get_dynamic_sql_string(lex, &query_len)) ||
|
||||
! (stmt= new Prepared_statement(thd, &thd->protocol_simple)))
|
||||
! (stmt= new Prepared_statement(thd, &thd->protocol_text)))
|
||||
{
|
||||
DBUG_VOID_RETURN; /* out of memory */
|
||||
}
|
||||
@ -2628,14 +2629,14 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Select_fetch_protocol_prep
|
||||
Select_fetch_protocol_binary
|
||||
****************************************************************************/
|
||||
|
||||
Select_fetch_protocol_prep::Select_fetch_protocol_prep(THD *thd_arg)
|
||||
Select_fetch_protocol_binary::Select_fetch_protocol_binary(THD *thd_arg)
|
||||
:protocol(thd_arg)
|
||||
{}
|
||||
|
||||
bool Select_fetch_protocol_prep::send_fields(List<Item> &list, uint flags)
|
||||
bool Select_fetch_protocol_binary::send_fields(List<Item> &list, uint flags)
|
||||
{
|
||||
bool rc;
|
||||
Protocol *save_protocol= thd->protocol;
|
||||
@ -2653,7 +2654,7 @@ bool Select_fetch_protocol_prep::send_fields(List<Item> &list, uint flags)
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool Select_fetch_protocol_prep::send_eof()
|
||||
bool Select_fetch_protocol_binary::send_eof()
|
||||
{
|
||||
Protocol *save_protocol= thd->protocol;
|
||||
|
||||
@ -2665,7 +2666,7 @@ bool Select_fetch_protocol_prep::send_eof()
|
||||
|
||||
|
||||
bool
|
||||
Select_fetch_protocol_prep::send_data(List<Item> &fields)
|
||||
Select_fetch_protocol_binary::send_data(List<Item> &fields)
|
||||
{
|
||||
Protocol *save_protocol= thd->protocol;
|
||||
bool rc;
|
||||
@ -2699,15 +2700,26 @@ Prepared_statement::Prepared_statement(THD *thd_arg, Protocol *protocol_arg)
|
||||
|
||||
void Prepared_statement::setup_set_params()
|
||||
{
|
||||
/* Setup binary logging */
|
||||
/*
|
||||
Note: BUG#25843 applies here too (query cache lookup uses thd->db, not
|
||||
db from "prepare" time).
|
||||
*/
|
||||
if (query_cache_maybe_disabled(thd)) // we won't expand the query
|
||||
lex->safe_to_cache_query= FALSE; // so don't cache it at Execution
|
||||
|
||||
/*
|
||||
Decide if we have to expand the query (because we must write it to logs or
|
||||
because we want to look it up in the query cache) or not.
|
||||
*/
|
||||
if (mysql_bin_log.is_open() && is_update_query(lex->sql_command) ||
|
||||
opt_log || opt_slow_log)
|
||||
opt_log || opt_slow_log ||
|
||||
query_cache_is_cacheable_query(lex))
|
||||
{
|
||||
set_params_from_vars= insert_params_from_vars_with_log;
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
set_params= insert_params_withlog;
|
||||
set_params= insert_params_with_log;
|
||||
#else
|
||||
set_params_data= emb_insert_params_withlog;
|
||||
set_params_data= emb_insert_params_with_log;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@ -2844,7 +2856,6 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
|
||||
error= MYSQLparse((void *)thd) || thd->is_fatal_error ||
|
||||
thd->net.report_error || init_param_array(this);
|
||||
|
||||
lex->safe_to_cache_query= FALSE;
|
||||
/*
|
||||
While doing context analysis of the query (in check_prepared_statement)
|
||||
we allocate a lot of additional memory: for open tables, JOINs, derived
|
||||
@ -2887,6 +2898,18 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
|
||||
thd->restore_backup_statement(this, &stmt_backup);
|
||||
thd->stmt_arena= old_stmt_arena;
|
||||
|
||||
if ((protocol->type() == Protocol::PROTOCOL_TEXT) && (param_count > 0))
|
||||
{
|
||||
/*
|
||||
This is a mysql_sql_stmt_prepare(); query expansion will insert user
|
||||
variable references, and user variables are uncacheable, thus we have to
|
||||
mark this statement as uncacheable.
|
||||
This has to be done before setup_set_params(), as it may make expansion
|
||||
unneeded.
|
||||
*/
|
||||
lex->safe_to_cache_query= FALSE;
|
||||
}
|
||||
|
||||
if (error == 0)
|
||||
{
|
||||
setup_set_params();
|
||||
@ -3003,11 +3026,26 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
|
||||
reinit_stmt_before_use(thd, lex);
|
||||
|
||||
thd->protocol= protocol; /* activate stmt protocol */
|
||||
error= (open_cursor ?
|
||||
mysql_open_cursor(thd, (uint) ALWAYS_MATERIALIZED_CURSOR,
|
||||
&result, &cursor) :
|
||||
mysql_execute_command(thd));
|
||||
thd->protocol= &thd->protocol_simple; /* use normal protocol */
|
||||
|
||||
if (open_cursor)
|
||||
error= mysql_open_cursor(thd, (uint) ALWAYS_MATERIALIZED_CURSOR,
|
||||
&result, &cursor);
|
||||
else
|
||||
{
|
||||
/*
|
||||
Try to find it in the query cache, if not, execute it.
|
||||
Note that multi-statements cannot exist here (they are not supported in
|
||||
prepared statements).
|
||||
*/
|
||||
if (query_cache_send_result_to_client(thd, thd->query,
|
||||
thd->query_length) <= 0)
|
||||
{
|
||||
error= mysql_execute_command(thd);
|
||||
query_cache_end_of_result(thd);
|
||||
}
|
||||
}
|
||||
|
||||
thd->protocol= &thd->protocol_text; /* use normal protocol */
|
||||
|
||||
/* Assert that if an error, no cursor is open */
|
||||
DBUG_ASSERT(! (error && cursor));
|
||||
|
@ -8193,9 +8193,14 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
|
||||
*/
|
||||
expr= simplify_joins(join, &nested_join->join_list,
|
||||
expr, FALSE);
|
||||
table->on_expr= expr;
|
||||
if (!table->prep_on_expr)
|
||||
|
||||
if (!table->prep_on_expr || expr != table->on_expr)
|
||||
{
|
||||
DBUG_ASSERT(expr);
|
||||
|
||||
table->on_expr= expr;
|
||||
table->prep_on_expr= expr->copy_andor_structure(join->thd);
|
||||
}
|
||||
}
|
||||
nested_join->used_tables= (table_map) 0;
|
||||
nested_join->not_null_tables=(table_map) 0;
|
||||
@ -8205,7 +8210,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(table->prep_on_expr))
|
||||
if (!table->prep_on_expr)
|
||||
table->prep_on_expr= table->on_expr;
|
||||
used_tables= table->table->map;
|
||||
if (conds)
|
||||
@ -8697,7 +8702,7 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
|
||||
if ((new_cond= new Item_func_eq(args[0],
|
||||
new Item_int("last_insert_id()",
|
||||
thd->read_first_successful_insert_id_in_prev_stmt(),
|
||||
21))))
|
||||
MY_INT64_NUM_DECIMAL_DIGITS))))
|
||||
{
|
||||
cond=new_cond;
|
||||
/*
|
||||
@ -8962,7 +8967,7 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
|
||||
break;
|
||||
case INT_RESULT:
|
||||
/* Select an integer type with the minimal fit precision */
|
||||
if (item->max_length > 11)
|
||||
if (item->max_length > MY_INT32_NUM_DECIMAL_DIGITS)
|
||||
new_field=new Field_longlong(item->max_length, maybe_null,
|
||||
item->name, item->unsigned_flag);
|
||||
else
|
||||
@ -15277,7 +15282,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
|
||||
examined_rows=(ha_rows)join->best_positions[i].records_read;
|
||||
|
||||
item_list.push_back(new Item_int((longlong) (ulonglong) examined_rows,
|
||||
21));
|
||||
MY_INT64_NUM_DECIMAL_DIGITS));
|
||||
|
||||
/* Add "filtered" field to item_list. */
|
||||
if (join->thd->lex->describe & DESCRIBE_EXTENDED)
|
||||
|
@ -38,6 +38,7 @@ enum enum_i_s_events_fields
|
||||
ISE_EVENT_SCHEMA,
|
||||
ISE_EVENT_NAME,
|
||||
ISE_DEFINER,
|
||||
ISE_TIME_ZONE,
|
||||
ISE_EVENT_BODY,
|
||||
ISE_EVENT_DEFINITION,
|
||||
ISE_EVENT_TYPE,
|
||||
@ -424,7 +425,8 @@ bool mysqld_show_column_types(THD *thd)
|
||||
DBUG_ENTER("mysqld_show_column_types");
|
||||
|
||||
field_list.push_back(new Item_empty_string("Type",30));
|
||||
field_list.push_back(new Item_int("Size",(longlong) 1,21));
|
||||
field_list.push_back(new Item_int("Size",(longlong) 1,
|
||||
MY_INT64_NUM_DECIMAL_DIGITS));
|
||||
field_list.push_back(new Item_empty_string("Min_Value",20));
|
||||
field_list.push_back(new Item_empty_string("Max_Value",20));
|
||||
field_list.push_back(new Item_return_int("Prec", 4, MYSQL_TYPE_SHORT));
|
||||
@ -1620,7 +1622,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
|
||||
Protocol *protocol= thd->protocol;
|
||||
DBUG_ENTER("mysqld_list_processes");
|
||||
|
||||
field_list.push_back(new Item_int("Id",0,11));
|
||||
field_list.push_back(new Item_int("Id", 0, MY_INT32_NUM_DECIMAL_DIGITS));
|
||||
field_list.push_back(new Item_empty_string("User",16));
|
||||
field_list.push_back(new Item_empty_string("Host",LIST_PROCESS_HOST_LEN));
|
||||
field_list.push_back(field=new Item_empty_string("db",NAME_LEN));
|
||||
@ -3510,7 +3512,7 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond)
|
||||
|
||||
err:
|
||||
proc_table->file->ha_index_end();
|
||||
close_proc_table(thd, &open_tables_state_backup);
|
||||
close_system_tables(thd, &open_tables_state_backup);
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
@ -4309,7 +4311,7 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
|
||||
|
||||
restore_record(sch_table, s->default_values);
|
||||
|
||||
if (et.load_from_row(event_table))
|
||||
if (et.load_from_row(thd, event_table))
|
||||
{
|
||||
my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0));
|
||||
DBUG_RETURN(1);
|
||||
@ -4336,6 +4338,9 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
|
||||
store(et.name.str, et.name.length, scs);
|
||||
sch_table->field[ISE_DEFINER]->
|
||||
store(et.definer.str, et.definer.length, scs);
|
||||
const String *tz_name= et.time_zone->get_name();
|
||||
sch_table->field[ISE_TIME_ZONE]->
|
||||
store(tz_name->ptr(), tz_name->length(), scs);
|
||||
sch_table->field[ISE_EVENT_BODY]->
|
||||
store(STRING_WITH_LEN("SQL"), scs);
|
||||
sch_table->field[ISE_EVENT_DEFINITION]->
|
||||
@ -4352,6 +4357,8 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
|
||||
store((const char*)sql_mode_str, sql_mode_len, scs);
|
||||
}
|
||||
|
||||
int not_used=0;
|
||||
|
||||
if (et.expression)
|
||||
{
|
||||
String show_str;
|
||||
@ -4371,15 +4378,17 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
|
||||
sch_table->field[ISE_INTERVAL_FIELD]->store(ival->str, ival->length, scs);
|
||||
|
||||
/* starts & ends . STARTS is always set - see sql_yacc.yy */
|
||||
et.time_zone->gmt_sec_to_TIME(&time, et.starts);
|
||||
sch_table->field[ISE_STARTS]->set_notnull();
|
||||
sch_table->field[ISE_STARTS]->
|
||||
store_time(&et.starts, MYSQL_TIMESTAMP_DATETIME);
|
||||
store_time(&time, MYSQL_TIMESTAMP_DATETIME);
|
||||
|
||||
if (!et.ends_null)
|
||||
{
|
||||
et.time_zone->gmt_sec_to_TIME(&time, et.ends);
|
||||
sch_table->field[ISE_ENDS]->set_notnull();
|
||||
sch_table->field[ISE_ENDS]->
|
||||
store_time(&et.ends, MYSQL_TIMESTAMP_DATETIME);
|
||||
store_time(&time, MYSQL_TIMESTAMP_DATETIME);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -4387,9 +4396,10 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
|
||||
/* type */
|
||||
sch_table->field[ISE_EVENT_TYPE]->store(STRING_WITH_LEN("ONE TIME"), scs);
|
||||
|
||||
et.time_zone->gmt_sec_to_TIME(&time, et.execute_at);
|
||||
sch_table->field[ISE_EXECUTE_AT]->set_notnull();
|
||||
sch_table->field[ISE_EXECUTE_AT]->
|
||||
store_time(&et.execute_at, MYSQL_TIMESTAMP_DATETIME);
|
||||
store_time(&time, MYSQL_TIMESTAMP_DATETIME);
|
||||
}
|
||||
|
||||
/* status */
|
||||
@ -4406,7 +4416,6 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
|
||||
sch_table->field[ISE_ON_COMPLETION]->
|
||||
store(STRING_WITH_LEN("PRESERVE"), scs);
|
||||
|
||||
int not_used=0;
|
||||
number_to_datetime(et.created, &time, 0, ¬_used);
|
||||
DBUG_ASSERT(not_used==0);
|
||||
sch_table->field[ISE_CREATED]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
|
||||
@ -4416,11 +4425,12 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
|
||||
sch_table->field[ISE_LAST_ALTERED]->
|
||||
store_time(&time, MYSQL_TIMESTAMP_DATETIME);
|
||||
|
||||
if (et.last_executed.year)
|
||||
if (et.last_executed)
|
||||
{
|
||||
et.time_zone->gmt_sec_to_TIME(&time, et.last_executed);
|
||||
sch_table->field[ISE_LAST_EXECUTED]->set_notnull();
|
||||
sch_table->field[ISE_LAST_EXECUTED]->
|
||||
store_time(&et.last_executed, MYSQL_TIMESTAMP_DATETIME);
|
||||
store_time(&time, MYSQL_TIMESTAMP_DATETIME);
|
||||
}
|
||||
|
||||
sch_table->field[ISE_EVENT_COMMENT]->
|
||||
@ -5334,20 +5344,25 @@ ST_FIELD_INFO tables_fields_info[]=
|
||||
{"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Name"},
|
||||
{"TABLE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
|
||||
{"ENGINE", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, "Engine"},
|
||||
{"VERSION", 21 , MYSQL_TYPE_LONG, 0, 1, "Version"},
|
||||
{"VERSION", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1, "Version"},
|
||||
{"ROW_FORMAT", 10, MYSQL_TYPE_STRING, 0, 1, "Row_format"},
|
||||
{"TABLE_ROWS", 21 , MYSQL_TYPE_LONG, 0, 1, "Rows"},
|
||||
{"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Avg_row_length"},
|
||||
{"DATA_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Data_length"},
|
||||
{"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Max_data_length"},
|
||||
{"INDEX_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Index_length"},
|
||||
{"DATA_FREE", 21 , MYSQL_TYPE_LONG, 0, 1, "Data_free"},
|
||||
{"AUTO_INCREMENT", 21 , MYSQL_TYPE_LONG, 0, 1, "Auto_increment"},
|
||||
{"TABLE_ROWS", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1, "Rows"},
|
||||
{"AVG_ROW_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1,
|
||||
"Avg_row_length"},
|
||||
{"DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1,
|
||||
"Data_length"},
|
||||
{"MAX_DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1,
|
||||
"Max_data_length"},
|
||||
{"INDEX_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1,
|
||||
"Index_length"},
|
||||
{"DATA_FREE", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1, "Data_free"},
|
||||
{"AUTO_INCREMENT", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1,
|
||||
"Auto_increment"},
|
||||
{"CREATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Create_time"},
|
||||
{"UPDATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Update_time"},
|
||||
{"CHECK_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Check_time"},
|
||||
{"TABLE_COLLATION", 64, MYSQL_TYPE_STRING, 0, 1, "Collation"},
|
||||
{"CHECKSUM", 21 , MYSQL_TYPE_LONG, 0, 1, "Checksum"},
|
||||
{"CHECKSUM", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1, "Checksum"},
|
||||
{"CREATE_OPTIONS", 255, MYSQL_TYPE_STRING, 0, 1, "Create_options"},
|
||||
{"TABLE_COMMENT", 80, MYSQL_TYPE_STRING, 0, 0, "Comment"},
|
||||
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
|
||||
@ -5360,14 +5375,15 @@ ST_FIELD_INFO columns_fields_info[]=
|
||||
{"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
|
||||
{"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
|
||||
{"COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Field"},
|
||||
{"ORDINAL_POSITION", 21 , MYSQL_TYPE_LONG, 0, 0, 0},
|
||||
{"ORDINAL_POSITION", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 0, 0},
|
||||
{"COLUMN_DEFAULT", MAX_FIELD_VARCHARLENGTH, MYSQL_TYPE_STRING, 0, 1, "Default"},
|
||||
{"IS_NULLABLE", 3, MYSQL_TYPE_STRING, 0, 0, "Null"},
|
||||
{"DATA_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
|
||||
{"CHARACTER_MAXIMUM_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
|
||||
{"CHARACTER_OCTET_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
|
||||
{"NUMERIC_PRECISION", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
|
||||
{"NUMERIC_SCALE", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
|
||||
{"CHARACTER_MAXIMUM_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1,
|
||||
0},
|
||||
{"CHARACTER_OCTET_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1, 0},
|
||||
{"NUMERIC_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1, 0},
|
||||
{"NUMERIC_SCALE", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1, 0},
|
||||
{"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0},
|
||||
{"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 1, "Collation"},
|
||||
{"COLUMN_TYPE", 65535, MYSQL_TYPE_STRING, 0, 0, "Type"},
|
||||
@ -5393,7 +5409,7 @@ ST_FIELD_INFO collation_fields_info[]=
|
||||
{
|
||||
{"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Collation"},
|
||||
{"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Charset"},
|
||||
{"ID", 11, MYSQL_TYPE_LONG, 0, 0, "Id"},
|
||||
{"ID", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Id"},
|
||||
{"IS_DEFAULT", 3, MYSQL_TYPE_STRING, 0, 0, "Default"},
|
||||
{"IS_COMPILED", 3, MYSQL_TYPE_STRING, 0, 0, "Compiled"},
|
||||
{"SORTLEN", 3 ,MYSQL_TYPE_LONG, 0, 0, "Sortlen"},
|
||||
@ -5419,6 +5435,7 @@ ST_FIELD_INFO events_fields_info[]=
|
||||
{"EVENT_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Db"},
|
||||
{"EVENT_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Name"},
|
||||
{"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, "Definer"},
|
||||
{"TIME_ZONE", 64, MYSQL_TYPE_STRING, 0, 0, "Time zone"},
|
||||
{"EVENT_BODY", 8, MYSQL_TYPE_STRING, 0, 0, 0},
|
||||
{"EVENT_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 0, 0},
|
||||
{"EVENT_TYPE", 9, MYSQL_TYPE_STRING, 0, 0, "Type"},
|
||||
@ -5484,7 +5501,7 @@ ST_FIELD_INFO stat_fields_info[]=
|
||||
{"SEQ_IN_INDEX", 2, MYSQL_TYPE_LONG, 0, 0, "Seq_in_index"},
|
||||
{"COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Column_name"},
|
||||
{"COLLATION", 1, MYSQL_TYPE_STRING, 0, 1, "Collation"},
|
||||
{"CARDINALITY", 21, MYSQL_TYPE_LONG, 0, 1, "Cardinality"},
|
||||
{"CARDINALITY", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 1, "Cardinality"},
|
||||
{"SUB_PART", 3, MYSQL_TYPE_LONG, 0, 1, "Sub_part"},
|
||||
{"PACKED", 10, MYSQL_TYPE_STRING, 0, 1, "Packed"},
|
||||
{"NULLABLE", 3, MYSQL_TYPE_STRING, 0, 0, "Null"},
|
||||
|
@ -6948,7 +6948,8 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
|
||||
|
||||
field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2));
|
||||
item->maybe_null= 1;
|
||||
field_list.push_back(item=new Item_int("Checksum",(longlong) 1,21));
|
||||
field_list.push_back(item= new Item_int("Checksum", (longlong) 1,
|
||||
MY_INT64_NUM_DECIMAL_DIGITS));
|
||||
item->maybe_null= 1;
|
||||
if (protocol->send_fields(&field_list,
|
||||
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
|
||||
|
@ -1302,8 +1302,6 @@ ok:
|
||||
(st_select_lex_node**)&old_lex->all_selects_list;
|
||||
|
||||
ok2:
|
||||
if (!old_lex->time_zone_tables_used && thd->lex->time_zone_tables_used)
|
||||
old_lex->time_zone_tables_used= thd->lex->time_zone_tables_used;
|
||||
DBUG_ASSERT(lex == thd->lex);
|
||||
thd->lex= old_lex; // Needed for prepare_security
|
||||
result= !table->prelocking_placeholder && table->prepare_security(thd);
|
||||
|
@ -493,7 +493,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
|
||||
Currently there is 287 shift/reduce conflict. We should not introduce
|
||||
new conflicts any more.
|
||||
*/
|
||||
%expect 287
|
||||
%expect 286
|
||||
|
||||
/*
|
||||
Comments for TOKENS.
|
||||
@ -1247,7 +1247,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
|
||||
statement sp_suid
|
||||
sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa
|
||||
load_data opt_field_or_var_spec fields_or_vars opt_load_data_set_spec
|
||||
definer view_replace_or_algorithm view_replace view_algorithm_opt
|
||||
definer view_replace_or_algorithm view_replace
|
||||
view_algorithm view_or_trigger_or_sp_or_event
|
||||
view_or_trigger_or_sp_or_event_tail
|
||||
view_suid view_tail view_list_opt view_list view_select
|
||||
@ -2407,6 +2407,9 @@ sp_decl:
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
sp_head *sp= lex->sphead;
|
||||
|
||||
lex->spcont= lex->spcont->push_context(LABEL_HANDLER_SCOPE);
|
||||
|
||||
sp_pcontext *ctx= lex->spcont;
|
||||
sp_instr_hpush_jump *i=
|
||||
new sp_instr_hpush_jump(sp->instructions(), ctx, $2,
|
||||
@ -2414,7 +2417,6 @@ sp_decl:
|
||||
|
||||
sp->add_instr(i);
|
||||
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
|
||||
sp->m_flags|= sp_head::IN_HANDLER;
|
||||
}
|
||||
sp_hcond_list sp_proc_stmt
|
||||
{
|
||||
@ -2438,10 +2440,12 @@ sp_decl:
|
||||
sp->push_backpatch(i, lex->spcont->last_label()); /* Block end */
|
||||
}
|
||||
lex->sphead->backpatch(hlab);
|
||||
sp->m_flags&= ~sp_head::IN_HANDLER;
|
||||
|
||||
lex->spcont= ctx->pop_context();
|
||||
|
||||
$$.vars= $$.conds= $$.curs= 0;
|
||||
$$.hndlrs= $6;
|
||||
ctx->add_handlers($6);
|
||||
lex->spcont->add_handlers($6);
|
||||
}
|
||||
| DECLARE_SYM ident CURSOR_SYM FOR_SYM sp_cursor_stmt
|
||||
{
|
||||
@ -2507,11 +2511,18 @@ sp_handler_type:
|
||||
;
|
||||
|
||||
sp_hcond_list:
|
||||
sp_hcond_element
|
||||
{ $$= 1; }
|
||||
| sp_hcond_list ',' sp_hcond_element
|
||||
{ $$+= 1; }
|
||||
;
|
||||
|
||||
sp_hcond_element:
|
||||
sp_hcond
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
sp_head *sp= lex->sphead;
|
||||
sp_pcontext *ctx= lex->spcont;
|
||||
sp_pcontext *ctx= lex->spcont->parent_context();
|
||||
|
||||
if (ctx->find_handler($1))
|
||||
{
|
||||
@ -2525,28 +2536,6 @@ sp_hcond_list:
|
||||
|
||||
i->add_condition($1);
|
||||
ctx->push_handler($1);
|
||||
$$= 1;
|
||||
}
|
||||
}
|
||||
| sp_hcond_list ',' sp_hcond
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
sp_head *sp= lex->sphead;
|
||||
sp_pcontext *ctx= lex->spcont;
|
||||
|
||||
if (ctx->find_handler($3))
|
||||
{
|
||||
my_message(ER_SP_DUP_HANDLER, ER(ER_SP_DUP_HANDLER), MYF(0));
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
else
|
||||
{
|
||||
sp_instr_hpush_jump *i=
|
||||
(sp_instr_hpush_jump *)sp->last_instruction();
|
||||
|
||||
i->add_condition($3);
|
||||
ctx->push_handler($3);
|
||||
$$= $1 + 1;
|
||||
}
|
||||
}
|
||||
;
|
||||
@ -3125,7 +3114,7 @@ sp_unlabeled_control:
|
||||
sp_label_t *lab= lex->spcont->last_label();
|
||||
|
||||
lab->type= SP_LAB_BEGIN;
|
||||
lex->spcont= lex->spcont->push_context();
|
||||
lex->spcont= lex->spcont->push_context(LABEL_DEFAULT_SCOPE);
|
||||
}
|
||||
sp_decls
|
||||
sp_proc_stmts
|
||||
@ -5157,18 +5146,25 @@ alter:
|
||||
lex->sql_command= SQLCOM_ALTER_FUNCTION;
|
||||
lex->spname= $3;
|
||||
}
|
||||
| ALTER view_algorithm_opt definer view_suid
|
||||
VIEW_SYM table_ident
|
||||
{
|
||||
THD *thd= YYTHD;
|
||||
LEX *lex= thd->lex;
|
||||
lex->sql_command= SQLCOM_CREATE_VIEW;
|
||||
lex->create_view_mode= VIEW_ALTER;
|
||||
/* first table in list is target VIEW name */
|
||||
lex->select_lex.add_table_to_list(thd, $6, NULL, TL_OPTION_UPDATING);
|
||||
}
|
||||
view_list_opt AS view_select view_check_option
|
||||
{}
|
||||
| ALTER view_algorithm definer
|
||||
{
|
||||
Lex->create_view_mode= VIEW_ALTER;
|
||||
}
|
||||
view_tail
|
||||
{}
|
||||
| ALTER definer
|
||||
/*
|
||||
We have two separate rules for ALTER VIEW rather that
|
||||
optional view_algorithm above, to resolve the ambiguity
|
||||
with the ALTER EVENT below.
|
||||
*/
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED;
|
||||
lex->create_view_mode= VIEW_ALTER;
|
||||
}
|
||||
view_tail
|
||||
{}
|
||||
| ALTER definer EVENT_SYM sp_name
|
||||
/*
|
||||
BE CAREFUL when you add a new rule to update the block where
|
||||
@ -10359,14 +10355,7 @@ internal_variable_name:
|
||||
MYSQL_YYABORT;
|
||||
$$.var= tmp;
|
||||
$$.base_name= null_lex_str;
|
||||
/*
|
||||
If this is time_zone variable we should open time zone
|
||||
describing tables
|
||||
*/
|
||||
if (tmp == &sys_time_zone &&
|
||||
lex->add_time_zone_tables_to_query_tables(YYTHD))
|
||||
MYSQL_YYABORT;
|
||||
else if (spc && tmp == &sys_autocommit)
|
||||
if (spc && tmp == &sys_autocommit)
|
||||
{
|
||||
/*
|
||||
We don't allow setting AUTOCOMMIT from a stored function
|
||||
@ -11300,13 +11289,6 @@ view_algorithm:
|
||||
{ Lex->create_view_algorithm= VIEW_ALGORITHM_TMPTABLE; }
|
||||
;
|
||||
|
||||
view_algorithm_opt:
|
||||
/* empty */
|
||||
{ Lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED; }
|
||||
| view_algorithm
|
||||
{}
|
||||
;
|
||||
|
||||
view_suid:
|
||||
/* empty */
|
||||
{ Lex->create_view_suid= VIEW_SUID_DEFAULT; }
|
||||
|
52
sql/table.cc
52
sql/table.cc
@ -245,6 +245,50 @@ void free_table_share(TABLE_SHARE *share)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Return TRUE if a table name matches one of the system table names.
|
||||
Currently these are:
|
||||
|
||||
help_category, help_keyword, help_relation, help_topic,
|
||||
proc,
|
||||
time_zone, time_zone_leap_second, time_zone_name, time_zone_transition,
|
||||
time_zone_transition_type
|
||||
|
||||
This function trades accuracy for speed, so may return false
|
||||
positives. Presumably mysql.* database is for internal purposes only
|
||||
and should not contain user tables.
|
||||
*/
|
||||
|
||||
inline bool is_system_table_name(const char *name, uint length)
|
||||
{
|
||||
CHARSET_INFO *ci= system_charset_info;
|
||||
|
||||
return (
|
||||
/* mysql.proc table */
|
||||
length == 4 &&
|
||||
my_tolower(ci, name[0]) == 'p' &&
|
||||
my_tolower(ci, name[1]) == 'r' &&
|
||||
my_tolower(ci, name[2]) == 'o' &&
|
||||
my_tolower(ci, name[3]) == 'c' ||
|
||||
|
||||
length > 4 &&
|
||||
(
|
||||
/* one of mysql.help* tables */
|
||||
my_tolower(ci, name[0]) == 'h' &&
|
||||
my_tolower(ci, name[1]) == 'e' &&
|
||||
my_tolower(ci, name[2]) == 'l' &&
|
||||
my_tolower(ci, name[3]) == 'p' ||
|
||||
|
||||
/* one of mysql.time_zone* tables */
|
||||
my_tolower(ci, name[0]) == 't' &&
|
||||
my_tolower(ci, name[1]) == 'i' &&
|
||||
my_tolower(ci, name[2]) == 'm' &&
|
||||
my_tolower(ci, name[3]) == 'e'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Read table definition from a binary / text based .frm file
|
||||
|
||||
@ -365,11 +409,9 @@ int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags)
|
||||
allow to lock such tables for writing with any other tables (even with
|
||||
other system tables) and some privilege tables need this.
|
||||
*/
|
||||
if (!(lower_case_table_names ?
|
||||
my_strcasecmp(system_charset_info, share->table_name.str, "proc") :
|
||||
strcmp(share->table_name.str, "proc")))
|
||||
share->system_table= 1;
|
||||
else
|
||||
share->system_table= is_system_table_name(share->table_name.str,
|
||||
share->table_name.length);
|
||||
if (!share->system_table)
|
||||
{
|
||||
share->log_table= check_if_log_table(share->db.length, share->db.str,
|
||||
share->table_name.length,
|
||||
|
203
sql/tztime.cc
203
sql/tztime.cc
@ -1505,26 +1505,20 @@ extern "C" byte* my_offset_tzs_get_key(Time_zone_offset *entry, uint *length,
|
||||
|
||||
|
||||
/*
|
||||
Prepare table list with time zone related tables from preallocated array
|
||||
and add to global table list.
|
||||
Prepare table list with time zone related tables from preallocated array.
|
||||
|
||||
SYNOPSIS
|
||||
tz_init_table_list()
|
||||
tz_tabs - pointer to preallocated array of MY_TZ_TABLES_COUNT
|
||||
TABLE_LIST objects
|
||||
global_next_ptr - pointer to variable which points to global_next member
|
||||
of last element of global table list (or list root
|
||||
then list is empty) (in/out).
|
||||
|
||||
DESCRIPTION
|
||||
This function prepares list of TABLE_LIST objects which can be used
|
||||
for opening of time zone tables from preallocated array. It also links
|
||||
this list to the end of global table list (it will read and update
|
||||
accordingly variable pointed by global_next_ptr for this).
|
||||
for opening of time zone tables from preallocated array.
|
||||
*/
|
||||
|
||||
static void
|
||||
tz_init_table_list(TABLE_LIST *tz_tabs, TABLE_LIST ***global_next_ptr)
|
||||
tz_init_table_list(TABLE_LIST *tz_tabs)
|
||||
{
|
||||
bzero(tz_tabs, sizeof(TABLE_LIST) * MY_TZ_TABLES_COUNT);
|
||||
|
||||
@ -1541,64 +1535,6 @@ tz_init_table_list(TABLE_LIST *tz_tabs, TABLE_LIST ***global_next_ptr)
|
||||
if (i != 0)
|
||||
tz_tabs[i].prev_global= &tz_tabs[i-1].next_global;
|
||||
}
|
||||
|
||||
/* Link into global list */
|
||||
tz_tabs[0].prev_global= *global_next_ptr;
|
||||
**global_next_ptr= tz_tabs;
|
||||
/* Update last-global-pointer to point to pointer in last table */
|
||||
*global_next_ptr= &tz_tabs[MY_TZ_TABLES_COUNT-1].next_global;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Fake table list object, pointer to which is returned by
|
||||
my_tz_get_tables_list() as indication of error.
|
||||
*/
|
||||
TABLE_LIST fake_time_zone_tables_list;
|
||||
|
||||
/*
|
||||
Create table list with time zone related tables and add it to the end
|
||||
of global table list.
|
||||
|
||||
SYNOPSIS
|
||||
my_tz_get_table_list()
|
||||
thd - current thread object
|
||||
global_next_ptr - pointer to variable which points to global_next member
|
||||
of last element of global table list (or list root
|
||||
then list is empty) (in/out).
|
||||
|
||||
DESCRIPTION
|
||||
This function creates list of TABLE_LIST objects allocated in thd's
|
||||
memroot, which can be used for opening of time zone tables. It will also
|
||||
link this list to the end of global table list (it will read and update
|
||||
accordingly variable pointed by global_next_ptr for this).
|
||||
|
||||
NOTE
|
||||
my_tz_check_n_skip_implicit_tables() function depends on fact that
|
||||
elements of list created are allocated as TABLE_LIST[MY_TZ_TABLES_COUNT]
|
||||
array.
|
||||
|
||||
RETURN VALUES
|
||||
Returns pointer to first TABLE_LIST object, (could be 0 if time zone
|
||||
tables don't exist) and &fake_time_zone_tables_list in case of error.
|
||||
*/
|
||||
|
||||
TABLE_LIST *
|
||||
my_tz_get_table_list(THD *thd, TABLE_LIST ***global_next_ptr)
|
||||
{
|
||||
TABLE_LIST *tz_tabs;
|
||||
DBUG_ENTER("my_tz_get_table_list");
|
||||
|
||||
if (!time_zone_tables_exist)
|
||||
DBUG_RETURN(0);
|
||||
|
||||
if (!(tz_tabs= (TABLE_LIST *)thd->alloc(sizeof(TABLE_LIST) *
|
||||
MY_TZ_TABLES_COUNT)))
|
||||
DBUG_RETURN(&fake_time_zone_tables_list);
|
||||
|
||||
tz_init_table_list(tz_tabs, global_next_ptr);
|
||||
|
||||
DBUG_RETURN(tz_tabs);
|
||||
}
|
||||
|
||||
|
||||
@ -1631,8 +1567,8 @@ my_bool
|
||||
my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
|
||||
{
|
||||
THD *thd;
|
||||
TABLE_LIST *tables= 0;
|
||||
TABLE_LIST tables_buff[1+MY_TZ_TABLES_COUNT], **last_global_next_ptr;
|
||||
TABLE_LIST tz_tables[1+MY_TZ_TABLES_COUNT];
|
||||
Open_tables_state open_tables_state_backup;
|
||||
TABLE *table;
|
||||
Tz_names_entry *tmp_tzname;
|
||||
my_bool return_val= 1;
|
||||
@ -1694,19 +1630,23 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
|
||||
*/
|
||||
|
||||
thd->set_db(db, sizeof(db)-1);
|
||||
bzero((char*) &tables_buff, sizeof(TABLE_LIST));
|
||||
tables_buff[0].alias= tables_buff[0].table_name=
|
||||
bzero((char*) &tz_tables[0], sizeof(TABLE_LIST));
|
||||
tz_tables[0].alias= tz_tables[0].table_name=
|
||||
(char*)"time_zone_leap_second";
|
||||
tables_buff[0].lock_type= TL_READ;
|
||||
tables_buff[0].db= db;
|
||||
/*
|
||||
Fill TABLE_LIST for the rest of the time zone describing tables
|
||||
and link it to first one.
|
||||
*/
|
||||
last_global_next_ptr= &(tables_buff[0].next_global);
|
||||
tz_init_table_list(tables_buff + 1, &last_global_next_ptr);
|
||||
tz_tables[0].table_name_length= 21;
|
||||
tz_tables[0].db= db;
|
||||
tz_tables[0].db_length= sizeof(db)-1;
|
||||
tz_tables[0].lock_type= TL_READ;
|
||||
|
||||
if (simple_open_n_lock_tables(thd, tables_buff))
|
||||
tz_init_table_list(tz_tables+1);
|
||||
tz_tables[0].next_global= tz_tables[0].next_local= &tz_tables[1];
|
||||
tz_tables[1].prev_global= &tz_tables[0].next_global;
|
||||
|
||||
/*
|
||||
We need to open only mysql.time_zone_leap_second, but we try to
|
||||
open all time zone tables to see if they exist.
|
||||
*/
|
||||
if (open_system_tables_for_read(thd, tz_tables, &open_tables_state_backup))
|
||||
{
|
||||
sql_print_warning("Can't open and lock time zone table: %s "
|
||||
"trying to live without them", thd->net.last_error);
|
||||
@ -1714,7 +1654,6 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
|
||||
return_val= time_zone_tables_exist= 0;
|
||||
goto end_with_setting_default_tz;
|
||||
}
|
||||
tables= tables_buff + 1;
|
||||
|
||||
/*
|
||||
Now we are going to load leap seconds descriptions that are shared
|
||||
@ -1730,7 +1669,7 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
|
||||
goto end_with_close;
|
||||
}
|
||||
|
||||
table= tables_buff[0].table;
|
||||
table= tz_tables[0].table;
|
||||
/*
|
||||
It is OK to ignore ha_index_init()/ha_index_end() return values since
|
||||
mysql.time_zone* tables are MyISAM and these operations always succeed
|
||||
@ -1787,7 +1726,12 @@ end_with_setting_default_tz:
|
||||
if (default_tzname)
|
||||
{
|
||||
String tmp_tzname2(default_tzname, &my_charset_latin1);
|
||||
if (!(global_system_variables.time_zone= my_tz_find(&tmp_tzname2, tables)))
|
||||
/*
|
||||
Time zone tables may be open here, and my_tz_find() may open
|
||||
most of them once more, but this is OK for system tables open
|
||||
for READ.
|
||||
*/
|
||||
if (!(global_system_variables.time_zone= my_tz_find(thd, &tmp_tzname2)))
|
||||
{
|
||||
sql_print_error("Fatal error: Illegal or unknown default time zone '%s'",
|
||||
default_tzname);
|
||||
@ -1796,8 +1740,11 @@ end_with_setting_default_tz:
|
||||
}
|
||||
|
||||
end_with_close:
|
||||
thd->version--; /* Force close to free memory */
|
||||
close_thread_tables(thd);
|
||||
if (time_zone_tables_exist)
|
||||
{
|
||||
thd->version--; /* Force close to free memory */
|
||||
close_system_tables(thd, &open_tables_state_backup);
|
||||
}
|
||||
|
||||
end_with_cleanup:
|
||||
|
||||
@ -1906,7 +1853,6 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
|
||||
*/
|
||||
table= tz_tables->table;
|
||||
tz_tables= tz_tables->next_local;
|
||||
table->use_all_columns();
|
||||
table->field[0]->store(tz_name->ptr(), tz_name->length(),
|
||||
&my_charset_latin1);
|
||||
/*
|
||||
@ -1939,7 +1885,6 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
|
||||
using the only index in this table).
|
||||
*/
|
||||
table= tz_tables->table;
|
||||
table->use_all_columns();
|
||||
tz_tables= tz_tables->next_local;
|
||||
table->field[0]->store((longlong) tzid, TRUE);
|
||||
(void)table->file->ha_index_init(0, 1);
|
||||
@ -1967,7 +1912,6 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
|
||||
Right - using special index.
|
||||
*/
|
||||
table= tz_tables->table;
|
||||
table->use_all_columns();
|
||||
tz_tables= tz_tables->next_local;
|
||||
table->field[0]->store((longlong) tzid, TRUE);
|
||||
(void)table->file->ha_index_init(0, 1);
|
||||
@ -2040,7 +1984,6 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
|
||||
in ascending order by index scan also satisfies us.
|
||||
*/
|
||||
table= tz_tables->table;
|
||||
table->use_all_columns();
|
||||
table->field[0]->store((longlong) tzid, TRUE);
|
||||
(void)table->file->ha_index_init(0, 1);
|
||||
|
||||
@ -2249,8 +2192,8 @@ str_to_offset(const char *str, uint length, long *offset)
|
||||
|
||||
SYNOPSIS
|
||||
my_tz_find()
|
||||
thd - pointer to thread THD structure
|
||||
name - time zone specification
|
||||
tz_tables - list of opened'n'locked time zone describing tables
|
||||
|
||||
DESCRIPTION
|
||||
This function checks if name is one of time zones described in db,
|
||||
@ -2272,11 +2215,10 @@ str_to_offset(const char *str, uint length, long *offset)
|
||||
values as parameter without additional external check and this property
|
||||
is used by @@time_zone variable handling code).
|
||||
|
||||
It will perform lookup in system tables (mysql.time_zone*) if needed
|
||||
using tz_tables as list of already opened tables (for info about this
|
||||
list look at tz_load_from_open_tables() description). It won't perform
|
||||
such lookup if no time zone describing tables were found during server
|
||||
start up.
|
||||
It will perform lookup in system tables (mysql.time_zone*),
|
||||
opening and locking them, and closing afterwards. It won't perform
|
||||
such lookup if no time zone describing tables were found during
|
||||
server start up.
|
||||
|
||||
RETURN VALUE
|
||||
Pointer to corresponding Time_zone object. 0 - in case of bad time zone
|
||||
@ -2284,7 +2226,7 @@ str_to_offset(const char *str, uint length, long *offset)
|
||||
|
||||
*/
|
||||
Time_zone *
|
||||
my_tz_find(const String * name, TABLE_LIST *tz_tables)
|
||||
my_tz_find(THD *thd, const String *name)
|
||||
{
|
||||
Tz_names_entry *tmp_tzname;
|
||||
Time_zone *result_tz= 0;
|
||||
@ -2292,8 +2234,6 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables)
|
||||
DBUG_ENTER("my_tz_find");
|
||||
DBUG_PRINT("enter", ("time zone name='%s'",
|
||||
name ? ((String *)name)->c_ptr_safe() : "NULL"));
|
||||
DBUG_ASSERT(!time_zone_tables_exist || tz_tables ||
|
||||
current_thd->slave_thread);
|
||||
|
||||
if (!name)
|
||||
DBUG_RETURN(0);
|
||||
@ -2325,8 +2265,19 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables)
|
||||
(const byte *)name->ptr(),
|
||||
name->length())))
|
||||
result_tz= tmp_tzname->tz;
|
||||
else if (time_zone_tables_exist && tz_tables)
|
||||
result_tz= tz_load_from_open_tables(name, tz_tables);
|
||||
else if (time_zone_tables_exist)
|
||||
{
|
||||
TABLE_LIST tz_tables[MY_TZ_TABLES_COUNT];
|
||||
Open_tables_state open_tables_state_backup;
|
||||
|
||||
tz_init_table_list(tz_tables);
|
||||
if (!open_system_tables_for_read(thd, tz_tables,
|
||||
&open_tables_state_backup))
|
||||
{
|
||||
result_tz= tz_load_from_open_tables(name, tz_tables);
|
||||
close_system_tables(thd, &open_tables_state_backup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VOID(pthread_mutex_unlock(&tz_LOCK));
|
||||
@ -2335,58 +2286,6 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
A more standalone version of my_tz_find(): will open tz tables if needed.
|
||||
This is so far only used by replication, where time zone setting does not
|
||||
happen in the usual query context.
|
||||
|
||||
SYNOPSIS
|
||||
my_tz_find_with_opening_tz_tables()
|
||||
thd - pointer to thread's THD structure
|
||||
name - time zone specification
|
||||
|
||||
DESCRIPTION
|
||||
This function tries to find a time zone which matches the named passed in
|
||||
argument. If it fails, it will open time zone tables and re-try the
|
||||
search.
|
||||
This function is needed for the slave SQL thread, which does not do the
|
||||
addition of time zone tables which is usually done during query parsing
|
||||
(as time zone setting by slave does not happen in mysql_parse() but
|
||||
before). So it needs to open tz tables by itself if needed.
|
||||
See notes of my_tz_find() as they also apply here.
|
||||
|
||||
RETURN VALUE
|
||||
Pointer to corresponding Time_zone object. 0 - in case of bad time zone
|
||||
specification or other error.
|
||||
*/
|
||||
|
||||
Time_zone *my_tz_find_with_opening_tz_tables(THD *thd, const String *name)
|
||||
{
|
||||
Time_zone *tz;
|
||||
DBUG_ENTER("my_tz_find_with_opening_tables");
|
||||
DBUG_ASSERT(thd);
|
||||
DBUG_ASSERT(thd->slave_thread); // intended for use with slave thread only
|
||||
|
||||
if (!(tz= my_tz_find(name, 0)) && time_zone_tables_exist)
|
||||
{
|
||||
/*
|
||||
Probably we have not loaded this time zone yet so let us look it up in
|
||||
our time zone tables. Note that if we don't have tz tables on this
|
||||
slave, we don't even try.
|
||||
*/
|
||||
TABLE_LIST tables[MY_TZ_TABLES_COUNT];
|
||||
TABLE_LIST *dummy;
|
||||
TABLE_LIST **dummyp= &dummy;
|
||||
tz_init_table_list(tables, &dummyp);
|
||||
if (simple_open_n_lock_tables(thd, tables))
|
||||
DBUG_RETURN(0);
|
||||
tz= my_tz_find(name, tables);
|
||||
/* We need to close tables _now_ to not pollute coming query */
|
||||
close_thread_tables(thd);
|
||||
}
|
||||
DBUG_RETURN(tz);
|
||||
}
|
||||
|
||||
#endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */
|
||||
|
||||
|
||||
|
35
sql/tztime.h
35
sql/tztime.h
@ -59,15 +59,11 @@ public:
|
||||
|
||||
extern Time_zone * my_tz_UTC;
|
||||
extern Time_zone * my_tz_SYSTEM;
|
||||
extern TABLE_LIST * my_tz_get_table_list(THD *thd, TABLE_LIST ***global_next_ptr);
|
||||
extern Time_zone * my_tz_find(const String *name, TABLE_LIST *tz_tables);
|
||||
extern Time_zone * my_tz_find_with_opening_tz_tables(THD *thd, const String *name);
|
||||
extern Time_zone * my_tz_find(THD *thd, const String *name);
|
||||
extern my_bool my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap);
|
||||
extern void my_tz_free();
|
||||
extern my_time_t sec_since_epoch_TIME(TIME *t);
|
||||
|
||||
extern TABLE_LIST fake_time_zone_tables_list;
|
||||
|
||||
/*
|
||||
Number of elements in table list produced by my_tz_get_table_list()
|
||||
(this table list contains tables which are needed for dynamical loading
|
||||
@ -77,34 +73,5 @@ extern TABLE_LIST fake_time_zone_tables_list;
|
||||
|
||||
static const int MY_TZ_TABLES_COUNT= 4;
|
||||
|
||||
/*
|
||||
Check if we have pointer to the begining of list of implicitly used time
|
||||
zone tables, set SELECT_ACL for them and fast-forward to its end.
|
||||
|
||||
SYNOPSIS
|
||||
my_tz_check_n_skip_implicit_tables()
|
||||
table - (in/out) pointer to element of table list to check
|
||||
tz_tables - list of implicitly used time zone tables received
|
||||
from my_tz_get_table_list() function.
|
||||
|
||||
NOTE
|
||||
This function relies on my_tz_get_table_list() implementation.
|
||||
|
||||
RETURN VALUE
|
||||
TRUE - if table points to the beggining of tz_tables list
|
||||
FALSE - otherwise.
|
||||
*/
|
||||
inline bool my_tz_check_n_skip_implicit_tables(TABLE_LIST **table,
|
||||
TABLE_LIST *tz_tables)
|
||||
{
|
||||
if (*table == tz_tables)
|
||||
{
|
||||
for (int i= 0; i < MY_TZ_TABLES_COUNT; i++)
|
||||
(*table)[i].grant.privilege= SELECT_ACL;
|
||||
(*table)+= MY_TZ_TABLES_COUNT - 1;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */
|
||||
|
@ -787,7 +787,8 @@ void ha_tina::update_status()
|
||||
|
||||
bool ha_tina::check_if_locking_is_allowed(uint sql_command,
|
||||
ulong type, TABLE *table,
|
||||
uint count,
|
||||
uint count, uint current,
|
||||
uint *system_count,
|
||||
bool called_by_privileged_thread)
|
||||
{
|
||||
if (!called_by_privileged_thread)
|
||||
|
@ -128,7 +128,8 @@ public:
|
||||
|
||||
virtual bool check_if_locking_is_allowed(uint sql_command,
|
||||
ulong type, TABLE *table,
|
||||
uint count,
|
||||
uint count, uint current,
|
||||
uint *system_count,
|
||||
bool called_by_logger_thread);
|
||||
int open(const char *name, int mode, uint open_options);
|
||||
int close(void);
|
||||
|
@ -600,7 +600,8 @@ err:
|
||||
|
||||
bool ha_myisam::check_if_locking_is_allowed(uint sql_command,
|
||||
ulong type, TABLE *table,
|
||||
uint count,
|
||||
uint count, uint current,
|
||||
uint *system_count,
|
||||
bool called_by_privileged_thread)
|
||||
{
|
||||
/*
|
||||
@ -609,11 +610,13 @@ bool ha_myisam::check_if_locking_is_allowed(uint sql_command,
|
||||
we have to disallow write-locking of these tables with any other tables.
|
||||
*/
|
||||
if (table->s->system_table &&
|
||||
table->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE &&
|
||||
count != 1)
|
||||
table->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE)
|
||||
(*system_count)++;
|
||||
|
||||
/* 'current' is an index, that's why '<=' below. */
|
||||
if (*system_count > 0 && *system_count <= current)
|
||||
{
|
||||
my_error(ER_WRONG_LOCK_OF_SYSTEM_TABLE, MYF(0), table->s->db.str,
|
||||
table->s->table_name.str);
|
||||
my_error(ER_WRONG_LOCK_OF_SYSTEM_TABLE, MYF(0));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,8 @@ class ha_myisam: public handler
|
||||
|
||||
virtual bool check_if_locking_is_allowed(uint sql_command,
|
||||
ulong type, TABLE *table,
|
||||
uint count,
|
||||
uint count, uint current,
|
||||
uint *system_count,
|
||||
bool called_by_logger_thread);
|
||||
int open(const char *name, int mode, uint test_if_locked);
|
||||
int close(void);
|
||||
|
@ -77,8 +77,8 @@ private:
|
||||
};
|
||||
|
||||
//
|
||||
// ERR prints an NdbError object togheter with a description of where
|
||||
// the error occured
|
||||
// ERR prints an NdbError object together with a description of where the
|
||||
// error occured
|
||||
//
|
||||
#define ERR_OUT(where, error) \
|
||||
{ where << "ERROR: " << error.code << " " \
|
||||
|
@ -26,7 +26,7 @@ extern "C" {
|
||||
#define NDBT_TEMPORARY 3
|
||||
/**
|
||||
* NDBT_ProgramExit
|
||||
* This function will print the returncode togheter with a prefix on
|
||||
* This function will print the returncode together with a prefix on
|
||||
* the screen and then exit the test program.
|
||||
* Call this function when exiting the main function in your test programs
|
||||
* Returns the return code
|
||||
|
@ -2354,6 +2354,271 @@ static void test_ps_conj_select()
|
||||
}
|
||||
|
||||
|
||||
/* reads Qcache_hits from server and returns its value */
|
||||
static uint query_cache_hits(MYSQL *conn)
|
||||
{
|
||||
MYSQL_RES *res;
|
||||
MYSQL_ROW row;
|
||||
int rc;
|
||||
uint result;
|
||||
|
||||
rc= mysql_query(conn, "show status like 'qcache_hits'");
|
||||
myquery(rc);
|
||||
res= mysql_use_result(conn);
|
||||
DIE_UNLESS(res);
|
||||
|
||||
row= mysql_fetch_row(res);
|
||||
DIE_UNLESS(row);
|
||||
|
||||
result= atoi(row[1]);
|
||||
mysql_free_result(res);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
utility for the next test; expects 3 rows in the result from a SELECT,
|
||||
compares each row/field with an expected value.
|
||||
*/
|
||||
#define test_ps_query_cache_result(i1,s1,l1,i2,s2,l2,i3,s3,l3) \
|
||||
r_metadata= mysql_stmt_result_metadata(stmt); \
|
||||
DIE_UNLESS(r_metadata != NULL); \
|
||||
rc= mysql_stmt_fetch(stmt); \
|
||||
check_execute(stmt, rc); \
|
||||
if (!opt_silent) \
|
||||
fprintf(stdout, "\n row 1: %d, %s(%lu)", r_int_data, \
|
||||
r_str_data, r_str_length); \
|
||||
DIE_UNLESS((r_int_data == i1) && (r_str_length == l1) && \
|
||||
(strcmp(r_str_data, s1) == 0)); \
|
||||
rc= mysql_stmt_fetch(stmt); \
|
||||
check_execute(stmt, rc); \
|
||||
if (!opt_silent) \
|
||||
fprintf(stdout, "\n row 2: %d, %s(%lu)", r_int_data, \
|
||||
r_str_data, r_str_length); \
|
||||
DIE_UNLESS((r_int_data == i2) && (r_str_length == l2) && \
|
||||
(strcmp(r_str_data, s2) == 0)); \
|
||||
rc= mysql_stmt_fetch(stmt); \
|
||||
check_execute(stmt, rc); \
|
||||
if (!opt_silent) \
|
||||
fprintf(stdout, "\n row 3: %d, %s(%lu)", r_int_data, \
|
||||
r_str_data, r_str_length); \
|
||||
DIE_UNLESS((r_int_data == i3) && (r_str_length == l3) && \
|
||||
(strcmp(r_str_data, s3) == 0)); \
|
||||
rc= mysql_stmt_fetch(stmt); \
|
||||
DIE_UNLESS(rc == MYSQL_NO_DATA); \
|
||||
mysql_free_result(r_metadata);
|
||||
|
||||
|
||||
/*
|
||||
Test that prepared statements make use of the query cache just as normal
|
||||
statements (BUG#735).
|
||||
*/
|
||||
static void test_ps_query_cache()
|
||||
{
|
||||
MYSQL *org_mysql= mysql, *lmysql;
|
||||
MYSQL_STMT *stmt;
|
||||
int rc;
|
||||
MYSQL_BIND p_bind[2],r_bind[2]; /* p: param bind; r: result bind */
|
||||
int32 p_int_data, r_int_data;
|
||||
char p_str_data[32], r_str_data[32];
|
||||
unsigned long p_str_length, r_str_length;
|
||||
MYSQL_RES *r_metadata;
|
||||
char query[MAX_TEST_QUERY_LENGTH];
|
||||
uint hits1, hits2;
|
||||
enum enum_test_ps_query_cache
|
||||
{
|
||||
/*
|
||||
We iterate the same prepare/executes block, but have iterations where
|
||||
we vary the query cache conditions.
|
||||
*/
|
||||
/* the query cache is enabled for the duration of prep&execs: */
|
||||
TEST_QCACHE_ON= 0,
|
||||
/*
|
||||
same but using a new connection (to see if qcache serves results from
|
||||
the previous connection as it should):
|
||||
*/
|
||||
TEST_QCACHE_ON_WITH_OTHER_CONN,
|
||||
/*
|
||||
First border case: disables the query cache before prepare and
|
||||
re-enables it before execution (to test if we have no bug then):
|
||||
*/
|
||||
TEST_QCACHE_OFF_ON,
|
||||
/*
|
||||
Second border case: enables the query cache before prepare and
|
||||
disables it before execution:
|
||||
*/
|
||||
TEST_QCACHE_ON_OFF
|
||||
};
|
||||
enum enum_test_ps_query_cache iteration;
|
||||
LINT_INIT(lmysql);
|
||||
|
||||
myheader("test_ps_query_cache");
|
||||
|
||||
/* prepare the table */
|
||||
|
||||
rc= mysql_query(mysql, "drop table if exists t1");
|
||||
myquery(rc);
|
||||
|
||||
rc= mysql_query(mysql, "create table t1 (id1 int(11) NOT NULL default '0', "
|
||||
"value2 varchar(100), value1 varchar(100))");
|
||||
myquery(rc);
|
||||
|
||||
rc= mysql_query(mysql, "insert into t1 values (1, 'hh', 'hh'), "
|
||||
"(2, 'hh', 'hh'), (1, 'ii', 'ii'), (2, 'ii', 'ii')");
|
||||
myquery(rc);
|
||||
|
||||
for (iteration= TEST_QCACHE_ON; iteration < TEST_QCACHE_ON_OFF; iteration++)
|
||||
{
|
||||
|
||||
switch (iteration)
|
||||
{
|
||||
case TEST_QCACHE_ON:
|
||||
case TEST_QCACHE_ON_OFF:
|
||||
rc= mysql_query(mysql, "set global query_cache_size=1000000");
|
||||
myquery(rc);
|
||||
break;
|
||||
case TEST_QCACHE_OFF_ON:
|
||||
rc= mysql_query(mysql, "set global query_cache_size=0");
|
||||
myquery(rc);
|
||||
break;
|
||||
case TEST_QCACHE_ON_WITH_OTHER_CONN:
|
||||
if (!opt_silent)
|
||||
fprintf(stdout, "\n Establishing a test connection ...");
|
||||
if (!(lmysql= mysql_init(NULL)))
|
||||
{
|
||||
myerror("mysql_init() failed");
|
||||
exit(1);
|
||||
}
|
||||
if (!(mysql_real_connect(lmysql, opt_host, opt_user,
|
||||
opt_password, current_db, opt_port,
|
||||
opt_unix_socket, 0)))
|
||||
{
|
||||
myerror("connection failed");
|
||||
mysql_close(lmysql);
|
||||
exit(1);
|
||||
}
|
||||
if (!opt_silent)
|
||||
fprintf(stdout, " OK");
|
||||
mysql= lmysql;
|
||||
}
|
||||
|
||||
strmov(query, "select id1, value1 from t1 where id1= ? or "
|
||||
"CONVERT(value1 USING utf8)= ?");
|
||||
stmt= mysql_simple_prepare(mysql, query);
|
||||
check_stmt(stmt);
|
||||
|
||||
verify_param_count(stmt, 2);
|
||||
|
||||
switch(iteration)
|
||||
{
|
||||
case TEST_QCACHE_OFF_ON:
|
||||
rc= mysql_query(mysql, "set global query_cache_size=1000000");
|
||||
myquery(rc);
|
||||
break;
|
||||
case TEST_QCACHE_ON_OFF:
|
||||
rc= mysql_query(mysql, "set global query_cache_size=0");
|
||||
myquery(rc);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
bzero((char*) p_bind, sizeof(p_bind));
|
||||
p_bind[0].buffer_type= MYSQL_TYPE_LONG;
|
||||
p_bind[0].buffer= (void *)&p_int_data;
|
||||
p_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING;
|
||||
p_bind[1].buffer= (void *)p_str_data;
|
||||
p_bind[1].buffer_length= array_elements(p_str_data);
|
||||
p_bind[1].length= &p_str_length;
|
||||
|
||||
rc= mysql_stmt_bind_param(stmt, p_bind);
|
||||
check_execute(stmt, rc);
|
||||
|
||||
p_int_data= 1;
|
||||
strmov(p_str_data, "hh");
|
||||
p_str_length= strlen(p_str_data);
|
||||
|
||||
bzero((char*) r_bind, sizeof(r_bind));
|
||||
r_bind[0].buffer_type= MYSQL_TYPE_LONG;
|
||||
r_bind[0].buffer= (void *)&r_int_data;
|
||||
r_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING;
|
||||
r_bind[1].buffer= (void *)r_str_data;
|
||||
r_bind[1].buffer_length= array_elements(r_str_data);
|
||||
r_bind[1].length= &r_str_length;
|
||||
|
||||
rc= mysql_stmt_bind_result(stmt, r_bind);
|
||||
check_execute(stmt, rc);
|
||||
|
||||
rc= mysql_stmt_execute(stmt);
|
||||
check_execute(stmt, rc);
|
||||
|
||||
test_ps_query_cache_result(1, "hh", 2, 2, "hh", 2, 1, "ii", 2);
|
||||
|
||||
/* now retry with the same parameter values and see qcache hits */
|
||||
hits1= query_cache_hits(mysql);
|
||||
rc= mysql_stmt_execute(stmt);
|
||||
check_execute(stmt, rc);
|
||||
test_ps_query_cache_result(1, "hh", 2, 2, "hh", 2, 1, "ii", 2);
|
||||
hits2= query_cache_hits(mysql);
|
||||
switch(iteration)
|
||||
{
|
||||
case TEST_QCACHE_ON_WITH_OTHER_CONN:
|
||||
case TEST_QCACHE_ON: /* should have hit */
|
||||
DIE_UNLESS(hits2-hits1 == 1);
|
||||
break;
|
||||
case TEST_QCACHE_OFF_ON:
|
||||
case TEST_QCACHE_ON_OFF: /* should not have hit */
|
||||
DIE_UNLESS(hits2-hits1 == 0);
|
||||
}
|
||||
|
||||
/* now modify parameter values and see qcache hits */
|
||||
strmov(p_str_data, "ii");
|
||||
p_str_length= strlen(p_str_data);
|
||||
rc= mysql_stmt_execute(stmt);
|
||||
check_execute(stmt, rc);
|
||||
test_ps_query_cache_result(1, "hh", 2, 1, "ii", 2, 2, "ii", 2);
|
||||
hits1= query_cache_hits(mysql);
|
||||
|
||||
switch(iteration)
|
||||
{
|
||||
case TEST_QCACHE_ON:
|
||||
case TEST_QCACHE_OFF_ON:
|
||||
case TEST_QCACHE_ON_OFF: /* should not have hit */
|
||||
DIE_UNLESS(hits2-hits1 == 0);
|
||||
break;
|
||||
case TEST_QCACHE_ON_WITH_OTHER_CONN: /* should have hit */
|
||||
DIE_UNLESS(hits1-hits2 == 1);
|
||||
}
|
||||
|
||||
rc= mysql_stmt_execute(stmt);
|
||||
check_execute(stmt, rc);
|
||||
|
||||
test_ps_query_cache_result(1, "hh", 2, 1, "ii", 2, 2, "ii", 2);
|
||||
hits2= query_cache_hits(mysql);
|
||||
|
||||
mysql_stmt_close(stmt);
|
||||
|
||||
switch(iteration)
|
||||
{
|
||||
case TEST_QCACHE_ON: /* should have hit */
|
||||
DIE_UNLESS(hits2-hits1 == 1);
|
||||
break;
|
||||
case TEST_QCACHE_OFF_ON:
|
||||
case TEST_QCACHE_ON_OFF: /* should not have hit */
|
||||
DIE_UNLESS(hits2-hits1 == 0);
|
||||
break;
|
||||
case TEST_QCACHE_ON_WITH_OTHER_CONN:
|
||||
mysql_close(lmysql);
|
||||
mysql= org_mysql;
|
||||
}
|
||||
|
||||
} /* for(iteration=...) */
|
||||
|
||||
rc= mysql_query(mysql, "set global query_cache_size=0");
|
||||
myquery(rc);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Test BUG#1115 (incorrect string parameter value allocation) */
|
||||
|
||||
static void test_bug1115()
|
||||
@ -4722,7 +4987,7 @@ static void test_stmt_close()
|
||||
close statements by hand once mysql_close() had been called.
|
||||
Now mysql_close() doesn't free any statements, so this test doesn't
|
||||
serve its original designation any more.
|
||||
Here we free stmt2 and stmt3 by hande to avoid memory leaks.
|
||||
Here we free stmt2 and stmt3 by hand to avoid memory leaks.
|
||||
*/
|
||||
mysql_stmt_close(stmt2);
|
||||
mysql_stmt_close(stmt3);
|
||||
@ -16067,8 +16332,9 @@ static struct my_tests_st my_tests[]= {
|
||||
{ "test_bug15518", test_bug15518 },
|
||||
{ "test_bug23383", test_bug23383 },
|
||||
{ "test_bug21635", test_bug21635 },
|
||||
{ "test_status", test_status},
|
||||
{ "test_status", test_status },
|
||||
{ "test_bug24179", test_bug24179 },
|
||||
{ "test_ps_query_cache", test_ps_query_cache },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user