Commit 4f0f021c authored by Guangbao Ni's avatar Guangbao Ni

BUG#41980 SBL, INSERT .. SELECT .. LIMIT = ERROR, even when @@SQL_LOG_BIN is 0 !

      
When binlog_format is STATEMENT and the statement is unsafe before,
the unsafe warning/error message was issued without checking
whether the SQL_LOG_BIN was turned on or not.
      
Fixed with adding a sql_log_bin_toplevel flag in THD to check
whether SQL_LOG_BIN is ON in current session whatever the current is in sp or not.


mysql-test/suite/binlog/r/binlog_unsafe.result:
  Test case result for unsafe warning/error message
mysql-test/suite/binlog/t/binlog_unsafe.test:
  Test case for unsafe message warning/error
sql/set_var.cc:
  Adding a function set_option_log_bin_bit() which specailly handles to
  the change of SQL_LOG_BIN bit in order to set sql_log_bin_toplevel
  according to SQL_LOG_BIN current value at the same time.
sql/sql_class.cc:
  Initialize the flag sql_log_bin_toplevel in THD::init(),
  and add the condition to check whether unsafe ror message was issued.
sql/sql_class.h:
  Add a sql_log_bin_toplevel flag in THD to indicate whether the toplevel SQL_LOG_BIN is
