summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Docs/mysqld_error.txt4
-rw-r--r--include/mysqld_error.h2
-rw-r--r--mysql-test/r/grant.result7
-rw-r--r--mysql-test/r/grant2.result163
-rw-r--r--mysql-test/r/ps_1general.result6
-rw-r--r--mysql-test/t/grant.test9
-rw-r--r--mysql-test/t/grant2.test147
-rw-r--r--sql/share/czech/errmsg.txt2
-rw-r--r--sql/share/danish/errmsg.txt2
-rw-r--r--sql/share/dutch/errmsg.txt2
-rw-r--r--sql/share/english/errmsg.txt2
-rw-r--r--sql/share/estonian/errmsg.txt2
-rw-r--r--sql/share/french/errmsg.txt2
-rw-r--r--sql/share/german/errmsg.txt2
-rw-r--r--sql/share/greek/errmsg.txt2
-rw-r--r--sql/share/hungarian/errmsg.txt2
-rw-r--r--sql/share/italian/errmsg.txt2
-rw-r--r--sql/share/japanese/errmsg.txt2
-rw-r--r--sql/share/korean/errmsg.txt2
-rw-r--r--sql/share/norwegian-ny/errmsg.txt2
-rw-r--r--sql/share/norwegian/errmsg.txt2
-rw-r--r--sql/share/polish/errmsg.txt2
-rw-r--r--sql/share/portuguese/errmsg.txt2
-rw-r--r--sql/share/romanian/errmsg.txt2
-rw-r--r--sql/share/russian/errmsg.txt2
-rw-r--r--sql/share/serbian/errmsg.txt2
-rw-r--r--sql/share/slovak/errmsg.txt2
-rw-r--r--sql/share/spanish/errmsg.txt2
-rw-r--r--sql/share/swedish/errmsg.txt2
-rw-r--r--sql/share/ukrainian/errmsg.txt2
-rw-r--r--sql/sql_acl.cc859
-rw-r--r--sql/sql_acl.h2
-rw-r--r--sql/sql_lex.h3
-rw-r--r--sql/sql_parse.cc34
-rw-r--r--sql/sql_yacc.yy103
35 files changed, 1169 insertions, 216 deletions
diff --git a/Docs/mysqld_error.txt b/Docs/mysqld_error.txt
index c164e8bd3a0..6370d8aac46 100644
--- a/Docs/mysqld_error.txt
+++ b/Docs/mysqld_error.txt
@@ -539,8 +539,8 @@ character-set=latin1
"Using storage engine %s for table '%s'",
#define ER_CANT_AGGREGATE_2COLLATIONS 1267
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-#define ER_DROP_USER 1268
-"Can't drop one or more of the requested users",
+#define ER_HANDLE_USER 1268
+"Operation %s failed for %d of the requested users",
#define ER_REVOKE_GRANTS 1269
"Can't revoke all privileges, grant for one or more of the requested users",
#define ER_CANT_AGGREGATE_3COLLATIONS 1270
diff --git a/include/mysqld_error.h b/include/mysqld_error.h
index 478b46dd246..f5994e8e71d 100644
--- a/include/mysqld_error.h
+++ b/include/mysqld_error.h
@@ -284,7 +284,7 @@
#define ER_WARN_DATA_TRUNCATED 1265
#define ER_WARN_USING_OTHER_HANDLER 1266
#define ER_CANT_AGGREGATE_2COLLATIONS 1267
-#define ER_DROP_USER 1268
+#define ER_HANDLE_USER 1268
#define ER_REVOKE_GRANTS 1269
#define ER_CANT_AGGREGATE_3COLLATIONS 1270
#define ER_CANT_AGGREGATE_NCOLLATIONS 1271
diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result
index 1ac6165e383..262afc3ce2f 100644
--- a/mysql-test/r/grant.result
+++ b/mysql-test/r/grant.result
@@ -218,17 +218,19 @@ grant select on test.* to drop_user3@localhost;
grant select on *.* to drop_user4@localhost;
drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost,
drop_user4@localhost;
-ERROR HY000: Can't drop one or more of the requested users
revoke all privileges, grant option from drop_user1@localhost, drop_user2@localhost,
drop_user3@localhost, drop_user4@localhost;
+ERROR HY000: Can't revoke all privileges, grant for one or more of the requested users
drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost,
drop_user4@localhost;
+ERROR HY000: Operation DROP USER failed for 4 of the requested users
drop table t1;
grant usage on *.* to mysqltest_1@localhost identified by "password";
-grant select, update, insert on test.* to mysqltest@localhost;
+grant select, update, insert on test.* to mysqltest_1@localhost;
show grants for mysqltest_1@localhost;
Grants for mysqltest_1@localhost
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' IDENTIFIED BY PASSWORD '*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19'
+GRANT SELECT, INSERT, UPDATE ON `test`.* TO 'mysqltest_1'@'localhost'
drop user mysqltest_1@localhost;
SET NAMES koi8r;
CREATE DATABASE ÂÄ;
@@ -252,6 +254,7 @@ Grants for ÀÚÅÒ@localhost
GRANT USAGE ON *.* TO 'ÀÚÅÒ'@'localhost'
GRANT SELECT (ËÏÌ) ON `ÂÄ`.`ÔÁÂ` TO 'ÀÚÅÒ'@'localhost'
REVOKE SELECT (ËÏÌ) ON ÂÄ.ÔÁÂ FROM ÀÚÅÒ@localhost;
+DROP USER ÀÚÅÒ@localhost;
DROP DATABASE ÂÄ;
SET NAMES latin1;
USE test;
diff --git a/mysql-test/r/grant2.result b/mysql-test/r/grant2.result
index 9e1e5d50f31..fee9150ca50 100644
--- a/mysql-test/r/grant2.result
+++ b/mysql-test/r/grant2.result
@@ -60,3 +60,166 @@ use test;
delete from mysql.user where user like 'mysqltest\_%';
delete from mysql.db where user like 'mysqltest\_%';
flush privileges;
+set sql_mode='maxdb';
+drop table if exists t1, t2;
+create table t1(c1 int);
+create table t2(c1 int, c2 int);
+create user 'mysqltest_1';
+create user 'mysqltest_1';
+ERROR HY000: Operation CREATE USER failed for 1 of the requested users
+create user 'mysqltest_2' identified by 'Mysqltest-2';
+create user 'mysqltest_3' identified by password 'fffffffffffffffffffffffffffffffffffffffff';
+grant select on *.* to 'mysqltest_2';
+grant insert on test.* to 'mysqltest_2';
+grant update on test.t1 to 'mysqltest_2';
+grant update (c2) on test.t2 to 'mysqltest_2';
+select host,user,password from mysql.user where user like 'mysqltest_%' order by host,user,password;
+host user password
+% mysqltest_1
+% mysqltest_2 *BD447CBA355AF58578D3AE33BA2E2CD388BA08D1
+% mysqltest_3 fffffffffffffffffffffffffffffffffffffffff
+select host,db,user from mysql.db where user like 'mysqltest_%' order by host,db,user;
+host db user
+% test mysqltest_2
+select host,db,user,table_name from mysql.tables_priv where user like 'mysqltest_%' order by host,db,user,table_name;
+host db user table_name
+% test mysqltest_2 t1
+% test mysqltest_2 t2
+select host,db,user,table_name,column_name from mysql.columns_priv where user like 'mysqltest_%' order by host,db,user,table_name,column_name;
+host db user table_name column_name
+% test mysqltest_2 t2 c2
+show grants for 'mysqltest_1';
+Grants for mysqltest_1@%
+GRANT USAGE ON *.* TO 'mysqltest_1'@'%'
+show grants for 'mysqltest_2';
+Grants for mysqltest_2@%
+GRANT SELECT ON *.* TO 'mysqltest_2'@'%' IDENTIFIED BY PASSWORD '*BD447CBA355AF58578D3AE33BA2E2CD388BA08D1'
+GRANT INSERT ON "test".* TO 'mysqltest_2'@'%'
+GRANT UPDATE (c2) ON "test"."t2" TO 'mysqltest_2'@'%'
+GRANT UPDATE ON "test"."t1" TO 'mysqltest_2'@'%'
+drop user 'mysqltest_1';
+select host,user,password from mysql.user where user like 'mysqltest_%' order by host,user,password;
+host user password
+% mysqltest_2 *BD447CBA355AF58578D3AE33BA2E2CD388BA08D1
+% mysqltest_3 fffffffffffffffffffffffffffffffffffffffff
+select host,db,user from mysql.db where user like 'mysqltest_%' order by host,db,user;
+host db user
+% test mysqltest_2
+select host,db,user,table_name from mysql.tables_priv where user like 'mysqltest_%' order by host,db,user,table_name;
+host db user table_name
+% test mysqltest_2 t1
+% test mysqltest_2 t2
+select host,db,user,table_name,column_name from mysql.columns_priv where user like 'mysqltest_%' order by host,db,user,table_name,column_name;
+host db user table_name column_name
+% test mysqltest_2 t2 c2
+show grants for 'mysqltest_1';
+ERROR 42000: There is no such grant defined for user 'mysqltest_1' on host '%'
+rename user 'mysqltest_2' to 'mysqltest_1';
+select host,user,password from mysql.user where user like 'mysqltest_%' order by host,user,password;
+host user password
+% mysqltest_1 *BD447CBA355AF58578D3AE33BA2E2CD388BA08D1
+% mysqltest_3 fffffffffffffffffffffffffffffffffffffffff
+select host,db,user from mysql.db where user like 'mysqltest_%' order by host,db,user;
+host db user
+% test mysqltest_1
+select host,db,user,table_name from mysql.tables_priv where user like 'mysqltest_%' order by host,db,user,table_name;
+host db user table_name
+% test mysqltest_1 t1
+% test mysqltest_1 t2
+select host,db,user,table_name,column_name from mysql.columns_priv where user like 'mysqltest_%' order by host,db,user,table_name,column_name;
+host db user table_name column_name
+% test mysqltest_1 t2 c2
+show grants for 'mysqltest_1';
+Grants for mysqltest_1@%
+GRANT SELECT ON *.* TO 'mysqltest_1'@'%' IDENTIFIED BY PASSWORD '*BD447CBA355AF58578D3AE33BA2E2CD388BA08D1'
+GRANT INSERT ON "test".* TO 'mysqltest_1'@'%'
+GRANT UPDATE (c2) ON "test"."t2" TO 'mysqltest_1'@'%'
+GRANT UPDATE ON "test"."t1" TO 'mysqltest_1'@'%'
+drop user 'mysqltest_1', 'mysqltest_3';
+drop table t1, t2;
+insert into mysql.db set user='mysqltest_1', db='%', host='%';
+flush privileges;
+show grants for 'mysqltest_1';
+ERROR 42000: There is no such grant defined for user 'mysqltest_1' on host '%'
+revoke all privileges, grant option from 'mysqltest_1';
+ERROR HY000: Can't revoke all privileges, grant for one or more of the requested users
+drop user 'mysqltest_1';
+select host,db,user from mysql.db where user = 'mysqltest_1' order by host,db,user;
+host db user
+insert into mysql.tables_priv set host='%', db='test', user='mysqltest_1', table_name='t1';
+flush privileges;
+show grants for 'mysqltest_1';
+ERROR 42000: There is no such grant defined for user 'mysqltest_1' on host '%'
+drop user 'mysqltest_1';
+select host,db,user,table_name from mysql.tables_priv where user = 'mysqltest_1' order by host,db,user,table_name;
+host db user table_name
+insert into mysql.columns_priv set host='%', db='test', user='mysqltest_1', table_name='t1', column_name='c1';
+flush privileges;
+show grants for 'mysqltest_1';
+ERROR 42000: There is no such grant defined for user 'mysqltest_1' on host '%'
+drop user 'mysqltest_1';
+select host,db,user,table_name,column_name from mysql.columns_priv where user = 'mysqltest_1' order by host,db,user,table_name,column_name;
+host db user table_name column_name
+create user 'mysqltest_1', 'mysqltest_2', 'mysqltest_3';
+drop user 'mysqltest_1', 'mysqltest_2', 'mysqltest_3';
+create user 'mysqltest_1', 'mysqltest_2' identified by 'Mysqltest-2', 'mysqltest_3' identified by password 'fffffffffffffffffffffffffffffffffffffffff';
+rename user 'mysqltest_1' to 'mysqltest_1a', 'mysqltest_2' TO 'mysqltest_2a', 'mysqltest_3' TO 'mysqltest_3a';
+drop user 'mysqltest_1', 'mysqltest_2', 'mysqltest_3';
+ERROR HY000: Operation DROP USER failed for 3 of the requested users
+drop user 'mysqltest_1a', 'mysqltest_2a', 'mysqltest_3a';
+create user 'mysqltest_1', 'mysqltest_2', 'mysqltest_3';
+create user 'mysqltest_1a', 'mysqltest_2', 'mysqltest_3a';
+ERROR HY000: Operation CREATE USER failed for 1 of the requested users
+rename user 'mysqltest_1a' to 'mysqltest_1b', 'mysqltest_2a' TO 'mysqltest_2b', 'mysqltest_3a' TO 'mysqltest_3b';
+ERROR HY000: Operation RENAME USER failed for 1 of the requested users
+drop user 'mysqltest_1', 'mysqltest_2', 'mysqltest_3';
+drop user 'mysqltest_1b', 'mysqltest_2b', 'mysqltest_3b';
+ERROR HY000: Operation DROP USER failed for 1 of the requested users
+create user 'mysqltest_2' identified by 'Mysqltest-2';
+drop user 'mysqltest_2' identified by 'Mysqltest-2';
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'identified by 'Mysqltest-2'' at line 1
+create user '%@b'@'b';
+show grants for '%@b'@'b';
+Grants for %@b@b
+GRANT USAGE ON *.* TO '%@b'@'b'
+grant select on mysql.* to '%@b'@'b';
+show grants for '%@b'@'b';
+Grants for %@b@b
+GRANT USAGE ON *.* TO '%@b'@'b'
+GRANT SELECT ON "mysql".* TO '%@b'@'b'
+rename user '%@b'@'b' to '%@a'@'a';
+show grants for '%@b'@'b';
+ERROR 42000: There is no such grant defined for user '%@b' on host 'b'
+show grants for '%@a'@'a';
+Grants for %@a@a
+GRANT USAGE ON *.* TO '%@a'@'a'
+GRANT SELECT ON "mysql".* TO '%@a'@'a'
+drop user '%@a'@'a';
+create user mysqltest_2@localhost;
+grant usage on *.* to mysqltest_2@localhost with grant option;
+select host,user,password from mysql.user order by host,user,password;
+ERROR 42000: Access denied for user 'mysqltest_2'@'localhost' to database 'mysql'
+create user mysqltest_A@'%';
+rename user mysqltest_A@'%' to mysqltest_B@'%';
+drop user mysqltest_B@'%';
+drop user mysqltest_2@localhost;
+create user mysqltest_3@localhost;
+grant all privileges on mysql.* to mysqltest_3@localhost;
+select host,user,password from mysql.user order by host,user,password;
+host user password
+% mysqltest_2 *BD447CBA355AF58578D3AE33BA2E2CD388BA08D1
+127.0.0.1 root
+chilla%
+chilla% root
+localhost
+localhost mysqltest_3
+localhost root
+insert into mysql.user set host='%', user='mysqltest_B';
+create user mysqltest_A@'%';
+ERROR 42000: Access denied for user 'mysqltest_3'@'localhost' to database 'mysql'
+rename user mysqltest_B@'%' to mysqltest_C@'%';
+ERROR 42000: Access denied for user 'mysqltest_3'@'localhost' to database 'mysql'
+drop user mysqltest_B@'%';
+ERROR 42000: Access denied for user 'mysqltest_3'@'localhost' to database 'mysql'
+drop user mysqltest_B@'%';
+drop user mysqltest_3@localhost;
diff --git a/mysql-test/r/ps_1general.result b/mysql-test/r/ps_1general.result
index e8d8e4063f1..9b12b0baa1d 100644
--- a/mysql-test/r/ps_1general.result
+++ b/mysql-test/r/ps_1general.result
@@ -835,19 +835,19 @@ identified by 'looser' ;
show grants for second_user@localhost ;
Grants for second_user@localhost
GRANT USAGE ON *.* TO 'second_user'@'localhost' IDENTIFIED BY PASSWORD '*13843FE600B19A81E32AF50D4A6FED25875FF1F3'
-GRANT SELECT ON `mysqltest`.`t9` TO 'second_user'@'localhost'
GRANT SELECT ON `mysqltest`.`t1` TO 'second_user'@'localhost'
+GRANT SELECT ON `mysqltest`.`t9` TO 'second_user'@'localhost'
drop table mysqltest.t9 ;
show grants for second_user@localhost ;
Grants for second_user@localhost
GRANT USAGE ON *.* TO 'second_user'@'localhost' IDENTIFIED BY PASSWORD '*13843FE600B19A81E32AF50D4A6FED25875FF1F3'
-GRANT SELECT ON `mysqltest`.`t9` TO 'second_user'@'localhost'
GRANT SELECT ON `mysqltest`.`t1` TO 'second_user'@'localhost'
+GRANT SELECT ON `mysqltest`.`t9` TO 'second_user'@'localhost'
show grants for second_user@localhost ;
Grants for second_user@localhost
GRANT USAGE ON *.* TO 'second_user'@'localhost' IDENTIFIED BY PASSWORD '*13843FE600B19A81E32AF50D4A6FED25875FF1F3'
-GRANT SELECT ON `mysqltest`.`t9` TO 'second_user'@'localhost'
GRANT SELECT ON `mysqltest`.`t1` TO 'second_user'@'localhost'
+GRANT SELECT ON `mysqltest`.`t9` TO 'second_user'@'localhost'
prepare s_t1 from 'select a as my_col from t1' ;
execute s_t1 ;
my_col
diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test
index dfd5f4db7c6..c004699d901 100644
--- a/mysql-test/t/grant.test
+++ b/mysql-test/t/grant.test
@@ -162,16 +162,18 @@ grant select(a) on test.t1 to drop_user1@localhost;
grant select on test.t1 to drop_user2@localhost;
grant select on test.* to drop_user3@localhost;
grant select on *.* to drop_user4@localhost;
---error 1268
+# Drop user now implicitly revokes all privileges.
drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost,
drop_user4@localhost;
+--error 1269
revoke all privileges, grant option from drop_user1@localhost, drop_user2@localhost,
drop_user3@localhost, drop_user4@localhost;
+--error 1268
drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost,
drop_user4@localhost;
drop table t1;
grant usage on *.* to mysqltest_1@localhost identified by "password";
-grant select, update, insert on test.* to mysqltest@localhost;
+grant select, update, insert on test.* to mysqltest_1@localhost;
show grants for mysqltest_1@localhost;
drop user mysqltest_1@localhost;
@@ -195,6 +197,9 @@ GRANT SELECT (ËÏÌ) ON ÂÄ.ÔÁÂ TO ÀÚÅÒ@localhost;
SHOW GRANTS FOR ÀÚÅÒ@localhost;
REVOKE SELECT (ËÏÌ) ON ÂÄ.ÔÁÂ FROM ÀÚÅÒ@localhost;
+# Revoke does not drop user. Leave a clean user table for the next tests.
+DROP USER ÀÚÅÒ@localhost;
+
DROP DATABASE ÂÄ;
SET NAMES latin1;
diff --git a/mysql-test/t/grant2.test b/mysql-test/t/grant2.test
index fe4a5b55b82..c439bd05d2f 100644
--- a/mysql-test/t/grant2.test
+++ b/mysql-test/t/grant2.test
@@ -78,3 +78,150 @@ use test;
delete from mysql.user where user like 'mysqltest\_%';
delete from mysql.db where user like 'mysqltest\_%';
flush privileges;
+
+#
+# Create and drop user
+#
+set sql_mode='maxdb';
+--disable_warnings
+drop table if exists t1, t2;
+--enable_warnings
+create table t1(c1 int);
+create table t2(c1 int, c2 int);
+#
+# Three forms of CREATE USER
+create user 'mysqltest_1';
+--error 1268
+create user 'mysqltest_1';
+create user 'mysqltest_2' identified by 'Mysqltest-2';
+create user 'mysqltest_3' identified by password 'fffffffffffffffffffffffffffffffffffffffff';
+grant select on *.* to 'mysqltest_2';
+grant insert on test.* to 'mysqltest_2';
+grant update on test.t1 to 'mysqltest_2';
+grant update (c2) on test.t2 to 'mysqltest_2';
+select host,user,password from mysql.user where user like 'mysqltest_%' order by host,user,password;
+select host,db,user from mysql.db where user like 'mysqltest_%' order by host,db,user;
+select host,db,user,table_name from mysql.tables_priv where user like 'mysqltest_%' order by host,db,user,table_name;
+select host,db,user,table_name,column_name from mysql.columns_priv where user like 'mysqltest_%' order by host,db,user,table_name,column_name;
+show grants for 'mysqltest_1';
+show grants for 'mysqltest_2';
+#
+# Drop
+drop user 'mysqltest_1';
+select host,user,password from mysql.user where user like 'mysqltest_%' order by host,user,password;
+select host,db,user from mysql.db where user like 'mysqltest_%' order by host,db,user;
+select host,db,user,table_name from mysql.tables_priv where user like 'mysqltest_%' order by host,db,user,table_name;
+select host,db,user,table_name,column_name from mysql.columns_priv where user like 'mysqltest_%' order by host,db,user,table_name,column_name;
+--error 1141
+show grants for 'mysqltest_1';
+#
+# Rename
+rename user 'mysqltest_2' to 'mysqltest_1';
+select host,user,password from mysql.user where user like 'mysqltest_%' order by host,user,password;
+select host,db,user from mysql.db where user like 'mysqltest_%' order by host,db,user;
+select host,db,user,table_name from mysql.tables_priv where user like 'mysqltest_%' order by host,db,user,table_name;
+select host,db,user,table_name,column_name from mysql.columns_priv where user like 'mysqltest_%' order by host,db,user,table_name,column_name;
+show grants for 'mysqltest_1';
+drop user 'mysqltest_1', 'mysqltest_3';
+#
+# Grant must not create user
+#grant all on test.t1 to 'mysqltest_1';
+#drop user 'mysqltest_1';
+#
+# Cleanup
+drop table t1, t2;
+#
+# Add a stray record
+insert into mysql.db set user='mysqltest_1', db='%', host='%';
+flush privileges;
+--error 1141
+show grants for 'mysqltest_1';
+--error 1269
+revoke all privileges, grant option from 'mysqltest_1';
+drop user 'mysqltest_1';
+select host,db,user from mysql.db where user = 'mysqltest_1' order by host,db,user;
+#
+# Add a stray record
+insert into mysql.tables_priv set host='%', db='test', user='mysqltest_1', table_name='t1';
+flush privileges;
+--error 1141
+show grants for 'mysqltest_1';
+drop user 'mysqltest_1';
+select host,db,user,table_name from mysql.tables_priv where user = 'mysqltest_1' order by host,db,user,table_name;
+#
+# Add a stray record
+insert into mysql.columns_priv set host='%', db='test', user='mysqltest_1', table_name='t1', column_name='c1';
+flush privileges;
+--error 1141
+show grants for 'mysqltest_1';
+drop user 'mysqltest_1';
+select host,db,user,table_name,column_name from mysql.columns_priv where user = 'mysqltest_1' order by host,db,user,table_name,column_name;
+#
+# Handle multi user lists
+create user 'mysqltest_1', 'mysqltest_2', 'mysqltest_3';
+drop user 'mysqltest_1', 'mysqltest_2', 'mysqltest_3';
+create user 'mysqltest_1', 'mysqltest_2' identified by 'Mysqltest-2', 'mysqltest_3' identified by password 'fffffffffffffffffffffffffffffffffffffffff';
+rename user 'mysqltest_1' to 'mysqltest_1a', 'mysqltest_2' TO 'mysqltest_2a', 'mysqltest_3' TO 'mysqltest_3a';
+--error 1268
+drop user 'mysqltest_1', 'mysqltest_2', 'mysqltest_3';
+drop user 'mysqltest_1a', 'mysqltest_2a', 'mysqltest_3a';
+#
+# Let one of multiple users fail
+create user 'mysqltest_1', 'mysqltest_2', 'mysqltest_3';
+--error 1268
+create user 'mysqltest_1a', 'mysqltest_2', 'mysqltest_3a';
+--error 1268
+rename user 'mysqltest_1a' to 'mysqltest_1b', 'mysqltest_2a' TO 'mysqltest_2b', 'mysqltest_3a' TO 'mysqltest_3b';
+drop user 'mysqltest_1', 'mysqltest_2', 'mysqltest_3';
+--error 1268
+drop user 'mysqltest_1b', 'mysqltest_2b', 'mysqltest_3b';
+#
+# Obsolete syntax has been dropped
+create user 'mysqltest_2' identified by 'Mysqltest-2';
+--error 1064
+drop user 'mysqltest_2' identified by 'Mysqltest-2';
+#
+# Strange user names
+create user '%@b'@'b';
+show grants for '%@b'@'b';
+grant select on mysql.* to '%@b'@'b';
+show grants for '%@b'@'b';
+rename user '%@b'@'b' to '%@a'@'a';
+--error 1141
+show grants for '%@b'@'b';
+show grants for '%@a'@'a';
+drop user '%@a'@'a';
+#
+# USAGE WITH GRANT OPTION is sufficient.
+create user mysqltest_2@localhost;
+grant usage on *.* to mysqltest_2@localhost with grant option;
+connect (user2,localhost,mysqltest_2,,);
+connection user2;
+--error 1044
+select host,user,password from mysql.user order by host,user,password;
+create user mysqltest_A@'%';
+rename user mysqltest_A@'%' to mysqltest_B@'%';
+drop user mysqltest_B@'%';
+disconnect user2;
+connection default;
+drop user mysqltest_2@localhost;
+#
+# ALL PRIVILEGES without GRANT OPTION is not sufficient.
+create user mysqltest_3@localhost;
+grant all privileges on mysql.* to mysqltest_3@localhost;
+connect (user3,localhost,mysqltest_3,,);
+connection user3;
+select host,user,password from mysql.user order by host,user,password;
+insert into mysql.user set host='%', user='mysqltest_B';
+--error 1044
+create user mysqltest_A@'%';
+--error 1044
+rename user mysqltest_B@'%' to mysqltest_C@'%';
+--error 1044
+drop user mysqltest_B@'%';
+disconnect user3;
+connection default;
+drop user mysqltest_B@'%';
+drop user mysqltest_3@localhost;
+#
+
diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt
index 55a8499145a..54d22e62dba 100644
--- a/sql/share/czech/errmsg.txt
+++ b/sql/share/czech/errmsg.txt
@@ -296,7 +296,7 @@ character-set=latin2
"Data truncated for column '%s' at row %ld",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
+"Operation %s failed for %d of the requested users",
"Can't revoke all privileges, grant for one or more of the requested users",
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt
index ee1341cf095..7385be9545c 100644
--- a/sql/share/danish/errmsg.txt
+++ b/sql/share/danish/errmsg.txt
@@ -287,7 +287,7 @@ character-set=latin1
"Data truncated for column '%s' at row %ld",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
+"Operation %s failed for %d of the requested users",
"Can't revoke all privileges, grant for one or more of the requested users",
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt
index 26ff759ca40..7015ed90789 100644
--- a/sql/share/dutch/errmsg.txt
+++ b/sql/share/dutch/errmsg.txt
@@ -296,7 +296,7 @@ character-set=latin1
"Data truncated for column '%s' at row %ld",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
+"Operation %s failed for %d of the requested users",
"Can't revoke all privileges, grant for one or more of the requested users",
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt
index 8abb684fe11..54ca033657e 100644
--- a/sql/share/english/errmsg.txt
+++ b/sql/share/english/errmsg.txt
@@ -284,7 +284,7 @@ character-set=latin1
"Data truncated for column '%s' at row %ld",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
+"Operation %s failed for %d of the requested users",
"Can't revoke all privileges, grant for one or more of the requested users",
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt
index 1211bd305dd..b89ebb42500 100644
--- a/sql/share/estonian/errmsg.txt
+++ b/sql/share/estonian/errmsg.txt
@@ -289,7 +289,7 @@ character-set=latin7
"Data truncated for column '%s' at row %ld",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
+"Operation %s failed for %d of the requested users",
"Can't revoke all privileges, grant for one or more of the requested users",
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt
index 5c54b5e01a8..4e370a63099 100644
--- a/sql/share/french/errmsg.txt
+++ b/sql/share/french/errmsg.txt
@@ -284,7 +284,7 @@ character-set=latin1
"Data truncated for column '%s' at row %ld",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
+"Operation %s failed for %d of the requested users",
"Can't revoke all privileges, grant for one or more of the requested users",
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt
index 4d1a4a17ebe..b4afa45ee46 100644
--- a/sql/share/german/errmsg.txt
+++ b/sql/share/german/errmsg.txt
@@ -297,7 +297,7 @@ character-set=latin1
"Daten abgeschnitten für Spalte '%s' in Zeile %ld",
"Für Tabelle '%s' wird Speicher-Engine %s benutzt",
"Unerlaubte Vermischung der Kollationen (%s,%s) und (%s,%s) für die Operation '%s'",
-"Kann einen oder mehrere der angegebenen Benutzer nicht löschen",
+"Das Kommando %s scheiterte für %d von den betroffenen Benutzern",
"Kann nicht alle Berechtigungen widerrufen, grant for one or more of the requested users",
"Unerlaubte Vermischung der Kollationen (%s,%s), (%s,%s), (%s,%s) für die Operation '%s'",
"Unerlaubte Vermischung der Kollationen für die Operation '%s'",
diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt
index 146d25cfaee..afc91d0c69e 100644
--- a/sql/share/greek/errmsg.txt
+++ b/sql/share/greek/errmsg.txt
@@ -284,7 +284,7 @@ character-set=greek
"Data truncated for column '%s' at row %ld",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
+"Operation %s failed for %d of the requested users",
"Can't revoke all privileges, grant for one or more of the requested users",
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt
index be195b86503..61c112170b2 100644
--- a/sql/share/hungarian/errmsg.txt
+++ b/sql/share/hungarian/errmsg.txt
@@ -289,7 +289,7 @@ character-set=latin2
"Data truncated for column '%s' at row %ld",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
+"Operation %s failed for %d of the requested users",
"Can't revoke all privileges, grant for one or more of the requested users",
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt
index 685d2d0c972..e6a00332093 100644
--- a/sql/share/italian/errmsg.txt
+++ b/sql/share/italian/errmsg.txt
@@ -284,7 +284,7 @@ character-set=latin1
"Data truncated for column '%s' at row %ld",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
+"Operation %s failed for %d of the requested users",
"Can't revoke all privileges, grant for one or more of the requested users",
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt
index 665e1991198..98282af52d6 100644
--- a/sql/share/japanese/errmsg.txt
+++ b/sql/share/japanese/errmsg.txt
@@ -288,7 +288,7 @@ character-set=ujis
"Data truncated for column '%s' at row %ld",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
+"Operation %s failed for %d of the requested users",
"Can't revoke all privileges, grant for one or more of the requested users",
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt
index d4f59b768ff..b10a83beee9 100644
--- a/sql/share/korean/errmsg.txt
+++ b/sql/share/korean/errmsg.txt
@@ -284,7 +284,7 @@ character-set=euckr
"Data truncated for column '%s' at row %ld",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
+"Operation %s failed for %d of the requested users",
"Can't revoke all privileges, grant for one or more of the requested users",
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt
index 780bfd8d8ca..e5a41b7d3d9 100644
--- a/sql/share/norwegian-ny/errmsg.txt
+++ b/sql/share/norwegian-ny/errmsg.txt
@@ -286,7 +286,7 @@ character-set=latin1
"Data truncated for column '%s' at row %ld",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
+"Operation %s failed for %d of the requested users",
"Can't revoke all privileges, grant for one or more of the requested users",
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt
index d723d0cc475..334313c1916 100644
--- a/sql/share/norwegian/errmsg.txt
+++ b/sql/share/norwegian/errmsg.txt
@@ -286,7 +286,7 @@ character-set=latin1
"Data truncated for column '%s' at row %ld",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
+"Operation %s failed for %d of the requested users",
"Can't revoke all privileges, grant for one or more of the requested users",
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt
index b3242c46310..0d8deb30e77 100644
--- a/sql/share/polish/errmsg.txt
+++ b/sql/share/polish/errmsg.txt
@@ -289,7 +289,7 @@ character-set=latin2
"Data truncated for column '%s' at row %ld",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
+"Operation %s failed for %d of the requested users",
"Can't revoke all privileges, grant for one or more of the requested users",
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt
index b2a993bf002..e47a69a5c25 100644
--- a/sql/share/portuguese/errmsg.txt
+++ b/sql/share/portuguese/errmsg.txt
@@ -286,7 +286,7 @@ character-set=latin1
"Dado truncado para coluna '%s' na linha %ld",
"Usando engine de armazenamento %s para tabela '%s'",
"Combinação ilegal de collations (%s,%s) e (%s,%s) para operação '%s'",
-"Não pode remover um ou mais dos usuários pedidos",
+"Operation %s failed for %d of the requested users",
"Não pode revocar todos os privilégios, grant para um ou mais dos usuários pedidos",
"Ilegal combinação de collations (%s,%s), (%s,%s), (%s,%s) para operação '%s'",
"Ilegal combinação de collations para operação '%s'",
diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt
index 7f5ef856d3a..c5a63223c22 100644
--- a/sql/share/romanian/errmsg.txt
+++ b/sql/share/romanian/errmsg.txt
@@ -289,7 +289,7 @@ character-set=latin2
"Data truncated for column '%s' at row %ld",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
+"Operation %s failed for %d of the requested users",
"Can't revoke all privileges, grant for one or more of the requested users",
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt
index 74cafac8b52..04c51d5f532 100644
--- a/sql/share/russian/errmsg.txt
+++ b/sql/share/russian/errmsg.txt
@@ -289,7 +289,7 @@ character-set=koi8r
"Data truncated for column '%s' at row %ld",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
+"Operation %s failed for %d of the requested users",
"Can't revoke all privileges, grant for one or more of the requested users",
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt
index 9a09358a35a..f267faeccbd 100644
--- a/sql/share/serbian/errmsg.txt
+++ b/sql/share/serbian/errmsg.txt
@@ -277,7 +277,7 @@ character-set=cp1250
"Data truncated for column '%s' at row %ld",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
+"Operation %s failed for %d of the requested users",
"Can't revoke all privileges, grant for one or more of the requested users",
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt
index 4c694fecc88..8b7bb730cf0 100644
--- a/sql/share/slovak/errmsg.txt
+++ b/sql/share/slovak/errmsg.txt
@@ -292,7 +292,7 @@ character-set=latin2
"Data truncated for column '%s' at row %ld",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
+"Operation %s failed for %d of the requested users",
"Can't revoke all privileges, grant for one or more of the requested users",
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt
index 94316edd083..c0e663d6484 100644
--- a/sql/share/spanish/errmsg.txt
+++ b/sql/share/spanish/errmsg.txt
@@ -288,7 +288,7 @@ character-set=latin1
"Datos truncados para columna '%s' en la línea %ld",
"Usando motor de almacenamiento %s para tabla '%s'",
"Ilegal mezcla de collations (%s,%s) y (%s,%s) para operación '%s'",
-"No puede remover uno o mas de los usuarios solicitados",
+"Operation %s failed for %d of the requested users",
"No puede revocar todos los privilegios, derecho para uno o mas de los usuarios solicitados",
"Ilegal mezcla de collations (%s,%s), (%s,%s), (%s,%s) para operación '%s'",
"Ilegal mezcla de collations para operación '%s'",
diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt
index cd57653969f..831ccfbe978 100644
--- a/sql/share/swedish/errmsg.txt
+++ b/sql/share/swedish/errmsg.txt
@@ -284,7 +284,7 @@ character-set=latin1
"Data truncated for column '%s' at row %ld",
"Använder handler %s för tabell '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
+"Operation %s failed for %d of the requested users",
"Can't revoke all privileges, grant for one or more of the requested users",
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt
index 0b3400a4e88..46a0adf922f 100644
--- a/sql/share/ukrainian/errmsg.txt
+++ b/sql/share/ukrainian/errmsg.txt
@@ -290,7 +290,7 @@ character-set=koi8u
"Data truncated for column '%s' at row %ld",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
+"Operation %s failed for %d of the requested users",
"Can't revoke all privileges, grant for one or more of the requested users",
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 9ce00a01e31..d3bfb5b4d1d 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -919,7 +919,7 @@ static void acl_update_user(const char *user, const char *host,
{
if (!acl_user->host.hostname && !host[0] ||
acl_user->host.hostname &&
- !my_strcasecmp(&my_charset_latin1, host, acl_user->host.hostname))
+ !my_strcasecmp(system_charset_info, host, acl_user->host.hostname))
{
acl_user->access=privileges;
if (mqh->bits & 1)
@@ -998,7 +998,7 @@ static void acl_update_db(const char *user, const char *host, const char *db,
{
if (!acl_db->host.hostname && !host[0] ||
acl_db->host.hostname &&
- !my_strcasecmp(&my_charset_latin1, host, acl_db->host.hostname))
+ !my_strcasecmp(system_charset_info, host, acl_db->host.hostname))
{
if (!acl_db->db && !db[0] ||
acl_db->db && !strcmp(db,acl_db->db))
@@ -1141,7 +1141,7 @@ static void init_check_host(void)
DBUG_ENTER("init_check_host");
VOID(my_init_dynamic_array(&acl_wild_hosts,sizeof(struct acl_host_and_ip),
acl_users.elements,1));
- VOID(hash_init(&acl_check_hosts,&my_charset_latin1,acl_users.elements,0,0,
+ VOID(hash_init(&acl_check_hosts,system_charset_info,acl_users.elements,0,0,
(hash_get_key) check_get_key,0,0));
if (!allow_all_hosts)
{
@@ -1157,7 +1157,7 @@ static void init_check_host(void)
{ // Check if host already exists
acl_host_and_ip *acl=dynamic_element(&acl_wild_hosts,j,
acl_host_and_ip *);
- if (!my_strcasecmp(&my_charset_latin1,
+ if (!my_strcasecmp(system_charset_info,
acl_user->host.hostname, acl->hostname))
break; // already stored
}
@@ -1233,7 +1233,7 @@ bool check_change_password(THD *thd, const char *host, const char *user,
}
if (!thd->slave_thread &&
(strcmp(thd->user,user) ||
- my_strcasecmp(&my_charset_latin1, host, thd->host_or_ip)))
+ my_strcasecmp(system_charset_info, host, thd->host_or_ip)))
{
if (check_access(thd, UPDATE_ACL, "mysql",0,1,0))
return(1);
@@ -1402,7 +1402,7 @@ static bool compare_hostname(const acl_host_and_ip *host, const char *hostname,
return (tmp & host->ip_mask) == host->ip;
}
return (!host->hostname ||
- (hostname && !wild_case_compare(&my_charset_latin1,
+ (hostname && !wild_case_compare(system_charset_info,
hostname,host->hostname)) ||
(ip && !wild_compare(ip,host->hostname,0)));
}
@@ -1415,7 +1415,7 @@ bool hostname_requires_resolving(const char *hostname)
int namelen= strlen(hostname);
int lhlen= strlen(my_localhost);
if ((namelen == lhlen) &&
- !my_strnncoll(&my_charset_latin1, (const uchar *)hostname, namelen,
+ !my_strnncoll(system_charset_info, (const uchar *)hostname, namelen,
(const uchar *)my_localhost, strlen(my_localhost)))
return FALSE;
for (; (cur=*hostname); hostname++)
@@ -1464,8 +1464,8 @@ static bool update_user_table(THD *thd, const char *host, const char *user,
if (!(table=open_ltable(thd,&tables,TL_WRITE)))
DBUG_RETURN(1); /* purecov: deadcode */
- table->field[0]->store(host,(uint) strlen(host), &my_charset_latin1);
- table->field[1]->store(user,(uint) strlen(user), &my_charset_latin1);
+ table->field[0]->store(host,(uint) strlen(host), system_charset_info);
+ table->field[1]->store(user,(uint) strlen(user), system_charset_info);
table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
if (table->file->index_read_idx(table->record[0],0,
@@ -1478,7 +1478,7 @@ static bool update_user_table(THD *thd, const char *host, const char *user,
DBUG_RETURN(1); /* purecov: deadcode */
}
store_record(table,record[1]);
- table->field[2]->store(new_password, new_password_len, &my_charset_latin1);
+ table->field[2]->store(new_password, new_password_len, system_charset_info);
if ((error=table->file->update_row(table->record[1],table->record[0])))
{
table->file->print_error(error,MYF(0)); /* purecov: deadcode */
@@ -1546,8 +1546,8 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
password=combo.password.str;
}
- table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1);
- table->field[1]->store(combo.user.str,combo.user.length, &my_charset_latin1);
+ table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
+ table->field[1]->store(combo.user.str,combo.user.length, system_charset_info);
table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
if (table->file->index_read_idx(table->record[0], 0,
(byte*) table->field[0]->ptr,
@@ -1581,11 +1581,11 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
old_row_exists = 0;
restore_record(table,default_values); // cp empty row from default_values
table->field[0]->store(combo.host.str,combo.host.length,
- &my_charset_latin1);
+ system_charset_info);
table->field[1]->store(combo.user.str,combo.user.length,
- &my_charset_latin1);
+ system_charset_info);
table->field[2]->store(password, password_len,
- &my_charset_latin1);
+ system_charset_info);
}
else
{
@@ -1596,14 +1596,14 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
DBUG_ASSERT(combo.host.str);
if (thd->user && combo.password.str &&
(strcmp(thd->user,combo.user.str) ||
- my_strcasecmp(&my_charset_latin1,
+ my_strcasecmp(system_charset_info,
combo.host.str, thd->host_or_ip)) &&
check_access(thd, UPDATE_ACL, "mysql",0,1,0))
goto end;
old_row_exists = 1;
store_record(table,record[1]); // Save copy for update
if (combo.password.str) // If password given
- table->field[2]->store(password, password_len, &my_charset_latin1);
+ table->field[2]->store(password, password_len, system_charset_info);
else if (!rights && !revoke_grant &&
lex->ssl_type == SSL_TYPE_NOT_SPECIFIED && !lex->mqh.bits)
{
@@ -1648,13 +1648,13 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
table->field[27]->store("", 0, &my_charset_latin1);
if (lex->ssl_cipher)
table->field[25]->store(lex->ssl_cipher,
- strlen(lex->ssl_cipher), &my_charset_latin1);
+ strlen(lex->ssl_cipher), system_charset_info);
if (lex->x509_issuer)
table->field[26]->store(lex->x509_issuer,
- strlen(lex->x509_issuer), &my_charset_latin1);
+ strlen(lex->x509_issuer), system_charset_info);
if (lex->x509_subject)
table->field[27]->store(lex->x509_subject,
- strlen(lex->x509_subject), &my_charset_latin1);
+ strlen(lex->x509_subject), system_charset_info);
break;
case SSL_TYPE_NOT_SPECIFIED:
break;
@@ -1756,9 +1756,9 @@ static int replace_db_table(TABLE *table, const char *db,
DBUG_RETURN(-1);
}
- table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1);
- table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1);
- table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
+ table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
+ table->field[1]->store(db,(uint) strlen(db), system_charset_info);
+ table->field[2]->store(combo.user.str,combo.user.length, system_charset_info);
table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
if (table->file->index_read_idx(table->record[0],0,
(byte*) table->field[0]->ptr,
@@ -1772,9 +1772,9 @@ static int replace_db_table(TABLE *table, const char *db,
}
old_row_exists = 0;
restore_record(table,default_values); // cp empty row from default_values
- table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1);
- table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1);
- table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
+ table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
+ table->field[1]->store(db,(uint) strlen(db), system_charset_info);
+ table->field[2]->store(combo.user.str,combo.user.length, system_charset_info);
}
else
{
@@ -1862,6 +1862,7 @@ public:
GRANT_TABLE(const char *h, const char *d,const char *u,
const char *t, ulong p, ulong c);
GRANT_TABLE (TABLE *form, TABLE *col_privs);
+ ~GRANT_TABLE();
bool ok() { return privs != 0 || cols != 0; }
};
@@ -1887,7 +1888,7 @@ GRANT_TABLE::GRANT_TABLE(const char *h, const char *d,const char *u,
key_length =(uint) strlen(d)+(uint) strlen(u)+(uint) strlen(t)+3;
hash_key = (char*) alloc_root(&memex,key_length);
strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
- (void) hash_init(&hash_columns,&my_charset_latin1,
+ (void) hash_init(&hash_columns,system_charset_info,
0,0,0, (hash_get_key) get_key_column,0,0);
}
@@ -1911,7 +1912,8 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
if (!db || !tname)
{
/* Wrong table row; Ignore it */
- privs = cols = 0; /* purecov: inspected */
+ hash_clear(&hash_columns); /* allow for destruction */
+ privs= cols= 0; /* purecov: inspected */
return; /* purecov: inspected */
}
if (lower_case_table_names)
@@ -1928,16 +1930,16 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
privs = fix_rights_for_table(privs);
cols = fix_rights_for_column(cols);
- (void) hash_init(&hash_columns,&my_charset_latin1,
+ (void) hash_init(&hash_columns,system_charset_info,
0,0,0, (hash_get_key) get_key_column,0,0);
if (cols)
{
int key_len;
col_privs->field[0]->store(orig_host,(uint) strlen(orig_host),
- &my_charset_latin1);
- col_privs->field[1]->store(db,(uint) strlen(db), &my_charset_latin1);
- col_privs->field[2]->store(user,(uint) strlen(user), &my_charset_latin1);
- col_privs->field[3]->store(tname,(uint) strlen(tname), &my_charset_latin1);
+ system_charset_info);
+ col_privs->field[1]->store(db,(uint) strlen(db), system_charset_info);
+ col_privs->field[2]->store(user,(uint) strlen(user), system_charset_info);
+ col_privs->field[3]->store(tname,(uint) strlen(tname), system_charset_info);
key_len=(col_privs->field[0]->pack_length()+
col_privs->field[1]->pack_length()+
col_privs->field[2]->pack_length()+
@@ -1975,6 +1977,12 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
}
+GRANT_TABLE::~GRANT_TABLE()
+{
+ hash_free(&hash_columns);
+}
+
+
static byte* get_grant_table(GRANT_TABLE *buff,uint *length,
my_bool not_used __attribute__((unused)))
{
@@ -2011,15 +2019,15 @@ static GRANT_TABLE *table_hash_search(const char *host,const char* ip,
if (exact)
{
if ((host &&
- !my_strcasecmp(&my_charset_latin1, host, grant_table->host)) ||
+ !my_strcasecmp(system_charset_info, host, grant_table->host)) ||
(ip && !strcmp(ip,grant_table->host)))
return grant_table;
}
else
{
- if (((host && !wild_case_compare(&my_charset_latin1,
+ if (((host && !wild_case_compare(system_charset_info,
host,grant_table->host)) ||
- (ip && !wild_case_compare(&my_charset_latin1,
+ (ip && !wild_case_compare(system_charset_info,
ip,grant_table->host))) &&
(!found || found->sort < grant_table->sort))
found=grant_table; // Host ok
@@ -2048,10 +2056,10 @@ static int replace_column_table(GRANT_TABLE *g_t,
byte key[MAX_KEY_LENGTH];
DBUG_ENTER("replace_column_table");
- table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1);
- table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1);
- table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
- table->field[3]->store(table_name,(uint) strlen(table_name), &my_charset_latin1);
+ table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
+ table->field[1]->store(db,(uint) strlen(db), system_charset_info);
+ table->field[2]->store(combo.user.str,combo.user.length, system_charset_info);
+ table->field[3]->store(table_name,(uint) strlen(table_name), system_charset_info);
key_length=(table->field[0]->pack_length()+ table->field[1]->pack_length()+
table->field[2]->pack_length()+ table->field[3]->pack_length());
key_copy(key,table->record[0],table->key_info,key_length);
@@ -2069,7 +2077,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
bool old_row_exists=0;
key_restore(table->record[0],key,table->key_info,key_length);
table->field[4]->store(xx->column.ptr(),xx->column.length(),
- &my_charset_latin1);
+ system_charset_info);
table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
if (table->file->index_read(table->record[0],(byte*) table->field[0]->ptr,
@@ -2088,7 +2096,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
restore_record(table,default_values); // Get empty record
key_restore(table->record[0],key,table->key_info,key_length);
table->field[4]->store(xx->column.ptr(),xx->column.length(),
- &my_charset_latin1);
+ system_charset_info);
}
else
{
@@ -2160,7 +2168,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
{
GRANT_COLUMN *grant_column = NULL;
char colum_name_buf[HOSTNAME_LENGTH+1];
- String column_name(colum_name_buf,sizeof(colum_name_buf),&my_charset_latin1);
+ String column_name(colum_name_buf,sizeof(colum_name_buf),system_charset_info);
privileges&= ~rights;
table->field[6]->store((longlong)
@@ -2231,10 +2239,10 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
}
restore_record(table,default_values); // Get empty record
- table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1);
- table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1);
- table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
- table->field[3]->store(table_name,(uint) strlen(table_name), &my_charset_latin1);
+ table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
+ table->field[1]->store(db,(uint) strlen(db), system_charset_info);
+ table->field[2]->store(combo.user.str,combo.user.length, system_charset_info);
+ table->field[3]->store(table_name,(uint) strlen(table_name), system_charset_info);
store_record(table,record[1]); // store at pos 1
table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
if (table->file->index_read_idx(table->record[0],0,
@@ -2279,7 +2287,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
}
}
- table->field[4]->store(grantor,(uint) strlen(grantor), &my_charset_latin1);
+ table->field[4]->store(grantor,(uint) strlen(grantor), system_charset_info);
table->field[6]->store((longlong) store_table_rights);
table->field[7]->store((longlong) store_col_rights);
rights=fix_rights_for_table(store_table_rights);
@@ -2694,7 +2702,7 @@ my_bool grant_init(THD *org_thd)
DBUG_ENTER("grant_init");
grant_option = FALSE;
- (void) hash_init(&column_priv_hash,&my_charset_latin1,
+ (void) hash_init(&column_priv_hash,system_charset_info,
0,0,0, (hash_get_key) get_grant_table,
(hash_free_key) free_grant_table,0);
init_sql_alloc(&memex, ACL_ALLOC_BLOCK_SIZE, 0);
@@ -2759,8 +2767,11 @@ my_bool grant_init(THD *org_thd)
}
}
- if (mem_check->ok() && my_hash_insert(&column_priv_hash,(byte*) mem_check))
+ if (! mem_check->ok())
+ delete mem_check;
+ else if (my_hash_insert(&column_priv_hash,(byte*) mem_check))
{
+ delete mem_check;
grant_option= FALSE;
goto end_unlock;
}
@@ -3077,9 +3088,9 @@ bool check_grant_db(THD *thd,const char *db)
idx);
if (len < grant_table->key_length &&
!memcmp(grant_table->hash_key,helping,len) &&
- (thd->host && !wild_case_compare(&my_charset_latin1,
+ (thd->host && !wild_case_compare(system_charset_info,
thd->host,grant_table->host) ||
- (thd->ip && !wild_case_compare(&my_charset_latin1,
+ (thd->ip && !wild_case_compare(system_charset_info,
thd->ip,grant_table->host))))
{
error=0; // Found match
@@ -3230,7 +3241,7 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
if (!(host=acl_user->host.hostname))
host= "";
if (!strcmp(lex_user->user.str,user) &&
- !my_strcasecmp(&my_charset_latin1, lex_user->host.str, host))
+ !my_strcasecmp(system_charset_info, lex_user->host.str, host))
break;
}
if (counter == acl_users.elements)
@@ -3284,7 +3295,8 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
global.append(lex_user->user.str, lex_user->user.length,
system_charset_info);
global.append ("'@'",3);
- global.append(lex_user->host.str,lex_user->host.length);
+ global.append(lex_user->host.str,lex_user->host.length,
+ system_charset_info);
global.append ('\'');
if (acl_user->salt_len)
{
@@ -3318,7 +3330,8 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
if (ssl_options++)
global.append(' ');
global.append("SUBJECT \'",9);
- global.append(acl_user->x509_subject,strlen(acl_user->x509_subject));
+ global.append(acl_user->x509_subject,strlen(acl_user->x509_subject),
+ system_charset_info);
global.append('\'');
}
if (acl_user->ssl_cipher)
@@ -3326,7 +3339,8 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
if (ssl_options++)
global.append(' ');
global.append("CIPHER '",8);
- global.append(acl_user->ssl_cipher,strlen(acl_user->ssl_cipher));
+ global.append(acl_user->ssl_cipher,strlen(acl_user->ssl_cipher),
+ system_charset_info);
global.append('\'');
}
}
@@ -3365,7 +3379,7 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
host= "";
if (!strcmp(lex_user->user.str,user) &&
- !my_strcasecmp(&my_charset_latin1, lex_user->host.str, host))
+ !my_strcasecmp(system_charset_info, lex_user->host.str, host))
{
want_access=acl_db->access;
if (want_access)
@@ -3399,7 +3413,8 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
db.append(lex_user->user.str, lex_user->user.length,
system_charset_info);
db.append ("'@'",3);
- db.append(lex_user->host.str, lex_user->host.length);
+ db.append(lex_user->host.str, lex_user->host.length,
+ system_charset_info);
db.append ('\'');
if (want_access & GRANT_ACL)
db.append(" WITH GRANT OPTION",18);
@@ -3425,7 +3440,7 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
user= "";
if (!strcmp(lex_user->user.str,user) &&
- !my_strcasecmp(&my_charset_latin1, lex_user->host.str,
+ !my_strcasecmp(system_charset_info, lex_user->host.str,
grant_table->orig_host))
{
ulong table_access= grant_table->privs;
@@ -3505,7 +3520,8 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
global.append(lex_user->user.str, lex_user->user.length,
system_charset_info);
global.append("'@'",3);
- global.append(lex_user->host.str,lex_user->host.length);
+ global.append(lex_user->host.str,lex_user->host.length,
+ system_charset_info);
global.append('\'');
if (table_access & GRANT_ACL)
global.append(" WITH GRANT OPTION",18);
@@ -3565,6 +3581,27 @@ void get_mqh(const char *user, const char *host, USER_CONN *uc)
bzero((char*) &uc->user_resources, sizeof(uc->user_resources));
}
+/*
+ Open the grant tables.
+
+ SYNOPSIS
+ open_grant_tables()
+ thd The current thread.
+ tables (out) The 4 elements array for the opened tables.
+
+ DESCRIPTION
+ Tables are numbered as follows:
+ 0 user
+ 1 db
+ 2 tables_priv
+ 3 columns_priv
+
+ RETURN
+ 1 Skip GRANT handling during replication.
+ 0 OK.
+ < 0 Error.
+*/
+
int open_grant_tables(THD *thd, TABLE_LIST *tables)
{
DBUG_ENTER("open_grant_tables");
@@ -3640,111 +3677,641 @@ ACL_USER *check_acl_user(LEX_USER *user_name,
}
-bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
+/*
+ Modify a privilege table.
+
+ SYNOPSIS
+ modify_grant_table()
+ table The table to modify.
+ host_field The host name field.
+ user_field The user name field.
+ user_to The new name for the user if to be renamed,
+ NULL otherwise.
+
+ DESCRIPTION
+ Update user/host in the current record if user_to is not NULL.
+ Delete the current record if user_to is NULL.
+
+ RETURN
+ 0 OK.
+ != 0 Error.
+*/
+
+static int modify_grant_table(TABLE *table, Field *host_field,
+ Field *user_field, LEX_USER *user_to)
{
- uint counter, acl_userd;
- int result;
- ACL_USER *acl_user;
- ACL_DB *acl_db;
- TABLE_LIST tables[4];
+ int error;
+ DBUG_ENTER("modify_grant_table");
- DBUG_ENTER("mysql_drop_user");
+ if (user_to)
+ {
+ /* rename */
+ store_record(table, record[1]);
+ host_field->store(user_to->host.str, user_to->host.length,
+ system_charset_info);
+ user_field->store(user_to->user.str, user_to->user.length,
+ system_charset_info);
+ if ((error= table->file->update_row(table->record[1], table->record[0])))
+ table->file->print_error(error, MYF(0));
+ }
+ else
+ {
+ /* delete */
+ if ((error=table->file->delete_row(table->record[0])))
+ table->file->print_error(error, MYF(0));
+ }
- if ((result= open_grant_tables(thd, tables)))
- DBUG_RETURN(result != 1);
+ DBUG_RETURN(error);
+}
- rw_wrlock(&LOCK_grant);
- VOID(pthread_mutex_lock(&acl_cache->lock));
- LEX_USER *user_name;
- List_iterator <LEX_USER> user_list(list);
- while ((user_name=user_list++))
+/*
+ Handle a privilege table.
+
+ SYNOPSIS
+ handle_grant_table()
+ tables The array with the four open tables.
+ table_no The number of the table to handle (0..3).
+ drop If user_from is to be dropped.
+ user_from The the user to be searched/dropped/renamed.
+ user_to The new name for the user if to be renamed,
+ NULL otherwise.
+
+ DESCRIPTION
+ Scan through all records in a grant table and apply the requested
+ operation. For the "user" table, a single index access is sufficient,
+ since there is an unique index on (host, user).
+ Delete from grant table if drop is true.
+ Update in grant table if drop is false and user_to is not NULL.
+ Search in grant table if drop is false and user_to is NULL.
+ Tables are numbered as follows:
+ 0 user
+ 1 db
+ 2 tables_priv
+ 3 columns_priv
+
+ RETURN
+ > 0 At least one record matched.
+ 0 OK, but no record matched.
+ < 0 Error.
+*/
+
+static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
+ LEX_USER *user_from, LEX_USER *user_to)
+{
+ int result= 0;
+ int error;
+ TABLE *table= tables[table_no].table;
+ Field *host_field= table->field[0];
+ Field *user_field= table->field[table_no ? 2 : 1];
+ char *host_str= user_from->host.str;
+ char *user_str= user_from->user.str;
+ const char *host;
+ const char *user;
+ DBUG_ENTER("handle_grant_table");
+
+ if (! table_no)
{
- if (!(acl_user= check_acl_user(user_name, &counter)))
+ /*
+ The 'user' table has an unique index on (host, user).
+ Thus, we can handle everything with a single index access.
+ The host- and user fields are consecutive in the user table records.
+ So we set host- and user fields of table->record[0] and use the
+ pointer to the host field as key.
+ index_read_idx() will replace table->record[0] (its first argument)
+ by the searched record, if it exists.
+ */
+ DBUG_PRINT("info",("read table: '%s' search: '%s'@'%s'",
+ table->real_name, user_str, host_str));
+ host_field->store(host_str, user_from->host.length, system_charset_info);
+ user_field->store(user_str, user_from->user.length, system_charset_info);
+ if ((error= table->file->index_read_idx(table->record[0], 0,
+ (byte*) host_field->ptr, 0,
+ HA_READ_KEY_EXACT)))
{
- sql_print_error("DROP USER: Can't drop user: '%s'@'%s'; No such user",
- user_name->user.str,
- user_name->host.str);
- result= -1;
- continue;
+ if (error != HA_ERR_KEY_NOT_FOUND)
+ {
+ table->file->print_error(error, MYF(0));
+ result= -1;
+ }
}
- if ((acl_user->access & ~0))
+ else
{
- sql_print_error("DROP USER: Can't drop user: '%s'@'%s'; Global privileges exists",
- user_name->user.str,
- user_name->host.str);
+ /* If requested, delete or update the record. */
+ result= ((drop || user_to) &&
+ modify_grant_table(table, host_field, user_field, user_to)) ?
+ -1 : 1; /* Error or found. */
+ }
+ DBUG_PRINT("info",("read result: %d", result));
+ }
+ else
+ {
+ /*
+ The non-'user' table do not have indexes on (host, user).
+ And their host- and user fields are not consecutive.
+ Thus, we need to do a table scan to find all matching records.
+ */
+ if ((error= table->file->ha_rnd_init(1)))
+ {
+ table->file->print_error(error, MYF(0));
result= -1;
+ }
+ else
+ {
+#ifdef EXTRA_DEBUG
+ DBUG_PRINT("info",("scan table: '%s' search: '%s'@'%s'",
+ table->real_name, user_str, host_str));
+#endif
+ while ((error= table->file->rnd_next(table->record[0])) !=
+ HA_ERR_END_OF_FILE)
+ {
+ if (error)
+ {
+ /* Most probable 'deleted record'. */
+ DBUG_PRINT("info",("scan error: %d", error));
+ continue;
+ }
+ if (! (host= get_field(&mem, host_field)))
+ host= "";
+ if (! (user= get_field(&mem, user_field)))
+ user= "";
+
+#ifdef EXTRA_DEBUG
+ DBUG_PRINT("loop",("scan fields: '%s'@'%s' '%s' '%s' '%s'",
+ user, host,
+ get_field(&mem, table->field[1]) /*db*/,
+ get_field(&mem, table->field[3]) /*table*/,
+ get_field(&mem, table->field[4]) /*column*/));
+#endif
+ if (strcmp(user_str, user) ||
+ my_strcasecmp(system_charset_info, host_str, host))
+ continue;
+
+ /* If requested, delete or update the record. */
+ result= ((drop || user_to) &&
+ modify_grant_table(table, host_field, user_field, user_to)) ?
+ -1 : result ? result : 1; /* Error or keep result or found. */
+ /* If search is requested, we do not need to search further. */
+ if (! drop && ! user_to)
+ break ;
+ }
+ (void) table->file->ha_rnd_end();
+ DBUG_PRINT("info",("scan result: %d", result));
+ }
+ }
+
+ DBUG_RETURN(result);
+}
+
+
+/*
+ Handle an in-memory privilege structure.
+
+ SYNOPSIS
+ handle_grant_struct()
+ struct_no The number of the structure to handle (0..2).
+ drop If user_from is to be dropped.
+ user_from The the user to be searched/dropped/renamed.
+ user_to The new name for the user if to be renamed,
+ NULL otherwise.
+
+ DESCRIPTION
+ Scan through all elements in an in-memory grant structure and apply
+ the requested operation.
+ Delete from grant structure if drop is true.
+ Update in grant structure if drop is false and user_to is not NULL.
+ Search in grant structure if drop is false and user_to is NULL.
+ Structures are numbered as follows:
+ 0 acl_users
+ 1 acl_dbs
+ 2 column_priv_hash
+
+ RETURN
+ > 0 At least one element matched.
+ 0 OK, but no element matched.
+*/
+
+static int handle_grant_struct(uint struct_no, bool drop,
+ LEX_USER *user_from, LEX_USER *user_to)
+{
+ int result= 0;
+ uint idx;
+ uint elements;
+ const char *user;
+ const char *host;
+ ACL_USER *acl_user;
+ ACL_DB *acl_db;
+ GRANT_TABLE *grant_table;
+ DBUG_ENTER("handle_grant_struct");
+ LINT_INIT(acl_user);
+ LINT_INIT(acl_db);
+ LINT_INIT(grant_table);
+ DBUG_PRINT("info",("scan struct: %u search: '%s'@'%s'",
+ struct_no, user_from->user.str, user_from->host.str));
+
+ /* Get the number of elements in the in-memory structure. */
+ switch (struct_no)
+ {
+ case 0:
+ elements= acl_users.elements;
+ break;
+ case 1:
+ elements= acl_dbs.elements;
+ break;
+ default:
+ elements= column_priv_hash.records;
+ }
+
+#ifdef EXTRA_DEBUG
+ DBUG_PRINT("loop",("scan struct: %u search user: '%s' host: '%s'",
+ struct_no, user_from->user.str, user_from->host.str));
+#endif
+ /* Loop over all elements. */
+ for (idx= 0; idx < elements; idx++)
+ {
+ /*
+ Get a pointer to the element.
+ Unfortunaltely, the host default differs for the structures.
+ */
+ switch (struct_no)
+ {
+ case 0:
+ acl_user= dynamic_element(&acl_users, idx, ACL_USER*);
+ user= acl_user->user;
+ if (!(host= acl_user->host.hostname))
+ host= "%";
+ break;
+
+ case 1:
+ acl_db= dynamic_element(&acl_dbs, idx, ACL_DB*);
+ user= acl_db->user;
+ host= acl_db->host.hostname;
+ break;
+
+ default:
+ grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash, idx);
+ user= grant_table->user;
+ host= grant_table->host;
+ }
+ if (! user)
+ user= "";
+ if (! host)
+ host= "";
+#ifdef EXTRA_DEBUG
+ DBUG_PRINT("loop",("scan struct: %u index: %u user: '%s' host: '%s'",
+ struct_no, idx, user, host));
+#endif
+ if (strcmp(user_from->user.str, user) ||
+ my_strcasecmp(system_charset_info, user_from->host.str, host))
continue;
+
+ result= 1; /* At least one element found. */
+ if ( drop )
+ {
+ switch ( struct_no )
+ {
+ case 0:
+ delete_dynamic_element(&acl_users, idx);
+ break;
+
+ case 1:
+ delete_dynamic_element(&acl_dbs, idx);
+ break;
+
+ default:
+ hash_delete(&column_priv_hash, (byte*) grant_table);
+ }
+ elements--;
+ idx--;
}
- acl_userd= counter;
+ else if ( user_to )
+ {
+ switch ( struct_no )
+ {
+ case 0:
+ acl_user->user= strdup_root(&mem, user_to->user.str);
+ acl_user->host.hostname= strdup_root(&mem, user_to->host.str);
+ break;
+
+ case 1:
+ acl_db->user= strdup_root(&mem, user_to->user.str);
+ acl_db->host.hostname= strdup_root(&mem, user_to->host.str);
+ break;
- for (counter= 0 ; counter < acl_dbs.elements ; counter++)
+ default:
+ grant_table->user= strdup_root(&mem, user_to->user.str);
+ grant_table->host= strdup_root(&mem, user_to->host.str);
+ }
+ }
+ else
{
- const char *user,*host;
- acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
- if (!(user= acl_db->user))
- user= "";
- if (!(host= acl_db->host.hostname))
- host= "";
-
- if (!strcmp(user_name->user.str,user) &&
- !my_strcasecmp(system_charset_info, user_name->host.str, host))
- break;
+ /* If search is requested, we do not need to search further. */
+ break;
+ }
+ }
+#ifdef EXTRA_DEBUG
+ DBUG_PRINT("loop",("scan struct: %u result %d", struct_no, result));
+#endif
+
+ DBUG_RETURN(result);
+}
+
+
+/*
+ Handle all privilege tables and in-memory privilege structures.
+
+ SYNOPSIS
+ handle_grant_data()
+ tables The array with the four open tables.
+ drop If user_from is to be dropped.
+ user_from The the user to be searched/dropped/renamed.
+ user_to The new name for the user if to be renamed,
+ NULL otherwise.
+
+ DESCRIPTION
+ Go through all grant tables and in-memory grant structures and apply
+ the requested operation.
+ Delete from grant data if drop is true.
+ Update in grant data if drop is false and user_to is not NULL.
+ Search in grant data if drop is false and user_to is NULL.
+
+ RETURN
+ > 0 At least one element matched.
+ 0 OK, but no element matched.
+ < 0 Error.
+*/
+
+static int handle_grant_data(TABLE_LIST *tables, bool drop,
+ LEX_USER *user_from, LEX_USER *user_to)
+{
+ int result= 0;
+ int found;
+ DBUG_ENTER("handle_grant_data");
+
+ /* Handle user table. */
+ if ((found= handle_grant_table(tables, 0, drop, user_from, user_to)) < 0)
+ {
+ /* Handle of table failed, don't touch the in-memory array. */
+ result= -1;
+ }
+ else
+ {
+ /* Handle user array. */
+ if ((handle_grant_struct(0, drop, user_from, user_to) && ! result) || found)
+ {
+ result= 1; /* At least one record/element found. */
+ /* If search is requested, we do not need to search further. */
+ if (! drop && ! user_to)
+ goto end;
}
- if (counter != acl_dbs.elements)
+ }
+
+ /* Handle db table. */
+ if ((found= handle_grant_table(tables, 1, drop, user_from, user_to)) < 0)
+ {
+ /* Handle of table failed, don't touch the in-memory array. */
+ result= -1;
+ }
+ else
+ {
+ /* Handle db array. */
+ if (((handle_grant_struct(1, drop, user_from, user_to) && ! result) ||
+ found) && ! result)
{
- sql_print_error("DROP USER: Can't drop user: '%s'@'%s'; Database privileges exists",
- user_name->user.str,
- user_name->host.str);
- result= -1;
- continue;
+ result= 1; /* At least one record/element found. */
+ /* If search is requested, we do not need to search further. */
+ if (! drop && ! user_to)
+ goto end;
}
+ }
- for (counter= 0 ; counter < column_priv_hash.records ; counter++)
+ /* Handle tables table. */
+ if ((found= handle_grant_table(tables, 2, drop, user_from, user_to)) < 0)
+ {
+ /* Handle of table failed, don't touch columns and in-memory array. */
+ result= -1;
+ }
+ else
+ {
+ if (found && ! result)
{
- const char *user,*host;
- GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash,
- counter);
- if (!(user=grant_table->user))
- user= "";
- if (!(host=grant_table->host))
- host= "";
-
- if (!strcmp(user_name->user.str,user) &&
- !my_strcasecmp(system_charset_info, user_name->host.str, host))
- break;
+ result= 1; /* At least one record found. */
+ /* If search is requested, we do not need to search further. */
+ if (! drop && ! user_to)
+ goto end;
}
- if (counter != column_priv_hash.records)
+
+ /* Handle columns table. */
+ if ((found= handle_grant_table(tables, 3, drop, user_from, user_to)) < 0)
{
- sql_print_error("DROP USER: Can't drop user: '%s'@'%s'; Table privileges exists",
- user_name->user.str,
- user_name->host.str);
+ /* Handle of table failed, don't touch the in-memory array. */
result= -1;
- continue;
}
+ else
+ {
+ /* Handle columns hash. */
+ if (((handle_grant_struct(2, drop, user_from, user_to) && ! result) ||
+ found) && ! result)
+ result= 1; /* At least one record/element found. */
+ }
+ }
+ end:
+ DBUG_RETURN(result);
+}
+
+
+/*
+ Create a list of users.
+
+ SYNOPSIS
+ mysql_create_user()
+ thd The current thread.
+ list The users to create.
+
+ RETURN
+ FALSE OK.
+ TRUE Error.
+*/
+
+bool mysql_create_user(THD *thd, List <LEX_USER> &list)
+{
+ int result;
+ int found;
+ uint failures;
+ ulong sql_mode;
+ LEX_USER *user_name;
+ List_iterator <LEX_USER> user_list(list);
+ TABLE_LIST tables[4];
+ DBUG_ENTER("mysql_create_user");
+
+ /* CREATE USER may be skipped on replication client. */
+ if ((result= open_grant_tables(thd, tables)))
+ DBUG_RETURN(result != 1);
+
+ rw_wrlock(&LOCK_grant);
+ VOID(pthread_mutex_lock(&acl_cache->lock));
+
+ failures= 0;
+ while ((user_name= user_list++))
+ {
+ /*
+ Search all in-memory structures and grant tables
+ for a mention of the new user name.
+ */
+ if ((found= handle_grant_data(tables, 0, user_name, NULL)))
+ {
+ if (found > 0)
+ sql_print_error("CREATE USER: Cannot create user: '%s'@'%s': "
+ "User exists",
+ user_name->user.str,
+ user_name->host.str);
+ failures++;
+ result= TRUE;
+ }
+
+ sql_mode= thd->variables.sql_mode;
+ thd->variables.sql_mode&= ~MODE_NO_AUTO_CREATE_USER;
+ if (replace_user_table(thd, tables[0].table, *user_name, 0, 0, 1))
+ {
+ failures++;
+ result= TRUE;
+ }
+ thd->variables.sql_mode= sql_mode;
+ }
+
+ VOID(pthread_mutex_unlock(&acl_cache->lock));
+ rw_unlock(&LOCK_grant);
+ close_thread_tables(thd);
+ if (result)
+ my_error(ER_HANDLE_USER, MYF(0), "CREATE USER" , failures );
+ DBUG_RETURN(result);
+}
+
+
+/*
+ Drop a list of users and all their privileges.
+
+ SYNOPSIS
+ mysql_drop_user()
+ thd The current thread.
+ list The users to drop.
+
+ RETURN
+ FALSE OK.
+ TRUE Error.
+*/
+
+bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
+{
+ int result;
+ int found;
+ uint failures;
+ LEX_USER *user_name;
+ List_iterator <LEX_USER> user_list(list);
+ TABLE_LIST tables[4];
+ DBUG_ENTER("mysql_drop_user");
+
+ /* CREATE USER may be skipped on replication client. */
+ if ((result= open_grant_tables(thd, tables)))
+ DBUG_RETURN(result != 1);
+
+ rw_wrlock(&LOCK_grant);
+ VOID(pthread_mutex_lock(&acl_cache->lock));
+
+ failures= 0;
+ while ((user_name= user_list++))
+ {
+ if ((found= handle_grant_data(tables, 1, user_name, NULL)) < 0)
+ {
+ failures++;
+ result= TRUE;
+ }
+ else if (! found)
+ {
+ sql_print_error("DROP USER: Cannot drop user '%s'@'%s': "
+ "No such user",
+ user_name->user.str,
+ user_name->host.str);
+ failures++;
+ result= TRUE;
+ }
+ }
+
+ VOID(pthread_mutex_unlock(&acl_cache->lock));
+ rw_unlock(&LOCK_grant);
+ close_thread_tables(thd);
+ if (result)
+ my_error(ER_HANDLE_USER, MYF(0), "DROP USER" , failures );
+ DBUG_RETURN(result);
+}
+
- tables[0].table->field[0]->store(user_name->host.str,(uint)
- user_name->host.length,
- system_charset_info);
- tables[0].table->field[1]->store(user_name->user.str,(uint)
- user_name->user.length,
- system_charset_info);
- tables[0].table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
- if (!tables[0].table->file->index_read_idx(tables[0].table->record[0],0,
- (byte*) tables[0].table->
- field[0]->ptr,
- tables[0].table->
- key_info[0].key_length,
- HA_READ_KEY_EXACT))
+/*
+ Rename a user.
+
+ SYNOPSIS
+ mysql_rename_user()
+ thd The current thread.
+ list The user name pairs: (from, to).
+
+ RETURN
+ FALSE OK.
+ TRUE Error.
+*/
+
+bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
+{
+ int result= 0;
+ int found;
+ uint failures;
+ LEX_USER *user_from;
+ LEX_USER *user_to;
+ List_iterator <LEX_USER> user_list(list);
+ TABLE_LIST tables[4];
+ DBUG_ENTER("mysql_rename_user");
+
+ /* CREATE USER may be skipped on replication client. */
+ if ((result= open_grant_tables(thd, tables)))
+ DBUG_RETURN(result != 1);
+
+ rw_wrlock(&LOCK_grant);
+ VOID(pthread_mutex_lock(&acl_cache->lock));
+
+ failures= 0;
+ while ((user_from= user_list++))
+ {
+ user_to= user_list++;
+ DBUG_ASSERT((user_to)); /* Syntax enforces pairs of users. */
+
+ /*
+ Search all in-memory structures and grant tables
+ for a mention of the new user name.
+ */
+ if ((found= handle_grant_data(tables, 0, user_to, NULL)))
{
- int error;
- if ((error = tables[0].table->file->delete_row(tables[0].table->
- record[0])))
+ if (found > 0)
+ sql_print_error("RENAME USER: Cannot rename to: '%s'@'%s': User exists",
+ user_to->user.str,
+ user_to->host.str);
+ failures++;
+ result= TRUE;
+ }
+ else
+ {
+ if ((found= handle_grant_data(tables, 0, user_from, user_to)) < 0)
{
- tables[0].table->file->print_error(error, MYF(0));
- DBUG_RETURN(TRUE);
+ failures++;
+ result= TRUE;
+ }
+ else if (! found)
+ {
+ sql_print_error("RENAME USER: Cannot rename user: '%s'@'%s': "
+ "No such user",
+ user_from->user.str,
+ user_from->host.str);
+ failures++;
+ result= TRUE;
}
- delete_dynamic_element(&acl_users, acl_userd);
}
}
@@ -3752,10 +4319,24 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
rw_unlock(&LOCK_grant);
close_thread_tables(thd);
if (result)
- my_message(ER_DROP_USER, ER(ER_DROP_USER), MYF(0));
+ my_error(ER_HANDLE_USER, MYF(0), "RENAME USER", failures);
DBUG_RETURN(result);
}
+/*
+ Revoke all privileges from a list of users.
+
+ SYNOPSIS
+ mysql_revoke_all()
+ thd The current thread.
+ list The users to revoke all privileges from.
+
+ RETURN
+ > 0 Error. Error message already sent.
+ 0 OK.
+ < 0 Error. Error message not yet sent.
+*/
+
bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
{
uint counter, revoked;
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index f6074da5279..8f3ee072f43 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -182,7 +182,9 @@ ulong get_column_grant(THD *thd, GRANT_INFO *grant,
bool mysql_show_grants(THD *thd, LEX_USER *user);
void get_privilege_desc(char *to, uint max_length, ulong access);
void get_mqh(const char *user, const char *host, USER_CONN *uc);
+bool mysql_create_user(THD *thd, List <LEX_USER> &list);
bool mysql_drop_user(THD *thd, List <LEX_USER> &list);
+bool mysql_rename_user(THD *thd, List <LEX_USER> &list);
bool mysql_revoke_all(THD *thd, List <LEX_USER> &list);
void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
const char *db, const char *table);
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 605204fe35d..e911b0ad4d1 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -78,7 +78,8 @@ enum enum_sql_command {
SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER, SQLCOM_DO,
SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS,
SQLCOM_SHOW_COLUMN_TYPES, SQLCOM_SHOW_STORAGE_ENGINES, SQLCOM_SHOW_PRIVILEGES,
- SQLCOM_HELP, SQLCOM_DROP_USER, SQLCOM_REVOKE_ALL, SQLCOM_CHECKSUM,
+ SQLCOM_HELP, SQLCOM_CREATE_USER, SQLCOM_DROP_USER, SQLCOM_RENAME_USER,
+ SQLCOM_REVOKE_ALL, SQLCOM_CHECKSUM,
SQLCOM_CREATE_PROCEDURE, SQLCOM_CREATE_SPFUNCTION, SQLCOM_CALL,
SQLCOM_DROP_PROCEDURE, SQLCOM_ALTER_PROCEDURE,SQLCOM_ALTER_FUNCTION,
SQLCOM_SHOW_CREATE_PROC, SQLCOM_SHOW_CREATE_FUNC,
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index fce8d294456..2dba134f54e 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -3370,6 +3370,21 @@ create_error:
break;
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ case SQLCOM_CREATE_USER:
+ {
+ if (check_access(thd, GRANT_ACL,"mysql",0,1,0))
+ break;
+ if (!(res= mysql_create_user(thd, lex->users_list)))
+ {
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ mysql_bin_log.write(&qinfo);
+ }
+ send_ok(thd);
+ }
+ break;
+ }
case SQLCOM_DROP_USER:
{
if (check_access(thd, GRANT_ACL,"mysql",0,1,0))
@@ -3378,8 +3393,23 @@ create_error:
{
if (mysql_bin_log.is_open())
{
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
- mysql_bin_log.write(&qinfo);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ mysql_bin_log.write(&qinfo);
+ }
+ send_ok(thd);
+ }
+ break;
+ }
+ case SQLCOM_RENAME_USER:
+ {
+ if (check_access(thd, GRANT_ACL,"mysql",0,1,0))
+ break;
+ if (!(res= mysql_rename_user(thd, lex->users_list)))
+ {
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ mysql_bin_log.write(&qinfo);
}
send_ok(thd);
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index dd9cd4af0f3..8e9b649acc3 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -788,9 +788,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
opt_delete_options opt_delete_option varchar nchar nvarchar
opt_outer table_list table_name opt_option opt_place
opt_attribute opt_attribute_list attribute column_list column_list_id
- opt_column_list grant_privileges opt_table user_list grant_option
- grant_privilege grant_privilege_list
- flush_options flush_option
+ opt_column_list grant_privileges opt_table grant_list grant_option
+ grant_privilege grant_privilege_list user_list rename_list
+ clear_privileges flush_options flush_option
equal optional_braces opt_key_definition key_usage_list2
opt_mi_check_type opt_to mi_check_types normal_join
table_to_table_list table_to_table opt_table_list opt_as
@@ -1287,8 +1287,26 @@ create:
TL_WRITE))
YYABORT;
}
+ | CREATE USER clear_privileges grant_list
+ {
+ Lex->sql_command = SQLCOM_CREATE_USER;
+ }
;
+clear_privileges:
+ /* Nothing */
+ {
+ LEX *lex=Lex;
+ lex->users_list.empty();
+ lex->columns.empty();
+ lex->grant= lex->grant_tot_col= 0;
+ lex->select_lex.db= 0;
+ lex->ssl_type= SSL_TYPE_NOT_SPECIFIED;
+ lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0;
+ bzero((char *)&(lex->mqh),sizeof(lex->mqh));
+ }
+ ;
+
sp_name:
IDENT_sys '.' IDENT_sys
{
@@ -3671,8 +3689,25 @@ rename:
}
table_to_table_list
{}
+ | RENAME USER clear_privileges rename_list
+ {
+ Lex->sql_command = SQLCOM_RENAME_USER;
+ }
;
+rename_list:
+ user TO_SYM user
+ {
+ if (Lex->users_list.push_back($1) || Lex->users_list.push_back($3))
+ YYABORT;
+ }
+ | rename_list ',' user TO_SYM user
+ {
+ if (Lex->users_list.push_back($3) || Lex->users_list.push_back($5))
+ YYABORT;
+ }
+ ;
+
table_to_table_list:
table_to_table
| table_to_table_list ',' table_to_table;
@@ -5479,14 +5514,10 @@ drop:
lex->drop_if_exists= $3;
lex->spname= $4;
}
- | DROP USER
+ | DROP USER clear_privileges user_list
{
- LEX *lex=Lex;
- lex->sql_command = SQLCOM_DROP_USER;
- lex->users_list.empty();
- }
- user_list
- {}
+ Lex->sql_command = SQLCOM_DROP_USER;
+ }
| DROP VIEW_SYM if_exists table_list opt_restrict
{
THD *thd= YYTHD;
@@ -7478,48 +7509,28 @@ handler_rkey_mode:
/* GRANT / REVOKE */
revoke:
- REVOKE
- {
- LEX *lex=Lex;
- lex->sql_command = SQLCOM_REVOKE;
- lex->users_list.empty();
- lex->columns.empty();
- lex->grant= lex->grant_tot_col=0;
- lex->select_lex.db=0;
- lex->ssl_type= SSL_TYPE_NOT_SPECIFIED;
- lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0;
- bzero((char*) &lex->mqh, sizeof(lex->mqh));
- }
- revoke_command
+ REVOKE clear_privileges revoke_command
{}
;
revoke_command:
- grant_privileges ON opt_table FROM user_list
- {}
+ grant_privileges ON opt_table FROM grant_list
+ {
+ Lex->sql_command = SQLCOM_REVOKE;
+ }
|
- ALL opt_privileges ',' GRANT OPTION FROM user_list
+ ALL opt_privileges ',' GRANT OPTION FROM grant_list
{
Lex->sql_command = SQLCOM_REVOKE_ALL;
}
;
grant:
- GRANT
- {
- LEX *lex=Lex;
- lex->users_list.empty();
- lex->columns.empty();
- lex->sql_command = SQLCOM_GRANT;
- lex->grant= lex->grant_tot_col= 0;
- lex->select_lex.db= 0;
- lex->ssl_type= SSL_TYPE_NOT_SPECIFIED;
- lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0;
- bzero((char *)&(lex->mqh),sizeof(lex->mqh));
- }
- grant_privileges ON opt_table TO_SYM user_list
+ GRANT clear_privileges grant_privileges ON opt_table TO_SYM grant_list
require_clause grant_options
- {}
+ {
+ Lex->sql_command = SQLCOM_GRANT;
+ }
;
grant_privileges:
@@ -7659,8 +7670,18 @@ opt_table:
user_list:
+ user { if (Lex->users_list.push_back($1)) YYABORT;}
+ | user_list ',' user
+ {
+ if (Lex->users_list.push_back($3))
+ YYABORT;
+ }
+ ;
+
+
+grant_list:
grant_user { if (Lex->users_list.push_back($1)) YYABORT;}
- | user_list ',' grant_user
+ | grant_list ',' grant_user
{
if (Lex->users_list.push_back($3))
YYABORT;