Skip to content

Commit cb608f0

Browse files
committed
Bug #21807286: "CREATE USER IF NOT EXISTS" REPORTS AN ERROR
CREATE|ALTER IF [NOT] EXISTS ... IDENTIFIED BY ... was failing if the user existed(not existed for alter) and raw error log was off due to considerations of wrong binlogging in that case. Converted this to a warning (regardless of the raw log option) because this is how it operates without the IDENTIFIED BY option. Logging IDENTIFIED BY is safe, since it's converted on the fly to IDENTIFIED WITH (hence is not revealing the password). Also made sure that the warning for a user is not counted towards the number of users successfully processed by CREATE USER. Also made sure that the IDENTIFIED clauses are handled properly when binlogged. Added test case and updated the existing tests to cover the change. Now logging of all user operations involving credentials that are a no-op on the master is inhibited.
1 parent d3d412b commit cb608f0

File tree

7 files changed

+99
-29
lines changed

7 files changed

+99
-29
lines changed

mysql-test/r/user_if_exists.result

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,16 +205,20 @@ password_expired N
205205
password_lifetime NULL
206206
CREATE USER IF NOT EXISTS user1@localhost
207207
IDENTIFIED WITH 'mysql_native_password' BY 'auth_string#%y';
208-
ERROR HY000: Operation CREATE USER failed for 'user1'@'localhost'
208+
Warnings:
209+
Note 3163 User 'user1'@'localhost' already exists.
209210
CREATE USER IF NOT EXISTS ne_user1@localhost,user1@localhost
210211
IDENTIFIED WITH 'mysql_native_password' BY 'auth_string';
211-
ERROR HY000: Operation CREATE USER failed for 'user1'@'localhost'
212+
Warnings:
213+
Note 3163 User 'user1'@'localhost' already exists.
212214
ALTER USER IF EXISTS ne_user2@localhost
213215
IDENTIFIED WITH 'mysql_native_password' BY 'auth_string#%y';
214-
ERROR HY000: Operation ALTER USER failed for 'ne_user2'@'localhost'
216+
Warnings:
217+
Note 3162 User 'ne_user2'@'localhost' does not exist.
215218
ALTER USER IF EXISTS user1@localhost,ne_user3@localhost
216219
IDENTIFIED WITH 'mysql_native_password' BY 'auth_string#%y';
217-
ERROR HY000: Operation ALTER USER failed for 'ne_user3'@'localhost'
220+
Warnings:
221+
Note 3162 User 'ne_user3'@'localhost' does not exist.
218222
DROP USER IF EXISTS user1@localhost,user2@localhost,ne_user1@localhost,
219223
ne_user2@localhost,ne_user3@localhost;
220224
Warnings:
@@ -249,3 +253,17 @@ ne_user2@localhost,ne_user3@localhost;
249253
Warnings:
250254
Note 3162 User 'ne_user2'@'localhost' does not exist.
251255
Note 3162 User 'ne_user3'@'localhost' does not exist.
256+
#
257+
# Bug #21807286: "CREATE USER IF NOT EXISTS" REPORTS AN ERROR
258+
#
259+
CREATE USER IF NOT EXISTS b21807286@localhost IDENTIFIED BY 'xyz';
260+
# Must not fail but return a warning
261+
CREATE USER IF NOT EXISTS b21807286@localhost IDENTIFIED BY 'xyz';
262+
Warnings:
263+
Note 3163 User 'b21807286'@'localhost' already exists.
264+
DROP USER b21807286@localhost;
265+
# Must not fail but return a warning
266+
ALTER USER IF EXISTS b21807286@localhost IDENTIFIED BY 'xyz';
267+
Warnings:
268+
Note 3162 User 'b21807286'@'localhost' does not exist.
269+
# End of 5.7 tests