parent 16c0631f
...@@ -227,3 +227,86 @@ UPDATE t1 SET b = '%s%s%s%s%s%s%s%s%s%s%s%s%s%s' WHERE a = 'a' LIMIT 1; ...@@ -227,3 +227,86 @@ UPDATE t1 SET b = '%s%s%s%s%s%s%s%s%s%s%s%s%s%s' WHERE a = 'a' LIMIT 1;
Warnings: Warnings:
Warning 1592 Statement is not safe to log in statement format. Warning 1592 Statement is not safe to log in statement format.
DROP TABLE t1; DROP TABLE t1;
DROP TABLE IF EXISTS t1, t2;
CREATE TABLE t1(i INT PRIMARY KEY);
CREATE TABLE t2(i INT PRIMARY KEY);
CREATE TABLE t3(i INT, ch CHAR(50));
"Should issue message Statement is not safe to log in statement format."
INSERT INTO t1 SELECT * FROM t2 LIMIT 1;
Warnings:
Warning 1592 Statement is not safe to log in statement format.
CREATE FUNCTION func6()
RETURNS INT
BEGIN
INSERT INTO t1 VALUES (10);
INSERT INTO t1 VALUES (11);
INSERT INTO t1 VALUES (12);
RETURN 0;
END|
"Should issue message Statement is not safe to log in statement format only once"
INSERT INTO t3 VALUES(func6(), UUID());
Warnings:
Warning 1592 Statement is not safe to log in statement format.
"Check whether SET @@SQL_LOG_BIN = 0/1 doesn't work in substatements"
CREATE FUNCTION fun_check_log_bin() RETURNS INT
BEGIN
SET @@SQL_LOG_BIN = 0;
INSERT INTO t1 VALUES(@@global.sync_binlog);
RETURN 100;
END|
"One unsafe warning should be issued in the following statement"
SELECT fun_check_log_bin();
fun_check_log_bin()
100
Warnings:
Warning 1592 Statement is not safe to log in statement format.
"SQL_LOG_BIN should be ON still"
SHOW VARIABLES LIKE "SQL_LOG_BIN";
Variable_name Value
sql_log_bin ON
set @save_log_bin = @@SESSION.SQL_LOG_BIN;
set @@SESSION.SQL_LOG_BIN = 0;
"Should NOT have any warning message issued in the following statements"
INSERT INTO t1 SELECT * FROM t2 LIMIT 1;
DROP TABLE t1,t2;
"Should NOT have any warning message issued in the following func7() and trig"
CREATE TABLE t1 (a INT);
CREATE TABLE t2 (a CHAR(40));
CREATE TABLE trigger_table (a CHAR(7));
CREATE FUNCTION func7()
RETURNS INT
BEGIN
INSERT INTO t1 VALUES (@@global.sync_binlog);
INSERT INTO t1 VALUES (@@session.insert_id);
INSERT INTO t2 SELECT UUID();
INSERT INTO t2 VALUES (@@session.sql_mode);
INSERT INTO t2 VALUES (@@global.init_slave);
RETURN 0;
END|
SHOW VARIABLES LIKE "SQL_LOG_BIN";
Variable_name Value
sql_log_bin OFF
SELECT func7();
func7()
0
---- Insert from trigger ----
CREATE TRIGGER trig
BEFORE INSERT ON trigger_table
FOR EACH ROW
BEGIN
INSERT INTO t1 VALUES (@@global.sync_binlog);
INSERT INTO t1 VALUES (@@session.insert_id);
INSERT INTO t1 VALUES (@@global.auto_increment_increment);
INSERT INTO t2 SELECT UUID();
INSERT INTO t2 VALUES (@@session.sql_mode);
INSERT INTO t2 VALUES (@@global.init_slave);
INSERT INTO t2 VALUES (@@hostname);
END|
INSERT INTO trigger_table VALUES ('bye.');
DROP FUNCTION fun_check_log_bin;
DROP FUNCTION func6;
DROP FUNCTION func7;
DROP TRIGGER trig;
DROP TABLE t1, t2, t3, trigger_table;
set @@SESSION.SQL_LOG_BIN = @save_log_bin;
"End of tests"
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
# executed cannot be determined (e.g., INSERT DELAYED). Such # executed cannot be determined (e.g., INSERT DELAYED). Such
# statements should be marked unsafe. All unsafe statements should # statements should be marked unsafe. All unsafe statements should
# give a warning. # give a warning.
# Yet the warning/error message isn't issued when SQL_LOG_BIN is turned off.
# #
# This test verifies that a warning is generated for statements that # This test verifies that a warning is generated for statements that
# should be unsafe, when they are executed under statement mode # should be unsafe, when they are executed under statement mode
...@@ -32,14 +33,19 @@ ...@@ -32,14 +33,19 @@
# We try to insert the variables that should not be unsafe into a # We try to insert the variables that should not be unsafe into a
# table, and verify that *no* warning is issued. # table, and verify that *no* warning is issued.
# #
# # Execute a unsafe statement calling a trigger or stored function
# or neither when SQL_LOG_BIN is turned ON, a warning/error should be issued
# Execute a unsafe statement calling a trigger or stored function
# or neither when @@SQL_LOG_BIN is turned OFF,
# no warning/error is issued
# ==== Related bugs and worklogs ==== # ==== Related bugs and worklogs ====
# #
# WL#3339: Issue warnings when statement-based replication may fail # WL#3339: Issue warnings when statement-based replication may fail
# BUG#31168: @@hostname does not replicate # BUG#31168: @@hostname does not replicate
# BUG#34732: mysqlbinlog does not print default values for auto_increment variables # BUG#34732: mysqlbinlog does not print default values for auto_increment variables
# BUG#34768: nondeterministic INSERT using LIMIT logged in stmt mode if binlog_format=mixed # BUG#34768: nondeterministic INSERT using LIMIT logged in stmt mode if binlog_format=mixed
# # BUG#41980, SBL, INSERT .. SELECT .. LIMIT = ERROR, even when @@SQL_LOG_BIN is 0
# #
# ==== Related test cases ==== # ==== Related test cases ====
# #
...@@ -271,3 +277,96 @@ INSERT INTO t1 VALUES ('a','b'); ...@@ -271,3 +277,96 @@ INSERT INTO t1 VALUES ('a','b');
UPDATE t1 SET b = '%s%s%s%s%s%s%s%s%s%s%s%s%s%s' WHERE a = 'a' LIMIT 1; UPDATE t1 SET b = '%s%s%s%s%s%s%s%s%s%s%s%s%s%s' WHERE a = 'a' LIMIT 1;
DROP TABLE t1; DROP TABLE t1;
#
#For bug#41980, SBL, INSERT .. SELECT .. LIMIT = ERROR, even when @@SQL_LOG_BIN is 0
#
--disable_warnings
DROP TABLE IF EXISTS t1, t2;
--enable_warnings
CREATE TABLE t1(i INT PRIMARY KEY);
CREATE TABLE t2(i INT PRIMARY KEY);
CREATE TABLE t3(i INT, ch CHAR(50));
--echo "Should issue message Statement is not safe to log in statement format."
INSERT INTO t1 SELECT * FROM t2 LIMIT 1;
DELIMITER |;
CREATE FUNCTION func6()
RETURNS INT
BEGIN
INSERT INTO t1 VALUES (10);
INSERT INTO t1 VALUES (11);
INSERT INTO t1 VALUES (12);
RETURN 0;
END|
DELIMITER ;|
--echo "Should issue message Statement is not safe to log in statement format only once"
INSERT INTO t3 VALUES(func6(), UUID());
--echo "Check whether SET @@SQL_LOG_BIN = 0/1 doesn't work in substatements"
DELIMITER |;
CREATE FUNCTION fun_check_log_bin() RETURNS INT
BEGIN
SET @@SQL_LOG_BIN = 0;
INSERT INTO t1 VALUES(@@global.sync_binlog);
RETURN 100;
END|
DELIMITER ;|
--echo "One unsafe warning should be issued in the following statement"
SELECT fun_check_log_bin();
--echo "SQL_LOG_BIN should be ON still"
SHOW VARIABLES LIKE "SQL_LOG_BIN";
set @save_log_bin = @@SESSION.SQL_LOG_BIN;
set @@SESSION.SQL_LOG_BIN = 0;
--echo "Should NOT have any warning message issued in the following statements"
INSERT INTO t1 SELECT * FROM t2 LIMIT 1;
DROP TABLE t1,t2;
--echo "Should NOT have any warning message issued in the following func7() and trig"
CREATE TABLE t1 (a INT);
CREATE TABLE t2 (a CHAR(40));
CREATE TABLE trigger_table (a CHAR(7));
DELIMITER |;
CREATE FUNCTION func7()
RETURNS INT
BEGIN
INSERT INTO t1 VALUES (@@global.sync_binlog);
INSERT INTO t1 VALUES (@@session.insert_id);
INSERT INTO t2 SELECT UUID();
INSERT INTO t2 VALUES (@@session.sql_mode);
INSERT INTO t2 VALUES (@@global.init_slave);
RETURN 0;
END|
DELIMITER ;|
SHOW VARIABLES LIKE "SQL_LOG_BIN";
SELECT func7();
--echo ---- Insert from trigger ----
DELIMITER |;
CREATE TRIGGER trig
BEFORE INSERT ON trigger_table
FOR EACH ROW
BEGIN
INSERT INTO t1 VALUES (@@global.sync_binlog);
INSERT INTO t1 VALUES (@@session.insert_id);
INSERT INTO t1 VALUES (@@global.auto_increment_increment);
INSERT INTO t2 SELECT UUID();
INSERT INTO t2 VALUES (@@session.sql_mode);
INSERT INTO t2 VALUES (@@global.init_slave);
INSERT INTO t2 VALUES (@@hostname);
END|
DELIMITER ;|
INSERT INTO trigger_table VALUES ('bye.');
#clean up
DROP FUNCTION fun_check_log_bin;
DROP FUNCTION func6;
DROP FUNCTION func7;
DROP TRIGGER trig;
DROP TABLE t1, t2, t3, trigger_table;
set @@SESSION.SQL_LOG_BIN = @save_log_bin;
--echo "End of tests"
...@@ -110,6 +110,7 @@ static void sys_default_init_connect(THD*, enum_var_type type); ...@@ -110,6 +110,7 @@ static void sys_default_init_connect(THD*, enum_var_type type);
static bool sys_update_init_slave(THD*, set_var*); static bool sys_update_init_slave(THD*, set_var*);
static void sys_default_init_slave(THD*, enum_var_type type); static void sys_default_init_slave(THD*, enum_var_type type);
static bool set_option_bit(THD *thd, set_var *var); static bool set_option_bit(THD *thd, set_var *var);
static bool set_option_log_bin_bit(THD *thd, set_var *var);
static bool set_option_autocommit(THD *thd, set_var *var); static bool set_option_autocommit(THD *thd, set_var *var);
static int check_log_update(THD *thd, set_var *var); static int check_log_update(THD *thd, set_var *var);
static bool set_log_update(THD *thd, set_var *var); static bool set_log_update(THD *thd, set_var *var);
...@@ -731,7 +732,7 @@ static sys_var_thd_bit sys_log_update(&vars, "sql_log_update", ...@@ -731,7 +732,7 @@ static sys_var_thd_bit sys_log_update(&vars, "sql_log_update",
OPTION_BIN_LOG); OPTION_BIN_LOG);
static sys_var_thd_bit sys_log_binlog(&vars, "sql_log_bin", static sys_var_thd_bit sys_log_binlog(&vars, "sql_log_bin",
check_log_update, check_log_update,
set_option_bit, set_option_log_bin_bit,
OPTION_BIN_LOG); OPTION_BIN_LOG);
static sys_var_thd_bit sys_sql_warnings(&vars, "sql_warnings", 0, static sys_var_thd_bit sys_sql_warnings(&vars, "sql_warnings", 0,
set_option_bit, set_option_bit,
...@@ -2963,6 +2964,16 @@ static bool set_option_bit(THD *thd, set_var *var) ...@@ -2963,6 +2964,16 @@ static bool set_option_bit(THD *thd, set_var *var)
return 0; return 0;
} }
/*
Functions to be only used to update thd->options OPTION_BIN_LOG bit
*/
static bool set_option_log_bin_bit(THD *thd, set_var *var)
{
set_option_bit(thd, var);
if (!thd->in_sub_stmt)
thd->sql_log_bin_toplevel= thd->options & OPTION_BIN_LOG;
return 0;
}
static bool set_option_autocommit(THD *thd, set_var *var) static bool set_option_autocommit(THD *thd, set_var *var)
{ {
......
...@@ -538,6 +538,7 @@ THD::THD() ...@@ -538,6 +538,7 @@ THD::THD()
Open_tables_state(refresh_version), rli_fake(0), Open_tables_state(refresh_version), rli_fake(0),
lock_id(&main_lock_id), lock_id(&main_lock_id),
user_time(0), in_sub_stmt(0), user_time(0), in_sub_stmt(0),
sql_log_bin_toplevel(false),
binlog_table_maps(0), binlog_flags(0UL), binlog_table_maps(0), binlog_flags(0UL),
table_map_for_update(0), table_map_for_update(0),
arg_of_last_insert_id_function(FALSE), arg_of_last_insert_id_function(FALSE),
...@@ -787,6 +788,7 @@ void THD::init(void) ...@@ -787,6 +788,7 @@ void THD::init(void)
update_charset(); update_charset();
reset_current_stmt_binlog_row_based(); reset_current_stmt_binlog_row_based();
bzero((char *) &status_var, sizeof(status_var)); bzero((char *) &status_var, sizeof(status_var));
sql_log_bin_toplevel= options & OPTION_BIN_LOG;
} }
...@@ -3662,7 +3664,7 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg, ...@@ -3662,7 +3664,7 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
If we are in statement mode and trying to log an unsafe statement, If we are in statement mode and trying to log an unsafe statement,
we should print a warning. we should print a warning.
*/ */
if (lex->is_stmt_unsafe() && if (sql_log_bin_toplevel && lex->is_stmt_unsafe() &&
variables.binlog_format == BINLOG_FORMAT_STMT) variables.binlog_format == BINLOG_FORMAT_STMT)
{ {
push_warning(this, MYSQL_ERROR::WARN_LEVEL_WARN, push_warning(this, MYSQL_ERROR::WARN_LEVEL_WARN,
......
...@@ -1350,6 +1350,8 @@ public: ...@@ -1350,6 +1350,8 @@ public:
/* <> 0 if we are inside of trigger or stored function. */ /* <> 0 if we are inside of trigger or stored function. */
uint in_sub_stmt; uint in_sub_stmt;
/* TRUE when the current top has SQL_LOG_BIN ON */
bool sql_log_bin_toplevel;
/* container for handler's private per-connection data */ /* container for handler's private per-connection data */
Ha_data ha_data[MAX_HA]; Ha_data ha_data[MAX_HA];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment