From a5d9aba6df08ff5e79a66a2cbf2576b6d269fcf8 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Sat, 25 Feb 2012 12:14:34 -0800 Subject: [PATCH] Implement server-side statement timeout support Introduce a server-side time limit for the execution of statements. This feature works by interrupting the execution of statements that take over a specified number of milliseconds to complete. After the specified number of milliseconds has passed, the server attempts to abort the statement without affecting the session (connection) itself. The implementation is optimized for the case where a statement finishes executing before reaching the time limit. Also, because the timeout event is an asynchronous operation to the statement being executed, it is possible that a given statement may not be interrupted immediatelyafter the time limit is exceeded. The maximum execution time can be set with the max_statement_time variable. Using the @@max_statement_time variable a user should be able to specify the maximum execution time for any statement. The variable value is based on a unsigned 64 bits long integer, which represents milliseconds. An infinite timeout is represented by a zero value, meaning that no timeout value is set. Lastly, the maximum execution time only applies to top-level statements or queries; compound statements are treated as a regular component of the top-level statement. --- config.h.cmake | 4 + configure.cmake | 17 ++ include/my_global.h | 17 +- include/my_timer.h | 69 +++++ include/mysql/plugin.h | 7 + include/mysql/plugin_audit.h.pp | 1 + include/mysql/plugin_auth.h.pp | 1 + include/mysql/plugin_ftparser.h.pp | 1 + libmysqld/CMakeLists.txt | 3 + mysql-test/include/have_statement_timeout.inc | 4 + mysql-test/r/grant.result | 3 + mysql-test/r/have_statement_timeout.require | 2 + mysql-test/r/max_statement_time.result | 157 ++++++++++++ mysql-test/r/ps.result | 6 +- mysql-test/r/system_mysql_db.result | 1 + mysql-test/suite/funcs_1/r/is_columns_mysql.result | 2 + .../suite/funcs_1/r/is_user_privileges.result | 33 +++ mysql-test/suite/randgen/t/max_statement_time.test | 16 ++ .../sys_vars/r/have_statement_timeout_basic.result | 53 ++++ .../sys_vars/r/max_statement_time_basic.result | 91 +++++++ .../sys_vars/r/max_statement_time_func.result | 66 +++++ .../sys_vars/t/have_statement_timeout_basic.test | 55 ++++ .../suite/sys_vars/t/max_statement_time_basic.test | 78 ++++++ .../suite/sys_vars/t/max_statement_time_func.test | 75 ++++++ mysql-test/t/max_statement_time.test | 220 ++++++++++++++++ mysys/CMakeLists.txt | 8 + mysys/kqueue_timers.c | 219 ++++++++++++++++ mysys/posix_timers.c | 256 +++++++++++++++++++ scripts/mysql_system_tables.sql | 2 +- scripts/mysql_system_tables_data.sql | 8 +- scripts/mysql_system_tables_fix.sql | 4 + sql/CMakeLists.txt | 4 + sql/handler.cc | 18 ++ sql/handler.h | 4 + sql/lex.h | 1 + sql/mysqld.cc | 23 ++ sql/set_var.h | 1 + sql/share/errmsg-utf8.txt | 5 +- sql/signal_handler.cc | 3 + sql/sql_acl.cc | 42 +++- sql/sql_class.cc | 31 +++- sql/sql_class.h | 11 + sql/sql_lex.cc | 3 + sql/sql_lex.h | 3 + sql/sql_parse.cc | 93 +++++++- sql/sql_timer.cc | 253 +++++++++++++++++++ sql/sql_timer.h | 50 ++++ sql/sql_yacc.yy | 42 +++- sql/structs.h | 4 +- sql/sys_vars.cc | 10 + storage/innobase/handler/ha_innodb.cc | 37 +++- unittest/mysys/CMakeLists.txt | 4 + unittest/mysys/my_timer-t.c | 264 ++++++++++++++++++++ 53 files changed, 2360 insertions(+), 25 deletions(-) create mode 100644 include/my_timer.h create mode 100644 mysql-test/include/have_statement_timeout.inc create mode 100644 mysql-test/r/have_statement_timeout.require create mode 100644 mysql-test/r/max_statement_time.result create mode 100644 mysql-test/suite/randgen/r/max_statement_time.result create mode 100644 mysql-test/suite/randgen/t/max_statement_time.test create mode 100644 mysql-test/suite/sys_vars/r/have_statement_timeout_basic.result create mode 100644 mysql-test/suite/sys_vars/r/max_statement_time_basic.result create mode 100644 mysql-test/suite/sys_vars/r/max_statement_time_func.result create mode 100644 mysql-test/suite/sys_vars/t/have_statement_timeout_basic.test create mode 100644 mysql-test/suite/sys_vars/t/max_statement_time_basic.test create mode 100644 mysql-test/suite/sys_vars/t/max_statement_time_func.test create mode 100644 mysql-test/t/max_statement_time.test create mode 100644 mysys/kqueue_timers.c create mode 100644 mysys/posix_timers.c create mode 100644 sql/sql_timer.cc create mode 100644 sql/sql_timer.h create mode 100644 unittest/mysys/my_timer-t.c diff --git a/config.h.cmake b/config.h.cmake index 67ed72c..289bbae 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -308,6 +308,10 @@ #cmakedefine STRUCT_DIRENT_HAS_D_NAMLEN 1 #cmakedefine SPRINTF_RETURNS_INT 1 +#cmakedefine HAVE_POSIX_TIMERS 1 +#cmakedefine HAVE_KQUEUE_TIMERS 1 +#cmakedefine HAVE_MY_TIMER 1 + #define USE_MB 1 #define USE_MB_IDENT 1 diff --git a/configure.cmake b/configure.cmake index e55b405..2735f46 100644 --- a/configure.cmake +++ b/configure.cmake @@ -147,6 +147,7 @@ IF(UNIX) IF(NOT LIBRT) MY_SEARCH_LIBS(clock_gettime rt LIBRT) ENDIF() + MY_SEARCH_LIBS(timer_create rt LIBRT) FIND_PACKAGE(Threads) SET(CMAKE_REQUIRED_LIBRARIES @@ -454,6 +455,9 @@ CHECK_FUNCTION_EXISTS (valloc HAVE_VALLOC) CHECK_FUNCTION_EXISTS (memalign HAVE_MEMALIGN) CHECK_FUNCTION_EXISTS (chown HAVE_CHOWN) CHECK_FUNCTION_EXISTS (nl_langinfo HAVE_NL_LANGINFO) +CHECK_FUNCTION_EXISTS (timer_create HAVE_TIMER_CREATE) +CHECK_FUNCTION_EXISTS (timer_settime HAVE_TIMER_SETTIME) +CHECK_FUNCTION_EXISTS (kqueue HAVE_KQUEUE) #-------------------------------------------------------------------- # Support for WL#2373 (Use cycle counter for timing) @@ -495,6 +499,8 @@ CHECK_SYMBOL_EXISTS(FIONREAD "sys/ioctl.h" FIONREAD_IN_SYS_IOCTL) CHECK_SYMBOL_EXISTS(TIOCSTAT "sys/ioctl.h" TIOCSTAT_IN_SYS_IOCTL) CHECK_SYMBOL_EXISTS(FIONREAD "sys/filio.h" FIONREAD_IN_SYS_FILIO) CHECK_SYMBOL_EXISTS(gettimeofday "sys/time.h" HAVE_GETTIMEOFDAY) +CHECK_SYMBOL_EXISTS(SIGEV_THREAD_ID "signal.h;time.h" HAVE_SIGEV_THREAD_ID) +CHECK_SYMBOL_EXISTS(EVFILT_TIMER "sys/types.h;sys/event.h;sys/time.h" HAVE_EVFILT_TIMER) CHECK_SYMBOL_EXISTS(finite "math.h" HAVE_FINITE_IN_MATH_H) IF(HAVE_FINITE_IN_MATH_H) @@ -514,7 +520,18 @@ int main() { return 0; }" HAVE_ISINF) +# Check for the Linux-specific POSIX timers API. +IF(HAVE_TIMER_CREATE AND HAVE_TIMER_SETTIME AND HAVE_SIGEV_THREAD_ID) + SET(HAVE_POSIX_TIMERS 1 CACHE INTERNAL "Have POSIX timer-related functions") +ENDIF() + +IF(HAVE_KQUEUE AND HAVE_EVFILT_TIMER) + SET(HAVE_KQUEUE_TIMERS 1 CACHE INTERNAL "Have kqueue timer-related filter") +ENDIF() +IF(HAVE_POSIX_TIMERS OR HAVE_KQUEUE_TIMERS) + SET(HAVE_MY_TIMER 1 CACHE INTERNAL "Have mysys timer-related functions") +ENDIF() # # Test for endianess diff --git a/include/my_global.h b/include/my_global.h index 11ff377..aa1b38e 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -377,6 +377,19 @@ C_MODE_END #include #endif +/** + Cast a member of a structure to the structure that contains it. + + @param ptr Pointer to the member. + @param type Type of the structure that contains the member. + @param member Name of the member within the structure. +*/ +#define my_container_of(ptr, type, member) \ + ({ \ + const typeof(((type *)0)->member) *__mptr= (ptr); \ + (type *)((char *)__mptr - offsetof(type, member)); \ + }) + /* A lot of our programs uses asserts, so better to always include it This also fixes a problem when people uses DBUG_ASSERT without including @@ -1418,9 +1431,7 @@ do { doubleget_union _tmp; \ #define NEED_EXPLICIT_SYNC_DIR 1 #endif -#if !defined(__cplusplus) && !defined(bool) -#define bool In_C_you_should_use_my_bool_instead() -#endif +#include /* Provide __func__ macro definition for platforms that miss it. */ #if __STDC_VERSION__ < 199901L diff --git a/include/my_timer.h b/include/my_timer.h new file mode 100644 index 0000000..96a52eb --- /dev/null +++ b/include/my_timer.h @@ -0,0 +1,69 @@ +/* Copyright (c) 2012, Twitter, Inc. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + +#ifndef MY_TIMER_H +#define MY_TIMER_H + +#include "my_global.h" /* C_MODE_START, C_MODE_END */ +#include "my_config.h" /* HAVE_*_TIMERS */ + +/* POSIX timers API. */ +#ifdef HAVE_POSIX_TIMERS +# include /* timer_t */ + typedef timer_t os_timer_t; +#elif HAVE_KQUEUE_TIMERS +# include /* uintptr_t */ + typedef uintptr_t os_timer_t; +#endif + +/* Whether timer API is implemented. */ +#ifdef HAVE_MY_TIMER + +C_MODE_START + +typedef struct st_my_timer my_timer_t; + +/** Non-copyable timer object. */ +struct st_my_timer +{ + /** Timer ID used to identify the timer in timer requests. */ + os_timer_t id; + + /** Timer expiration notification function. */ + void (*notify_function)(my_timer_t *); +}; + +/* Initialize internal components. */ +int my_timer_init_ext(void); + +/* Release any resources acquired. */ +void my_timer_deinit(void); + +/* Create a timer object. */ +int my_timer_create(my_timer_t *timer); + +/* Set the time (in milliseconds) until the next expiration of the timer. */ +int my_timer_set(my_timer_t *timer, unsigned long time); + +/* Reset the time until the next expiration of the timer. */ +int my_timer_reset(my_timer_t *timer, int *state); + +/* Delete a timer object. */ +void my_timer_delete(my_timer_t *timer); + +C_MODE_END + +#endif /* HAVE_MY_TIMER */ +#endif /* MY_TIMER_H */ diff --git a/include/mysql/plugin.h b/include/mysql/plugin.h index de040c9..b0895b4 100644 --- a/include/mysql/plugin.h +++ b/include/mysql/plugin.h @@ -584,6 +584,13 @@ int thd_killed(const MYSQL_THD thd); /** + Set the killed status of the current statement. + + @param thd user thread connection handle +*/ +void thd_set_kill_status(const MYSQL_THD thd); + +/** Return the thread id of a user thread @param thd user thread connection handle diff --git a/include/mysql/plugin_audit.h.pp b/include/mysql/plugin_audit.h.pp index d4b3afa..d3d6580 100644 --- a/include/mysql/plugin_audit.h.pp +++ b/include/mysql/plugin_audit.h.pp @@ -189,6 +189,7 @@ void thd_inc_row_count(void* thd); int mysql_tmpfile(const char *prefix); void* thd_get_current_thd(); int thd_killed(const void* thd); +void thd_set_kill_status(const void* thd); unsigned long thd_get_thread_id(const void* thd); void thd_get_xid(const void* thd, MYSQL_XID *xid); void mysql_query_cache_invalidate4(void* thd, diff --git a/include/mysql/plugin_auth.h.pp b/include/mysql/plugin_auth.h.pp index f66be5e..0b9d31e 100644 --- a/include/mysql/plugin_auth.h.pp +++ b/include/mysql/plugin_auth.h.pp @@ -189,6 +189,7 @@ void thd_inc_row_count(void* thd); int mysql_tmpfile(const char *prefix); void* thd_get_current_thd(); int thd_killed(const void* thd); +void thd_set_kill_status(const void* thd); unsigned long thd_get_thread_id(const void* thd); void thd_get_xid(const void* thd, MYSQL_XID *xid); void mysql_query_cache_invalidate4(void* thd, diff --git a/include/mysql/plugin_ftparser.h.pp b/include/mysql/plugin_ftparser.h.pp index d2e9451..97b6a51 100644 --- a/include/mysql/plugin_ftparser.h.pp +++ b/include/mysql/plugin_ftparser.h.pp @@ -142,6 +142,7 @@ void thd_inc_row_count(void* thd); int mysql_tmpfile(const char *prefix); void* thd_get_current_thd(); int thd_killed(const void* thd); +void thd_set_kill_status(const void* thd); unsigned long thd_get_thread_id(const void* thd); void thd_get_xid(const void* thd, MYSQL_XID *xid); void mysql_query_cache_invalidate4(void* thd, diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index 3019f23..3e35804 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -92,6 +92,9 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc ${MYSYS_LIBWRAP_SOURCE} ) +IF(HAVE_MY_TIMER) + SET(SQL_EMBEDDED_SOURCES ${SQL_EMBEDDED_SOURCES} ../sql/sql_timer.cc) +ENDIF() ADD_CONVENIENCE_LIBRARY(sql_embedded ${SQL_EMBEDDED_SOURCES}) DTRACE_INSTRUMENT(sql_embedded) diff --git a/mysql-test/include/have_statement_timeout.inc b/mysql-test/include/have_statement_timeout.inc new file mode 100644 index 0000000..5784672 --- /dev/null +++ b/mysql-test/include/have_statement_timeout.inc @@ -0,0 +1,4 @@ +-- require r/have_statement_timeout.require +disable_query_log; +show variables like 'have_statement_timeout'; +enable_query_log; diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index 7603e4b..4cdcd92 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -55,6 +55,7 @@ max_connections 0 max_user_connections 0 plugin authentication_string NULL +max_statement_time 0 show grants for mysqltest_1@localhost; Grants for mysqltest_1@localhost GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' REQUIRE CIPHER 'EDH-RSA-DES-CBC3-SHA' @@ -126,6 +127,7 @@ max_connections 0 max_user_connections 0 plugin authentication_string NULL +max_statement_time 0 show grants for mysqltest_1@localhost; Grants for mysqltest_1@localhost GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_QUERIES_PER_HOUR 10 @@ -173,6 +175,7 @@ max_connections 30 max_user_connections 0 plugin authentication_string NULL +max_statement_time 0 show grants for mysqltest_1@localhost; Grants for mysqltest_1@localhost GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_QUERIES_PER_HOUR 10 MAX_UPDATES_PER_HOUR 20 MAX_CONNECTIONS_PER_HOUR 30 diff --git a/mysql-test/r/have_statement_timeout.require b/mysql-test/r/have_statement_timeout.require new file mode 100644 index 0000000..deb2d76 --- /dev/null +++ b/mysql-test/r/have_statement_timeout.require @@ -0,0 +1,2 @@ +Variable_name Value +have_statement_timeout YES diff --git a/mysql-test/r/max_statement_time.result b/mysql-test/r/max_statement_time.result new file mode 100644 index 0000000..0e5126e --- /dev/null +++ b/mysql-test/r/max_statement_time.result @@ -0,0 +1,157 @@ + +# Test MAX_STATEMENT_TIME option syntax. + +CREATE TABLE t1 (a INT); +SET @var = (SELECT MAX_STATEMENT_TIME=0 1); +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 '1)' at line 1 +SELECT 1 FROM t1 WHERE a IN (SELECT MAX_STATEMENT_TIME=0 1); +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 '1)' at line 1 +SELECT (SELECT MAX_STATEMENT_TIME=0 a FROM t1); +ERROR 42S22: Unknown column 'MAX_STATEMENT_TIME' in 'field list' +SELECT a FROM t1 WHERE a IN (SELECT MAX_STATEMENT_TIME=0 a FROM t1); +ERROR 42S22: Unknown column 'MAX_STATEMENT_TIME' in 'field list' +SELECT * FROM t1 WHERE a IN (SELECT MAX_STATEMENT_TIME=0 a FROM t1); +ERROR 42S22: Unknown column 'MAX_STATEMENT_TIME' in 'field list' +SELECT MAX_STATEMENT_TIME=0 * FROM t1 +WHERE a IN (SELECT MAX_STATEMENT_TIME=0 a FROM t1); +ERROR 42S22: Unknown column 'MAX_STATEMENT_TIME' in 'field list' +SELECT * FROM t1 +WHERE a IN (SELECT a FROM t1 UNION SELECT MAX_STATEMENT_TIME=0 a FROM t1); +ERROR 42S22: Unknown column 'MAX_STATEMENT_TIME' in 'field list' +SELECT MAX_STATEMENT_TIME=0 * FROM t1 +WHERE a IN (SELECT a FROM t1 UNION SELECT MAX_STATEMENT_TIME=0 a FROM t1); +ERROR 42S22: Unknown column 'MAX_STATEMENT_TIME' in 'field list' +SELECT * FROM t1 UNION SELECT MAX_STATEMENT_TIME=0 * FROM t1; +ERROR 42000: Incorrect usage/placement of 'MAX_STATEMENT_TIME' +SELECT MAX_STATEMENT_TIME=0 * FROM t1 +UNION SELECT MAX_STATEMENT_TIME=0 * FROM t1; +ERROR 42000: Incorrect usage/placement of 'MAX_STATEMENT_TIME' +INSERT INTO t1 SELECT MAX_STATEMENT_TIME=0 * FROM t1; +ERROR 42000: Incorrect usage/placement of 'MAX_STATEMENT_TIME' +CREATE TABLE t1 AS SELECT MAX_STATEMENT_TIME=0 * FROM t1; +ERROR 42000: Incorrect usage/placement of 'MAX_STATEMENT_TIME' +CREATE TABLE t1 AS SELECT 1 A UNION SELECT 2 UNION SELECT MAX_STATEMENT_TIME=0 3; +ERROR 42000: Incorrect usage/placement of 'MAX_STATEMENT_TIME' +SELECT MAX_STATEMENT_TIME=0 * FROM t1; +a +DROP TABLE t1; + +# Test the MAX_STATEMENT_TIME option. + +SELECT MAX_STATEMENT_TIME=1 SLEEP(1); +SLEEP(1) +1 +CREATE TABLE t1 (a INT, b VARCHAR(300)); +INSERT INTO t1 VALUES (1, 'string'); +SELECT 996; +996 +996 +DROP TABLE t1; + +# Test the MAX_STATEMENT_TIME option with SF. + +CREATE TABLE t1 (a INT, b VARCHAR(300)); +INSERT INTO t1 VALUES (1, 'string'); +CREATE FUNCTION f1() RETURNS INT +BEGIN +WHILE true DO +INSERT INTO t1 SELECT * FROM t1; +END WHILE; +RETURN 1; +END| +SELECT MAX_STATEMENT_TIME=500 f1(); +ERROR 70100: Query execution was interrupted, max_statement_time exceeded +DROP FUNCTION f1; +DROP TABLE t1; + +# MAX_STATEMENT_TIME option takes precedence over @@max_statement_time. + +SET @@SESSION.max_statement_time = 100; +SELECT MAX_STATEMENT_TIME=2000 SLEEP(1); +SLEEP(1) +0 +SET @@SESSION.max_statement_time = DEFAULT; + +# MAX_STATEMENT_TIME account resource + +GRANT USAGE ON *.* TO user1@localhost WITH MAX_STATEMENT_TIME 5000; +# con1 +SELECT @@max_statement_time; +@@max_statement_time +5000 +# restart and reconnect +SELECT @@max_statement_time; +@@max_statement_time +5000 +DROP USER user1@localhost; + +# MAX_STATEMENT_TIME status variables. + +SELECT CONVERT(VARIABLE_VALUE, UNSIGNED) INTO @time_set +FROM INFORMATION_SCHEMA.GLOBAL_STATUS +WHERE VARIABLE_NAME = 'MAX_STATEMENT_TIME_SET'; +SELECT CONVERT(VARIABLE_VALUE, UNSIGNED) INTO @time_exceeded +FROM INFORMATION_SCHEMA.GLOBAL_STATUS +WHERE VARIABLE_NAME = 'MAX_STATEMENT_TIME_EXCEEDED'; +SELECT MAX_STATEMENT_TIME=10 SLEEP(1); +SLEEP(1) +1 +# Ensure that the counters for: +# - statements that are time limited; and +# - statements that exceeded their maximum execution time +# are incremented. +SELECT 1 AS STATUS FROM INFORMATION_SCHEMA.GLOBAL_STATUS +WHERE VARIABLE_NAME = 'MAX_STATEMENT_TIME_SET' + AND CONVERT(VARIABLE_VALUE, UNSIGNED) > @time_set; +STATUS +1 +SELECT 1 AS STATUS FROM INFORMATION_SCHEMA.GLOBAL_STATUS +WHERE VARIABLE_NAME = 'MAX_STATEMENT_TIME_EXCEEDED' + AND CONVERT(VARIABLE_VALUE, UNSIGNED) > @time_exceeded; +STATUS +1 + +# Check that the appropriate error status is set. + +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +START TRANSACTION; +SELECT * FROM t1 FOR UPDATE; +a +1 +SET @@SESSION.max_statement_time = 500; +UPDATE t1 SET a = 2; +ERROR 70100: Query execution was interrupted, max_statement_time exceeded +SHOW WARNINGS; +Level Code Message +Error 996 Query execution was interrupted, max_statement_time exceeded +Error 996 Query execution was interrupted, max_statement_time exceeded +ROLLBACK; +DROP TABLE t1; + +# Test interaction with lock waits. + +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +SET @@SESSION.max_statement_time = 500; +LOCK TABLES t1 WRITE; +LOCK TABLES t1 READ; +ERROR 70100: Query execution was interrupted, max_statement_time exceeded +UNLOCK TABLES; +BEGIN; +SELECT * FROM t1; +a +1 +ALTER TABLE t1 ADD COLUMN b INT; +ERROR 70100: Query execution was interrupted, max_statement_time exceeded +ROLLBACK; +SELECT GET_LOCK('lock', 1); +GET_LOCK('lock', 1) +1 +SELECT GET_LOCK('lock', 1); +GET_LOCK('lock', 1) +NULL +SELECT RELEASE_LOCK('lock'); +RELEASE_LOCK('lock') +1 +DROP TABLE t1; diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index afa105a..d411774 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -1194,13 +1194,13 @@ SET @aux= "SELECT COUNT(*) prepare my_stmt from @aux; execute my_stmt; COUNT(*) -42 +43 execute my_stmt; COUNT(*) -42 +43 execute my_stmt; COUNT(*) -42 +43 deallocate prepare my_stmt; drop procedure if exists p1| drop table if exists t1| diff --git a/mysql-test/r/system_mysql_db.result b/mysql-test/r/system_mysql_db.result index 0e0d555..eeb2d49 100644 --- a/mysql-test/r/system_mysql_db.result +++ b/mysql-test/r/system_mysql_db.result @@ -122,6 +122,7 @@ user CREATE TABLE `user` ( `max_user_connections` int(11) unsigned NOT NULL DEFAULT '0', `plugin` char(64) COLLATE utf8_bin DEFAULT '', `authentication_string` text COLLATE utf8_bin, + `max_statement_time` int(11) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`Host`,`User`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Users and global privileges' show create table func; diff --git a/mysql-test/suite/funcs_1/r/is_columns_mysql.result b/mysql-test/suite/funcs_1/r/is_columns_mysql.result index 95ffd62..9e52182 100644 --- a/mysql-test/suite/funcs_1/r/is_columns_mysql.result +++ b/mysql-test/suite/funcs_1/r/is_columns_mysql.result @@ -204,6 +204,7 @@ def mysql user Insert_priv 5 N NO enum 1 3 NULL NULL utf8 utf8_general_ci enum(' def mysql user Lock_tables_priv 21 N NO enum 1 3 NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references def mysql user max_connections 39 0 NO int NULL NULL 10 0 NULL NULL int(11) unsigned select,insert,update,references def mysql user max_questions 37 0 NO int NULL NULL 10 0 NULL NULL int(11) unsigned select,insert,update,references +def mysql user max_statement_time 43 0 NO int NULL NULL 10 0 NULL NULL int(11) unsigned select,insert,update,references def mysql user max_updates 38 0 NO int NULL NULL 10 0 NULL NULL int(11) unsigned select,insert,update,references def mysql user max_user_connections 40 0 NO int NULL NULL 10 0 NULL NULL int(11) unsigned select,insert,update,references def mysql user Password 3 NO char 41 41 NULL NULL latin1 latin1_bin char(41) select,insert,update,references @@ -518,3 +519,4 @@ NULL mysql user max_connections int NULL NULL NULL NULL int(11) unsigned NULL mysql user max_user_connections int NULL NULL NULL NULL int(11) unsigned 3.0000 mysql user plugin char 64 192 utf8 utf8_bin char(64) 1.0000 mysql user authentication_string text 65535 65535 utf8 utf8_bin text +NULL mysql user max_statement_time int NULL NULL NULL NULL int(11) unsigned diff --git a/mysql-test/suite/funcs_1/r/is_user_privileges.result b/mysql-test/suite/funcs_1/r/is_user_privileges.result index b269da5..f425b19 100644 --- a/mysql-test/suite/funcs_1/r/is_user_privileges.result +++ b/mysql-test/suite/funcs_1/r/is_user_privileges.result @@ -129,6 +129,7 @@ max_connections 0 max_user_connections 0 plugin authentication_string NULL +max_statement_time 0 Host localhost User testuser2 Password @@ -171,6 +172,7 @@ max_connections 0 max_user_connections 0 plugin authentication_string NULL +max_statement_time 0 Host localhost User testuser3 Password @@ -213,6 +215,7 @@ max_connections 0 max_user_connections 0 plugin authentication_string NULL +max_statement_time 0 # # Add GRANT OPTION db_datadict.* to testuser1; GRANT UPDATE ON db_datadict.* TO 'testuser1'@'localhost' WITH GRANT OPTION; @@ -279,6 +282,7 @@ max_connections 0 max_user_connections 0 plugin authentication_string NULL +max_statement_time 0 Host localhost User testuser2 Password @@ -321,6 +325,7 @@ max_connections 0 max_user_connections 0 plugin authentication_string NULL +max_statement_time 0 Host localhost User testuser3 Password @@ -363,6 +368,7 @@ max_connections 0 max_user_connections 0 plugin authentication_string NULL +max_statement_time 0 # Establish connection testuser1 (user=testuser1) SELECT * FROM information_schema.user_privileges WHERE grantee LIKE '''testuser%''' @@ -415,6 +421,7 @@ max_connections 0 max_user_connections 0 plugin authentication_string NULL +max_statement_time 0 Host localhost User testuser2 Password @@ -457,6 +464,7 @@ max_connections 0 max_user_connections 0 plugin authentication_string NULL +max_statement_time 0 Host localhost User testuser3 Password @@ -499,6 +507,7 @@ max_connections 0 max_user_connections 0 plugin authentication_string NULL +max_statement_time 0 SHOW GRANTS; Grants for testuser1@localhost GRANT USAGE ON *.* TO 'testuser1'@'localhost' @@ -573,6 +582,7 @@ max_connections 0 max_user_connections 0 plugin authentication_string NULL +max_statement_time 0 Host localhost User testuser2 Password @@ -615,6 +625,7 @@ max_connections 0 max_user_connections 0 plugin authentication_string NULL +max_statement_time 0 Host localhost User testuser3 Password @@ -657,6 +668,7 @@ max_connections 0 max_user_connections 0 plugin authentication_string NULL +max_statement_time 0 GRANT SELECT ON *.* TO 'testuser1'@'localhost' WITH GRANT OPTION; # # Here