mysql-test/suite/binlog/r/binlog_user_if_exists.result

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,30 @@ Note 3163 User 'u1'@'localhost' already exists.
1616
ALTER USER IF EXISTS u1@localhost ACCOUNT LOCK;
1717
DROP USER u1@localhost;
1818
DROP USER IF EXISTS u2@localhost;
19+
#
20+
# Bug #21807286: "CREATE USER IF NOT EXISTS" REPORTS AN ERROR
21+
#
22+
CREATE USER IF NOT EXISTS b21807286@localhost IDENTIFIED BY 'haha';
23+
CREATE USER IF NOT EXISTS b21807286@localhost IDENTIFIED BY 'haha2';
24+
Warnings:
25+
Note 3163 User 'b21807286'@'localhost' already exists.
26+
ALTER USER IF EXISTS b21807286@localhost IDENTIFIED BY 'haha3';
27+
ALTER USER IF EXISTS b21807286_not_exists@localhost IDENTIFIED BY 'haha4';
28+
Warnings:
29+
Note 3162 User 'b21807286_not_exists'@'localhost' does not exist.
30+
DROP USER b21807286@localhost;
1931
include/sync_slave_sql_with_master.inc
2032
[On Slave]
2133
include/show_binlog_events.inc
2234
Log_name Pos Event_type Server_id End_log_pos Info
2335
slave-bin.000001 # Query # # use `test`; CREATE USER 'u1'@'localhost' IDENTIFIED WITH 'mysql_native_password'
24-
slave-bin.000001 # Query # # use `test`; CREATE USER IF NOT EXISTS 'u1'@'localhost' IDENTIFIED WITH 'mysql_native_password','u2'@'localhost' IDENTIFIED WITH 'mysql_native_password'
36+
slave-bin.000001 # Query # # use `test`; CREATE USER IF NOT EXISTS 'u2'@'localhost' IDENTIFIED WITH 'mysql_native_password'
2537
slave-bin.000001 # Query # # use `test`; ALTER USER IF EXISTS 'u1'@'localhost' ACCOUNT LOCK
2638
slave-bin.000001 # Query # # use `test`; DROP USER u1@localhost
2739
slave-bin.000001 # Query # # use `test`; DROP USER IF EXISTS u2@localhost
40+
slave-bin.000001 # Query # # use `test`; CREATE USER IF NOT EXISTS 'b21807286'@'localhost' IDENTIFIED WITH 'mysql_native_password' AS '*85D0F19E5598AC04AC7B3FCF5383247D28FB59EF'
41+
slave-bin.000001 # Query # # use `test`; ALTER USER IF EXISTS 'b21807286'@'localhost' IDENTIFIED WITH 'mysql_native_password' AS '*7B8BEAA4240FE1A214BFAEDD99FB3842E4234E5E'
42+
slave-bin.000001 # Query # # use `test`; DROP USER b21807286@localhost
2843
include/rpl_end.inc
2944

3045
End of 5.7 tests!

mysql-test/suite/binlog/t/binlog_user_if_exists.test

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,18 @@ ALTER USER IF EXISTS u1@localhost ACCOUNT LOCK;
1616
DROP USER u1@localhost;
1717
DROP USER IF EXISTS u2@localhost;
1818

19+
--echo #
20+
--echo # Bug #21807286: "CREATE USER IF NOT EXISTS" REPORTS AN ERROR
21+
--echo #
22+
23+
24+
CREATE USER IF NOT EXISTS b21807286@localhost IDENTIFIED BY 'haha';
25+
CREATE USER IF NOT EXISTS b21807286@localhost IDENTIFIED BY 'haha2';
26+
ALTER USER IF EXISTS b21807286@localhost IDENTIFIED BY 'haha3';
27+
ALTER USER IF EXISTS b21807286_not_exists@localhost IDENTIFIED BY 'haha4';
28+
DROP USER b21807286@localhost;
29+
30+
1931
--source include/sync_slave_sql_with_master.inc
2032
--echo [On Slave]
2133
--source include/show_binlog_events.inc

mysql-test/t/user_if_exists.test

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -116,24 +116,18 @@ IDENTIFIED WITH 'mysql_native_password'
116116
query_vertical SELECT User,plugin,authentication_string,ssl_type,
117117
password_expired,password_lifetime FROM mysql.user WHERE USER='user2';
118118

119-
# CREATE USER IF NOT EXISTS statements with plain-text passwords will
120-
# trigger an error if the user does exist and --log-raw=OFF.
121-
--error ER_CANNOT_USER
119+
# CREATE USER IF NOT EXISTS statements with plain-text passwords will work
122120
CREATE USER IF NOT EXISTS user1@localhost
123121
IDENTIFIED WITH 'mysql_native_password' BY 'auth_string#%y';
124122

