summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/suite/rpl/r/rpl_conditional_comments.result67
-rw-r--r--mysql-test/suite/rpl/t/rpl_conditional_comments.test74
-rw-r--r--sql/sql_lex.cc21
-rw-r--r--sql/sql_lex.h24
-rw-r--r--sql/sql_parse.cc10
-rw-r--r--sql/sql_parse.h2
-rw-r--r--sql/sql_partition.cc2
-rw-r--r--sql/sql_partition.h2
-rw-r--r--sql/table.h2
9 files changed, 185 insertions, 19 deletions
diff --git a/mysql-test/suite/rpl/r/rpl_conditional_comments.result b/mysql-test/suite/rpl/r/rpl_conditional_comments.result
new file mode 100644
index 00000000000..f3de3e5eb70
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_conditional_comments.result
@@ -0,0 +1,67 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+CREATE TABLE t1(c1 INT);
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # use `test`; CREATE TABLE t1(c1 INT)
+
+# Case 1:
+# ------------------------------------------------------------------
+# In a statement, some CCs are applied while others are not. The CCs
+# which are not applied on master will be binlogged as common comments.
+/*!99999 --- */INSERT /*!INTO*/ /*!10000 t1 */ VALUES(10) /*!99999 ,(11)*/;
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # BEGIN
+master-bin.000001 # Query # # use `test`; /* 99999 --- */INSERT /*!INTO*/ /*!10000 t1 */ VALUES(10) /* 99999 ,(11)*/
+master-bin.000001 # Query # # COMMIT
+Comparing tables master:test.t1 and slave:test.t1
+
+# Case 2:
+# -----------------------------------------------------------------
+# Verify whether it can be binlogged correctly when executing prepared
+# statement.
+PREPARE stmt FROM 'INSERT INTO /*!99999 blabla*/ t1 VALUES(60) /*!99999 ,(61)*/';
+EXECUTE stmt;
+DROP TABLE t1;
+CREATE TABLE t1(c1 INT);
+EXECUTE stmt;
+Comparing tables master:test.t1 and slave:test.t1
+
+SET @value=62;
+PREPARE stmt FROM 'INSERT INTO /*!99999 blabla */ t1 VALUES(?) /*!99999 ,(63)*/';
+EXECUTE stmt USING @value;
+DROP TABLE t1;
+CREATE TABLE t1(c1 INT);
+EXECUTE stmt USING @value;
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # BEGIN
+master-bin.000001 # Query # # use `test`; INSERT INTO /* 99999 blabla*/ t1 VALUES(60) /* 99999 ,(61)*/
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Query # # use `test`; DROP TABLE t1
+master-bin.000001 # Query # # use `test`; CREATE TABLE t1(c1 INT)
+master-bin.000001 # Query # # BEGIN
+master-bin.000001 # Query # # use `test`; INSERT INTO /* 99999 blabla*/ t1 VALUES(60) /* 99999 ,(61)*/
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Query # # BEGIN
+master-bin.000001 # Query # # use `test`; INSERT INTO /* 99999 blabla */ t1 VALUES(62) /* 99999 ,(63)*/
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Query # # use `test`; DROP TABLE t1
+master-bin.000001 # Query # # use `test`; CREATE TABLE t1(c1 INT)
+master-bin.000001 # Query # # BEGIN
+master-bin.000001 # Query # # use `test`; INSERT INTO /* 99999 blabla */ t1 VALUES(62) /* 99999 ,(63)*/
+master-bin.000001 # Query # # COMMIT
+Comparing tables master:test.t1 and slave:test.t1
+
+# Case 3:
+# -----------------------------------------------------------------
+# Verify it can restore the '!', if the it is an uncomplete conditional
+# comments
+SELECT c1 FROM /*!99999 t1 WHEREN;
+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 '/*!99999 t1 WHEREN' at line 1
+DROP TABLE t1;
diff --git a/mysql-test/suite/rpl/t/rpl_conditional_comments.test b/mysql-test/suite/rpl/t/rpl_conditional_comments.test
new file mode 100644
index 00000000000..14251d5eb37
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_conditional_comments.test
@@ -0,0 +1,74 @@
+###############################################################################
+# After the patch for BUG#49124:
+# - Use ' ' instead of '!' in the conditional comments which are not applied on
+# master. So they become common comments and will not be applied on slave.
+#
+# - Example:
+# 'INSERT INTO t1 VALUES (1) /*!10000, (2)*/ /*!99999 ,(3)*/
+# will be binlogged as
+# 'INSERT INTO t1 VALUES (1) /*!10000, (2)*/ /* 99999 ,(3)*/'.
+###############################################################################
+source include/master-slave.inc;
+source include/have_binlog_format_statement.inc;
+
+CREATE TABLE t1(c1 INT);
+source include/show_binlog_events.inc;
+let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1);
+
+--echo
+--echo # Case 1:
+--echo # ------------------------------------------------------------------
+--echo # In a statement, some CCs are applied while others are not. The CCs
+--echo # which are not applied on master will be binlogged as common comments.
+
+/*!99999 --- */INSERT /*!INTO*/ /*!10000 t1 */ VALUES(10) /*!99999 ,(11)*/;
+
+source include/show_binlog_events.inc;
+let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1);
+sync_slave_with_master;
+let $diff_table_1=master:test.t1;
+let $diff_table_2=slave:test.t1;
+source include/diff_tables.inc;
+
+--echo
+--echo # Case 2:
+--echo # -----------------------------------------------------------------
+--echo # Verify whether it can be binlogged correctly when executing prepared
+--echo # statement.
+PREPARE stmt FROM 'INSERT INTO /*!99999 blabla*/ t1 VALUES(60) /*!99999 ,(61)*/';
+EXECUTE stmt;
+DROP TABLE t1;
+CREATE TABLE t1(c1 INT);
+EXECUTE stmt;
+
+sync_slave_with_master;
+let $diff_table_1=master:test.t1;
+let $diff_table_2=slave:test.t1;
+source include/diff_tables.inc;
+
+--echo
+SET @value=62;
+PREPARE stmt FROM 'INSERT INTO /*!99999 blabla */ t1 VALUES(?) /*!99999 ,(63)*/';
+EXECUTE stmt USING @value;
+DROP TABLE t1;
+CREATE TABLE t1(c1 INT);
+EXECUTE stmt USING @value;
+
+source include/show_binlog_events.inc;
+let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1);
+
+sync_slave_with_master;
+let $diff_table_1=master:test.t1;
+let $diff_table_2=slave:test.t1;
+source include/diff_tables.inc;
+
+--echo
+--echo # Case 3:
+--echo # -----------------------------------------------------------------
+--echo # Verify it can restore the '!', if the it is an uncomplete conditional
+--echo # comments
+--error 1064
+SELECT c1 FROM /*!99999 t1 WHEREN;
+
+DROP TABLE t1;
+source include/master-slave-end.inc;
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index aefddc0b6a5..59a1085728a 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -153,7 +153,7 @@ st_parsing_options::reset()
*/
bool Lex_input_stream::init(THD *thd,
- const char* buff,
+ char* buff,
unsigned int length)
{
DBUG_EXECUTE_IF("bug42064_simulate_oom",
@@ -183,7 +183,7 @@ bool Lex_input_stream::init(THD *thd,
*/
void
-Lex_input_stream::reset(const char *buffer, unsigned int length)
+Lex_input_stream::reset(char *buffer, unsigned int length)
{
yylineno= 1;
yytoklen= 0;
@@ -1425,11 +1425,10 @@ int lex_one_token(void *arg, void *yythd)
ulong version;
version=strtol(version_str, NULL, 10);
- /* Accept 'M' 'm' 'm' 'd' 'd' */
- lip->yySkipn(5);
-
if (version <= MYSQL_VERSION_ID)
{
+ /* Accept 'M' 'm' 'm' 'd' 'd' */
+ lip->yySkipn(5);
/* Expand the content of the special comment as real code */
lip->set_echo(TRUE);
state=MY_LEX_START;
@@ -1437,7 +1436,19 @@ int lex_one_token(void *arg, void *yythd)
}
else
{
+ const char* version_mark= lip->get_ptr() - 1;
+ DBUG_ASSERT(*version_mark == '!');
+ /*
+ Patch and skip the conditional comment to avoid it
+ being propagated infinitely (eg. to a slave).
+ */
+ char *pcom= lip->yyUnput(' ');
comment_closed= ! consume_comment(lip, 1);
+ if (! comment_closed)
+ {
+ DBUG_ASSERT(pcom == version_mark);
+ *pcom= '!';
+ }
/* version allowed to have one level of comment inside. */
}
}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index b8bf3b220c9..feb8079a06b 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1394,9 +1394,9 @@ public:
@retval FALSE OK
@retval TRUE Error
*/
- bool init(THD *thd, const char *buff, unsigned int length);
+ bool init(THD *thd, char *buff, unsigned int length);
- void reset(const char *buff, unsigned int length);
+ void reset(char *buff, unsigned int length);
/**
Set the echo mode.
@@ -1512,6 +1512,20 @@ public:
}
/**
+ Puts a character back into the stream, canceling
+ the effect of the last yyGet() or yySkip().
+ Note that the echo mode should not change between calls
+ to unput, get, or skip from the stream.
+ */
+ char *yyUnput(char ch)
+ {
+ *--m_ptr= ch;
+ if (m_echo)
+ m_cpp_ptr--;
+ return m_ptr;
+ }
+
+ /**
End of file indicator for the query text to parse.
@return true if there are no more characters to parse
*/
@@ -1668,7 +1682,7 @@ public:
private:
/** Pointer to the current position in the raw input stream. */
- const char *m_ptr;
+ char *m_ptr;
/** Starting position of the last token parsed, in the raw buffer. */
const char *m_tok_start;
@@ -2350,7 +2364,7 @@ public:
@retval FALSE OK
@retval TRUE Error
*/
- bool init(THD *thd, const char *buff, unsigned int length)
+ bool init(THD *thd, char *buff, unsigned int length)
{
return m_lip.init(thd, buff, length);
}
@@ -2361,7 +2375,7 @@ public:
Lex_input_stream m_lip;
Yacc_state m_yacc;
- void reset(const char *found_semicolon, unsigned int length)
+ void reset(char *found_semicolon, unsigned int length)
{
m_lip.reset(found_semicolon, length);
m_yacc.reset();
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index d31723c36e3..57a13d523a0 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -5817,13 +5817,13 @@ void mysql_init_multi_delete(LEX *lex)
Parse a query.
@param thd Current thread
- @param inBuf Begining of the query text
+ @param rawbuf Begining of the query text
@param length Length of the query text
@param[out] found_semicolon For multi queries, position of the character of
the next query in the query text.
*/
-void mysql_parse(THD *thd, const char *inBuf, uint length,
+void mysql_parse(THD *thd, char *rawbuf, uint length,
Parser_state *parser_state)
{
int error __attribute__((unused));
@@ -5850,7 +5850,7 @@ void mysql_parse(THD *thd, const char *inBuf, uint length,
lex_start(thd);
mysql_reset_thd_for_next_command(thd);
- if (query_cache_send_result_to_client(thd, (char*) inBuf, length) <= 0)
+ if (query_cache_send_result_to_client(thd, rawbuf, length) <= 0)
{
LEX *lex= thd->lex;
@@ -5938,14 +5938,14 @@ void mysql_parse(THD *thd, const char *inBuf, uint length,
1 can be ignored
*/
-bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
+bool mysql_test_parse_for_slave(THD *thd, char *rawbuf, uint length)
{
LEX *lex= thd->lex;
bool error= 0;
DBUG_ENTER("mysql_test_parse_for_slave");
Parser_state parser_state;
- if (!(error= parser_state.init(thd, inBuf, length)))
+ if (!(error= parser_state.init(thd, rawbuf, length)))
{
lex_start(thd);
mysql_reset_thd_for_next_command(thd);
diff --git a/sql/sql_parse.h b/sql/sql_parse.h
index 475811d45b7..b55e8a46bc3 100644
--- a/sql/sql_parse.h
+++ b/sql/sql_parse.h
@@ -84,7 +84,7 @@ bool is_update_query(enum enum_sql_command command);
bool is_log_table_write_query(enum enum_sql_command command);
bool alloc_query(THD *thd, const char *packet, uint packet_length);
void mysql_init_select(LEX *lex);
-void mysql_parse(THD *thd, const char *inBuf, uint length,
+void mysql_parse(THD *thd, char *rawbuf, uint length,
Parser_state *parser_state);
void mysql_reset_thd_for_next_command(THD *thd);
bool mysql_new_select(LEX *lex, bool move_down);
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 49f972f35ca..ed6d3af2e43 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -4183,7 +4183,7 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index,
*/
bool mysql_unpack_partition(THD *thd,
- const char *part_buf, uint part_info_len,
+ char *part_buf, uint part_info_len,
TABLE* table, bool is_create_table_ind,
handlerton *default_db_type,
bool *work_part_info_used)
diff --git a/sql/sql_partition.h b/sql/sql_partition.h
index 2e0ea740555..c644e63794c 100644
--- a/sql/sql_partition.h
+++ b/sql/sql_partition.h
@@ -110,7 +110,7 @@ void get_full_part_id_from_key(const TABLE *table, uchar *buf,
KEY *key_info,
const key_range *key_spec,
part_id_range *part_spec);
-bool mysql_unpack_partition(THD *thd, const char *part_buf,
+bool mysql_unpack_partition(THD *thd, char *part_buf,
uint part_info_len,
TABLE *table, bool is_create_table_ind,
handlerton *default_db_type,
diff --git a/sql/table.h b/sql/table.h
index 2bf390aee4d..7579a8a6df3 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -629,7 +629,7 @@ struct TABLE_SHARE
#ifdef WITH_PARTITION_STORAGE_ENGINE
/* filled in when reading from frm */
bool auto_partitioned;
- const char *partition_info_str;
+ char *partition_info_str;
uint partition_info_str_len;
uint partition_info_buffer_size;
handlerton *default_part_db_type;