Allow one to block an account by using GRANT max_user_connections = -1

One can set @@global.max_user_connections to -1 to block anyone, except SUPER user, to login.
If max_user_connection is 0, one can't change it without a restart (needed to get user connections counting to work correctly)


mysql-test/r/system_mysql_db.result:
  Changed max_user_connections to handle negative numbers.
mysql-test/r/user_limits-2.result:
  New test case that one can't change max_user_connection if it was 0
mysql-test/r/user_limits.result:
  Fixed wrong error messages.
mysql-test/r/variables.result:
  Store / restore max_user_connections (needed as there is now a --master.opt file that changes it)
mysql-test/t/subselect_mat_cost-master.opt:
  Enable slow query log (as this test found some errors in slow query logging)
mysql-test/t/user_limits-2.test:
  New test case that one can't change max_user_connection if it was 0
mysql-test/t/user_limits-master.opt:
  Set max_user_connections (as one can't change it if it was 0)
mysql-test/t/user_limits.test:
  Test max_user_connections -1
mysql-test/t/variables-master.opt:
  Set max_user_connections (as one can't change it if it was 0)
mysql-test/t/variables.test:
  Set/restore max_user_connections
scripts/Makefile.am:
  Add a text message to mysql_fix_privilege_tables.sql that it's automaticly generated
scripts/mysql_system_tables.sql:
  Change max_user_connections to signed
scripts/mysql_system_tables_fix.sql:
  Change max_user_connections to signed
sql/item_func.cc:
  Change SHOW_INT to be signed.
  (Needed for max_user_connections and it's probably a bug that it was not originally signed)
sql/log.cc:
  Remove some code that was not needed (All these variables are reset at start of query)
sql/mysql_priv.h:
  Made max_user_connections signed.
  Added max_user_connections_checking
sql/mysqld.cc:
  Added max_user_connections_checking so that we know if max_user_connections was 0 at startup
  (Which means that we will not do connection counting for accounts that don't have user resource limits)
  Set thd->start_utime at same time as thr_create_utime. (Before start_utime could be < thr_create_utime which lead to wrong query counting)
sql/set_var.cc:
  Don't allow one to change 'max_user_connections' if it was 0 at startup.
sql/sql_acl.cc:
  Change user_connection counting to be negative.
sql/sql_connect.cc:
  If max_user_connections is < 0 then only SUPER user can login.
  Fixed wrong variable names for error messages.
  Fixed wrong initial value for questions.
  Set thd->start_utime and thd->thr_create_utime at startup.  Needed to get time_out_user_resource_limits() to work.
sql/sql_show.cc:
  SHOW_INT is now negative
sql/sql_yacc.yy:
  Support negative values for MAX_USER_CONNECTIONS
sql/structs.h:
  Make user connect counting work with signed numbers.
This commit is contained in:
Michael Widenius 2011-09-26 20:26:47 +03:00
parent f0c6ce9ade
commit 7800d93bc3
23 changed files with 173 additions and 54 deletions

View File

@ -117,7 +117,7 @@ user CREATE TABLE `user` (
`max_questions` int(11) unsigned NOT NULL DEFAULT '0', `max_questions` int(11) unsigned NOT NULL DEFAULT '0',
`max_updates` 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_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 '', `plugin` char(60) CHARACTER SET latin1 NOT NULL DEFAULT '',
`auth_string` text COLLATE utf8_bin NOT NULL, `auth_string` text COLLATE utf8_bin NOT NULL,
PRIMARY KEY (`Host`,`User`) PRIMARY KEY (`Host`,`User`)

View File

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

View File

@ -1,3 +1,4 @@
set @my_max_user_connections= @@global.max_user_connections;
drop table if exists t1; drop table if exists t1;
create table t1 (i int); create table t1 (i int);
delete from mysql.user where user like 'mysqltest\_%'; delete from mysql.user where user like 'mysqltest\_%';
@ -12,9 +13,9 @@ i
select * from t1; select * from t1;
i i
select * from t1; 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; 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; drop user mysqltest_1@localhost;
grant usage on *.* to mysqltest_1@localhost with max_updates_per_hour 2; grant usage on *.* to mysqltest_1@localhost with max_updates_per_hour 2;
flush user_resources; flush user_resources;
@ -27,11 +28,11 @@ i
delete from t1; delete from t1;
delete from t1; 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; select * from t1;
i i
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; select * from t1;
i i
drop user mysqltest_1@localhost; drop user mysqltest_1@localhost;
@ -65,10 +66,20 @@ select * from t1;
i i
connect(localhost,mysqltest_1,,test,MYSQL_PORT,MYSQL_SOCK); connect(localhost,mysqltest_1,,test,MYSQL_PORT,MYSQL_SOCK);
ERROR 42000: User 'mysqltest_1' has exceeded the 'max_user_connections' resource (current value: 3) 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; drop user mysqltest_1@localhost;
select @@session.max_user_connections, @@global.max_user_connections; select @@session.max_user_connections, @@global.max_user_connections;
@@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; set session max_user_connections= 2;
ERROR HY000: Variable 'max_user_connections' is a GLOBAL variable and should be set with SET GLOBAL ERROR HY000: Variable 'max_user_connections' is a GLOBAL variable and should be set with SET GLOBAL
set global max_user_connections= 2; 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); connect(localhost,mysqltest_1,,test,MYSQL_PORT,MYSQL_SOCK);
ERROR 42000: User 'mysqltest_1' has exceeded the 'max_user_connections' resource (current value: 3) ERROR 42000: User 'mysqltest_1' has exceeded the 'max_user_connections' resource (current value: 3)
set global max_user_connections= 0; 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 user mysqltest_1@localhost;
drop table t1; drop table t1;
set global max_user_connections= @my_max_user_connections;

View File

@ -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_heap_table_size =@@global.max_heap_table_size;
set @my_max_insert_delayed_threads=@@global.max_insert_delayed_threads; set @my_max_insert_delayed_threads=@@global.max_insert_delayed_threads;
set @my_max_join_size =@@global.max_join_size; 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_data_pointer_size =@@global.myisam_data_pointer_size;
set @my_myisam_max_sort_file_size =@@global.myisam_max_sort_file_size; set @my_myisam_max_sort_file_size =@@global.myisam_max_sort_file_size;
set @my_net_buffer_length =@@global.net_buffer_length; 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_heap_table_size =@my_max_heap_table_size;
set global max_insert_delayed_threads=@my_max_insert_delayed_threads; set global max_insert_delayed_threads=@my_max_insert_delayed_threads;
set global max_join_size =@my_max_join_size; 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 max_write_lock_count =default;
set global myisam_data_pointer_size =@my_myisam_data_pointer_size; set global myisam_data_pointer_size =@my_myisam_data_pointer_size;
set global myisam_max_sort_file_size =@my_myisam_max_sort_file_size; set global myisam_max_sort_file_size =@my_myisam_max_sort_file_size;

View File

@ -0,0 +1 @@
--log-output=TABLE,FILE --log --log-slow-queries --slow-query-log=1

View File

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

View File

@ -0,0 +1 @@
--max-user-connections=1000

View File

@ -8,6 +8,8 @@
# Save the initial number of concurrent sessions # Save the initial number of concurrent sessions
--source include/count_sessions.inc --source include/count_sessions.inc
set @my_max_user_connections= @@global.max_user_connections;
# Prepare play-ground # Prepare play-ground
--disable_warnings --disable_warnings
drop table if exists t1; drop table if exists t1;
@ -120,8 +122,18 @@ select * from t1;
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK --replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
--error ER_USER_LIMIT_REACHED --error ER_USER_LIMIT_REACHED
connect (muc5, localhost, mysqltest_1,,); connect (muc5, localhost, mysqltest_1,,);
# Clean up
connection default; 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 muc2;
disconnect muc3; disconnect muc3;
disconnect muc4; disconnect muc4;
@ -165,12 +177,37 @@ disconnect muca1;
disconnect muca2; disconnect muca2;
disconnect muca3; disconnect muca3;
set global max_user_connections= 0; set global max_user_connections= 0;
drop user mysqltest_1@localhost;
--enable_ps_protocol --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 # Final cleanup
drop table t1; drop table t1;
# Wait till all disconnects are completed # Wait till all disconnects are completed
--source include/wait_until_count_sessions.inc --source include/wait_until_count_sessions.inc
set global max_user_connections= @my_max_user_connections;

View File

@ -0,0 +1 @@
--max-user-connections=1

View File

@ -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_heap_table_size =@@global.max_heap_table_size;
set @my_max_insert_delayed_threads=@@global.max_insert_delayed_threads; set @my_max_insert_delayed_threads=@@global.max_insert_delayed_threads;
set @my_max_join_size =@@global.max_join_size; 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_data_pointer_size =@@global.myisam_data_pointer_size;
set @my_myisam_max_sort_file_size =@@global.myisam_max_sort_file_size; set @my_myisam_max_sort_file_size =@@global.myisam_max_sort_file_size;
set @my_net_buffer_length =@@global.net_buffer_length; 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_heap_table_size =@my_max_heap_table_size;
set global max_insert_delayed_threads=@my_max_insert_delayed_threads; set global max_insert_delayed_threads=@my_max_insert_delayed_threads;
set global max_join_size =@my_max_join_size; 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 max_write_lock_count =default;
set global myisam_data_pointer_size =@my_myisam_data_pointer_size; set global myisam_data_pointer_size =@my_myisam_data_pointer_size;
set global myisam_max_sort_file_size =@my_myisam_max_sort_file_size; set global myisam_max_sort_file_size =@my_myisam_max_sort_file_size;

View File

@ -117,7 +117,10 @@ mysqlbug: ${top_builddir}/config.status mysqlbug.sh
mysql_fix_privilege_tables.sql: mysql_system_tables.sql \ mysql_fix_privilege_tables.sql: mysql_system_tables.sql \
mysql_system_tables_fix.sql mysql_system_tables_fix.sql
@echo "Building $@"; @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 # Build mysql_fix_privilege_tables_sql.c from

View File

@ -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 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 -- Remember for later if user table already existed
set @had_user_table= @@warning_count != 0; set @had_user_table= @@warning_count != 0;

View File

@ -326,8 +326,11 @@ UPDATE host SET Create_routine_priv=Create_priv, Alter_routine_priv=Alter_priv,
# #
# Add max_user_connections resource limit # 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 # user.Create_user_priv

View File

@ -5063,12 +5063,16 @@ void Item_func_get_system_var::fix_length_and_dec()
switch (var->show_type()) switch (var->show_type())
{ {
case SHOW_LONG: case SHOW_LONG:
case SHOW_INT:
case SHOW_HA_ROWS: case SHOW_HA_ROWS:
unsigned_flag= TRUE; unsigned_flag= TRUE;
max_length= MY_INT64_NUM_DECIMAL_DIGITS; max_length= MY_INT64_NUM_DECIMAL_DIGITS;
decimals=0; decimals=0;
break; break;
case SHOW_INT:
unsigned_flag= FALSE;
max_length= MY_INT64_NUM_DECIMAL_DIGITS;
decimals=0;
break;
case SHOW_LONGLONG: case SHOW_LONGLONG:
unsigned_flag= TRUE; unsigned_flag= TRUE;
max_length= MY_INT64_NUM_DECIMAL_DIGITS; max_length= MY_INT64_NUM_DECIMAL_DIGITS;
@ -5209,7 +5213,7 @@ longlong Item_func_get_system_var::val_int()
switch (var->show_type()) 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_LONG: get_sys_var_safe (ulong);
case SHOW_LONGLONG: get_sys_var_safe (ulonglong); case SHOW_LONGLONG: get_sys_var_safe (ulonglong);
case SHOW_HA_ROWS: get_sys_var_safe (ha_rows); case SHOW_HA_ROWS: get_sys_var_safe (ha_rows);

View File

@ -1062,17 +1062,6 @@ bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length,
query_length= command_name[thd->command].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 ;) for (current_handler= slow_log_handler_list; *current_handler ;)
error= (*current_handler++)->log_slow(thd, current_time, error= (*current_handler++)->log_slow(thd, current_time,
user_host_buff, user_host_len, user_host_buff, user_host_len,

View File

@ -2151,7 +2151,8 @@ extern MYSQL_PLUGIN_IMPORT ulong max_connections;
extern ulong max_connect_errors, connect_timeout; extern ulong max_connect_errors, connect_timeout;
extern ulong extra_max_connections; extern ulong extra_max_connections;
extern ulong slave_net_timeout, slave_trans_retries; 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 ulonglong denied_connections;
extern ulong what_to_log,flush_time; extern ulong what_to_log,flush_time;
extern ulong query_buff_size; extern ulong query_buff_size;

View File

@ -669,7 +669,8 @@ ulong extra_max_connections;
*/ */
ulong max_long_data_size; ulong max_long_data_size;
uint max_user_connections= 0; int max_user_connections= 0;
bool max_user_connections_checking=0;
ulonglong denied_connections; ulonglong denied_connections;
/** /**
Limit of the total number of prepared statements in the server. 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->mysys_var->abort= 0;
thd->thr_create_utime= microsecond_interval_timer(); thd->thr_create_utime= microsecond_interval_timer();
thd->start_utime= thd->thr_create_utime;
threads.append(thd); threads.append(thd);
return(1); return(1);
} }
@ -5263,7 +5265,7 @@ void create_thread_to_handle_connection(THD *thd)
thread_created++; thread_created++;
threads.append(thd); threads.append(thd);
DBUG_PRINT("info",(("creating thread %lu"), thd->thread_id)); 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, if ((error=pthread_create(&thd->real_id,&connection_attrib,
handle_one_connection, handle_one_connection,
(void*) thd))) (void*) thd)))
@ -7432,9 +7434,9 @@ each time the SQL thread starts.",
&max_system_variables.max_tmp_tables, 0, GET_ULONG, &max_system_variables.max_tmp_tables, 0, GET_ULONG,
REQUIRED_ARG, 32, 1, (longlong) ULONG_MAX, 0, 1, 0}, REQUIRED_ARG, 32, 1, (longlong) ULONG_MAX, 0, 1, 0},
{"max_user_connections", OPT_MAX_USER_CONNECTIONS, {"max_user_connections", OPT_MAX_USER_CONNECTIONS,
"The maximum number of active connections for a single user (0 = no limit).", "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_UINT, &max_user_connections, &max_user_connections, 0, GET_INT,
REQUIRED_ARG, 0, 0, UINT_MAX, 0, 1, 0}, REQUIRED_ARG, 0, 0, INT_MAX, 0, 1, 0},
{"max_write_lock_count", OPT_MAX_WRITE_LOCK_COUNT, {"max_write_lock_count", OPT_MAX_WRITE_LOCK_COUNT,
"After this many write locks, allow some read locks to run in between.", "After this many write locks, allow some read locks to run in between.",
&max_write_lock_count, &max_write_lock_count, 0, GET_ULONG, &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) if (!max_long_data_size_used)
max_long_data_size= global_system_variables.max_allowed_packet; 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; return 0;
} }

View File

@ -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) bool sys_var_max_user_conn::check(THD *thd, set_var *var)
{ {
if (var->type == OPT_GLOBAL) 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); return sys_var_thd::check(thd, var);
}
else else
{ {
/* /*
@ -3098,7 +3110,7 @@ bool sys_var_max_user_conn::update(THD *thd, set_var *var)
{ {
DBUG_ASSERT(var->type == OPT_GLOBAL); DBUG_ASSERT(var->type == OPT_GLOBAL);
pthread_mutex_lock(&LOCK_global_system_variables); 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); pthread_mutex_unlock(&LOCK_global_system_variables);
return 0; return 0;
} }

View File

@ -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); table->field[next_field+2]->store((longlong) mqh.conn_per_hour, TRUE);
if (table->s->fields >= 36 && if (table->s->fields >= 36 &&
(mqh.specified_limits & USER_RESOURCES::USER_CONNECTIONS)) (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; mqh_used= mqh_used || mqh.questions || mqh.updates || mqh.conn_per_hour;
next_field+=4; next_field+=4;
@ -4578,7 +4578,8 @@ ulong get_column_grant(THD *thd, GRANT_INFO *grant,
/* Help function for mysql_show_grants */ /* 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) if (value)
{ {
@ -4586,7 +4587,7 @@ static void add_user_option(String *grant, ulong value, const char *name)
grant->append(' '); grant->append(' ');
grant->append(name, strlen(name)); grant->append(name, strlen(name));
grant->append(' '); grant->append(' ');
p=int10_to_str(value, buff, 10); p=int10_to_str(value, buff, is_signed ? -10 : 10);
grant->append(buff,p-buff); grant->append(buff,p-buff);
} }
} }
@ -4768,13 +4769,13 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
if (want_access & GRANT_ACL) if (want_access & GRANT_ACL)
global.append(STRING_WITH_LEN(" GRANT OPTION")); global.append(STRING_WITH_LEN(" GRANT OPTION"));
add_user_option(&global, acl_user->user_resource.questions, 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, 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, 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, add_user_option(&global, acl_user->user_resource.user_conn,
"MAX_USER_CONNECTIONS"); "MAX_USER_CONNECTIONS", 1);
} }
protocol->prepare_for_resend(); protocol->prepare_for_resend();
protocol->store(global.ptr(),global.length(),global.charset()); protocol->store(global.ptr(),global.length(),global.charset());
@ -8147,10 +8148,16 @@ bool acl_authenticate(THD *thd, uint connect_errors,
DBUG_RETURN(1); 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.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, get_or_create_user_conn(thd,
(opt_old_style_user_limits ? sctx->user : sctx->priv_user), (opt_old_style_user_limits ? sctx->user : sctx->priv_user),
(opt_old_style_user_limits ? sctx->host_or_ip : sctx->priv_host), (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 && if (thd->user_connect &&
(thd->user_connect->user_resources.conn_per_hour || (thd->user_connect->user_resources.conn_per_hour ||
thd->user_connect->user_resources.user_conn || thd->user_connect->user_resources.user_conn ||
max_user_connections) && max_user_connections_checking) &&
check_for_max_user_connections(thd, thd->user_connect)) check_for_max_user_connections(thd, thd->user_connect))
{ {
/* Ensure we don't decrement thd->user_connections->connections twice */ /* Ensure we don't decrement thd->user_connections->connections twice */

View File

@ -113,8 +113,11 @@ int check_for_max_user_connections(THD *thd, USER_CONN *uc)
DBUG_ENTER("check_for_max_user_connections"); DBUG_ENTER("check_for_max_user_connections");
(void) pthread_mutex_lock(&LOCK_user_conn); (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 && 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); my_error(ER_TOO_MANY_USER_CONNECTIONS, MYF(0), uc->user);
goto end; 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 more than a hour since last check, reset resource checking */
if (check_time - uc->reset_utime >= LL(3600000000)) if (check_time - uc->reset_utime >= LL(3600000000))
{ {
uc->questions=1; uc->questions=0;
uc->updates=0; uc->updates=0;
uc->conn_per_hour=0; uc->conn_per_hour=0;
uc->reset_utime= check_time; uc->reset_utime= check_time;
@ -231,7 +234,7 @@ bool check_mqh(THD *thd, uint check_command)
if (uc->user_resources.questions && if (uc->user_resources.questions &&
uc->questions++ >= 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); (long) uc->user_resources.questions);
error=1; error=1;
goto end; goto end;
@ -243,7 +246,7 @@ bool check_mqh(THD *thd, uint check_command)
(sql_command_flags[check_command] & CF_CHANGES_DATA) && (sql_command_flags[check_command] & CF_CHANGES_DATA) &&
uc->updates++ >= uc->user_resources.updates) 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); (long) uc->user_resources.updates);
error=1; error=1;
goto end; goto end;
@ -1131,6 +1134,8 @@ pthread_handler_t handle_one_connection(void *arg)
THD *thd= (THD*) arg; THD *thd= (THD*) arg;
thd->thr_create_utime= microsecond_interval_timer(); 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()) if (thread_scheduler.init_new_connection_thread())
{ {

View File

@ -2439,7 +2439,7 @@ static bool show_status_array(THD *thd, const char *wild,
end= strmov(buff, *(my_bool*) value ? "ON" : "OFF"); end= strmov(buff, *(my_bool*) value ? "ON" : "OFF");
break; break;
case SHOW_INT: case SHOW_INT:
end= int10_to_str((long) *(uint32*) value, buff, 10); end= int10_to_str((long) *(int*) value, buff, -10);
break; break;
case SHOW_HAVE: case SHOW_HAVE:
{ {

View File

@ -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 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 ev_alter_on_schedule_completion opt_ev_rename_to opt_ev_sql_stmt
optional_flush_tables_arguments opt_dyncol_type dyncol_type 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> %type <ulong_num>
ulong_num real_ulong_num merge_insert_types 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: ulong_num:
NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); } NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); }
| HEX_NUM { $$= (ulong) strtol($1.str, (char**) 0, 16); } | HEX_NUM { $$= (ulong) strtol($1.str, (char**) 0, 16); }
@ -13434,7 +13440,7 @@ grant_option:
lex->mqh.conn_per_hour= $2; lex->mqh.conn_per_hour= $2;
lex->mqh.specified_limits|= USER_RESOURCES::CONNECTIONS_PER_HOUR; 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 *lex=Lex;
lex->mqh.user_conn= $2; lex->mqh.user_conn= $2;

View File

@ -222,8 +222,11 @@ typedef struct user_resources {
uint updates; uint updates;
/* Maximum number of connections established per hour. */ /* Maximum number of connections established per hour. */
uint conn_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 Values of this enum and specified_limits member are used by the
parser to store which user limits were specified in GRANT statement. parser to store which user limits were specified in GRANT statement.
@ -256,7 +259,7 @@ typedef struct user_conn {
/* Total length of the key. */ /* Total length of the key. */
uint len; uint len;
/* Current amount of concurrent connections for this account. */ /* Current amount of concurrent connections for this account. */
uint connections; int connections;
/* /*
Current number of connections per hour, number of updating statements Current number of connections per hour, number of updating statements
per hour and total number of statements per hour for this account. per hour and total number of statements per hour for this account.