summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <bar@bar.myoffice.izhnet.ru>2007-06-01 15:16:57 +0500
committerunknown <bar@bar.myoffice.izhnet.ru>2007-06-01 15:16:57 +0500
commit075346acc8e5b17a9612718d3eda320762350f3a (patch)
tree2e85d3308d352fd698b690a2eb4867e50c17bbbe
parent924eacee08f63732a92d20c36306e96ec4f0a69b (diff)
parente319a0493461000f9eeabceed7f2c5d57cfc44cd (diff)
downloadmariadb-git-075346acc8e5b17a9612718d3eda320762350f3a.tar.gz
Merge abarkov@bk-internal.mysql.com:/home/bk/mysql-5.1-rpl
into mysql.com:/home/bar/mysql-work/mysql-5.1.b28600
-rw-r--r--mysql-test/r/binlog_unsafe.result13
-rw-r--r--mysql-test/r/check.result3
-rw-r--r--mysql-test/r/rpl_slave_skip.result136
-rw-r--r--mysql-test/r/rpl_udf.result8
-rw-r--r--mysql-test/t/binlog_unsafe.test16
-rw-r--r--mysql-test/t/check.test3
-rw-r--r--mysql-test/t/func_misc.test2
-rw-r--r--mysql-test/t/rpl_slave_skip.test71
-rw-r--r--sql/item_create.cc4
-rw-r--r--sql/log_event.cc27
-rw-r--r--sql/log_event.h2
-rw-r--r--sql/share/errmsg.txt3
-rw-r--r--sql/sp_head.cc2
-rw-r--r--sql/sp_head.h2
-rw-r--r--sql/sql_base.cc4
-rw-r--r--sql/sql_class.cc23
-rw-r--r--sql/sql_class.h12
-rw-r--r--sql/sql_insert.cc1
-rw-r--r--sql/sql_lex.cc2
-rw-r--r--sql/sql_lex.h44
-rw-r--r--sql/sql_view.cc4
21 files changed, 362 insertions, 20 deletions
diff --git a/mysql-test/r/binlog_unsafe.result b/mysql-test/r/binlog_unsafe.result
new file mode 100644
index 00000000000..36213cbb2ae
--- /dev/null
+++ b/mysql-test/r/binlog_unsafe.result
@@ -0,0 +1,13 @@
+SET BINLOG_FORMAT=STATEMENT;
+CREATE TABLE t1 (a CHAR(40));
+CREATE TABLE t2 (a INT AUTO_INCREMENT PRIMARY KEY);
+CREATE TABLE t3 (b INT AUTO_INCREMENT PRIMARY KEY);
+CREATE VIEW v1(a,b) AS SELECT a,b FROM t2,t3;
+INSERT INTO t1 SELECT UUID();
+Warnings:
+Warning 1588 Statement is not safe to log in statement format.
+SHOW WARNINGS;
+Level Warning
+Code 1588
+Message Statement is not safe to log in statement format.
+DROP TABLE t1,t2,t3;
diff --git a/mysql-test/r/check.result b/mysql-test/r/check.result
index 60806e7393e..739eab2ed76 100644
--- a/mysql-test/r/check.result
+++ b/mysql-test/r/check.result
@@ -1,4 +1,5 @@
-drop table if exists t1;
+drop table if exists t1,t2;
+drop view if exists v1;
create table t1(n int not null, key(n), key(n), key(n), key(n));
check table t1 extended;
insert into t1 values (200000);
diff --git a/mysql-test/r/rpl_slave_skip.result b/mysql-test/r/rpl_slave_skip.result
new file mode 100644
index 00000000000..e2bc34eeb41
--- /dev/null
+++ b/mysql-test/r/rpl_slave_skip.result
@@ -0,0 +1,136 @@
+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;
+**** On Slave ****
+STOP SLAVE;
+**** On Master ****
+SET SESSION BINLOG_FORMAT=ROW;
+CREATE TABLE t1 (a INT, b INT);
+CREATE TABLE t2 (c INT, d INT);
+INSERT INTO t1 VALUES (1,1),(2,4),(3,9);
+INSERT INTO t2 VALUES (1,1),(2,8),(3,27);
+UPDATE t1,t2 SET b = d, d = b * 2 WHERE a = c;
+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 (a INT, b INT)
+master-bin.000001 # Query # # use `test`; CREATE TABLE t2 (c INT, d INT)
+master-bin.000001 # Table_map # # table_id: # (test.t1)
+master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000001 # Table_map # # table_id: # (test.t2)
+master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000001 # Table_map # # table_id: # (test.t1)
+master-bin.000001 # Table_map # # table_id: # (test.t2)
+master-bin.000001 # Update_rows # # table_id: #
+master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F
+SELECT * FROM t1;
+a b
+1 1
+2 8
+3 27
+SELECT * FROM t2;
+c d
+1 2
+2 16
+3 54
+**** On Slave ****
+START SLAVE UNTIL MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=484;
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos 714
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 0
+Last_Error
+Skip_Counter 0
+Exec_Master_Log_Pos 484
+Relay_Log_Space #
+Until_Condition Master
+Until_Log_File master-bin.000001
+Until_Log_Pos 484
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+Master_SSL_Verify_Server_Cert No
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
+START SLAVE;
+SELECT * FROM t1;
+a b
+1 1
+2 4
+3 9
+SELECT * FROM t2;
+c d
+1 1
+2 8
+3 27
+STOP SLAVE;
+RESET SLAVE;
+RESET MASTER;
+SET SESSION BINLOG_FORMAT=STATEMENT;
+SET @foo = 12;
+INSERT INTO t1 VALUES(@foo, 2*@foo);
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # User var # # @`foo`=12
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES(@foo, 2*@foo)
+START SLAVE UNTIL MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=106;
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
+START SLAVE;
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos 248
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running Yes
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 0
+Last_Error
+Skip_Counter 0
+Exec_Master_Log_Pos 248
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+Master_SSL_Verify_Server_Cert No
+**** On Master ****
+DROP TABLE t1, t2;
diff --git a/mysql-test/r/rpl_udf.result b/mysql-test/r/rpl_udf.result
index 6587632bca0..220358aab9c 100644
--- a/mysql-test/r/rpl_udf.result
+++ b/mysql-test/r/rpl_udf.result
@@ -181,12 +181,20 @@ affected rows: 2
CREATE TABLE t1(sum INT, price FLOAT(24)) ENGINE=MyISAM;
affected rows: 0
INSERT INTO t1 VALUES(myfunc_int(100), myfunc_double(50.00));
+Warnings:
+Warning 1588 Statement is not safe to log in statement format.
affected rows: 1
INSERT INTO t1 VALUES(myfunc_int(10), myfunc_double(5.00));
+Warnings:
+Warning 1588 Statement is not safe to log in statement format.
affected rows: 1
INSERT INTO t1 VALUES(myfunc_int(200), myfunc_double(25.00));
+Warnings:
+Warning 1588 Statement is not safe to log in statement format.
affected rows: 1
INSERT INTO t1 VALUES(myfunc_int(1), myfunc_double(500.00));
+Warnings:
+Warning 1588 Statement is not safe to log in statement format.
affected rows: 1
SELECT * FROM t1 ORDER BY sum;
sum price
diff --git a/mysql-test/t/binlog_unsafe.test b/mysql-test/t/binlog_unsafe.test
new file mode 100644
index 00000000000..9e0716cf2b4
--- /dev/null
+++ b/mysql-test/t/binlog_unsafe.test
@@ -0,0 +1,16 @@
+# Test to check that a warning is generated for unsafe statements
+# executed under statement mode logging.
+
+SET BINLOG_FORMAT=STATEMENT;
+
+CREATE TABLE t1 (a CHAR(40));
+CREATE TABLE t2 (a INT AUTO_INCREMENT PRIMARY KEY);
+CREATE TABLE t3 (b INT AUTO_INCREMENT PRIMARY KEY);
+CREATE VIEW v1(a,b) AS SELECT a,b FROM t2,t3;
+
+INSERT INTO t1 SELECT UUID();
+query_vertical SHOW WARNINGS;
+
+DROP TABLE t1,t2,t3;
+
+
diff --git a/mysql-test/t/check.test b/mysql-test/t/check.test
index 8d9d70bd29a..eb72d75da3c 100644
--- a/mysql-test/t/check.test
+++ b/mysql-test/t/check.test
@@ -2,7 +2,8 @@ connect (con1,localhost,root,,);
connect (con2,localhost,root,,);
connection con1;
--disable_warnings
-drop table if exists t1;
+drop table if exists t1,t2;
+drop view if exists v1;
--enable_warnings
# Add a lot of keys to slow down check
diff --git a/mysql-test/t/func_misc.test b/mysql-test/t/func_misc.test
index 8ff62f68e45..23b8db607b8 100644
--- a/mysql-test/t/func_misc.test
+++ b/mysql-test/t/func_misc.test
@@ -89,7 +89,9 @@ select export_set(3, _latin1'foo', _utf8'bar', ',', 4);
#
# Test for BUG#9535
#
+--disable_warnings
create table t1 as select uuid(), length(uuid());
+--enable_warnings
show create table t1;
drop table t1;
diff --git a/mysql-test/t/rpl_slave_skip.test b/mysql-test/t/rpl_slave_skip.test
new file mode 100644
index 00000000000..70a5b23c288
--- /dev/null
+++ b/mysql-test/t/rpl_slave_skip.test
@@ -0,0 +1,71 @@
+source include/master-slave.inc;
+
+--echo **** On Slave ****
+connection slave;
+STOP SLAVE;
+
+--echo **** On Master ****
+connection master;
+SET SESSION BINLOG_FORMAT=ROW;
+
+CREATE TABLE t1 (a INT, b INT);
+CREATE TABLE t2 (c INT, d INT);
+INSERT INTO t1 VALUES (1,1),(2,4),(3,9);
+INSERT INTO t2 VALUES (1,1),(2,8),(3,27);
+UPDATE t1,t2 SET b = d, d = b * 2 WHERE a = c;
+source include/show_binlog_events.inc;
+
+# These tables should be changed
+SELECT * FROM t1;
+SELECT * FROM t2;
+save_master_pos;
+
+--echo **** On Slave ****
+connection slave;
+
+# Stop when reaching the the first table map event.
+START SLAVE UNTIL MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=484;
+wait_for_slave_to_stop;
+--replace_result $MASTER_MYPORT MASTER_PORT
+--replace_column 1 # 8 # 9 # 23 # 33 #
+query_vertical SHOW SLAVE STATUS;
+
+# Now we skip *one* table map event. If the execution starts right
+# after that table map event, *one* of the involved tables will be
+# changed.
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
+START SLAVE;
+sync_with_master;
+
+# These values should be what was inserted, not what was
+# updated. Since we are skipping the first table map of the group
+# representing the UPDATE statement above, we should skip the entire
+# group and not start executing at the first table map.
+SELECT * FROM t1;
+SELECT * FROM t2;
+
+STOP SLAVE;
+RESET SLAVE;
+connection master;
+RESET MASTER;
+
+SET SESSION BINLOG_FORMAT=STATEMENT;
+SET @foo = 12;
+INSERT INTO t1 VALUES(@foo, 2*@foo);
+save_master_pos;
+source include/show_binlog_events.inc;
+
+connection slave;
+START SLAVE UNTIL MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=106;
+wait_for_slave_to_stop;
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
+START SLAVE;
+sync_with_master;
+--replace_result $MASTER_MYPORT MASTER_PORT
+--replace_column 1 # 8 # 9 # 23 # 33 #
+query_vertical SHOW SLAVE STATUS;
+
+--echo **** On Master ****
+connection master;
+DROP TABLE t1, t2;
+sync_slave_with_master;
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 62f44996f4b..5dd09bc7b2c 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -2341,7 +2341,7 @@ Create_udf_func::create(THD *thd, udf_func *udf, List<Item> *item_list)
if (item_list != NULL)
arg_count= item_list->elements;
- thd->lex->binlog_row_based_if_mixed= TRUE;
+ thd->lex->set_stmt_unsafe();
DBUG_ASSERT( (udf->type == UDFTYPE_FUNCTION)
|| (udf->type == UDFTYPE_AGGREGATE));
@@ -4528,7 +4528,7 @@ Create_func_uuid Create_func_uuid::s_singleton;
Item*
Create_func_uuid::create(THD *thd)
{
- thd->lex->binlog_row_based_if_mixed= TRUE;
+ thd->lex->set_stmt_unsafe();
return new (thd->mem_root) Item_func_uuid();
}
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 3cca8d53f07..d33c0382d7c 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -6149,6 +6149,20 @@ int Rows_log_event::do_apply_event(RELAY_LOG_INFO const *rli)
DBUG_RETURN(0);
}
+Log_event::enum_skip_reason
+Rows_log_event::do_shall_skip(RELAY_LOG_INFO *rli)
+{
+ /*
+ If the slave skip counter is 1 and this event does not end a
+ statement, then we should not start executing on the next event.
+ Otherwise, we defer the decision to the normal skipping logic.
+ */
+ if (rli->slave_skip_counter == 1 && !get_flags(STMT_END_F))
+ return Log_event::EVENT_SKIP_IGNORE;
+ else
+ return Log_event::do_shall_skip(rli);
+}
+
int
Rows_log_event::do_update_pos(RELAY_LOG_INFO *rli)
{
@@ -6622,6 +6636,19 @@ err:
DBUG_RETURN(error);
}
+Log_event::enum_skip_reason
+Table_map_log_event::do_shall_skip(RELAY_LOG_INFO *rli)
+{
+ /*
+ If the slave skip counter is 1, then we should not start executing
+ on the next event.
+ */
+ if (rli->slave_skip_counter == 1)
+ return Log_event::EVENT_SKIP_IGNORE;
+ else
+ return Log_event::do_shall_skip(rli);
+}
+
int Table_map_log_event::do_update_pos(RELAY_LOG_INFO *rli)
{
rli->inc_event_relay_log_pos();
diff --git a/sql/log_event.h b/sql/log_event.h
index bb69043969d..092b349350e 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -2067,6 +2067,7 @@ private:
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
virtual int do_apply_event(RELAY_LOG_INFO const *rli);
virtual int do_update_pos(RELAY_LOG_INFO *rli);
+ virtual enum_skip_reason do_shall_skip(RELAY_LOG_INFO *rli);
#endif
#ifndef MYSQL_CLIENT
@@ -2245,6 +2246,7 @@ private:
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
virtual int do_apply_event(RELAY_LOG_INFO const *rli);
virtual int do_update_pos(RELAY_LOG_INFO *rli);
+ virtual enum_skip_reason do_shall_skip(RELAY_LOG_INFO *rli);
/*
Primitive to prepare for a sequence of row executions.
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index bb2d9c25a77..40744d0b07b 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -6059,3 +6059,6 @@ ER_SLAVE_INCIDENT
eng "The incident %s occured on the master. Message: %-.64s"
ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT
eng "Table has no partition for some existing values"
+ER_BINLOG_UNSAFE_STATEMENT
+ eng "Statement is not safe to log in statement format."
+ swe "Detta är inte säkert att logga i statement-format."
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 566aadcc864..8a09cede337 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -1855,7 +1855,7 @@ sp_head::restore_lex(THD *thd)
cannot switch from statement-based to row-based only for this
substatement).
*/
- if (sublex->binlog_row_based_if_mixed)
+ if (sublex->is_stmt_unsafe())
m_flags|= BINLOG_ROW_BASED_IF_MIXED;
/*
diff --git a/sql/sp_head.h b/sql/sp_head.h
index 4e3e11e468d..a6a41ec68f9 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -378,7 +378,7 @@ public:
the substatements not).
*/
if (m_flags & BINLOG_ROW_BASED_IF_MIXED)
- lex->binlog_row_based_if_mixed= TRUE;
+ lex->set_stmt_unsafe();
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index a97d285810e..1986c09b2d2 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -3992,7 +3992,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
/*
CREATE ... SELECT UUID() locks no tables, we have to test here.
*/
- if (thd->lex->binlog_row_based_if_mixed)
+ if (thd->lex->is_stmt_unsafe())
thd->set_current_stmt_binlog_row_based_if_mixed();
if (!tables && !thd->lex->requires_prelocking())
@@ -4033,7 +4033,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
if (thd->variables.binlog_format == BINLOG_FORMAT_MIXED &&
has_two_write_locked_tables_with_auto_increment(tables))
{
- thd->lex->binlog_row_based_if_mixed= TRUE;
+ thd->lex->set_stmt_unsafe();
thd->set_current_stmt_binlog_row_based_if_mixed();
}
}
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 018425099bb..cc3b281f892 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -329,7 +329,7 @@ THD::THD()
Open_tables_state(refresh_version), rli_fake(0),
lock_id(&main_lock_id),
user_time(0), in_sub_stmt(0),
- binlog_table_maps(0),
+ binlog_table_maps(0), binlog_flags(0UL),
arg_of_last_insert_id_function(FALSE),
first_successful_insert_id_in_prev_stmt(0),
first_successful_insert_id_in_prev_stmt_for_binlog(0),
@@ -3103,6 +3103,27 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query,
if (int error= binlog_flush_pending_rows_event(TRUE))
DBUG_RETURN(error);
+ /*
+ If we are in statement mode and trying to log an unsafe statement,
+ we should print a warning.
+ */
+ if (lex->is_stmt_unsafe() &&
+ variables.binlog_format == BINLOG_FORMAT_STMT)
+ {
+ DBUG_ASSERT(this->query != NULL);
+ push_warning(this, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_BINLOG_UNSAFE_STATEMENT,
+ ER(ER_BINLOG_UNSAFE_STATEMENT));
+ if (!(binlog_flags & BINLOG_FLAG_UNSAFE_STMT_PRINTED))
+ {
+ char warn_buf[MYSQL_ERRMSG_SIZE];
+ my_snprintf(warn_buf, MYSQL_ERRMSG_SIZE, "%s Statement: %s",
+ ER(ER_BINLOG_UNSAFE_STATEMENT), this->query);
+ sql_print_warning(warn_buf);
+ binlog_flags|= BINLOG_FLAG_UNSAFE_STMT_PRINTED;
+ }
+ }
+
switch (qtype) {
case THD::ROW_QUERY_TYPE:
if (current_stmt_binlog_row_based)
diff --git a/sql/sql_class.h b/sql/sql_class.h
index a0b1402d060..fb713d8a80b 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1110,6 +1110,17 @@ public:
private:
uint binlog_table_maps; // Number of table maps currently in the binlog
+
+ enum enum_binlog_flag {
+ BINLOG_FLAG_UNSAFE_STMT_PRINTED,
+ BINLOG_FLAG_COUNT
+ };
+
+ /**
+ Flags with per-thread information regarding the status of the
+ binary log.
+ */
+ uint32 binlog_flags;
public:
uint get_binlog_table_maps() const {
return binlog_table_maps;
@@ -1680,6 +1691,7 @@ public:
void restore_sub_statement_state(Sub_statement_state *backup);
void set_n_backup_active_arena(Query_arena *set, Query_arena *backup);
void restore_active_arena(Query_arena *set, Query_arena *backup);
+
inline void set_current_stmt_binlog_row_based_if_mixed()
{
/*
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 5fd0ec669bd..6be2c95a661 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1664,6 +1664,7 @@ public:
Statement-based replication of INSERT DELAYED has problems with RAND()
and user vars, so in mixed mode we go to row-based.
*/
+ thd.lex->set_stmt_unsafe();
thd.set_current_stmt_binlog_row_based_if_mixed();
bzero((char*) &thd.net, sizeof(thd.net)); // Safety
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index c19c224f0a3..684db21c2c9 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1782,7 +1782,7 @@ void Query_tables_list::reset_query_tables_list(bool init)
sroutines_list.empty();
sroutines_list_own_last= sroutines_list.next;
sroutines_list_own_elements= 0;
- binlog_row_based_if_mixed= FALSE;
+ binlog_stmt_flags= 0;
}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 68a3092cd77..a953f1a2684 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -951,14 +951,6 @@ public:
uint sroutines_list_own_elements;
/*
- Tells if the parsing stage detected that some items require row-based
- binlogging to give a reliable binlog/replication, or if we will use
- stored functions or triggers which themselves need require row-based
- binlogging.
- */
- bool binlog_row_based_if_mixed;
-
- /*
These constructor and destructor serve for creation/destruction
of Query_tables_list instances which are used as backup storage.
*/
@@ -1005,12 +997,48 @@ public:
query_tables_own_last= 0;
}
}
+
+ /**
+ Has the parser/scanner detected that this statement is unsafe?
+ */
+ inline bool is_stmt_unsafe() const {
+ return binlog_stmt_flags & (1U << BINLOG_STMT_FLAG_UNSAFE);
+ }
+
+ /**
+ Flag the current (top-level) statement as unsafe.
+
+ The flag will be reset after the statement has finished.
+
+ */
+ inline void set_stmt_unsafe() {
+ binlog_stmt_flags|= (1U << BINLOG_STMT_FLAG_UNSAFE);
+ }
+
+ inline void clear_stmt_unsafe() {
+ binlog_stmt_flags&= ~(1U << BINLOG_STMT_FLAG_UNSAFE);
+ }
+
/**
true if the parsed tree contains references to stored procedures
or functions, false otherwise
*/
bool uses_stored_routines() const
{ return sroutines_list.elements != 0; }
+
+private:
+ enum enum_binlog_stmt_flag {
+ BINLOG_STMT_FLAG_UNSAFE,
+ BINLOG_STMT_FLAG_COUNT
+ };
+
+ /*
+ Tells if the parsing stage detected properties of the statement,
+ for example: that some items require row-based binlogging to give
+ a reliable binlog/replication, or if we will use stored functions
+ or triggers which themselves need require row-based binlogging.
+ */
+ uint32 binlog_stmt_flags;
};
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 8645cc60d89..64f2f9d32b8 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -1118,8 +1118,8 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
If the view's body needs row-based binlogging (e.g. the VIEW is created
from SELECT UUID()), the top statement also needs it.
*/
- if (lex->binlog_row_based_if_mixed)
- old_lex->binlog_row_based_if_mixed= TRUE;
+ if (lex->is_stmt_unsafe())
+ old_lex->set_stmt_unsafe();
view_is_mergeable= (table->algorithm != VIEW_ALGORITHM_TMPTABLE &&
lex->can_be_merged());
LINT_INIT(view_main_select_tables);