Merge tsmith@bk-internal.mysql.com:/home/bk/mysql-5.1

into  quadxeon.mysql.com:/benchmarks/ext3/TOSAVE/tsmith/bk/maint/51


include/my_global.h:
  Auto merged
mysql-test/mysql-test-run.pl:
  Auto merged
mysql-test/r/help.result:
  Auto merged
mysql-test/t/help.test:
  Auto merged
sql/mysql_priv.h:
  Auto merged
sql/sql_class.cc:
  Auto merged
sql/sql_yacc.yy:
  Auto merged
This commit is contained in:
unknown 2007-03-22 01:04:39 +01:00
commit b636ad25c7
99 changed files with 3645 additions and 1121 deletions

View file

@ -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);

View file

@ -1509,4 +1509,10 @@ inline void operator delete[](void*, void*) { /* Do nothing */ }
#endif
#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 */

View file

@ -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;

View file

@ -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;

View file

@ -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`;

View file

@ -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 )

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -85,7 +85,7 @@ SELECT * FROM slow_event_test;
slo_val val
20 0
1 0
"Check slow log. Should see 1 row because 4 is over the threshold of 3 for GLOBAL, though under SESSION which is 10"
"Check slow log. Should see 1 row because 2 is over the threshold of 1 for GLOBAL, though under SESSION which is 10"
SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
user_host query_time db sql_text
USER_HOST SLEEPVAL events_test INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(2)

View file

@ -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"

View 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.

View file

@ -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.

View file

@ -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.

View file

@ -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;

View file

@ -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.

View file

@ -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;

View 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;

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -89,10 +89,12 @@ DROP EVENT long_event;
SET GLOBAL long_query_time=1;
CREATE EVENT long_event2 ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(2);
--echo "Sleep some more time than the actual event run will take"
--sleep 2.5
let $wait_timeout= 30;
let $wait_condition= SELECT COUNT(*) = 1 FROM mysql.slow_log;
--source include/wait_condition.inc
--echo "Check our table. Should see 2 rows"
SELECT * FROM slow_event_test;
--echo "Check slow log. Should see 1 row because 4 is over the threshold of 3 for GLOBAL, though under SESSION which is 10"
--echo "Check slow log. Should see 1 row because 2 is over the threshold of 1 for GLOBAL, though under SESSION which is 10"
--replace_column 1 USER_HOST 2 SLEEPVAL
SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
DROP EVENT long_event2;

View file

@ -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"

View 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.

View file

@ -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

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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;

View 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

View file

@ -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
#

View file

@ -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
#

View file

@ -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.

View file

@ -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

View file

@ -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.

View file

@ -70,7 +70,7 @@ CALL create_slow_log_table();
DROP PROCEDURE create_slow_log_table;
CREATE TABLE IF NOT EXISTS event ( db char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '', name char(64) CHARACTER SET utf8 NOT NULL default '', body longblob NOT NULL, definer char(77) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '', execute_at DATETIME default NULL, interval_value int(11) default NULL, interval_field ENUM('YEAR','QUARTER','MONTH','DAY','HOUR','MINUTE','WEEK','SECOND','MICROSECOND','YEAR_MONTH','DAY_HOUR','DAY_MINUTE','DAY_SECOND','HOUR_MINUTE','HOUR_SECOND','MINUTE_SECOND','DAY_MICROSECOND','HOUR_MICROSECOND','MINUTE_MICROSECOND','SECOND_MICROSECOND') default NULL, created TIMESTAMP NOT NULL, modified TIMESTAMP NOT NULL, last_executed DATETIME default NULL, starts DATETIME default NULL, ends DATETIME default NULL, status ENUM('ENABLED','DISABLED') NOT NULL default 'ENABLED', 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') DEFAULT '' NOT NULL, comment char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '', PRIMARY KEY (db, name) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT 'Events';
CREATE TABLE IF NOT EXISTS event ( db char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '', name char(64) CHARACTER SET utf8 NOT NULL default '', body longblob NOT NULL, definer char(77) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '', execute_at DATETIME default NULL, interval_value int(11) default NULL, interval_field ENUM('YEAR','QUARTER','MONTH','DAY','HOUR','MINUTE','WEEK','SECOND','MICROSECOND','YEAR_MONTH','DAY_HOUR','DAY_MINUTE','DAY_SECOND','HOUR_MINUTE','HOUR_SECOND','MINUTE_SECOND','DAY_MICROSECOND','HOUR_MICROSECOND','MINUTE_MICROSECOND','SECOND_MICROSECOND') default NULL, created TIMESTAMP NOT NULL, modified TIMESTAMP NOT NULL, last_executed DATETIME default NULL, starts DATETIME default NULL, ends DATETIME default NULL, status ENUM('ENABLED','DISABLED') NOT NULL default 'ENABLED', 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') 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';
CREATE TABLE IF NOT EXISTS ndb_binlog_index (Position BIGINT UNSIGNED NOT NULL, File VARCHAR(255) NOT NULL, epoch BIGINT UNSIGNED NOT NULL, inserts BIGINT UNSIGNED NOT NULL, updates BIGINT UNSIGNED NOT NULL, deletes BIGINT UNSIGNED NOT NULL, schemaops BIGINT UNSIGNED NOT NULL, PRIMARY KEY(epoch)) ENGINE=MYISAM;

View file

@ -424,82 +424,24 @@ END//
delimiter ;
CALL create_log_tables();
DROP PROCEDURE create_log_tables;
#
# EVENT table
#
CREATE TABLE event (
db char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
name char(64) CHARACTER SET utf8 NOT NULL default '',
body longblob NOT NULL,
definer char(77) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
execute_at DATETIME default NULL,
interval_value int(11) default NULL,
interval_field ENUM('YEAR','QUARTER','MONTH','DAY','HOUR','MINUTE','WEEK',
'SECOND','MICROSECOND', 'YEAR_MONTH','DAY_HOUR',
'DAY_MINUTE','DAY_SECOND',
'HOUR_MINUTE','HOUR_SECOND',
'MINUTE_SECOND','DAY_MICROSECOND',
'HOUR_MICROSECOND','MINUTE_MICROSECOND',
'SECOND_MICROSECOND') default NULL,
created TIMESTAMP NOT NULL,
modified TIMESTAMP NOT NULL,
last_executed DATETIME default NULL,
starts DATETIME default NULL,
ends DATETIME default NULL,
status ENUM('ENABLED','DISABLED') NOT NULL default 'ENABLED',
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'
) DEFAULT '' NOT NULL,
comment char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
PRIMARY KEY (db,name)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT 'Events';
#
# EVENT privilege
#
SET @hadEventPriv := 0;
SELECT @hadEventPriv :=1 FROM user WHERE Event_priv LIKE '%';
ALTER TABLE user add Event_priv enum('N','Y') character set utf8 DEFAULT 'N' NOT NULL AFTER Create_user_priv;
ALTER TABLE user MODIFY Event_priv enum('N','Y') character set utf8 DEFAULT 'N' NOT NULL AFTER Create_user_priv;
UPDATE user SET Event_priv=Super_priv WHERE @hadEventPriv = 0;
ALTER TABLE db add Event_priv enum('N','Y') character set utf8 DEFAULT 'N' NOT NULL;
ALTER TABLE db MODIFY Event_priv enum('N','Y') character set utf8 DEFAULT 'N' NOT NULL;
#
# EVENT table
#
ALTER TABLE event DROP PRIMARY KEY;
ALTER TABLE event ADD PRIMARY KEY(db, name);
ALTER TABLE event ADD sql_mode
@ -534,10 +476,11 @@ 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
#

View file

@ -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(&ltime, TIME_NO_ZERO_DATE)))
goto wrong_value;
if (TIME_to_ulonglong_datetime(&ltime) <
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(&ltime,t=TIME_to_timestamp(thd,&ltime,&not_used));
if (!t)
ltime_utc= TIME_to_timestamp(thd,&ltime,&not_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(&ltime, 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, &ltime, &not_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(&ltime)));
if (TIME_to_ulonglong_datetime(&ltime) <
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(&ltime,t=TIME_to_timestamp(thd, &ltime,
&not_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(&ltime, 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(&ltime,t=TIME_to_timestamp(thd, &ltime,
&not_used));
if (!t)
ltime_utc= TIME_to_timestamp(thd, &ltime, &not_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, &ltime) != -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(&ltime_now, (my_time_t)thd->query_start());
if (my_time_compare(&ltime_now, &ltime) == 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, &not_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, &microsec_diff))
bool negative= calc_time_diff(&local_now, &local_start, 1,
&seconds_diff, &microsec_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= (my_time_t) 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= (my_time_t) 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

View file

@ -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 &);
};

View file

@ -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)

View file

@ -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 :) */
};

View file

@ -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;
}

View file

@ -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;

View file

@ -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)))

View file

@ -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

View file

@ -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);

View file

@ -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,

View file

@ -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;

View file

@ -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:

View file

@ -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; }

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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();
}

View file

@ -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();

View file

@ -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())))

View file

@ -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;

View file

@ -647,6 +647,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;
@ -673,6 +674,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)
@ -689,6 +695,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*/
/*
@ -1430,6 +1438,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,

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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);
}

View file

@ -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"

View file

@ -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, &not_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, &not_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;
}

View file

@ -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);
/*

View file

@ -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;

View file

@ -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:

View file

@ -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;
}

View file

@ -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

View file

@ -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, &not_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, &not_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);
}

View file

@ -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,

View file

@ -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();

View file

@ -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

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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();

View file

@ -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,

View file

@ -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));

View file

@ -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)

View file

@ -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, &not_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"},

View file

@ -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))

View file

@ -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);

View file

@ -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; }

View file

@ -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,

View file

@ -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) */

View file

@ -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) */

View file

@ -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)

View file

@ -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);

View file

@ -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;
}

View file

@ -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);

View file

@ -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 << " " \

View file

@ -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

View file

@ -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 }
};