125-
--error ER_CANNOT_USER
126-
# Operation CREATE USER failed for 'user3'@'localhost'
123+
# Operation CREATE USER works but triggers a warning
127124
CREATE USER IF NOT EXISTS ne_user1@localhost,user1@localhost
128125
IDENTIFIED WITH 'mysql_native_password' BY 'auth_string';
129126

130-
# ALTER USER IF EXISTS statements with plain-text passwords will trigger
131-
# an error if the user does not exist and --log-raw=OFF
132-
--error ER_CANNOT_USER
127+
# Operation ALTER USER works with a password too
133128
ALTER USER IF EXISTS ne_user2@localhost
134129
IDENTIFIED WITH 'mysql_native_password' BY 'auth_string#%y';
135-
--error ER_CANNOT_USER
136-
# Operation ALTER USER failed for 'ne_user3'@'localhost'
130+
# Operation ALTER USER works with a password too
137131
ALTER USER IF EXISTS user1@localhost,ne_user3@localhost
138132
IDENTIFIED WITH 'mysql_native_password' BY 'auth_string#%y';
139133

@@ -191,3 +185,16 @@ ALTER USER IF EXISTS user1@localhost,ne_user3@localhost
191185
DROP USER IF EXISTS user1@localhost,user2@localhost,ne_user1@localhost,
192186
ne_user2@localhost,ne_user3@localhost;
193187

188+
--echo #
189+
--echo # Bug #21807286: "CREATE USER IF NOT EXISTS" REPORTS AN ERROR
190+
--echo #
191+
192+
CREATE USER IF NOT EXISTS b21807286@localhost IDENTIFIED BY 'xyz';
193+
--echo # Must not fail but return a warning
194+
CREATE USER IF NOT EXISTS b21807286@localhost IDENTIFIED BY 'xyz';
195+
DROP USER b21807286@localhost;
196+
--echo # Must not fail but return a warning
197+
ALTER USER IF EXISTS b21807286@localhost IDENTIFIED BY 'xyz';
198+
199+
200+
--echo # End of 5.7 tests

sql/auth/auth_common.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef AUTH_COMMON_INCLUDED
22
#define AUTH_COMMON_INCLUDED
33

4-
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
4+
/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
55
66
This program is free software; you can redistribute it and/or modify
77
it under the terms of the GNU General Public License as published by
@@ -21,6 +21,7 @@
2121
#include "sql_string.h" /* String */
2222
#include "table.h" /* TABLE_LIST */
2323
#include "field.h"
24+
#include <set>
2425

2526
/* Forward Declarations */
2627
class LEX_COLUMN;
@@ -549,7 +550,8 @@ bool acl_check_host(const char *host, const char *ip);
549550
#define ACCOUNT_LOCK_ATTR (1L << 6) /* update account lock status */
550551

551552
/* rewrite CREATE/ALTER/GRANT user */
552-
void mysql_rewrite_create_alter_user(THD *thd, String *rlb);
553+
void mysql_rewrite_create_alter_user(THD *thd, String *rlb,
554+
std::set<LEX_USER *> *users_not_to_log= NULL);
553555
void mysql_rewrite_grant(THD *thd, String *rlb);
554556

555557
/* sql_user */

sql/auth/sql_user.cc

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
22
This program is free software; you can redistribute it and/or modify
33
it under the terms of the GNU General Public License as published by
44
the Free Software Foundation; version 2 of the License.
@@ -1243,6 +1243,7 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list, bool if_not_exists)
12431243
ulong what_to_update= 0;
12441244
bool is_anonymous_user= false;
12451245
bool rollback_whole_statement= false;
1246+
std::set<LEX_USER *> users_not_to_log;
12461247
DBUG_ENTER("mysql_create_user");
12471248

12481249
/*
@@ -1307,16 +1308,20 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list, bool if_not_exists)
13071308
result= true;
13081309
break;
13091310
}
1310-
else if (if_not_exists &&
1311-
(opt_general_log_raw
1312-
|| !user_name->uses_identified_by_clause))
1311+
else if (if_not_exists)
13131312
{
13141313
String warn_user;
13151314
append_user(thd, &warn_user, user_name, FALSE, FALSE);
13161315
push_warning_printf(thd, Sql_condition::SL_NOTE,
13171316
ER_USER_ALREADY_EXISTS,
13181317
ER_THD(thd, ER_USER_ALREADY_EXISTS),
13191318
warn_user.c_ptr_safe());
1319+
try
1320+
{
1321+
users_not_to_log.insert(tmp_user_name);
1322+
}
1323+
catch (...) {}
1324+
continue;
13201325
}
13211326
else
13221327
{
@@ -1340,11 +1345,12 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list, bool if_not_exists)
13401345
my_error(ER_CANNOT_USER, MYF(0), "CREATE USER", wrong_users.c_ptr_safe());
13411346
}
13421347

1343-
if (some_users_created || if_not_exists)
1348+
if (some_users_created ||
1349+
(if_not_exists && users_not_to_log.size() < list.elements))
13441350
{
13451351
String *rlb= &thd->rewritten_query;
13461352
rlb->mem_free();
1347-
mysql_rewrite_create_alter_user(thd, rlb);
1353+
mysql_rewrite_create_alter_user(thd, rlb, &users_not_to_log);
13481354

13491355
if (!thd->rewritten_query.length())
13501356
result|= write_bin_log(thd, false, thd->query().str, thd->query().length,
@@ -1647,6 +1653,7 @@ bool mysql_alter_user(THD *thd, List <LEX_USER> &list, bool if_exists)
16471653
bool save_binlog_row_based;
16481654
bool is_privileged_user= false;
16491655
bool rollback_whole_statement= false;
1656+
std::set<LEX_USER *> users_not_to_log;
16501657

16511658
DBUG_ENTER("mysql_alter_user");
16521659

@@ -1715,15 +1722,19 @@ bool mysql_alter_user(THD *thd, List <LEX_USER> &list, bool if_exists)
17151722
if (!(acl_user= find_acl_user(user_from->host.str,
17161723
user_from->user.str, TRUE)))
17171724
{
1718-
if (if_exists && (opt_general_log_raw
1719-
|| !user_from->uses_identified_by_clause))
1725+
if (if_exists)
17201726
{
17211727
String warn_user;
17221728
append_user(thd, &warn_user, user_from, FALSE, FALSE);
17231729
push_warning_printf(thd, Sql_condition::SL_NOTE,
17241730
ER_USER_DOES_NOT_EXIST,
17251731
ER_THD(thd, ER_USER_DOES_NOT_EXIST),
17261732
warn_user.c_ptr_safe());
1733+
try
1734+
{
1735+
users_not_to_log.insert(tmp_user_from);
1736+
}
1737+
catch (...) {}
17271738
}
17281739
else
17291740
{
@@ -1799,12 +1810,13 @@ bool mysql_alter_user(THD *thd, List <LEX_USER> &list, bool if_exists)
17991810
my_error(ER_CANNOT_USER, MYF(0), "ALTER USER", wrong_users.c_ptr_safe());
18001811
}
18011812

1802-
if (some_user_altered || if_exists)
1813+
if (some_user_altered ||
1814+
(if_exists && users_not_to_log.size() < list.elements))
18031815
{
18041816
/* do query rewrite for ALTER USER */
18051817
String *rlb= &thd->rewritten_query;
18061818
rlb->mem_free();
1807-
mysql_rewrite_create_alter_user(thd, rlb);
1819+
mysql_rewrite_create_alter_user(thd, rlb, &users_not_to_log);
18081820

18091821
result|= (write_bin_log(thd, false,
18101822
thd->rewritten_query.c_ptr_safe(),

sql/sql_rewrite.cc

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or
44
modify it under the terms of the GNU General Public License
@@ -344,7 +344,8 @@ static void mysql_rewrite_set(THD *thd, String *rlb)
344344
@param rlb An empty String object to put the rewritten query in.
345345
*/
346346

347-
void mysql_rewrite_create_alter_user(THD *thd, String *rlb)
347+
void mysql_rewrite_create_alter_user(THD *thd, String *rlb,
348+
std::set<LEX_USER *> *users_not_to_log)
348349
{
349350
LEX *lex= thd->lex;
350351
LEX_USER *user_name, *tmp_user_name;
@@ -366,6 +367,9 @@ void mysql_rewrite_create_alter_user(THD *thd, String *rlb)
366367

367368
while ((tmp_user_name= user_list++))
368369
{
370+
if (users_not_to_log &&
371+
users_not_to_log->find(tmp_user_name) != users_not_to_log->end())
372+
continue;
369373
if ((user_name= get_current_user(thd, tmp_user_name)))
370374
{
371375
if (opt_log_builtin_as_identified_by_password &&

0 commit comments

Comments
 (0)