diff options
author | Michael Widenius <monty@askmonty.org> | 2011-09-26 23:54:00 +0300 |
---|---|---|
committer | Michael Widenius <monty@askmonty.org> | 2011-09-26 23:54:00 +0300 |
commit | c85d1efc82ef9c946d77424ab58e4e760a392822 (patch) | |
tree | 44adbb2ba60761aee046df6fd57109fa79762711 | |
parent | 5c8305651d171fb627adc7907ebfb4db5ea1e57b (diff) | |
parent | 7800d93bc3caca0143334941f626dc6aa3ff2b26 (diff) | |
download | mariadb-git-c85d1efc82ef9c946d77424ab58e4e760a392822.tar.gz |
Automatic merge
60 files changed, 578 insertions, 220 deletions
diff --git a/include/mysql.h.pp b/include/mysql.h.pp index 659f30a2a67..780dbc9db3d 100644 --- a/include/mysql.h.pp +++ b/include/mysql.h.pp @@ -67,8 +67,8 @@ enum mysql_enum_shutdown_level { SHUTDOWN_WAIT_UPDATES= (unsigned char)(1 << 3), SHUTDOWN_WAIT_ALL_BUFFERS= ((unsigned char)(1 << 3) << 1), SHUTDOWN_WAIT_CRITICAL_BUFFERS= ((unsigned char)(1 << 3) << 1) + 1, - KILL_QUERY= 254, - KILL_CONNECTION= 255 + SHUTDOWN_KILL_QUERY= 254, + SHUTDOWN_KILL_CONNECTION= 255 }; enum enum_cursor_type { diff --git a/include/mysql_com.h b/include/mysql_com.h index 119676df5ce..81e0f4abaf6 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -385,12 +385,15 @@ enum mysql_enum_shutdown_level { /* don't flush InnoDB buffers, flush other storage engines' buffers*/ SHUTDOWN_WAIT_CRITICAL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1) + 1, /* Now the 2 levels of the KILL command */ -#if MYSQL_VERSION_ID >= 50000 - KILL_QUERY= 254, -#endif - KILL_CONNECTION= 255 + SHUTDOWN_KILL_QUERY= 254, + SHUTDOWN_KILL_CONNECTION= 255 }; +/* Compatibility */ +#if !defined(MYSQL_SERVER) && defined(USE_OLD_FUNCTIONS) +#define KILL_QUERY SHUTDOWN_KILL_QUERY +#define KILL_CONNECTION SHUTDOWN_KILL_CONNECTION +#endif enum enum_cursor_type { diff --git a/mysql-test/r/kill.result b/mysql-test/r/kill.result index 8b6830d4798..fa6b90ea891 100644 --- a/mysql-test/r/kill.result +++ b/mysql-test/r/kill.result @@ -125,6 +125,7 @@ release_lock("lock27563") drop table t1, t2; drop function bug27563; drop procedure proc27563; +set session optimizer_search_depth=0; PREPARE stmt FROM 'EXPLAIN SELECT * FROM t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23,t24,t25,t26,t27,t28,t29,t30,t31,t32,t33,t34,t35,t36,t37,t38,t39,t40 WHERE a1=a2 AND a2=a3 AND a3=a4 AND a4=a5 AND a5=a6 AND a6=a7 AND a7=a8 AND a8=a9 AND a9=a10 AND a10=a11 AND a11=a12 AND a12=a13 AND a13=a14 AND a14=a15 AND a15=a16 AND a16=a17 AND a17=a18 AND a18=a19 AND a19=a20 AND a20=a21 AND a21=a22 AND a22=a23 AND a23=a24 AND a24=a25 AND a25=a26 AND a26=a27 AND a27=a28 AND a28=a29 AND a29=a30 AND a30=a31 AND a31=a32 AND a32=a33 AND a33=a34 AND a34=a35 AND a35=a36 AND a36=a37 AND a37=a38 AND a38=a39 AND a39=a40 '; EXECUTE stmt; # @@ -138,4 +139,27 @@ KILL CONNECTION_ID(); # of close of the connection socket SELECT 1; Got one of the listed errors +# +# Test kill USER +# +grant ALL on test.* to test@localhost; +grant ALL on test.* to test2@localhost; +kill hard query user test2@nohost; +affected rows: 0 +kill soft query user test@localhost; +affected rows: 1 +kill hard query user test@localhost; +affected rows: 1 +kill soft connection user test2; +affected rows: 1 +kill hard connection user test@localhost; +affected rows: 1 +revoke all privileges on test.* from test@localhost; +revoke all privileges on test.* from test2@localhost; +drop user test@localhost; +drop user test2@localhost; +select 1; +Got one of the listed errors +select 1; +Got one of the listed errors set @@global.concurrent_insert= @old_concurrent_insert; diff --git a/mysql-test/r/subselect_mat_cost.result b/mysql-test/r/subselect_mat_cost.result index a642c498e53..e8312c837e6 100644 --- a/mysql-test/r/subselect_mat_cost.result +++ b/mysql-test/r/subselect_mat_cost.result @@ -1,5 +1,6 @@ set @subselect_mat_cost=@@optimizer_switch; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; +set log_slow_time=0.1; TEST GROUP 1: Typical cases of in-to-exists and materialization subquery strategies ===================================================================== diff --git a/mysql-test/r/system_mysql_db.result b/mysql-test/r/system_mysql_db.result index d3cbc134de9..5079d72aaea 100644 --- a/mysql-test/r/system_mysql_db.result +++ b/mysql-test/r/system_mysql_db.result @@ -117,7 +117,7 @@ user CREATE TABLE `user` ( `max_questions` int(11) unsigned NOT NULL DEFAULT '0', `max_updates` int(11) unsigned NOT NULL DEFAULT '0', `max_connections` int(11) unsigned NOT NULL DEFAULT '0', - `max_user_connections` int(11) unsigned NOT NULL DEFAULT '0', + `max_user_connections` int(11) NOT NULL DEFAULT '0', `plugin` char(60) CHARACTER SET latin1 NOT NULL DEFAULT '', `auth_string` text COLLATE utf8_bin NOT NULL, PRIMARY KEY (`Host`,`User`) diff --git a/mysql-test/r/user_limits-2.result b/mysql-test/r/user_limits-2.result new file mode 100644 index 00000000000..d9daec5c089 --- /dev/null +++ b/mysql-test/r/user_limits-2.result @@ -0,0 +1,2 @@ +set global max_user_connections=100; +ERROR HY000: The MySQL server is running with the --max-user-connections=0 option so it cannot execute this statement diff --git a/mysql-test/r/user_limits.result b/mysql-test/r/user_limits.result index a94eb4616d1..776a25d55e6 100644 --- a/mysql-test/r/user_limits.result +++ b/mysql-test/r/user_limits.result @@ -1,3 +1,4 @@ +set @my_max_user_connections= @@global.max_user_connections; drop table if exists t1; create table t1 (i int); delete from mysql.user where user like 'mysqltest\_%'; @@ -12,9 +13,9 @@ i select * from t1; i select * from t1; -ERROR 42000: User 'mysqltest_1' has exceeded the 'max_questions' resource (current value: 2) +ERROR 42000: User 'mysqltest_1' has exceeded the 'max_queries_per_hour' resource (current value: 2) select * from t1; -ERROR 42000: User 'mysqltest_1' has exceeded the 'max_questions' resource (current value: 2) +ERROR 42000: User 'mysqltest_1' has exceeded the 'max_queries_per_hour' resource (current value: 2) drop user mysqltest_1@localhost; grant usage on *.* to mysqltest_1@localhost with max_updates_per_hour 2; flush user_resources; @@ -27,11 +28,11 @@ i delete from t1; delete from t1; delete from t1; -ERROR 42000: User 'mysqltest_1' has exceeded the 'max_updates' resource (current value: 2) +ERROR 42000: User 'mysqltest_1' has exceeded the 'max_updates_per_hour' resource (current value: 2) select * from t1; i delete from t1; -ERROR 42000: User 'mysqltest_1' has exceeded the 'max_updates' resource (current value: 2) +ERROR 42000: User 'mysqltest_1' has exceeded the 'max_updates_per_hour' resource (current value: 2) select * from t1; i drop user mysqltest_1@localhost; @@ -65,10 +66,20 @@ select * from t1; i connect(localhost,mysqltest_1,,test,MYSQL_PORT,MYSQL_SOCK); ERROR 42000: User 'mysqltest_1' has exceeded the 'max_user_connections' resource (current value: 3) +grant usage on *.* to mysqltest_1@localhost with max_user_connections -1; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_USER_CONNECTIONS -1 +flush user_resources; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_USER_CONNECTIONS -1 +connect(localhost,mysqltest_1,,test,MYSQL_PORT,MYSQL_SOCK); +ERROR 42000: User 'mysqltest_1' has exceeded the 'max_user_connections' resource (current value: -1) drop user mysqltest_1@localhost; select @@session.max_user_connections, @@global.max_user_connections; @@session.max_user_connections @@global.max_user_connections -0 0 +1000 1000 set session max_user_connections= 2; ERROR HY000: Variable 'max_user_connections' is a GLOBAL variable and should be set with SET GLOBAL set global max_user_connections= 2; @@ -92,5 +103,21 @@ select @@session.max_user_connections, @@global.max_user_connections; connect(localhost,mysqltest_1,,test,MYSQL_PORT,MYSQL_SOCK); ERROR 42000: User 'mysqltest_1' has exceeded the 'max_user_connections' resource (current value: 3) set global max_user_connections= 0; +grant usage on *.* to mysqltest_1@localhost with max_user_connections 0; +set global max_user_connections=-1; +show variables like "max_user_user_connections"; +Variable_name Value +select @@max_user_connections; +@@max_user_connections +-1 +select @@global.max_user_connections; +@@global.max_user_connections +-1 +connect(localhost,mysqltest_1,,test,MYSQL_PORT,MYSQL_SOCK); +ERROR 42000: User mysqltest_1 already has more than 'max_user_connections' active connections +set global max_user_connections=1; +connect(localhost,mysqltest_1,,test,MYSQL_PORT,MYSQL_SOCK); +ERROR 42000: User mysqltest_1 already has more than 'max_user_connections' active connections drop user mysqltest_1@localhost; drop table t1; +set global max_user_connections= @my_max_user_connections; diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index f2eb58b5b4f..44eddb18667 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -14,6 +14,7 @@ set @my_max_delayed_threads =@@global.max_delayed_threads; set @my_max_heap_table_size =@@global.max_heap_table_size; set @my_max_insert_delayed_threads=@@global.max_insert_delayed_threads; set @my_max_join_size =@@global.max_join_size; +set @my_max_user_connections =@@global.max_user_connections; set @my_myisam_data_pointer_size =@@global.myisam_data_pointer_size; set @my_myisam_max_sort_file_size =@@global.myisam_max_sort_file_size; set @my_net_buffer_length =@@global.net_buffer_length; @@ -1049,7 +1050,7 @@ set global max_delayed_threads =@my_max_delayed_threads; set global max_heap_table_size =@my_max_heap_table_size; set global max_insert_delayed_threads=@my_max_insert_delayed_threads; set global max_join_size =@my_max_join_size; -set global max_user_connections =default; +set global max_user_connections =@my_max_user_connections; set global max_write_lock_count =default; set global myisam_data_pointer_size =@my_myisam_data_pointer_size; set global myisam_max_sort_file_size =@my_myisam_max_sort_file_size; diff --git a/mysql-test/suite/rpl/r/rpl_stm_000001.result b/mysql-test/suite/rpl/r/rpl_stm_000001.result index 3a67772d11a..afe4096b84c 100644 --- a/mysql-test/suite/rpl/r/rpl_stm_000001.result +++ b/mysql-test/suite/rpl/r/rpl_stm_000001.result @@ -48,7 +48,7 @@ select (@id := id) - id from t2; kill @id; drop table t2; Got one of the listed errors -include/wait_for_slave_sql_error_and_skip.inc [errno=1053] +include/wait_for_slave_sql_error_and_skip.inc [errno=1927] select count(*) from t1; count(*) 5000 diff --git a/mysql-test/suite/rpl/t/rpl_stm_000001.test b/mysql-test/suite/rpl/t/rpl_stm_000001.test index 9841ecb040a..4056b700b3b 100644 --- a/mysql-test/suite/rpl/t/rpl_stm_000001.test +++ b/mysql-test/suite/rpl/t/rpl_stm_000001.test @@ -96,14 +96,14 @@ drop table t2; connection master; # The get_lock function causes warning for unsafe statement. --disable_warnings ---error 1317,2013 +--error ER_QUERY_INTERRUPTED,ER_CONNECTION_KILLED reap; --enable_warnings connection slave; # The SQL slave thread should now have stopped because the query was killed on # the master (so it has a non-zero error code in the binlog). -# 1053 = ER_SERVER_SHUTDOWN ---let $slave_sql_errno= 1053 +# 1927 = ER_CONNECTION_KILLED +--let $slave_sql_errno= 1927 --source include/wait_for_slave_sql_error_and_skip.inc select count(*) from t1; diff --git a/mysql-test/t/flush_read_lock_kill.test b/mysql-test/t/flush_read_lock_kill.test index 2d359383949..ada73755067 100644 --- a/mysql-test/t/flush_read_lock_kill.test +++ b/mysql-test/t/flush_read_lock_kill.test @@ -57,7 +57,7 @@ connection con1; # debug build running without our --debug=make_global..., will be # error 0 (no error). The only important thing to test is that on # debug builds with our --debug=make_global... we don't hang forever. ---error 0,1317,2013 +--error 0,ER_CONNECTION_KILLED,2013 reap; connection con2; diff --git a/mysql-test/t/kill.test b/mysql-test/t/kill.test index b199a1224c3..f51b9723142 100644 --- a/mysql-test/t/kill.test +++ b/mysql-test/t/kill.test @@ -99,7 +99,7 @@ select ((@id := kill_id) - kill_id) from t3; kill @id; connection conn1; --- error 1317,2013 +-- error ER_QUERY_INTERRUPTED,ER_CONNECTION_KILLED,2013 reap; connection default; @@ -337,5 +337,35 @@ SELECT 1; ########################################################################### +--echo # +--echo # Test kill USER +--echo # + +grant ALL on test.* to test@localhost; +grant ALL on test.* to test2@localhost; +connect (con3, localhost, test,,); +connect (con4, localhost, test2,,); +connection default; +--enable_info +kill hard query user test2@nohost; +kill soft query user test@localhost; +kill hard query user test@localhost; +kill soft connection user test2; +kill hard connection user test@localhost; +--disable_info +revoke all privileges on test.* from test@localhost; +revoke all privileges on test.* from test2@localhost; +drop user test@localhost; +drop user test2@localhost; + +connection con3; +--error 2013,2006 +select 1; +connection con4; +--error 2013,2006 +select 1; +connection default; + + # Restore global concurrent_insert value. Keep in the end of the test file. set @@global.concurrent_insert= @old_concurrent_insert; diff --git a/mysql-test/t/subselect_mat_cost-master.opt b/mysql-test/t/subselect_mat_cost-master.opt new file mode 100644 index 00000000000..dc7ac6cc205 --- /dev/null +++ b/mysql-test/t/subselect_mat_cost-master.opt @@ -0,0 +1 @@ +--log-output=TABLE,FILE --log --log-slow-queries --slow-query-log=1 diff --git a/mysql-test/t/subselect_mat_cost.test b/mysql-test/t/subselect_mat_cost.test index 8a0d1ac702d..9d7d950114c 100644 --- a/mysql-test/t/subselect_mat_cost.test +++ b/mysql-test/t/subselect_mat_cost.test @@ -15,6 +15,11 @@ set @subselect_mat_cost=@@optimizer_switch; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; +# +# Test logging to slow log (there was some errors in the log files about +# the slow log when running under valgrind, so better to get this tested) +# +set log_slow_time=0.1; -- echo TEST GROUP 1: diff --git a/mysql-test/t/user_limits-2.test b/mysql-test/t/user_limits-2.test new file mode 100644 index 00000000000..a376c78a09b --- /dev/null +++ b/mysql-test/t/user_limits-2.test @@ -0,0 +1,11 @@ +# +# Test behavior of various per-account limits (aka quotas) +# +--source include/not_embedded.inc + +# +# We will get an error as it was set to 0 at startup +# +--error ER_OPTION_PREVENTS_STATEMENT +set global max_user_connections=100; + diff --git a/mysql-test/t/user_limits-master.opt b/mysql-test/t/user_limits-master.opt new file mode 100644 index 00000000000..107b2e4a27f --- /dev/null +++ b/mysql-test/t/user_limits-master.opt @@ -0,0 +1 @@ +--max-user-connections=1000 diff --git a/mysql-test/t/user_limits.test b/mysql-test/t/user_limits.test index 41af032b97e..becaa0963cc 100644 --- a/mysql-test/t/user_limits.test +++ b/mysql-test/t/user_limits.test @@ -8,6 +8,8 @@ # Save the initial number of concurrent sessions --source include/count_sessions.inc +set @my_max_user_connections= @@global.max_user_connections; + # Prepare play-ground --disable_warnings drop table if exists t1; @@ -120,8 +122,18 @@ select * from t1; --replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK --error ER_USER_LIMIT_REACHED connect (muc5, localhost, mysqltest_1,,); -# Clean up + connection default; +# Test with negative max_user_connections +grant usage on *.* to mysqltest_1@localhost with max_user_connections -1; +show grants for mysqltest_1@localhost; +flush user_resources; +show grants for mysqltest_1@localhost; +--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK +--error ER_USER_LIMIT_REACHED +connect (muc5, localhost, mysqltest_1,,); + +# Clean up disconnect muc2; disconnect muc3; disconnect muc4; @@ -165,12 +177,37 @@ disconnect muca1; disconnect muca2; disconnect muca3; set global max_user_connections= 0; -drop user mysqltest_1@localhost; --enable_ps_protocol +# +# Test setting negative values of max_user_connections +# +grant usage on *.* to mysqltest_1@localhost with max_user_connections 0; +set global max_user_connections=-1; +show variables like "max_user_user_connections"; +select @@max_user_connections; +select @@global.max_user_connections; +# Check that we can't connect anymore except as root +--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK +--error ER_TOO_MANY_USER_CONNECTIONS +connect (muca2, localhost, mysqltest_1,,); +connect (muca2, localhost, root,,); +disconnect muca2; +connection default; +set global max_user_connections=1; +# Check that we can connect one time, not two +connect (muca2, localhost, mysqltest_1,,); +--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK +--error ER_TOO_MANY_USER_CONNECTIONS +connect (muca3, localhost, mysqltest_1,,); +disconnect muca2; +connection default; +drop user mysqltest_1@localhost; + # Final cleanup drop table t1; # Wait till all disconnects are completed --source include/wait_until_count_sessions.inc +set global max_user_connections= @my_max_user_connections; diff --git a/mysql-test/t/variables-master.opt b/mysql-test/t/variables-master.opt new file mode 100644 index 00000000000..e4b213a0323 --- /dev/null +++ b/mysql-test/t/variables-master.opt @@ -0,0 +1 @@ +--max-user-connections=1 diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index 38bbd2c9de8..6a9d0372c0a 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -23,6 +23,7 @@ set @my_max_delayed_threads =@@global.max_delayed_threads; set @my_max_heap_table_size =@@global.max_heap_table_size; set @my_max_insert_delayed_threads=@@global.max_insert_delayed_threads; set @my_max_join_size =@@global.max_join_size; +set @my_max_user_connections =@@global.max_user_connections; set @my_myisam_data_pointer_size =@@global.myisam_data_pointer_size; set @my_myisam_max_sort_file_size =@@global.myisam_max_sort_file_size; set @my_net_buffer_length =@@global.net_buffer_length; @@ -830,7 +831,7 @@ set global max_delayed_threads =@my_max_delayed_threads; set global max_heap_table_size =@my_max_heap_table_size; set global max_insert_delayed_threads=@my_max_insert_delayed_threads; set global max_join_size =@my_max_join_size; -set global max_user_connections =default; +set global max_user_connections =@my_max_user_connections; set global max_write_lock_count =default; set global myisam_data_pointer_size =@my_myisam_data_pointer_size; set global myisam_max_sort_file_size =@my_myisam_max_sort_file_size; diff --git a/plugin/handler_socket/handlersocket/database.cpp b/plugin/handler_socket/handlersocket/database.cpp index f63f011d9b1..311eec55fa8 100644 --- a/plugin/handler_socket/handlersocket/database.cpp +++ b/plugin/handler_socket/handlersocket/database.cpp @@ -246,11 +246,11 @@ wait_server_to_start(THD *thd, volatile int& shutdown_flag) &abstime); pthread_mutex_unlock(&LOCK_server_started); pthread_mutex_lock(&thd->mysys_var->mutex); - THD::killed_state st = thd->killed; + killed_state st = thd->killed; pthread_mutex_unlock(&thd->mysys_var->mutex); DBG_SHUT(fprintf(stderr, "HNDSOCK wsts kst %d\n", (int)st)); pthread_mutex_lock(&LOCK_server_started); - if (st != THD::NOT_KILLED) { + if (st != NOT_KILLED) { DBG_SHUT(fprintf(stderr, "HNDSOCK wsts kst %d break\n", (int)st)); r = -1; break; @@ -357,11 +357,11 @@ bool dbcontext::check_alive() { pthread_mutex_lock(&thd->mysys_var->mutex); - THD::killed_state st = thd->killed; + killed_state st = thd->killed; pthread_mutex_unlock(&thd->mysys_var->mutex); DBG_SHUT(fprintf(stderr, "chk HNDSOCK kst %p %p %d %zu\n", thd, &thd->killed, (int)st, sizeof(*thd))); - if (st != THD::NOT_KILLED) { + if (st != NOT_KILLED) { DBG_SHUT(fprintf(stderr, "chk HNDSOCK kst %d break\n", (int)st)); return false; } diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 16180ce0f6a..e7504453fbc 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -117,7 +117,10 @@ mysqlbug: ${top_builddir}/config.status mysqlbug.sh mysql_fix_privilege_tables.sql: mysql_system_tables.sql \ mysql_system_tables_fix.sql @echo "Building $@"; - @cat mysql_system_tables.sql mysql_system_tables_fix.sql > $@ + @echo "-- This file is automaticly generated from" > $@ + @echo "-- mysql_system_tables.sql & mysql_system_tables_fix.sql" >> $@ + @echo "" >> $@ + @cat mysql_system_tables.sql mysql_system_tables_fix.sql >> $@ # # Build mysql_fix_privilege_tables_sql.c from diff --git a/scripts/mysql_system_tables.sql b/scripts/mysql_system_tables.sql index 468517d27cd..c21d9525bb2 100644 --- a/scripts/mysql_system_tables.sql +++ b/scripts/mysql_system_tables.sql @@ -13,7 +13,7 @@ set @had_db_table= @@warning_count != 0; CREATE TABLE IF NOT EXISTS host ( Host char(60) binary DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, Select_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Insert_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Update_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Delete_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Drop_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Grant_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, References_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Index_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_tmp_table_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Lock_tables_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Trigger_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, PRIMARY KEY Host (Host,Db) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Host privileges; Merged with database privileges'; -CREATE TABLE IF NOT EXISTS user ( Host char(60) binary DEFAULT '' NOT NULL, User char(16) binary DEFAULT '' NOT NULL, Password char(41) character set latin1 collate latin1_bin DEFAULT '' NOT NULL, Select_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Insert_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Update_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Delete_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Drop_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Reload_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Shutdown_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Process_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, File_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Grant_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, References_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Index_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_db_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Super_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_tmp_table_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Lock_tables_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Repl_slave_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Repl_client_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_user_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Event_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Trigger_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, ssl_type enum('','ANY','X509', 'SPECIFIED') COLLATE utf8_general_ci DEFAULT '' NOT NULL, ssl_cipher BLOB NOT NULL, x509_issuer BLOB NOT NULL, x509_subject BLOB NOT NULL, max_questions int(11) unsigned DEFAULT 0 NOT NULL, max_updates int(11) unsigned DEFAULT 0 NOT NULL, max_connections int(11) unsigned DEFAULT 0 NOT NULL, max_user_connections int(11) unsigned DEFAULT 0 NOT NULL, plugin char(60) CHARACTER SET latin1 DEFAULT '' NOT NULL, auth_string TEXT NOT NULL, PRIMARY KEY Host (Host,User) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Users and global privileges'; +CREATE TABLE IF NOT EXISTS user ( Host char(60) binary DEFAULT '' NOT NULL, User char(16) binary DEFAULT '' NOT NULL, Password char(41) character set latin1 collate latin1_bin DEFAULT '' NOT NULL, Select_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Insert_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Update_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Delete_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Drop_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Reload_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Shutdown_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Process_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, File_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Grant_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, References_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Index_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_db_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Super_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_tmp_table_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Lock_tables_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Repl_slave_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Repl_client_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_user_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Event_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Trigger_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, ssl_type enum('','ANY','X509', 'SPECIFIED') COLLATE utf8_general_ci DEFAULT '' NOT NULL, ssl_cipher BLOB NOT NULL, x509_issuer BLOB NOT NULL, x509_subject BLOB NOT NULL, max_questions int(11) unsigned DEFAULT 0 NOT NULL, max_updates int(11) unsigned DEFAULT 0 NOT NULL, max_connections int(11) unsigned DEFAULT 0 NOT NULL, max_user_connections int(11) DEFAULT 0 NOT NULL, plugin char(60) CHARACTER SET latin1 DEFAULT '' NOT NULL, auth_string TEXT NOT NULL, PRIMARY KEY Host (Host,User) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Users and global privileges'; -- Remember for later if user table already existed set @had_user_table= @@warning_count != 0; diff --git a/scripts/mysql_system_tables_fix.sql b/scripts/mysql_system_tables_fix.sql index 245bfe01c0a..7d791a5fc61 100644 --- a/scripts/mysql_system_tables_fix.sql +++ b/scripts/mysql_system_tables_fix.sql @@ -326,8 +326,11 @@ UPDATE host SET Create_routine_priv=Create_priv, Alter_routine_priv=Alter_priv, # # Add max_user_connections resource limit +# this is signed in MariaDB so that if one sets it's to -1 then the user +# can't connect anymore. # -ALTER TABLE user ADD max_user_connections int(11) unsigned DEFAULT '0' NOT NULL AFTER max_connections; +ALTER TABLE user ADD max_user_connections int(11) DEFAULT '0' NOT NULL AFTER max_connections; +ALTER TABLE user MODIFY max_user_connections int(11) DEFAULT '0' NOT NULL AFTER max_connections; # # user.Create_user_priv diff --git a/sql/debug_sync.cc b/sql/debug_sync.cc index 322db38adf2..5e5e5a72850 100644 --- a/sql/debug_sync.cc +++ b/sql/debug_sync.cc @@ -1078,7 +1078,7 @@ static bool debug_sync_set_action(THD *thd, st_debug_sync_action *action) point decremented it to 0. In this case the following happened: - an error message was reported with my_error() and - - the statement was killed with thd->killed= THD::KILL_QUERY. + - the statement was killed with thd->killed= KILL_QUERY. If a statement reports an error, it must not call send_ok(). The calling functions will not call send_ok(), if we return TRUE @@ -1852,7 +1852,7 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action) { if (!--action->hit_limit) { - thd->killed= THD::KILL_QUERY; + thd->killed= KILL_QUERY; my_error(ER_DEBUG_SYNC_HIT_LIMIT, MYF(0)); } DBUG_PRINT("debug_sync_exec", ("hit_limit: %lu at: '%s'", diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index ecddcb7ca46..240d2df8e65 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -642,7 +642,7 @@ Event_scheduler::stop() sql_print_information("Event Scheduler: Killing the scheduler thread, " "thread id %lu", scheduler_thd->thread_id); - scheduler_thd->awake(THD::KILL_CONNECTION); + scheduler_thd->awake(KILL_CONNECTION); pthread_mutex_unlock(&scheduler_thd->LOCK_thd_data); /* thd could be 0x0, when shutting down */ diff --git a/sql/filesort.cc b/sql/filesort.cc index b3bb15bd7f0..da275c1c14f 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -506,7 +506,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, my_off_t record; TABLE *sort_form; THD *thd= current_thd; - volatile THD::killed_state *killed= &thd->killed; + volatile killed_state *killed= &thd->killed; handler *file; MY_BITMAP *save_read_set, *save_write_set, *save_vcol_set; DBUG_ENTER("find_all_keys"); @@ -1239,9 +1239,9 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file, void *first_cmp_arg; element_count dupl_count= 0; uchar *src; - THD::killed_state not_killable; + killed_state not_killable; uchar *unique_buff= param->unique_buff; - volatile THD::killed_state *killed= ¤t_thd->killed; + volatile killed_state *killed= ¤t_thd->killed; DBUG_ENTER("merge_buffers"); status_var_increment(current_thd->status_var.filesort_merge_passes); @@ -1249,7 +1249,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file, if (param->not_killable) { killed= ¬_killable; - not_killable= THD::NOT_KILLED; + not_killable= NOT_KILLED; } error=0; diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index 77851119e34..5a3365b29d2 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -1855,7 +1855,7 @@ static void ndb_binlog_query(THD *thd, Cluster_schema *schema) else thd->server_id= schema->any_value; thd->db= schema->db; - int errcode = query_error_code(thd, thd->killed == THD::NOT_KILLED); + int errcode = query_error_code(thd, thd->killed == NOT_KILLED); thd->binlog_query(THD::STMT_QUERY_TYPE, schema->query, schema->query_length, FALSE, schema->name[0] == 0 || thd->db[0] == 0, diff --git a/sql/handler.cc b/sql/handler.cc index a9f5b6f20b6..66e22aa40dc 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1404,13 +1404,12 @@ int ha_rollback_trans(THD *thd, bool all) the error log; but we don't want users to wonder why they have this message in the error log, so we don't send it. - We don't have to test for thd->killed == THD::KILL_SYSTEM_THREAD as + We don't have to test for thd->killed == KILL_SYSTEM_THREAD as it doesn't matter if a warning is pushed to a system thread or not: No one will see it... */ if (is_real_trans && thd->transaction.all.modified_non_trans_table && - !thd->slave_thread && thd->killed != THD::KILL_CONNECTION && - thd->killed != THD::KILL_SERVER) + !thd->slave_thread && thd->killed < KILL_CONNECTION) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARNING_NOT_COMPLETE_ROLLBACK, ER(ER_WARNING_NOT_COMPLETE_ROLLBACK)); @@ -2564,7 +2563,7 @@ int handler::update_auto_increment() /* first test if the query was aborted due to strict mode constraints */ - if (thd->killed == THD::KILL_BAD_DATA) + if (killed_mask_hard(thd->killed) == KILL_BAD_DATA) DBUG_RETURN(HA_ERR_AUTOINC_ERANGE); /* diff --git a/sql/item_func.cc b/sql/item_func.cc index b907d1f432e..ce43f90be8d 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -5063,12 +5063,16 @@ void Item_func_get_system_var::fix_length_and_dec() switch (var->show_type()) { case SHOW_LONG: - case SHOW_INT: case SHOW_HA_ROWS: unsigned_flag= TRUE; max_length= MY_INT64_NUM_DECIMAL_DIGITS; decimals=0; break; + case SHOW_INT: + unsigned_flag= FALSE; + max_length= MY_INT64_NUM_DECIMAL_DIGITS; + decimals=0; + break; case SHOW_LONGLONG: unsigned_flag= TRUE; max_length= MY_INT64_NUM_DECIMAL_DIGITS; @@ -5209,7 +5213,7 @@ longlong Item_func_get_system_var::val_int() switch (var->show_type()) { - case SHOW_INT: get_sys_var_safe (uint); + case SHOW_INT: get_sys_var_safe (int); case SHOW_LONG: get_sys_var_safe (ulong); case SHOW_LONGLONG: get_sys_var_safe (ulonglong); case SHOW_HA_ROWS: get_sys_var_safe (ha_rows); diff --git a/sql/lex.h b/sql/lex.h index 6ab234f8d81..3041168e4fb 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -238,6 +238,7 @@ static SYMBOL symbols[] = { { "GRANTS", SYM(GRANTS)}, { "GROUP", SYM(GROUP_SYM)}, { "HANDLER", SYM(HANDLER_SYM)}, + { "HARD", SYM(HARD_SYM)}, { "HASH", SYM(HASH_SYM)}, { "HAVING", SYM(HAVING)}, { "HELP", SYM(HELP_SYM)}, @@ -496,6 +497,7 @@ static SYMBOL symbols[] = { { "SNAPSHOT", SYM(SNAPSHOT_SYM)}, { "SMALLINT", SYM(SMALLINT)}, { "SOCKET", SYM(SOCKET_SYM)}, + { "SOFT", SYM(SOFT_SYM)}, { "SOME", SYM(ANY_SYM)}, { "SONAME", SYM(SONAME_SYM)}, { "SOUNDS", SYM(SOUNDS_SYM)}, diff --git a/sql/log.cc b/sql/log.cc index e53c8d12770..332cdce803e 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1062,17 +1062,6 @@ bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length, query_length= command_name[thd->command].length; } - if (!query_length) - { - /* - Not a real query; Reset counts for slow query logging - (QQ: Wonder if this is really needed) - */ - thd->sent_row_count= thd->examined_row_count= 0; - thd->query_plan_flags= QPLAN_INIT; - thd->query_plan_fsort_passes= 0; - } - for (current_handler= slow_log_handler_list; *current_handler ;) error= (*current_handler++)->log_slow(thd, current_time, user_host_buff, user_host_len, @@ -1809,7 +1798,7 @@ static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv) log_query.append(thd->lex->ident.str, thd->lex->ident.length) || log_query.append("`")) DBUG_RETURN(1); - int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); + int errcode= query_error_code(thd, thd->killed == NOT_KILLED); Query_log_event qinfo(thd, log_query.ptr(), log_query.length(), TRUE, TRUE, errcode); DBUG_RETURN(mysql_bin_log.write(&qinfo)); @@ -1833,7 +1822,7 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) log_query.append(thd->lex->ident.str, thd->lex->ident.length) || log_query.append("`")) DBUG_RETURN(1); - int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); + int errcode= query_error_code(thd, thd->killed == NOT_KILLED); Query_log_event qinfo(thd, log_query.ptr(), log_query.length(), TRUE, TRUE, errcode); DBUG_RETURN(mysql_bin_log.write(&qinfo)); @@ -5166,7 +5155,7 @@ int query_error_code(THD *thd, bool not_killed) { int error; - if (not_killed || (thd->killed == THD::KILL_BAD_DATA)) + if (not_killed || (killed_mask_hard(thd->killed) == KILL_BAD_DATA)) { error= thd->is_error() ? thd->main_da.sql_errno() : 0; @@ -5176,7 +5165,7 @@ int query_error_code(THD *thd, bool not_killed) caller. */ if (error == ER_SERVER_SHUTDOWN || error == ER_QUERY_INTERRUPTED || - error == ER_NEW_ABORTING_CONNECTION) + error == ER_NEW_ABORTING_CONNECTION || error == ER_CONNECTION_KILLED) error= 0; } else diff --git a/sql/log_event.cc b/sql/log_event.cc index 3dad0c87e00..ae7a37f2b3d 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -437,6 +437,7 @@ inline bool unexpected_error_code(int unexpected_error) case ER_NET_READ_ERROR: case ER_NET_ERROR_ON_WRITE: case ER_QUERY_INTERRUPTED: + case ER_CONNECTION_KILLED: case ER_SERVER_SHUTDOWN: case ER_NEW_ABORTING_CONNECTION: return(TRUE); @@ -3686,7 +3687,7 @@ Default database: '%s'. Query: '%s'", { DBUG_PRINT("info",("error ignored")); clear_all_errors(thd, const_cast<Relay_log_info*>(rli)); - thd->killed= THD::NOT_KILLED; + thd->killed= NOT_KILLED; /* When an error is expected and matches the actual error the slave does not report any error and by consequence changes diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index b38253c866a..bccd5b189ff 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -118,8 +118,6 @@ char *sql_strmake_with_convert(const char *str, size_t arg_length, CHARSET_INFO *from_cs, size_t max_res_length, CHARSET_INFO *to_cs, size_t *result_length); -uint kill_one_thread(THD *thd, ulong id, bool only_kill_query); -void sql_kill(THD *thd, ulong id, bool only_kill_query); bool net_request_file(NET* net, const char* fname); char* query_table_status(THD *thd,const char *db,const char *table_name); @@ -1074,6 +1072,10 @@ struct Query_cache_query_flags #define query_cache_is_cacheable_query(L) 0 #endif /*HAVE_QUERY_CACHE*/ +uint kill_one_thread(THD *thd, ulong id, killed_state kill_signal); +void sql_kill(THD *thd, ulong id, killed_state kill_signal); +void sql_kill_user(THD *thd, LEX_USER *str, killed_state kill_signal); + /* Error injector Macros to enable easy testing of recovery after failures in various error cases. @@ -2149,7 +2151,8 @@ extern MYSQL_PLUGIN_IMPORT ulong max_connections; extern ulong max_connect_errors, connect_timeout; extern ulong extra_max_connections; extern ulong slave_net_timeout, slave_trans_retries; -extern uint max_user_connections; +extern int max_user_connections; +extern bool max_user_connections_checking; extern ulonglong denied_connections; extern ulong what_to_log,flush_time; extern ulong query_buff_size; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 7f87ada8011..be66aa957e9 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -669,7 +669,8 @@ ulong extra_max_connections; */ ulong max_long_data_size; -uint max_user_connections= 0; +int max_user_connections= 0; +bool max_user_connections_checking=0; ulonglong denied_connections; /** Limit of the total number of prepared statements in the server. @@ -1082,7 +1083,7 @@ static void close_connections(void) if (tmp->slave_thread) continue; - tmp->killed= THD::KILL_CONNECTION; + tmp->killed= KILL_SERVER_HARD; thread_scheduler.post_kill_notification(tmp); pthread_mutex_lock(&tmp->LOCK_thd_data); if (tmp->mysys_var) @@ -2033,7 +2034,7 @@ void close_connection(THD *thd, uint errcode, bool lock) errcode ? ER(errcode) : "")); if (lock) (void) pthread_mutex_lock(&LOCK_thread_count); - thd->killed= THD::KILL_CONNECTION; + thd->killed= KILL_CONNECTION; if (global_system_variables.log_warnings > 3) { @@ -2142,6 +2143,7 @@ static bool cache_thread() */ thd->mysys_var->abort= 0; thd->thr_create_utime= microsecond_interval_timer(); + thd->start_utime= thd->thr_create_utime; threads.append(thd); return(1); } @@ -2728,27 +2730,30 @@ the thread stack. Please read http://dev.mysql.com/doc/mysql/en/linux.html\n\n", { const char *kreason= "UNKNOWN"; switch (thd->killed) { - case THD::NOT_KILLED: + case NOT_KILLED: + case KILL_HARD_BIT: kreason= "NOT_KILLED"; break; - case THD::KILL_BAD_DATA: + case KILL_BAD_DATA: + case KILL_BAD_DATA_HARD: kreason= "KILL_BAD_DATA"; break; - case THD::KILL_CONNECTION: + case KILL_CONNECTION: + case KILL_CONNECTION_HARD: kreason= "KILL_CONNECTION"; break; - case THD::KILL_QUERY: + case KILL_QUERY: + case KILL_QUERY_HARD: kreason= "KILL_QUERY"; break; - case THD::KILL_SYSTEM_THREAD: + case KILL_SYSTEM_THREAD: + case KILL_SYSTEM_THREAD_HARD: kreason= "KILL_SYSTEM_THREAD"; break; - case THD::KILL_SERVER: + case KILL_SERVER: + case KILL_SERVER_HARD: kreason= "KILL_SERVER"; break; - case THD::KILLED_NO_VALUE: - kreason= "KILLED_NO_VALUE"; - break; } fprintf(stderr, "\nTrying to get some variables.\n" "Some pointers may be invalid and cause the dump to abort.\n"); @@ -5260,7 +5265,7 @@ void create_thread_to_handle_connection(THD *thd) thread_created++; threads.append(thd); DBUG_PRINT("info",(("creating thread %lu"), thd->thread_id)); - thd->prior_thr_create_utime= thd->start_utime= microsecond_interval_timer(); + thd->prior_thr_create_utime= microsecond_interval_timer(); if ((error=pthread_create(&thd->real_id,&connection_attrib, handle_one_connection, (void*) thd))) @@ -5270,7 +5275,7 @@ void create_thread_to_handle_connection(THD *thd) ("Can't create thread to handle request (error %d)", error)); thread_count--; - thd->killed= THD::KILL_CONNECTION; // Safety + thd->killed= KILL_CONNECTION; // Safety (void) pthread_mutex_unlock(&LOCK_thread_count); pthread_mutex_lock(&LOCK_connection_count); @@ -7429,9 +7434,9 @@ each time the SQL thread starts.", &max_system_variables.max_tmp_tables, 0, GET_ULONG, REQUIRED_ARG, 32, 1, (longlong) ULONG_MAX, 0, 1, 0}, {"max_user_connections", OPT_MAX_USER_CONNECTIONS, - "The maximum number of active connections for a single user (0 = no limit).", - &max_user_connections, &max_user_connections, 0, GET_UINT, - REQUIRED_ARG, 0, 0, UINT_MAX, 0, 1, 0}, + "The maximum number of active connections for a single user (0 = no limit. In addition global max_user_connections counting and checking is permanently disabled).", + &max_user_connections, &max_user_connections, 0, GET_INT, + REQUIRED_ARG, 0, 0, INT_MAX, 0, 1, 0}, {"max_write_lock_count", OPT_MAX_WRITE_LOCK_COUNT, "After this many write locks, allow some read locks to run in between.", &max_write_lock_count, &max_write_lock_count, 0, GET_ULONG, @@ -9638,6 +9643,8 @@ static int get_options(int *argc,char **argv) if (!max_long_data_size_used) max_long_data_size= global_system_variables.max_allowed_packet; + /* Rember if max_user_connections was 0 at startup */ + max_user_connections_checking= max_user_connections != 0; return 0; } diff --git a/sql/scheduler.cc b/sql/scheduler.cc index 6dd93640dc5..5b83bb4753e 100644 --- a/sql/scheduler.cc +++ b/sql/scheduler.cc @@ -376,9 +376,7 @@ void libevent_kill_thd_callback(int Fd, short, void*) { THD *thd= (THD*)list->data; list= list_rest(list); - if (thd->killed == THD::KILL_CONNECTION || - thd->killed == THD::KILL_SYSTEM_THREAD || - thd->killed == THD::KILL_SERVER) + if ((int) thd->killed >= (int) KILL_CONNECTION) { /* Delete from libevent and add to the processing queue. @@ -512,7 +510,7 @@ static void libevent_connection_close(THD *thd) DBUG_ENTER("libevent_connection_close"); DBUG_PRINT("enter", ("thd: %p", thd)); - thd->killed= THD::KILL_CONNECTION; // Avoid error messages + thd->killed= KILL_CONNECTION; // Avoid error messages if (thd->net.vio->sd >= 0) // not already closed { @@ -535,8 +533,7 @@ static bool libevent_should_close_connection(THD* thd) { return (thd->net.error || thd->net.vio == 0 || - thd->killed == THD::KILL_CONNECTION || - thd->killed == THD::KILL_SERVER); + (int) thd->killed >= (int) KILL_CONNECTION); } diff --git a/sql/set_var.cc b/sql/set_var.cc index a934d0dc4dc..289e82f20ee 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -3082,7 +3082,19 @@ void sys_var_thd_time_zone::set_default(THD *thd, enum_var_type type) bool sys_var_max_user_conn::check(THD *thd, set_var *var) { if (var->type == OPT_GLOBAL) + { + if (! max_user_connections_checking) + { + /* + We can't change the value of max_user_connections from 0 as then + connect counting would be wrong. + */ + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), + "--max-user-connections=0"); + return TRUE; + } return sys_var_thd::check(thd, var); + } else { /* @@ -3098,7 +3110,7 @@ bool sys_var_max_user_conn::update(THD *thd, set_var *var) { DBUG_ASSERT(var->type == OPT_GLOBAL); pthread_mutex_lock(&LOCK_global_system_variables); - max_user_connections= (uint)var->save_result.ulonglong_value; + max_user_connections= (int) var->save_result.ulonglong_value; pthread_mutex_unlock(&LOCK_global_system_variables); return 0; } diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 928a28aba24..5f6931ab155 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6290,3 +6290,5 @@ ER_QUERY_CACHE_IS_GLOBALY_DISABLED eng "Query cache is globally disabled and you can't enable it only for this session" ER_VIEW_ORDERBY_IGNORED eng "View '%-.192s'.'%-.192s' ORDER BY clause ignored because there is other ORDER BY clause already." +ER_CONNECTION_KILLED 70100 + eng "Connection was killed" diff --git a/sql/slave.cc b/sql/slave.cc index aa8b4ba920b..cb93cf93081 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -524,7 +524,7 @@ terminate_slave_thread(THD *thd, IF_DBUG(int err= ) pthread_kill(thd->real_id, thr_client_alarm); DBUG_ASSERT(err != EINVAL); #endif - thd->awake(THD::NOT_KILLED); + thd->awake(KILL_CONNECTION); pthread_mutex_unlock(&thd->LOCK_thd_data); /* diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 6532e6c56f2..fda922f91ae 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1312,7 +1312,7 @@ sp_head::execute(THD *thd) ctx->enter_handler(hip); thd->clear_error(); thd->is_fatal_error= 0; - thd->killed= THD::NOT_KILLED; + thd->killed= NOT_KILLED; thd->mysys_var->abort= 0; continue; } @@ -1362,10 +1362,7 @@ sp_head::execute(THD *thd) If the DB has changed, the pointer has changed too, but the original thd->db will then have been freed */ - if (cur_db_changed && - thd->killed != THD::KILL_CONNECTION && - thd->killed != THD::KILL_SERVER && - thd->killed != THD::KILL_SYSTEM_THREAD) + if (cur_db_changed && thd->killed < KILL_CONNECTION) { /* Force switching back to the saved current database, because it may be @@ -1799,7 +1796,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, thd->options= binlog_save_options; if (thd->binlog_evt_union.unioned_events) { - int errcode = query_error_code(thd, thd->killed == THD::NOT_KILLED); + int errcode = query_error_code(thd, thd->killed == NOT_KILLED); Query_log_event qinfo(thd, binlog_buf.ptr(), binlog_buf.length(), thd->binlog_evt_union.unioned_events_trans, FALSE, errcode); if (mysql_bin_log.write(&qinfo) && diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 61a6ac0cb87..ae286878cea 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2089,7 +2089,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, table->field[next_field+2]->store((longlong) mqh.conn_per_hour, TRUE); if (table->s->fields >= 36 && (mqh.specified_limits & USER_RESOURCES::USER_CONNECTIONS)) - table->field[next_field+3]->store((longlong) mqh.user_conn, TRUE); + table->field[next_field+3]->store((longlong) mqh.user_conn, FALSE); mqh_used= mqh_used || mqh.questions || mqh.updates || mqh.conn_per_hour; next_field+=4; @@ -4578,7 +4578,8 @@ ulong get_column_grant(THD *thd, GRANT_INFO *grant, /* Help function for mysql_show_grants */ -static void add_user_option(String *grant, ulong value, const char *name) +static void add_user_option(String *grant, long value, const char *name, + my_bool is_signed) { if (value) { @@ -4586,7 +4587,7 @@ static void add_user_option(String *grant, ulong value, const char *name) grant->append(' '); grant->append(name, strlen(name)); grant->append(' '); - p=int10_to_str(value, buff, 10); + p=int10_to_str(value, buff, is_signed ? -10 : 10); grant->append(buff,p-buff); } } @@ -4768,13 +4769,13 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) if (want_access & GRANT_ACL) global.append(STRING_WITH_LEN(" GRANT OPTION")); add_user_option(&global, acl_user->user_resource.questions, - "MAX_QUERIES_PER_HOUR"); + "MAX_QUERIES_PER_HOUR", 0); add_user_option(&global, acl_user->user_resource.updates, - "MAX_UPDATES_PER_HOUR"); + "MAX_UPDATES_PER_HOUR", 0); add_user_option(&global, acl_user->user_resource.conn_per_hour, - "MAX_CONNECTIONS_PER_HOUR"); + "MAX_CONNECTIONS_PER_HOUR", 0); add_user_option(&global, acl_user->user_resource.user_conn, - "MAX_USER_CONNECTIONS"); + "MAX_USER_CONNECTIONS", 1); } protocol->prepare_for_resend(); protocol->store(global.ptr(),global.length(),global.charset()); @@ -8147,10 +8148,16 @@ bool acl_authenticate(THD *thd, uint connect_errors, DBUG_RETURN(1); } - /* Don't allow the user to connect if he has done too many queries */ - if ((acl_user->user_resource.questions || acl_user->user_resource.updates || + /* + Don't allow the user to connect if he has done too many queries. + As we are testing max_user_connections == 0 here, it means that we + can't let the user change max_user_connections from 0 in the server + without a restart as it would lead to wrong connect counting. + */ + if ((acl_user->user_resource.questions || + acl_user->user_resource.updates || acl_user->user_resource.conn_per_hour || - acl_user->user_resource.user_conn || max_user_connections) && + acl_user->user_resource.user_conn || max_user_connections_checking) && get_or_create_user_conn(thd, (opt_old_style_user_limits ? sctx->user : sctx->priv_user), (opt_old_style_user_limits ? sctx->host_or_ip : sctx->priv_host), @@ -8163,7 +8170,7 @@ bool acl_authenticate(THD *thd, uint connect_errors, if (thd->user_connect && (thd->user_connect->user_resources.conn_per_hour || thd->user_connect->user_resources.user_conn || - max_user_connections) && + max_user_connections_checking) && check_for_max_user_connections(thd, thd->user_connect)) { /* Ensure we don't decrement thd->user_connections->connections twice */ diff --git a/sql/sql_base.cc b/sql/sql_base.cc index e2142bc2734..cacec989518 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8910,7 +8910,7 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name, { if (!in_use->killed) { - in_use->killed= THD::KILL_SYSTEM_THREAD; + in_use->killed= KILL_SYSTEM_THREAD; pthread_mutex_lock(&in_use->mysys_var->mutex); if (in_use->mysys_var->current_cond) { @@ -9244,7 +9244,7 @@ void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) && ! in_use->killed) { - in_use->killed= THD::KILL_SYSTEM_THREAD; + in_use->killed= KILL_SYSTEM_THREAD; pthread_mutex_lock(&in_use->mysys_var->mutex); if (in_use->mysys_var->current_cond) { diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 5378390ebb4..8631a13eae7 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -391,7 +391,7 @@ static void debug_wait_for_kill(const char *info) sql_print_information("%s", info); while(!thd->killed) my_sleep(1000); - thd->killed= THD::NOT_KILLED; + thd->killed= NOT_KILLED; /* Remove the set debug variable, to ensure we don't get stuck on it again This is needed as for MyISAM, invalidate_table() may be called twice @@ -4439,7 +4439,7 @@ void Query_cache::wreck(uint line, const char *message) DBUG_PRINT("warning", ("%5d QUERY CACHE WRECK => DISABLED",line)); DBUG_PRINT("warning", ("==================================")); if (thd) - thd->killed= THD::KILL_CONNECTION; + thd->killed= KILL_CONNECTION; cache_dump(); /* check_integrity(0); */ /* Can't call it here because of locks */ bins_dump(); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 16165cdedbb..39edcdca3de 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1266,7 +1266,7 @@ void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var, #endif -void THD::awake(THD::killed_state state_to_set) +void THD::awake(killed_state state_to_set) { DBUG_ENTER("THD::awake"); DBUG_PRINT("enter", ("this: 0x%lx", (long) this)); @@ -1283,7 +1283,7 @@ void THD::awake(THD::killed_state state_to_set) "KILLED"); } killed= state_to_set; - if (state_to_set != THD::KILL_QUERY) + if (state_to_set >= KILL_CONNECTION) { thr_alarm_kill(thread_id); if (!slave_thread) @@ -1363,6 +1363,38 @@ void THD::awake(THD::killed_state state_to_set) DBUG_VOID_RETURN; } + +/* + Get error number for killed state + Note that the error message can't have any parameters. + See thd::kill_message() +*/ + +int killed_errno(killed_state killed) +{ + switch (killed) { + case NOT_KILLED: + case KILL_HARD_BIT: + return 0; // Probably wrong usage + case KILL_BAD_DATA: + case KILL_BAD_DATA_HARD: + return 0; // Not a real error + case KILL_CONNECTION: + case KILL_CONNECTION_HARD: + case KILL_SYSTEM_THREAD: + case KILL_SYSTEM_THREAD_HARD: + return ER_CONNECTION_KILLED; + case KILL_QUERY: + case KILL_QUERY_HARD: + return ER_QUERY_INTERRUPTED; + case KILL_SERVER: + case KILL_SERVER_HARD: + return ER_SERVER_SHUTDOWN; + } + return 0; // Keep compiler happy +} + + /* Remember the location of thread info, the structure needed for sql_alloc() and the structure for the net buffer @@ -3397,12 +3429,13 @@ void THD::restore_backup_open_tables_state(Open_tables_state *backup) @param thd user thread @retval 0 the user thread is active @retval 1 the user thread has been killed + + This is used to signal a storage engine if it should be killed. */ extern "C" int thd_killed(const MYSQL_THD thd) { - if (thd->killed == THD::NOT_KILLED || thd->killed == THD::KILL_BAD_DATA || - thd->killed == THD::KILL_SYSTEM_THREAD) + if (!(thd->killed & KILL_HARD_BIT)) return 0; return thd->killed; } diff --git a/sql/sql_class.h b/sql/sql_class.h index e77d9c0cee2..0085e982abb 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -362,6 +362,38 @@ public: LEX_COLUMN (const String& x,const uint& y ): column (x),rights (y) {} }; + +/* Note: these states are actually bit coded with HARD */ +enum killed_state +{ + NOT_KILLED= 0, + KILL_HARD_BIT= 1, /* Bit for HARD KILL */ + KILL_BAD_DATA= 2, + KILL_BAD_DATA_HARD= 3, + KILL_QUERY= 4, + KILL_QUERY_HARD= 5, + /* + All of the following killed states will kill the connection + KILL_CONNECTION must be the first of these! + */ + KILL_CONNECTION= 6, + KILL_CONNECTION_HARD= 7, + KILL_SYSTEM_THREAD= 8, + KILL_SYSTEM_THREAD_HARD= 9, + KILL_SERVER= 10, + KILL_SERVER_HARD= 11 +}; + +extern int killed_errno(killed_state killed); +#define killed_mask_hard(killed) ((killed_state) ((killed) & ~KILL_HARD_BIT)) + +enum killed_type +{ + KILL_TYPE_ID, + KILL_TYPE_USER +}; + + #include "sql_lex.h" /* Must be here */ class Delayed_insert; @@ -1973,16 +2005,6 @@ public: DYNAMIC_ARRAY user_var_events; /* For user variables replication */ MEM_ROOT *user_var_events_alloc; /* Allocate above array elements here */ - enum killed_state - { - NOT_KILLED=0, - KILL_BAD_DATA=1, - KILL_CONNECTION=ER_SERVER_SHUTDOWN, - KILL_SYSTEM_THREAD=ER_NEW_ABORTING_CONNECTION, /* Kill connection nicely */ - KILL_QUERY=ER_QUERY_INTERRUPTED, - KILL_SERVER, /* Placeholder for shortdown */ - KILLED_NO_VALUE /* means neither of the states */ - }; killed_state volatile killed; /* scramble - random string sent to client on handshake */ @@ -2165,7 +2187,7 @@ public: } void close_active_vio(); #endif - void awake(THD::killed_state state_to_set); + void awake(killed_state state_to_set); #ifndef MYSQL_CLIENT enum enum_binlog_query_type { @@ -2399,18 +2421,13 @@ public: void end_statement(); inline int killed_errno() const { - killed_state killed_val; /* to cache the volatile 'killed' */ - return (killed_val= killed) != KILL_BAD_DATA ? killed_val : 0; + return ::killed_errno(killed); } inline void send_kill_message() const { int err= killed_errno(); if (err) - { - if ((err == KILL_CONNECTION) && !shutdown_in_progress) - err = KILL_QUERY; my_message(err, ER(err), MYF(0)); - } } /* return TRUE if we will abort query if we make a warning now */ inline bool really_abort_on_warning() diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 5b7d392d773..cd51fd25558 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -113,8 +113,11 @@ int check_for_max_user_connections(THD *thd, USER_CONN *uc) DBUG_ENTER("check_for_max_user_connections"); (void) pthread_mutex_lock(&LOCK_user_conn); + + /* Root is not affected by the value of max_user_connections */ if (max_user_connections && !uc->user_resources.user_conn && - max_user_connections < (uint) uc->connections) + max_user_connections < uc->connections && + !(thd->security_ctx->master_access & SUPER_ACL)) { my_error(ER_TOO_MANY_USER_CONNECTIONS, MYF(0), uc->user); goto end; @@ -202,7 +205,7 @@ void time_out_user_resource_limits(THD *thd, USER_CONN *uc) /* If more than a hour since last check, reset resource checking */ if (check_time - uc->reset_utime >= LL(3600000000)) { - uc->questions=1; + uc->questions=0; uc->updates=0; uc->conn_per_hour=0; uc->reset_utime= check_time; @@ -231,7 +234,7 @@ bool check_mqh(THD *thd, uint check_command) if (uc->user_resources.questions && uc->questions++ >= uc->user_resources.questions) { - my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_questions", + my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_queries_per_hour", (long) uc->user_resources.questions); error=1; goto end; @@ -243,7 +246,7 @@ bool check_mqh(THD *thd, uint check_command) (sql_command_flags[check_command] & CF_CHANGES_DATA) && uc->updates++ >= uc->user_resources.updates) { - my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_updates", + my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_updates_per_hour", (long) uc->user_resources.updates); error=1; goto end; @@ -1095,7 +1098,7 @@ void prepare_new_connection_state(THD* thd) execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect); if (thd->is_error()) { - thd->killed= THD::KILL_CONNECTION; + thd->killed= KILL_CONNECTION; sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION), thd->thread_id,(thd->db ? thd->db : "unconnected"), sctx->user ? sctx->user : "unauthenticated", @@ -1131,6 +1134,8 @@ pthread_handler_t handle_one_connection(void *arg) THD *thd= (THD*) arg; thd->thr_create_utime= microsecond_interval_timer(); + /* We need to set this because of time_out_user_resource_limits */ + thd->start_utime= thd->thr_create_utime; if (thread_scheduler.init_new_connection_thread()) { @@ -1181,8 +1186,7 @@ pthread_handler_t handle_one_connection(void *arg) prepare_new_connection_state(thd); while (!net->error && net->vio != 0 && - thd->killed != THD::KILL_CONNECTION && - thd->killed != THD::KILL_SERVER) + thd->killed < KILL_CONNECTION) { if (do_command(thd)) break; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index becc1ada7ae..98d034a4d5c 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -49,7 +49,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, bool triggers_applicable; uint usable_index= MAX_KEY; SELECT_LEX *select_lex= &thd->lex->select_lex; - THD::killed_state killed_status= THD::NOT_KILLED; + killed_state killed_status= NOT_KILLED; DBUG_ENTER("mysql_delete"); bool save_binlog_row_based; @@ -383,7 +383,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, table->file->unlock_row(); // Row failed selection, release lock on it } killed_status= thd->killed; - if (killed_status != THD::NOT_KILLED || thd->is_error()) + if (killed_status != NOT_KILLED || thd->is_error()) error= 1; // Aborted if (will_batch && (loc_error= table->file->end_bulk_delete())) { @@ -450,7 +450,7 @@ cleanup: if (error < 0) thd->clear_error(); else - errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); + errcode= query_error_code(thd, killed_status == NOT_KILLED); /* [binlog]: If 'handler::delete_all_rows()' was called and the @@ -916,7 +916,7 @@ void multi_delete::abort() */ if (mysql_bin_log.is_open()) { - int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); + int errcode= query_error_code(thd, thd->killed == NOT_KILLED); /* possible error of writing binary log is ignored deliberately */ (void) thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(), thd->query_length(), @@ -1066,7 +1066,7 @@ int multi_delete::do_table_deletes(TABLE *table, bool ignore) bool multi_delete::send_eof() { - THD::killed_state killed_status= THD::NOT_KILLED; + killed_state killed_status= NOT_KILLED; thd_proc_info(thd, "deleting from reference tables"); /* Does deletes for the last n - 1 tables, returns 0 if ok */ @@ -1074,7 +1074,7 @@ bool multi_delete::send_eof() /* compute a total error to know if something failed */ local_error= local_error || error; - killed_status= (local_error == 0)? THD::NOT_KILLED : thd->killed; + killed_status= (local_error == 0)? NOT_KILLED : thd->killed; /* reset used flags */ thd_proc_info(thd, "end"); @@ -1094,7 +1094,7 @@ bool multi_delete::send_eof() if (local_error == 0) thd->clear_error(); else - errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); + errcode= query_error_code(thd, killed_status == NOT_KILLED); if (thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(), thd->query_length(), transactional_tables, FALSE, errcode) && diff --git a/sql/sql_error.cc b/sql/sql_error.cc index 835e60cd6ba..1db4a110d01 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -131,7 +131,7 @@ MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, thd->no_warnings_for_error= 1; thd->spcont= NULL; - thd->killed= THD::KILL_BAD_DATA; + thd->killed= KILL_BAD_DATA; my_message(code, msg, MYF(0)); thd->spcont= spcont; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 5cb4c094a33..cf199c27518 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -943,7 +943,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, thd->clear_error(); } else - errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); + errcode= query_error_code(thd, thd->killed == NOT_KILLED); /* bug#22725: @@ -957,7 +957,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, routines did not result in any error due to the KILLED. In such case the flag is ignored for constructing binlog event. */ - DBUG_ASSERT(thd->killed != THD::KILL_BAD_DATA || error > 0); + DBUG_ASSERT(thd->killed != KILL_BAD_DATA || error > 0); if (thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(), thd->query_length(), transactional_table, FALSE, @@ -2362,7 +2362,7 @@ void kill_delayed_threads(void) Delayed_insert *di; while ((di= it++)) { - di->thd.killed= THD::KILL_SYSTEM_THREAD; + di->thd.killed= KILL_SYSTEM_THREAD; pthread_mutex_lock(&di->thd.LOCK_thd_data); if (di->thd.mysys_var) { @@ -2447,8 +2447,7 @@ static void handle_delayed_insert_impl(THD *thd, Delayed_insert *di) for (;;) { - if (thd->killed == THD::KILL_CONNECTION || - thd->killed == THD::KILL_SYSTEM_THREAD || thd->killed == THD::KILL_SERVER) + if (thd->killed >= KILL_CONNECTION) { uint lock_count; /* @@ -2496,7 +2495,7 @@ static void handle_delayed_insert_impl(THD *thd, Delayed_insert *di) break; if (error == ETIMEDOUT || error == ETIME) { - thd->killed= THD::KILL_SYSTEM_THREAD; + thd->killed= KILL_SYSTEM_THREAD; break; } } @@ -2529,7 +2528,7 @@ static void handle_delayed_insert_impl(THD *thd, Delayed_insert *di) { /* Fatal error */ di->dead= 1; - thd->killed= THD::KILL_SYSTEM_THREAD; + thd->killed= KILL_SYSTEM_THREAD; } pthread_cond_broadcast(&di->cond_client); } @@ -2539,7 +2538,7 @@ static void handle_delayed_insert_impl(THD *thd, Delayed_insert *di) { /* Some fatal error */ di->dead= 1; - thd->killed= THD::KILL_SYSTEM_THREAD; + thd->killed= KILL_SYSTEM_THREAD; } } di->status=0; @@ -2599,7 +2598,7 @@ pthread_handler_t handle_delayed_insert(void *arg) thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; thd->set_current_time(); threads.append(thd); - thd->killed=abort_loop ? THD::KILL_SYSTEM_THREAD : THD::NOT_KILLED; + thd->killed=abort_loop ? KILL_SYSTEM_THREAD : NOT_KILLED; pthread_mutex_unlock(&LOCK_thread_count); /* @@ -2633,7 +2632,7 @@ end: di->table=0; di->dead= 1; // If error - thd->killed= THD::KILL_SYSTEM_THREAD; // If error + thd->killed= KILL_SYSTEM_THREAD; // If error pthread_mutex_unlock(&di->mutex); close_thread_tables(thd); // Free the table @@ -2712,7 +2711,7 @@ bool Delayed_insert::handle_inserts(void) max_rows= delayed_insert_limit; if (thd.killed || table->needs_reopen_or_name_lock()) { - thd.killed= THD::KILL_SYSTEM_THREAD; + thd.killed= KILL_SYSTEM_THREAD; max_rows= ULONG_MAX; // Do as much as possible } @@ -2825,7 +2824,7 @@ bool Delayed_insert::handle_inserts(void) /* if the delayed insert was killed, the killed status is ignored while binlogging */ int errcode= 0; - if (thd.killed == THD::NOT_KILLED) + if (thd.killed == NOT_KILLED) errcode= query_error_code(&thd, TRUE); /* @@ -3354,7 +3353,7 @@ bool select_insert::send_eof() bool const trans_table= table->file->has_transactions(); ulonglong id; bool changed; - THD::killed_state killed_status= thd->killed; + killed_state killed_status= thd->killed; DBUG_ENTER("select_insert::send_eof"); DBUG_PRINT("enter", ("trans_table=%d, table_type='%s'", trans_table, table->file->table_type())); @@ -3389,7 +3388,7 @@ bool select_insert::send_eof() if (!error) thd->clear_error(); else - errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); + errcode= query_error_code(thd, killed_status == NOT_KILLED); if (write_to_binlog(trans_table, errcode)) { @@ -3463,7 +3462,7 @@ void select_insert::abort() { { if (mysql_bin_log.is_open()) { - int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); + int errcode= query_error_code(thd, thd->killed == NOT_KILLED); /* error of writing binary log is ignored */ write_to_binlog(transactional_table, errcode); } @@ -3824,7 +3823,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) !table->s->tmp_table && !ptr->get_create_info()->table_existed) { - int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); + int errcode= query_error_code(thd, thd->killed == NOT_KILLED); if (int error= ptr->binlog_show_create_table(tables, count, errcode)) return error; } @@ -3867,7 +3866,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) create_table->table_name); if (thd->current_stmt_binlog_row_based) { - int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); + int errcode= query_error_code(thd, thd->killed == NOT_KILLED); binlog_show_create_table(&(create_table->table), 1, errcode); } table= create_table->table; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 4ef24876474..32ad4f414c9 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1735,6 +1735,9 @@ typedef struct st_lex : public Query_tables_list LEX_SERVER_OPTIONS server_options; USER_RESOURCES mqh; ulong type; + /* The following is used by KILL */ + killed_state kill_signal; + killed_type kill_type; /* This variable is used in post-parse stage to declare that sum-functions, or functions which have sense only if GROUP BY is present, are allowed. diff --git a/sql/sql_load.cc b/sql/sql_load.cc index cc0527591e1..3df6305f620 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -130,7 +130,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, bool is_fifo=0; #ifndef EMBEDDED_LIBRARY LOAD_FILE_INFO lf_info; - THD::killed_state killed_status; + killed_state killed_status; #endif char *db = table_list->db; // This is never null /* @@ -471,11 +471,11 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, DBUG_EXECUTE_IF("simulate_kill_bug27571", { error=1; - thd->killed= THD::KILL_QUERY; + thd->killed= KILL_QUERY; };); #ifndef EMBEDDED_LIBRARY - killed_status= (error == 0) ? THD::NOT_KILLED : thd->killed; + killed_status= (error == 0) ? NOT_KILLED : thd->killed; #endif /* @@ -519,7 +519,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, /* If the file was not empty, wrote_create_file is true */ if (lf_info.wrote_create_file) { - int errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); + int errcode= query_error_code(thd, killed_status == NOT_KILLED); /* since there is already an error, the possible error of writing binary log will be ignored */ @@ -570,7 +570,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, read_info.end_io_cache(); if (lf_info.wrote_create_file) { - int errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); + int errcode= query_error_code(thd, killed_status == NOT_KILLED); error= write_execute_load_query_log_event(thd, ex, table_list->db, table_list->table_name, handle_duplicates, ignore, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f850dc9145f..acdd6b76df4 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -793,7 +793,7 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion) my_error(thd->killed_errno(), MYF(0)); else if ((res == 0) && do_release) { - thd->killed= THD::KILL_CONNECTION; + thd->killed= KILL_CONNECTION; if (global_system_variables.log_warnings > 3) { Security_context *sctx= &thd->main_security_ctx; @@ -1530,7 +1530,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, { status_var_increment(thd->status_var.com_stat[SQLCOM_KILL]); ulong id=(ulong) uint4korr(packet); - sql_kill(thd,id,false); + sql_kill(thd,id, KILL_CONNECTION_HARD); break; } case COM_SET_OPTION: @@ -1572,15 +1572,18 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } /* report error issued during command execution */ - if (thd->killed_errno()) + if (thd->killed) { - if (! thd->main_da.is_set()) - thd->send_kill_message(); - } - if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA) - { - thd->killed= THD::NOT_KILLED; - thd->mysys_var->abort= 0; + if (thd->killed_errno()) + { + if (! thd->main_da.is_set()) + thd->send_kill_message(); + } + if (thd->killed < KILL_CONNECTION) + { + thd->killed= NOT_KILLED; + thd->mysys_var->abort= 0; + } } /* If commit fails, we should be able to reset the OK status. */ @@ -4038,8 +4041,6 @@ end_with_restore_list: } case SQLCOM_KILL: { - Item *it= (Item *)lex->value_list.head(); - if (lex->table_or_sp_used()) { my_error(ER_NOT_SUPPORTED_YET, MYF(0), "Usage of subqueries or stored " @@ -4047,13 +4048,20 @@ end_with_restore_list: break; } - if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1)) + if (lex->kill_type == KILL_TYPE_ID) { - my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY), - MYF(0)); - goto error; + Item *it= (Item *)lex->value_list.head(); + if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1)) + { + my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY), + MYF(0)); + goto error; + } + sql_kill(thd, (ulong) it->val_int(), lex->kill_signal); } - sql_kill(thd, (ulong)it->val_int(), lex->type & ONLY_KILL_QUERY); + else + sql_kill_user(thd, get_current_user(thd, lex->users_list.head()), + lex->kill_signal); break; } #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -7174,12 +7182,13 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, This is written such that we have a short lock on LOCK_thread_count */ -uint kill_one_thread(THD *thd, ulong id, bool only_kill_query) +uint kill_one_thread(THD *thd, ulong id, killed_state kill_signal) { THD *tmp; uint error=ER_NO_SUCH_THREAD; DBUG_ENTER("kill_one_thread"); - DBUG_PRINT("enter", ("id=%lu only_kill=%d", id, only_kill_query)); + DBUG_PRINT("enter", ("id: %lu signal: %u", id, (uint) kill_signal)); + VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list I_List_iterator<THD> it(threads); while ((tmp=it++)) @@ -7219,7 +7228,7 @@ uint kill_one_thread(THD *thd, ulong id, bool only_kill_query) if ((thd->security_ctx->master_access & SUPER_ACL) || thd->security_ctx->user_matches(tmp->security_ctx)) { - tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION); + tmp->awake(kill_signal); error=0; } else @@ -7231,6 +7240,76 @@ uint kill_one_thread(THD *thd, ulong id, bool only_kill_query) } +/** + kill all threads from one user + + @param thd Thread class + @param user_name User name for threads we should kill + @param only_kill_query Should it kill the query or the connection + + @note + This is written such that we have a short lock on LOCK_thread_count + + If we can't kill all threads because of security issues, no threads + are killed. +*/ + +static uint kill_threads_for_user(THD *thd, LEX_USER *user, + killed_state kill_signal, ha_rows *rows) +{ + THD *tmp; + List<THD> threads_to_kill; + DBUG_ENTER("kill_threads_for_user"); + + *rows= 0; + + if (thd->is_fatal_error) // If we run out of memory + DBUG_RETURN(ER_OUT_OF_RESOURCES); + + DBUG_PRINT("enter", ("user: %s signal: %u", user->user.str, + (uint) kill_signal)); + + VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list + I_List_iterator<THD> it(threads); + while ((tmp=it++)) + { + if (tmp->command == COM_DAEMON) + continue; + /* + Check that hostname (if given) and user name matches. + + host.str[0] == '%' means that host name was not given. See sql_yacc.yy + */ + if (((user->host.str[0] == '%' && !user->host.str[1]) || + !strcmp(tmp->security_ctx->host, user->host.str)) && + !strcmp(tmp->security_ctx->user, user->user.str)) + { + if (!(thd->security_ctx->master_access & SUPER_ACL) && + !thd->security_ctx->user_matches(tmp->security_ctx)) + { + VOID(pthread_mutex_unlock(&LOCK_thread_count)); + DBUG_RETURN(ER_KILL_DENIED_ERROR); + } + if (!threads_to_kill.push_back(tmp, tmp->mem_root)) + pthread_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete + } + } + VOID(pthread_mutex_unlock(&LOCK_thread_count)); + if (!threads_to_kill.is_empty()) + { + List_iterator_fast<THD> it(threads_to_kill); + THD *ptr; + while ((ptr= it++)) + { + ptr->awake(kill_signal); + pthread_mutex_unlock(&ptr->LOCK_thd_data); + (*rows)++; + } + } + DBUG_RETURN(0); +} + + /* kills a thread and sends response @@ -7241,16 +7320,33 @@ uint kill_one_thread(THD *thd, ulong id, bool only_kill_query) only_kill_query Should it kill the query or the connection */ -void sql_kill(THD *thd, ulong id, bool only_kill_query) +void sql_kill(THD *thd, ulong id, killed_state state) { uint error; - if (!(error= kill_one_thread(thd, id, only_kill_query))) + if (!(error= kill_one_thread(thd, id, state))) my_ok(thd); else my_error(error, MYF(0), id); } +void sql_kill_user(THD *thd, LEX_USER *user, killed_state state) +{ + uint error; + ha_rows rows; + if (!(error= kill_threads_for_user(thd, user, state, &rows))) + my_ok(thd, rows); + else + { + /* + This is probably ER_OUT_OF_RESOURCES, but in the future we may + want to write the name of the user we tried to kill + */ + my_error(error, MYF(0), user->host.str, user->user.str); + } +} + + /** If pointer is not a null pointer, append filename to it. */ bool append_file_to_dir(THD *thd, const char **filename_ptr, diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 02b0fea09a5..e7363bffa9a 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1277,9 +1277,9 @@ err: idle, then this could last long, and if the slave reconnects, we could have 2 Binlog_dump threads in SHOW PROCESSLIST, until a query is written to the binlog. To avoid this, when the slave reconnects and sends COM_BINLOG_DUMP, - the master kills any existing thread with the slave's server id (if this id is - not zero; it will be true for real slaves, but false for mysqlbinlog when it - sends COM_BINLOG_DUMP to get a remote binlog dump). + the master kills any existing thread with the slave's server id (if this id + is not zero; it will be true for real slaves, but false for mysqlbinlog when + it sends COM_BINLOG_DUMP to get a remote binlog dump). SYNOPSIS kill_zombie_dump_threads() @@ -1311,7 +1311,7 @@ void kill_zombie_dump_threads(uint32 slave_server_id) it will be slow because it will iterate through the list again. We just to do kill the thread ourselves. */ - tmp->awake(THD::KILL_QUERY); + tmp->awake(KILL_QUERY); pthread_mutex_unlock(&tmp->LOCK_thd_data); } } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 2a717ba1572..062bfc347b3 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1943,8 +1943,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) pthread_mutex_lock(&tmp->LOCK_thd_data); if ((mysys_var= tmp->mysys_var)) pthread_mutex_lock(&mysys_var->mutex); - thd_info->proc_info= (char*) (tmp->killed != THD::NOT_KILLED && - tmp->killed != THD::KILL_BAD_DATA ? + thd_info->proc_info= (char*) (tmp->killed >= KILL_QUERY ? "Killed" : 0); #ifndef EMBEDDED_LIBRARY thd_info->state_info= (char*) (tmp->net.reading_or_writing ? @@ -2084,8 +2083,7 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) if ((mysys_var= tmp->mysys_var)) pthread_mutex_lock(&mysys_var->mutex); /* COMMAND */ - if ((val= (char *) ((tmp->killed != THD::NOT_KILLED && - tmp->killed != THD::KILL_BAD_DATA ? + if ((val= (char *) ((tmp->killed >= KILL_QUERY ? "Killed" : 0)))) table->field[4]->store(val, strlen(val), cs); else @@ -2441,7 +2439,7 @@ static bool show_status_array(THD *thd, const char *wild, end= strmov(buff, *(my_bool*) value ? "ON" : "OFF"); break; case SHOW_INT: - end= int10_to_str((long) *(uint32*) value, buff, 10); + end= int10_to_str((long) *(int*) value, buff, -10); break; case SHOW_HAVE: { diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 299e88107d7..e6ec80bbd8d 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -59,7 +59,7 @@ static void wait_for_kill_signal(THD *thd) while (thd->killed == 0) sleep(1); // Reset signal and continue as if nothing happend - thd->killed= THD::NOT_KILLED; + thd->killed= NOT_KILLED; } #endif diff --git a/sql/sql_union.cc b/sql/sql_union.cc index d2cb21a59a1..50de42d153c 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -645,6 +645,7 @@ bool st_select_lex_unit::exec() if (!saved_error) { examined_rows+= thd->examined_row_count; + thd->examined_row_count= 0; if (union_result->flush()) { thd->lex->current_select= lex_select_save; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index b516065eff7..80eb823c346 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -221,7 +221,7 @@ int mysql_update(THD *thd, bool need_reopen; ulonglong id; List<Item> all_fields; - THD::killed_state killed_status= THD::NOT_KILLED; + killed_state killed_status= NOT_KILLED; DBUG_ENTER("mysql_update"); for ( ; ; ) @@ -788,9 +788,9 @@ int mysql_update(THD *thd, // simulated killing after the loop must be ineffective for binlogging DBUG_EXECUTE_IF("simulate_kill_bug27571", { - thd->killed= THD::KILL_QUERY; + thd->killed= KILL_QUERY; };); - error= (killed_status == THD::NOT_KILLED)? error : 1; + error= (killed_status == NOT_KILLED)? error : 1; if (error && will_batch && @@ -851,7 +851,7 @@ int mysql_update(THD *thd, if (error < 0) thd->clear_error(); else - errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); + errcode= query_error_code(thd, killed_status == NOT_KILLED); if (thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(), thd->query_length(), @@ -1937,7 +1937,7 @@ void multi_update::abort() got caught and if happens later the killed error is written into repl event. */ - int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); + int errcode= query_error_code(thd, thd->killed == NOT_KILLED); /* the error of binary logging is ignored */ (void)thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(), thd->query_length(), @@ -2151,7 +2151,7 @@ bool multi_update::send_eof() { char buff[STRING_BUFFER_USUAL_SIZE]; ulonglong id; - THD::killed_state killed_status= THD::NOT_KILLED; + killed_state killed_status= NOT_KILLED; DBUG_ENTER("multi_update::send_eof"); thd_proc_info(thd, "updating reference tables"); @@ -2164,7 +2164,7 @@ bool multi_update::send_eof() if local_error is not set ON until after do_updates() then later carried out killing should not affect binlogging. */ - killed_status= (local_error == 0)? THD::NOT_KILLED : thd->killed; + killed_status= (local_error == 0) ? NOT_KILLED : thd->killed; thd_proc_info(thd, "end"); /* We must invalidate the query cache before binlog writing and @@ -2193,7 +2193,7 @@ bool multi_update::send_eof() if (local_error == 0) thd->clear_error(); else - errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); + errcode= query_error_code(thd, killed_status == NOT_KILLED); if (thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(), thd->query_length(), transactional_tables, FALSE, errcode)) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c2fea985aa1..0d0e0ef98a4 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -682,10 +682,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %pure_parser /* We have threads */ /* - Currently there are 171 shift/reduce conflicts. + Currently there are 174 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 171 +%expect 174 /* Comments for TOKENS. @@ -901,6 +901,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token GROUP_CONCAT_SYM %token GT_SYM /* OPERATOR */ %token HANDLER_SYM +%token HARD_SYM %token HASH_SYM %token HAVING /* SQL-2003-R */ %token HELP_SYM @@ -1169,6 +1170,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token SMALLINT /* SQL-2003-R */ %token SNAPSHOT_SYM %token SOCKET_SYM +%token SOFT_SYM %token SONAME_SYM %token SOUNDS_SYM %token SOURCE_SYM @@ -1348,7 +1350,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); opt_ev_status opt_ev_on_completion ev_on_completion opt_ev_comment ev_alter_on_schedule_completion opt_ev_rename_to opt_ev_sql_stmt optional_flush_tables_arguments opt_dyncol_type dyncol_type - opt_time_precision + opt_time_precision kill_type kill_option int_num %type <ulong_num> ulong_num real_ulong_num merge_insert_types @@ -1380,7 +1382,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); function_call_keyword function_call_nonkeyword function_call_generic - function_call_conflict + function_call_conflict kill_expr %type <item_num> NUM_literal @@ -9674,6 +9676,12 @@ delete_limit_clause: } ; +int_num: + NUM { int error; $$= (int) my_strtoll10($1.str, (char**) 0, &error); } + | '-' NUM { int error; $$= -(int) my_strtoll10($2.str, (char**) 0, &error); } + | '-' LONG_NUM { int error; $$= -(int) my_strtoll10($2.str, (char**) 0, &error); } + ; + ulong_num: NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); } | HEX_NUM { $$= (ulong) strtol($1.str, (char**) 0, 16); } @@ -11081,19 +11089,41 @@ purge_option: /* kill threads */ kill: - KILL_SYM kill_option expr + KILL_SYM { LEX *lex=Lex; lex->value_list.empty(); - lex->value_list.push_front($3); + lex->users_list.empty(); lex->sql_command= SQLCOM_KILL; } + kill_type kill_option kill_expr + { + Lex->kill_signal= (killed_state) ($3 | $4); + } ; +kill_type: + /* Empty */ { $$= (int) KILL_HARD_BIT; } + | HARD_SYM { $$= (int) KILL_HARD_BIT; } + | SOFT_SYM { $$= 0; } + kill_option: - /* empty */ { Lex->type= 0; } - | CONNECTION_SYM { Lex->type= 0; } - | QUERY_SYM { Lex->type= ONLY_KILL_QUERY; } + /* empty */ { $$= (int) KILL_CONNECTION; } + | CONNECTION_SYM { $$= (int) KILL_CONNECTION; } + | QUERY_SYM { $$= (int) KILL_QUERY; } + ; + +kill_expr: + expr + { + Lex->value_list.push_front($$); + Lex->kill_type= KILL_TYPE_ID; + } + | USER user + { + Lex->users_list.push_back($2); + Lex->kill_type= KILL_TYPE_USER; + } ; /* change database */ @@ -12208,6 +12238,7 @@ keyword_sp: | GRANTS {} | GLOBAL_SYM {} | HASH_SYM {} + | HARD_SYM {} | HOSTS_SYM {} | HOUR_SYM {} | IDENTIFIED_SYM {} @@ -12339,6 +12370,7 @@ keyword_sp: | SHUTDOWN {} | SLOW_SYM {} | SNAPSHOT_SYM {} + | SOFT_SYM {} | SOUNDS_SYM {} | SOURCE_SYM {} | SQL_CACHE_SYM {} @@ -13408,7 +13440,7 @@ grant_option: lex->mqh.conn_per_hour= $2; lex->mqh.specified_limits|= USER_RESOURCES::CONNECTIONS_PER_HOUR; } - | MAX_USER_CONNECTIONS_SYM ulong_num + | MAX_USER_CONNECTIONS_SYM int_num { LEX *lex=Lex; lex->mqh.user_conn= $2; diff --git a/sql/structs.h b/sql/structs.h index 29ccde3fb03..18f90d5b8b1 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -222,8 +222,11 @@ typedef struct user_resources { uint updates; /* Maximum number of connections established per hour. */ uint conn_per_hour; - /* Maximum number of concurrent connections. */ - uint user_conn; + /* + Maximum number of concurrent connections. If -1 then no new + connections allowed + */ + int user_conn; /* Values of this enum and specified_limits member are used by the parser to store which user limits were specified in GRANT statement. @@ -256,7 +259,7 @@ typedef struct user_conn { /* Total length of the key. */ uint len; /* Current amount of concurrent connections for this account. */ - uint connections; + int connections; /* Current number of connections per hour, number of updating statements per hour and total number of statements per hour for this account. diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc index f7efaf4566f..80292503904 100644 --- a/storage/archive/ha_archive.cc +++ b/storage/archive/ha_archive.cc @@ -17,6 +17,7 @@ #pragma implementation // gcc: Class implementation #endif +#define MYSQL_SERVER 1 #include "mysql_priv.h" #include <myisam.h> diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index abefe56095a..e65ac7e443c 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -2701,7 +2701,7 @@ int ha_maria::external_lock(THD *thd, int lock_type) changes to commit (rollback shouldn't be tested). */ DBUG_ASSERT(!thd->main_da.is_sent || - thd->killed == THD::KILL_CONNECTION); + thd->killed == KILL_CONNECTION); /* autocommit ? rollback a transaction */ #ifdef MARIA_CANNOT_ROLLBACK if (ma_commit(trn)) |