summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/system_mysql_db.result2
-rw-r--r--mysql-test/r/user_limits-2.result2
-rw-r--r--mysql-test/r/user_limits.result37
-rw-r--r--mysql-test/r/variables.result3
-rw-r--r--mysql-test/t/subselect_mat_cost-master.opt1
-rw-r--r--mysql-test/t/user_limits-2.test11
-rw-r--r--mysql-test/t/user_limits-master.opt1
-rw-r--r--mysql-test/t/user_limits.test41
-rw-r--r--mysql-test/t/variables-master.opt1
-rw-r--r--mysql-test/t/variables.test3
-rw-r--r--scripts/Makefile.am5
-rw-r--r--scripts/mysql_system_tables.sql2
-rw-r--r--scripts/mysql_system_tables_fix.sql5
-rw-r--r--sql/item_func.cc8
-rw-r--r--sql/log.cc11
-rw-r--r--sql/mysql_priv.h3
-rw-r--r--sql/mysqld.cc14
-rw-r--r--sql/set_var.cc14
-rw-r--r--sql/sql_acl.cc29
-rw-r--r--sql/sql_connect.cc13
-rw-r--r--sql/sql_show.cc2
-rw-r--r--sql/sql_yacc.yy10
-rw-r--r--sql/structs.h9
23 files changed, 173 insertions, 54 deletions
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/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/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/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/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/log.cc b/sql/log.cc
index 649db6a4c29..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,
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 62fdef5aec6..bccd5b189ff 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -2151,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 a54f845a762..09fc0258c1c 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.
@@ -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);
}
@@ -5263,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)))
@@ -7432,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,
@@ -9641,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/set_var.cc b/sql/set_var.cc
index 0a06b3254f6..10f3e20cc86 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/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_connect.cc b/sql/sql_connect.cc
index 5e0ab339418..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;
@@ -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())
{
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 57d6d585997..062bfc347b3 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -2439,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_yacc.yy b/sql/sql_yacc.yy
index 08738f14cca..0d0e0ef98a4 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1350,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 kill_type kill_option
+ opt_time_precision kill_type kill_option int_num
%type <ulong_num>
ulong_num real_ulong_num merge_insert_types
@@ -9676,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); }
@@ -13434,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.