Skip to content

Commit 3e03835

Browse files
Bug#28643405: LAST_ERROR_NUMBER: 1064 DURING GRANT SELECT
Problem ======= Replication breaks when 'GRANT SELECT' is executed on master when column names are keywords. Analysis ======== On master, column names in GRANT query were not quoted properly while writing to the binary log, leading to syntax error on slave. Fix === For GRANT commands, column names are properly quoted before writing to the binary log.
1 parent 037ed08 commit 3e03835

File tree

3 files changed

+189
-1
lines changed

3 files changed

+189
-1
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
include/master-slave.inc
2+
Warnings:
3+
Note #### Sending passwords in plain text without SSL/TLS is extremely insecure.
4+
Note #### Storing MySQL user name or password information in the master info repository is not secure and is therefore not recommended. Please consider using the USER and PASSWORD connection options for START SLAVE; see the 'START SLAVE Syntax' in the MySQL Manual for more information.
5+
[connection master]
6+
7+
# 1. Initial setup on master.
8+
# 1.1 Create tables with reserved words as column names.
9+
CREATE DATABASE `order`;
10+
CREATE TABLE `order`.`order` (`order` INT);
11+
CREATE DATABASE `column`;
12+
CREATE TABLE `column`.`column` (`column` INT);
13+
CREATE DATABASE `all`;
14+
CREATE TABLE `all`.`all`(
15+
id int NOT NULL PRIMARY KEY,
16+
item int,
17+
`table` varchar(10),
18+
`regexp` varchar(10));
19+
20+
# 1.2 Create users for granting column privileges.
21+
CREATE USER `order` IDENTIFIED BY 'password1';
22+
CREATE USER `column` IDENTIFIED BY 'password2';
23+
CREATE USER `all` IDENTIFIED BY 'password3';
24+
25+
# 2. With sql_mode='ANSI_QUOTES', execute GRANT SELECT commands on master.
26+
SET @saved_sql_mode= @@session.sql_mode;
27+
SET SESSION sql_mode= 'ANSI_QUOTES';
28+
Warnings:
29+
Warning 3090 Changing sql mode 'NO_AUTO_CREATE_USER' is deprecated. It will be removed in a future release.
30+
31+
# Execute GRANT SELECT commands on master.
32+
GRANT SELECT(`order`) ON `order`.`order` TO `order`;
33+
GRANT SELECT(id,`table`) ON `all`.`all` TO `all`;
34+
35+
# Verify the correctness of 'GRANT SELECT' statement by printing
36+
# the binlog entry for the statement.
37+
include/show_binlog_events.inc
38+
Log_name Pos Event_type Server_id End_log_pos Info
39+
master-bin.000001 # Query # # use `test`; GRANT SELECT ("order") ON "order"."order" TO 'order'@'%'
40+
master-bin.000001 # Query # # use `test`; GRANT SELECT ("id", "table") ON "all"."all" TO 'all'@'%'
41+
42+
# 3. With sql_mode='', execute GRANT SELECT commands on master.
43+
SET SESSION sql_mode= '';
44+
45+
# Execute GRANT SELECT commands on master.
46+
GRANT SELECT(`column`) ON `column`.`column` TO `column`;
47+
GRANT SELECT(item,`regexp`) ON `all`.`all` TO `all`;
48+
49+
# 4. Verify the correctness of 'GRANT SELECT' statement by printing
50+
# the binlog entry for the statement.
51+
include/show_binlog_events.inc
52+
Log_name Pos Event_type Server_id End_log_pos Info
53+
master-bin.000001 # Query # # use `test`; GRANT SELECT (`column`) ON `column`.`column` TO 'column'@'%'
54+
master-bin.000001 # Query # # use `test`; GRANT SELECT (`item`, `regexp`) ON `all`.`all` TO 'all'@'%'
55+
56+
# 5. Sync the slave with master.
57+
include/sync_slave_sql_with_master.inc
58+
59+
# 6. Verify that there is no difference in the column privileges
60+
# tables of master and slave.
61+
[connection master]
62+
include/diff_tables.inc [master:mysql.columns_priv, slave:mysql.columns_priv]
63+
SET SESSION sql_mode= @saved_sql_mode;
64+
Warnings:
65+
Warning 3090 Changing sql mode 'NO_AUTO_CREATE_USER' is deprecated. It will be removed in a future release.
66+
DROP USER `order`,`column`,`all`;
67+
DROP DATABASE `order`;
68+
DROP DATABASE `column`;
69+
DROP DATABASE `all`;
70+
include/rpl_end.inc
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# ==== Purpose ====
2+
#
3+
# Verify that columns in the 'GRANT SELECT' statements
4+
# are properly quoted before writing to the binary log.
5+
#
6+
# ==== Implementation ====
7+
#
8+
# 1. Initial setup on master.
9+
# 1.1 Create tables with reserved words as column names.
10+
# 1.2 Create users for granting column privileges.
11+
# 2. With sql_mode='ANSI_QUOTES', execute GRANT SELECT commands on master.
12+
# 3. With sql_mode='', execute GRANT SELECT commands on master.
13+
# 4. Verify the correctness of 'GRANT SELECT' statement by printing
14+
# the binlog entry for the statement.
15+
# 5. Sync the slave with master.
16+
# 6. Verify that there is no difference in the column privileges
17+
# tables of master and slave.
18+
#
19+
# ==== References ====
20+
#
21+
# Bug#28643405: LAST_ERROR_NUMBER: 1064 DURING GRANT SELECT
22+
#
23+
24+
--source include/have_binlog_format_statement.inc
25+
--source include/master-slave.inc
26+
27+
--echo
28+
--echo # 1. Initial setup on master.
29+
--echo # 1.1 Create tables with reserved words as column names.
30+
CREATE DATABASE `order`;
31+
CREATE TABLE `order`.`order` (`order` INT);
32+
33+
CREATE DATABASE `column`;
34+
CREATE TABLE `column`.`column` (`column` INT);
35+
36+
CREATE DATABASE `all`;
37+
CREATE TABLE `all`.`all`(
38+
id int NOT NULL PRIMARY KEY,
39+
item int,
40+
`table` varchar(10),
41+
`regexp` varchar(10));
42+
43+
--echo
44+
--echo # 1.2 Create users for granting column privileges.
45+
CREATE USER `order` IDENTIFIED BY 'password1';
46+
CREATE USER `column` IDENTIFIED BY 'password2';
47+
CREATE USER `all` IDENTIFIED BY 'password3';
48+
49+
--echo
50+
--echo # 2. With sql_mode='ANSI_QUOTES', execute GRANT SELECT commands on master.
51+
52+
# Setting sql_mode to ANSI_QUOTES before executing GRANT.
53+
# ANSI_QUOTES mode will make sure the "(double quote) is used
54+
# as the identifier quote character while writing to the binlog.
55+
# This mode treats "(double quotes) as an identifier quote character
56+
# and not as a string quote character.
57+
SET @saved_sql_mode= @@session.sql_mode;
58+
SET SESSION sql_mode= 'ANSI_QUOTES';
59+
60+
# Save master position
61+
--let $binlog_start= query_get_value('SHOW MASTER STATUS', Position, 1)
62+
63+
--echo
64+
--echo # Execute GRANT SELECT commands on master.
65+
66+
# Columns having reserved words
67+
GRANT SELECT(`order`) ON `order`.`order` TO `order`;
68+
69+
# Column names having both reserved words and non-reserved words
70+
GRANT SELECT(id,`table`) ON `all`.`all` TO `all`;
71+
72+
--echo
73+
--echo # Verify the correctness of 'GRANT SELECT' statement by printing
74+
--echo # the binlog entry for the statement.
75+
--source include/show_binlog_events.inc
76+
77+
--echo
78+
--echo # 3. With sql_mode='', execute GRANT SELECT commands on master.
79+
80+
# Reseting sql_mode. This will make sure `(backtick) is used as
81+
# the identifier quote character while writing to the binlog.
82+
SET SESSION sql_mode= '';
83+
84+
# Update master position
85+
--let $binlog_start= query_get_value('SHOW MASTER STATUS', Position, 1)
86+
87+
--echo
88+
--echo # Execute GRANT SELECT commands on master.
89+
90+
# Columns having reserved words
91+
GRANT SELECT(`column`) ON `column`.`column` TO `column`;
92+
93+
# Column names having both reserved words and non-reserved words
94+
GRANT SELECT(item,`regexp`) ON `all`.`all` TO `all`;
95+
96+
--echo
97+
--echo # 4. Verify the correctness of 'GRANT SELECT' statement by printing
98+
--echo # the binlog entry for the statement.
99+
--source include/show_binlog_events.inc
100+
101+
--echo
102+
--echo # 5. Sync the slave with master.
103+
--source include/sync_slave_sql_with_master.inc
104+
105+
--echo
106+
--echo # 6. Verify that there is no difference in the column privileges
107+
--echo # tables of master and slave.
108+
--source include/rpl_connection_master.inc
109+
--let diff_tables=master:mysql.columns_priv, slave:mysql.columns_priv
110+
--source include/diff_tables.inc
111+
112+
# Cleanup
113+
SET SESSION sql_mode= @saved_sql_mode;
114+
DROP USER `order`,`column`,`all`;
115+
DROP DATABASE `order`;
116+
DROP DATABASE `column`;
117+
DROP DATABASE `all`;
118+
--source include/rpl_end.inc

sql/sql_rewrite.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ void mysql_rewrite_grant(THD *thd, String *rlb)
233233
cols.append(STRING_WITH_LEN(", "));
234234
else
235235
comma_inner= TRUE;
236-
cols.append(column->column.ptr(),column->column.length());
236+
append_identifier(thd, &cols, column->column.ptr(), column->column.length());
237237
}
238238
}
239239
cols.append(STRING_WITH_LEN(")"));

0 commit comments

Comments
 (0)