Commit 66481aeb authored by Sven Sandberg's avatar Sven Sandberg

BUG#39934: Slave stops for engine that only support row-based logging

Post-push fix.
Problem: After the original bugfix, if a statement is unsafe,
binlog_format=mixed, and engine is statement-only, a warning was
generated and the statement executed. However, it is a fundamental
principle of binlogging that binlog_format=mixed should guarantee
correct logging, no compromise. So correct behavior is to generate
an error and don't execute the statement.
Fix: Generate error instead of warning.
Since issue_unsafe_warnings can only generate one error message,
this allows us to simplify the code a bit too:
decide_logging_format does not have to save the error code for
issue_unsafe_warnings


mysql-test/suite/binlog/r/binlog_statement_insert_delayed.result:
  updated result file
mysql-test/suite/binlog/r/binlog_stm_ps.result:
  updated result file
mysql-test/suite/binlog/r/binlog_stm_unsafe_warning.result:
  updated result file
mysql-test/suite/binlog/r/binlog_unsafe.result:
  updated result file
mysql-test/suite/rpl/r/rpl_stm_found_rows.result:
  updated result file
mysql-test/suite/rpl/r/rpl_stm_loadfile.result:
  updated result file
mysql-test/suite/rpl_ndb/r/rpl_ndb_binlog_format_errors.result:
  updated result file
mysql-test/suite/rpl_ndb/t/rpl_ndb_binlog_format_errors.test:
  updated test:
   - ER_BINLOG_UNSAFE_AND_STMT_ENGINE is now an error.
   - added test for multiple types of unsafety
sql/share/errmsg.txt:
   - Reformulated ER_BINLOG_UNSAFE_AND_STMT_ENGINE to reflect that it
     is now an error, not a warning.
   - Added "Reason for unsafeness" to ER_BINLOG_UNSAFE_STATEMENT and
     ER_BINLOG_UNSAFE_AND_STMT_ENGINE.
sql/sql_class.cc:
  In decide_logging_format:
   - generate an error immediately in case 3, instead of scheduling a
     warning to be generated later. also updated comments accordingly
   - in case 7, there is only one unsafe warning error code now, so we
     don't need to store it in binlog_unsafe_warning_flags
     (see changes in sql_lex.h)
   - fixed compilation warning in DBUG_PRINT
  
  In issue_binlog_warning:
   - moved array of error codes to sql_lex.h (so that they are
     accessible also from decide_logging_format)
   - simplified code after the first set of bits in
     binlog_unsafe_warning_flags was removed
sql/sql_class.h:
   - got rid of enum_binlog_stmt_warning. It's not needed anymore
     since we only have one type of unsafe warning (one of them
     turned into an error)
   - updated comments accordingly
sql/sql_lex.cc:
  added initialization of the array of error codes that has been
  moved from THD::issue_unsafe_warnings to LEX.
sql/sql_lex.h:
  Moved array of error codes from THD::issue_unsafe_warnings to LEX.
parent 89f8e5ef
...@@ -13,10 +13,10 @@ master-bin.000001 # Query # # use `test`; insert delayed into t1 values (300) ...@@ -13,10 +13,10 @@ master-bin.000001 # Query # # use `test`; insert delayed into t1 values (300)
master-bin.000001 # Query # # use `test`; FLUSH TABLES master-bin.000001 # Query # # use `test`; FLUSH TABLES
insert delayed into t1 values (null),(null),(null),(null); insert delayed into t1 values (null),(null),(null),(null);
Warnings: Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason: Statement uses INSERT DELAYED. This is unsafe because the time when rows are inserted cannot be predicted. Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statement uses INSERT DELAYED. This is unsafe because the time when rows are inserted cannot be predicted.
insert delayed into t1 values (null),(null),(400),(null); insert delayed into t1 values (null),(null),(400),(null);
Warnings: Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason: Statement uses INSERT DELAYED. This is unsafe because the time when rows are inserted cannot be predicted. Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statement uses INSERT DELAYED. This is unsafe because the time when rows are inserted cannot be predicted.
select * from t1; select * from t1;
a a
207 207
......
...@@ -11,7 +11,7 @@ prepare s from "insert into t1 select 100 limit ?"; ...@@ -11,7 +11,7 @@ prepare s from "insert into t1 select 100 limit ?";
set @a=100; set @a=100;
execute s using @a; execute s using @a;
Warnings: Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason: Statement uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted. Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statement uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted.
show binlog events from <binlog_start>; show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; create table t1 (a int) master-bin.000001 # Query # # use `test`; create table t1 (a int)
......
...@@ -4,10 +4,10 @@ CREATE TABLE t1 (a int, b int, primary key (a)); ...@@ -4,10 +4,10 @@ CREATE TABLE t1 (a int, b int, primary key (a));
INSERT INTO t1 VALUES (1,2), (2,3); INSERT INTO t1 VALUES (1,2), (2,3);
UPDATE t1 SET b='4' WHERE a=1 LIMIT 1; UPDATE t1 SET b='4' WHERE a=1 LIMIT 1;
Warnings: Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason: Statement uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted. Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statement uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted.
UPDATE t1 SET b='5' WHERE a=2 ORDER BY a LIMIT 1; UPDATE t1 SET b='5' WHERE a=2 ORDER BY a LIMIT 1;
Warnings: Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason: Statement uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted. Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statement uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted.
DROP TABLE t1; DROP TABLE t1;
### NOT filtered database => assertion: binlog disabled and warnings ARE NOT shown ### NOT filtered database => assertion: binlog disabled and warnings ARE NOT shown
SET SQL_LOG_BIN= 0; SET SQL_LOG_BIN= 0;
...@@ -38,11 +38,11 @@ CREATE TABLE t1 (a VARCHAR(36), b VARCHAR(10)); ...@@ -38,11 +38,11 @@ CREATE TABLE t1 (a VARCHAR(36), b VARCHAR(10));
SET GLOBAL LOG_WARNINGS = 0; SET GLOBAL LOG_WARNINGS = 0;
INSERT INTO t1 VALUES(UUID(), 'Bug#46265'); INSERT INTO t1 VALUES(UUID(), 'Bug#46265');
Warnings: Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason: Statement uses a system function whose value may differ on slave. Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statement uses a system function whose value may differ on slave.
SET GLOBAL LOG_WARNINGS = 1; SET GLOBAL LOG_WARNINGS = 1;
INSERT INTO t1 VALUES(UUID(), 'Bug#46265'); INSERT INTO t1 VALUES(UUID(), 'Bug#46265');
Warnings: Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason: Statement uses a system function whose value may differ on slave. Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statement uses a system function whose value may differ on slave.
DROP TABLE t1; DROP TABLE t1;
SET GLOBAL log_warnings = @old_log_warnings; SET GLOBAL log_warnings = @old_log_warnings;
# Count the number of times the "Unsafe" message was printed # Count the number of times the "Unsafe" message was printed
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -52,8 +52,8 @@ a ...@@ -52,8 +52,8 @@ a
a a
7 7
Warnings: Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason: Statement uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted. Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statement uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted.
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason: Statement uses a system function whose value may differ on slave. Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statement uses a system function whose value may differ on slave.
CREATE PROCEDURE just_log(sect INT, test INT, found_rows INT) BEGIN CREATE PROCEDURE just_log(sect INT, test INT, found_rows INT) BEGIN
INSERT INTO logtbl VALUES (sect,test,found_rows); INSERT INTO logtbl VALUES (sect,test,found_rows);
END $$ END $$
......
...@@ -10,7 +10,7 @@ CREATE TABLE test.t1 (a INT, blob_column LONGBLOB, PRIMARY KEY(a)); ...@@ -10,7 +10,7 @@ CREATE TABLE test.t1 (a INT, blob_column LONGBLOB, PRIMARY KEY(a));
INSERT INTO test.t1 VALUES(1,'test'); INSERT INTO test.t1 VALUES(1,'test');
UPDATE test.t1 SET blob_column=LOAD_FILE('../../std_data/words2.dat') WHERE a=1; UPDATE test.t1 SET blob_column=LOAD_FILE('../../std_data/words2.dat') WHERE a=1;
Warnings: Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason: Statement uses a system function whose value may differ on slave. Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statement uses a system function whose value may differ on slave.
create procedure test.p1() create procedure test.p1()
begin begin
INSERT INTO test.t1 VALUES(2,'test'); INSERT INTO test.t1 VALUES(2,'test');
...@@ -18,7 +18,7 @@ UPDATE test.t1 SET blob_column=LOAD_FILE('../../std_data/words2.dat') WHERE a=2; ...@@ -18,7 +18,7 @@ UPDATE test.t1 SET blob_column=LOAD_FILE('../../std_data/words2.dat') WHERE a=2;
end| end|
CALL test.p1(); CALL test.p1();
Warnings: Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason: Statement uses a system function whose value may differ on slave. Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statement uses a system function whose value may differ on slave.
SELECT * FROM test.t1 ORDER BY blob_column; SELECT * FROM test.t1 ORDER BY blob_column;
a blob_column a blob_column
1 abase 1 abase
......
...@@ -16,6 +16,10 @@ CREATE TABLE t_self_logging (a VARCHAR(100)) ENGINE = NDB; ...@@ -16,6 +16,10 @@ CREATE TABLE t_self_logging (a VARCHAR(100)) ENGINE = NDB;
CREATE TABLE t_row (a VARCHAR(100)) ENGINE = INNODB; CREATE TABLE t_row (a VARCHAR(100)) ENGINE = INNODB;
CREATE TABLE t_stmt (a VARCHAR(100)) ENGINE = EXAMPLE; CREATE TABLE t_stmt (a VARCHAR(100)) ENGINE = EXAMPLE;
CREATE TABLE t_slave_stmt (a VARCHAR(100)) ENGINE = MYISAM; CREATE TABLE t_slave_stmt (a VARCHAR(100)) ENGINE = MYISAM;
CREATE TABLE t_autoinc (a INT KEY AUTO_INCREMENT) ENGINE = MYISAM;
CREATE TABLE t_double_autoinc (a INT KEY AUTO_INCREMENT) ENGINE = MYISAM;
CREATE TRIGGER trig_autoinc BEFORE INSERT ON t_autoinc FOR EACH ROW BEGIN INSERT INTO t_stmt VALUES ('x'); END;
CREATE TRIGGER trig_double_autoinc BEFORE INSERT ON t_double_autoinc FOR EACH ROW BEGIN INSERT INTO t_autoinc VALUES (NULL); END;
CREATE DATABASE other; CREATE DATABASE other;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
[on slave] [on slave]
...@@ -64,8 +68,10 @@ SET @@global.binlog_format = MIXED; ...@@ -64,8 +68,10 @@ SET @@global.binlog_format = MIXED;
SET @@session.binlog_format = MIXED; SET @@session.binlog_format = MIXED;
* Unsafe statement and stmt-only engine * Unsafe statement and stmt-only engine
INSERT INTO t_stmt VALUES (UUID()); INSERT INTO t_stmt VALUES (UUID());
Warnings: ERROR HY000: Cannot execute statement: binlogging of unsafe statement is impossible when storage engine is limited to statement-logging and BINLOG_FORMAT = MIXED. Reason for unsafeness: Statement uses a system function whose value may differ on slave.
Note 1641 Unsafe statement binlogged as statement since storage engine is limited to statement-logging. Reason: Statement uses a system function whose value may differ on slave. * Multi-unsafe statement and stmt-only engine
INSERT DELAYED INTO t_double_autoinc SELECT CONCAT(UUID(), @@hostname, myfunc_int(), NULL) FROM mysql.general_log LIMIT 1;
ERROR HY000: Cannot execute statement: binlogging of unsafe statement is impossible when storage engine is limited to statement-logging and BINLOG_FORMAT = MIXED. Reason for unsafeness: Statement uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted.
---- binlog_format=statement ---- ---- binlog_format=statement ----
[on slave] [on slave]
include/stop_slave.inc include/stop_slave.inc
...@@ -102,7 +108,7 @@ USE test; ...@@ -102,7 +108,7 @@ USE test;
* Unsafe statement and binlog_format=statement * Unsafe statement and binlog_format=statement
INSERT INTO t VALUES (UUID()); INSERT INTO t VALUES (UUID());
Warnings: Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason: Statement uses a system function whose value may differ on slave. Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statement uses a system function whose value may differ on slave.
* Same statement, but db filtered out - no message * Same statement, but db filtered out - no message
USE other; USE other;
INSERT INTO test.t VALUES (UUID()); INSERT INTO test.t VALUES (UUID());
...@@ -119,7 +125,7 @@ set global sql_slave_skip_counter=1; ...@@ -119,7 +125,7 @@ set global sql_slave_skip_counter=1;
include/start_slave.inc include/start_slave.inc
[on master] [on master]
==== Clean up ==== ==== Clean up ====
DROP TABLE t, t_self_logging, t_row, t_stmt, t_slave_stmt; DROP TABLE t, t_self_logging, t_row, t_stmt, t_slave_stmt, t_autoinc, t_double_autoinc;
DROP DATABASE other; DROP DATABASE other;
SET @@global.binlog_format = @old_binlog_format; SET @@global.binlog_format = @old_binlog_format;
SET @@session.binlog_format = @old_binlog_format; SET @@session.binlog_format = @old_binlog_format;
......
...@@ -51,6 +51,11 @@ CREATE TABLE t_self_logging (a VARCHAR(100)) ENGINE = NDB; ...@@ -51,6 +51,11 @@ CREATE TABLE t_self_logging (a VARCHAR(100)) ENGINE = NDB;
CREATE TABLE t_row (a VARCHAR(100)) ENGINE = INNODB; CREATE TABLE t_row (a VARCHAR(100)) ENGINE = INNODB;
CREATE TABLE t_stmt (a VARCHAR(100)) ENGINE = EXAMPLE; CREATE TABLE t_stmt (a VARCHAR(100)) ENGINE = EXAMPLE;
CREATE TABLE t_slave_stmt (a VARCHAR(100)) ENGINE = MYISAM; CREATE TABLE t_slave_stmt (a VARCHAR(100)) ENGINE = MYISAM;
CREATE TABLE t_autoinc (a INT KEY AUTO_INCREMENT) ENGINE = MYISAM;
CREATE TABLE t_double_autoinc (a INT KEY AUTO_INCREMENT) ENGINE = MYISAM;
--eval CREATE TRIGGER trig_autoinc BEFORE INSERT ON t_autoinc FOR EACH ROW BEGIN INSERT INTO t_stmt VALUES ('x'); END
--eval CREATE TRIGGER trig_double_autoinc BEFORE INSERT ON t_double_autoinc FOR EACH ROW BEGIN INSERT INTO t_autoinc VALUES (NULL); END
CREATE DATABASE other; CREATE DATABASE other;
...@@ -127,9 +132,15 @@ SET @@global.binlog_format = MIXED; ...@@ -127,9 +132,15 @@ SET @@global.binlog_format = MIXED;
SET @@session.binlog_format = MIXED; SET @@session.binlog_format = MIXED;
--echo * Unsafe statement and stmt-only engine --echo * Unsafe statement and stmt-only engine
# This will give a warning. --error ER_BINLOG_UNSAFE_AND_STMT_ENGINE
INSERT INTO t_stmt VALUES (UUID()); INSERT INTO t_stmt VALUES (UUID());
# Concatenate three unsafe values, and then concatenate NULL to
# that so that the result is NULL and we instead use autoinc.
--echo * Multi-unsafe statement and stmt-only engine
--error ER_BINLOG_UNSAFE_AND_STMT_ENGINE
INSERT DELAYED INTO t_double_autoinc SELECT CONCAT(UUID(), @@hostname, myfunc_int(), NULL) FROM mysql.general_log LIMIT 1;
--echo ---- binlog_format=statement ---- --echo ---- binlog_format=statement ----
...@@ -213,7 +224,7 @@ INSERT INTO t VALUES (UUID()); ...@@ -213,7 +224,7 @@ INSERT INTO t VALUES (UUID());
--echo ==== Clean up ==== --echo ==== Clean up ====
DROP TABLE t, t_self_logging, t_row, t_stmt, t_slave_stmt; DROP TABLE t, t_self_logging, t_row, t_stmt, t_slave_stmt, t_autoinc, t_double_autoinc;
DROP DATABASE other; DROP DATABASE other;
SET @@global.binlog_format = @old_binlog_format; SET @@global.binlog_format = @old_binlog_format;
SET @@session.binlog_format = @old_binlog_format; SET @@session.binlog_format = @old_binlog_format;
......
...@@ -6076,7 +6076,7 @@ ER_SLAVE_INCIDENT ...@@ -6076,7 +6076,7 @@ ER_SLAVE_INCIDENT
ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT
eng "Table has no partition for some existing values" eng "Table has no partition for some existing values"
ER_BINLOG_UNSAFE_STATEMENT ER_BINLOG_UNSAFE_STATEMENT
eng "Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT." eng "Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: %s"
ER_SLAVE_FATAL_ERROR ER_SLAVE_FATAL_ERROR
eng "Fatal error: %s" eng "Fatal error: %s"
ER_SLAVE_RELAY_LOG_READ_FAILURE ER_SLAVE_RELAY_LOG_READ_FAILURE
...@@ -6211,7 +6211,7 @@ ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE ...@@ -6211,7 +6211,7 @@ ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE
ER_BINLOG_ROW_MODE_AND_STMT_ENGINE ER_BINLOG_ROW_MODE_AND_STMT_ENGINE
eng "Cannot execute statement: binlogging impossible since BINLOG_FORMAT = ROW and at least one table uses a storage engine limited to statement-logging." eng "Cannot execute statement: binlogging impossible since BINLOG_FORMAT = ROW and at least one table uses a storage engine limited to statement-logging."
ER_BINLOG_UNSAFE_AND_STMT_ENGINE ER_BINLOG_UNSAFE_AND_STMT_ENGINE
eng "Unsafe statement binlogged as statement since storage engine is limited to statement-logging." eng "Cannot execute statement: binlogging of unsafe statement is impossible when storage engine is limited to statement-logging and BINLOG_FORMAT = MIXED. Reason for unsafeness: %s"
ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE
eng "Cannot execute row injection: binlogging impossible since at least one table uses a storage engine limited to statement-logging." eng "Cannot execute row injection: binlogging impossible since at least one table uses a storage engine limited to statement-logging."
ER_BINLOG_STMT_MODE_AND_ROW_ENGINE ER_BINLOG_STMT_MODE_AND_ROW_ENGINE
...@@ -6236,7 +6236,5 @@ ER_BINLOG_UNSAFE_SYSTEM_VARIABLE ...@@ -6236,7 +6236,5 @@ ER_BINLOG_UNSAFE_SYSTEM_VARIABLE
ER_BINLOG_UNSAFE_SYSTEM_FUNCTION ER_BINLOG_UNSAFE_SYSTEM_FUNCTION
eng "Statement uses a system function whose value may differ on slave." eng "Statement uses a system function whose value may differ on slave."
ER_BINLOG_UNSAFE_WARNING_SHORT ER_MESSAGE_AND_STATEMENT
eng "%s Reason: %s" eng "%s Statement: %s"
ER_BINLOG_UNSAFE_WARNING_LONG
eng "%s Reason: %s Statement: %s"
...@@ -3282,8 +3282,8 @@ void xid_cache_delete(XID_STATE *xid_state) ...@@ -3282,8 +3282,8 @@ void xid_cache_delete(XID_STATE *xid_state)
binlog_format * SMRSMRSMR SMRSMRSMR SMRSMRSMR binlog_format * SMRSMRSMR SMRSMRSMR SMRSMRSMR
Logged format - SS-SS---- -RR-RR-RR SRRSRR-RR Logged format - SS-S----- -RR-RR-RR SRRSRR-RR
Warning/Error 1 --2332444 5--5--6-- ---7--6-- Warning/Error 1 --2732444 5--5--6-- ---7--6--
Legend Legend
------ ------
...@@ -3303,8 +3303,9 @@ void xid_cache_delete(XID_STATE *xid_state) ...@@ -3303,8 +3303,9 @@ void xid_cache_delete(XID_STATE *xid_state)
BINLOG_FORMAT = ROW and at least one table uses a storage engine BINLOG_FORMAT = ROW and at least one table uses a storage engine
limited to statement-logging. limited to statement-logging.
3. Warning: Unsafe statement binlogged as statement since storage 3. Error: Cannot execute statement: binlogging of unsafe statement
engine is limited to statement-logging. is impossible when storage engine is limited to statement-logging
and BINLOG_FORMAT = MIXED.
4. Error: Cannot execute row injection: binlogging impossible since 4. Error: Cannot execute row injection: binlogging impossible since
at least one table uses a storage engine limited to at least one table uses a storage engine limited to
...@@ -3457,17 +3458,16 @@ int THD::decide_logging_format(TABLE_LIST *tables) ...@@ -3457,17 +3458,16 @@ int THD::decide_logging_format(TABLE_LIST *tables)
else if ((unsafe_flags= lex->get_stmt_unsafe_flags()) != 0) else if ((unsafe_flags= lex->get_stmt_unsafe_flags()) != 0)
{ {
/* /*
3. Warning: Unsafe statement binlogged as statement since 3. Error: Cannot execute statement: binlogging of unsafe
storage engine is limited to statement-logging. statement is impossible when storage engine is limited to
statement-logging and BINLOG_FORMAT = MIXED.
*/ */
binlog_unsafe_warning_flags|= for (int unsafe_type= 0;
(1 << BINLOG_STMT_WARNING_UNSAFE_AND_STMT_ENGINE) | unsafe_type < LEX::BINLOG_STMT_UNSAFE_COUNT;
(unsafe_flags << BINLOG_STMT_WARNING_COUNT); unsafe_type++)
DBUG_PRINT("info", ("Scheduling warning to be issued by " if (unsafe_flags & (1 << unsafe_type))
"binlog_query: %s", my_error((error= ER_BINLOG_UNSAFE_AND_STMT_ENGINE), MYF(0),
ER(ER_BINLOG_UNSAFE_AND_STMT_ENGINE))); ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
DBUG_PRINT("info", ("binlog_unsafe_warning_flags: 0x%x",
binlog_unsafe_warning_flags));
} }
/* log in statement format! */ /* log in statement format! */
} }
...@@ -3499,13 +3499,11 @@ int THD::decide_logging_format(TABLE_LIST *tables) ...@@ -3499,13 +3499,11 @@ int THD::decide_logging_format(TABLE_LIST *tables)
7. Warning: Unsafe statement logged as statement due to 7. Warning: Unsafe statement logged as statement due to
binlog_format = STATEMENT binlog_format = STATEMENT
*/ */
binlog_unsafe_warning_flags|= binlog_unsafe_warning_flags|= unsafe_flags;
(1 << BINLOG_STMT_WARNING_UNSAFE_AND_STMT_MODE) |
(unsafe_flags << BINLOG_STMT_WARNING_COUNT);
DBUG_PRINT("info", ("Scheduling warning to be issued by " DBUG_PRINT("info", ("Scheduling warning to be issued by "
"binlog_query: '%s'", "binlog_query: '%s'",
ER(ER_BINLOG_UNSAFE_STATEMENT))); ER(ER_BINLOG_UNSAFE_STATEMENT)));
DBUG_PRINT("info", ("binlog_stmt_flags: 0x%x", DBUG_PRINT("info", ("binlog_unsafe_warning_flags: 0x%x",
binlog_unsafe_warning_flags)); binlog_unsafe_warning_flags));
} }
/* log in statement format! */ /* log in statement format! */
...@@ -3536,7 +3534,7 @@ int THD::decide_logging_format(TABLE_LIST *tables) ...@@ -3536,7 +3534,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
DBUG_PRINT("info", ("decision: no logging since " DBUG_PRINT("info", ("decision: no logging since "
"mysql_bin_log.is_open() = %d " "mysql_bin_log.is_open() = %d "
"and (options & OPTION_BIN_LOG) = 0x%llx " "and (options & OPTION_BIN_LOG) = 0x%llx "
"and binlog_format = %d " "and binlog_format = %ld "
"and binlog_filter->db_ok(db) = %d", "and binlog_filter->db_ok(db) = %d",
mysql_bin_log.is_open(), mysql_bin_log.is_open(),
(options & OPTION_BIN_LOG), (options & OPTION_BIN_LOG),
...@@ -4037,31 +4035,11 @@ void THD::issue_unsafe_warnings() ...@@ -4037,31 +4035,11 @@ void THD::issue_unsafe_warnings()
Ensure that binlog_unsafe_warning_flags is big enough to hold all Ensure that binlog_unsafe_warning_flags is big enough to hold all
bits. This is actually a constant expression. bits. This is actually a constant expression.
*/ */
DBUG_ASSERT(BINLOG_STMT_WARNING_COUNT + 2 * LEX::BINLOG_STMT_UNSAFE_COUNT <= DBUG_ASSERT(2 * LEX::BINLOG_STMT_UNSAFE_COUNT <=
sizeof(binlog_unsafe_warning_flags) * CHAR_BIT); sizeof(binlog_unsafe_warning_flags) * CHAR_BIT);
/** uint32 unsafe_type_flags= binlog_unsafe_warning_flags;
@note The order of the elements of this array must correspond to
the order of elements in enum_binlog_stmt_unsafe.
*/
static const int explanations[LEX::BINLOG_STMT_UNSAFE_COUNT] =
{
ER_BINLOG_UNSAFE_LIMIT,
ER_BINLOG_UNSAFE_INSERT_DELAYED,
ER_BINLOG_UNSAFE_SYSTEM_TABLE,
ER_BINLOG_UNSAFE_TWO_AUTOINC_COLUMNS,
ER_BINLOG_UNSAFE_UDF,
ER_BINLOG_UNSAFE_SYSTEM_VARIABLE,
ER_BINLOG_UNSAFE_SYSTEM_FUNCTION
};
uint32 flags= binlog_unsafe_warning_flags;
/* No warnings (yet) for this statement. */
if (flags == 0)
DBUG_VOID_RETURN;
/* Get the types of unsafeness that affect the current statement. */
uint32 unsafe_type_flags= flags >> BINLOG_STMT_WARNING_COUNT;
DBUG_ASSERT((unsafe_type_flags & LEX::BINLOG_STMT_UNSAFE_ALL_FLAGS) != 0);
/* /*
Clear: (1) bits above BINLOG_STMT_UNSAFE_COUNT; (2) bits for Clear: (1) bits above BINLOG_STMT_UNSAFE_COUNT; (2) bits for
warnings that have been printed already. warnings that have been printed already.
...@@ -4072,18 +4050,7 @@ void THD::issue_unsafe_warnings() ...@@ -4072,18 +4050,7 @@ void THD::issue_unsafe_warnings()
if (unsafe_type_flags == 0) if (unsafe_type_flags == 0)
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
/* Figure out which error code to issue. */ DBUG_PRINT("info", ("unsafe_type_flags: 0x%x", unsafe_type_flags));
int err;
if (binlog_unsafe_warning_flags &
(1 << BINLOG_STMT_WARNING_UNSAFE_AND_STMT_ENGINE))
err= ER_BINLOG_UNSAFE_AND_STMT_ENGINE;
else {
DBUG_ASSERT(binlog_unsafe_warning_flags &
(1 << BINLOG_STMT_WARNING_UNSAFE_AND_STMT_MODE));
err= ER_BINLOG_UNSAFE_STATEMENT;
}
DBUG_PRINT("info", ("flags: 0x%x err: %d", unsafe_type_flags, err));
/* /*
For each unsafe_type, check if the statement is unsafe in this way For each unsafe_type, check if the statement is unsafe in this way
...@@ -4095,20 +4062,25 @@ void THD::issue_unsafe_warnings() ...@@ -4095,20 +4062,25 @@ void THD::issue_unsafe_warnings()
{ {
if ((unsafe_type_flags & (1 << unsafe_type)) != 0) if ((unsafe_type_flags & (1 << unsafe_type)) != 0)
{ {
push_warning_printf(this, MYSQL_ERROR::WARN_LEVEL_NOTE, err, push_warning_printf(this, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER(ER_BINLOG_UNSAFE_WARNING_SHORT), ER_BINLOG_UNSAFE_STATEMENT,
ER(err), ER(explanations[unsafe_type])); ER(ER_BINLOG_UNSAFE_STATEMENT),
ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
if (global_system_variables.log_warnings) if (global_system_variables.log_warnings)
sql_print_warning(ER(ER_BINLOG_UNSAFE_WARNING_LONG), {
ER(err), ER(explanations[unsafe_type]), query); char buf[MYSQL_ERRMSG_SIZE * 2];
sprintf(buf, ER(ER_BINLOG_UNSAFE_STATEMENT),
ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
sql_print_warning(ER(ER_MESSAGE_AND_STATEMENT), buf, query);
}
} }
} }
/* /*
Mark these unsafe types as already printed, to avoid printing Mark these unsafe types as already printed, to avoid printing
warnings for them again. warnings for them again.
*/ */
binlog_unsafe_warning_flags|= unsafe_type_flags << binlog_unsafe_warning_flags|=
(BINLOG_STMT_WARNING_COUNT + LEX::BINLOG_STMT_UNSAFE_COUNT); unsafe_type_flags << LEX::BINLOG_STMT_UNSAFE_COUNT;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
......
...@@ -1449,42 +1449,21 @@ private: ...@@ -1449,42 +1449,21 @@ private:
*/ */
enum_binlog_format current_stmt_binlog_format; enum_binlog_format current_stmt_binlog_format;
/**
Enumeration listing binlog-related warnings that a statement can
cause.
*/
enum enum_binlog_stmt_warning {
/* ER_BINLOG_UNSAFE_AND_STMT_ENGINE affects current stmt */
BINLOG_STMT_WARNING_UNSAFE_AND_STMT_ENGINE= 0,
/* ER_BINLOG_UNSAFE_STATEMENT affects current stmt */
BINLOG_STMT_WARNING_UNSAFE_AND_STMT_MODE,
/** The last element of this enumeration type. */
BINLOG_STMT_WARNING_COUNT
};
/** /**
Bit field for the state of binlog warnings. Bit field for the state of binlog warnings.
There are three groups of bits: There are two groups of bits:
- The low BINLOG_STMT_WARNING_COUNT bits indicate the type of - The first Lex::BINLOG_STMT_UNSAFE_COUNT bits list all types of
warning that the current (top-level) statement will issue. At unsafeness that the current statement has.
most one of these bits should be set (this is ensured by the
logic in decide_logging_format).
- The following Lex::BINLOG_STMT_UNSAFE_COUNT bits list all types
of unsafeness that the current statement has.
- The following Lex::BINLOG_STMT_UNSAFE_COUNT bits list all types - The following Lex::BINLOG_STMT_UNSAFE_COUNT bits list all types
of unsafeness that the current statement has issued warnings of unsafeness that the current statement has issued warnings
for. for.
Hence, this variable must be big enough to hold Hence, this variable must be big enough to hold
BINLOG_STMT_WARNING_COUNT + 2 * Lex::BINLOG_STMT_UNSAFE_COUNT 2*Lex::BINLOG_STMT_UNSAFE_COUNT bits. This is asserted in @c
bits. This is asserted in @c issue_unsafe_warnings(). issue_unsafe_warnings().
The first and second groups of bits are set by @c The first and second groups of bits are set by @c
decide_logging_format() when it detects that a warning should be decide_logging_format() when it detects that a warning should be
......
...@@ -31,6 +31,23 @@ ...@@ -31,6 +31,23 @@
sys_var *trg_new_row_fake_var= (sys_var*) 0x01; sys_var *trg_new_row_fake_var= (sys_var*) 0x01;
/**
@note The order of the elements of this array must correspond to
the order of elements in enum_binlog_stmt_unsafe.
*/
const int
Query_tables_list::binlog_stmt_unsafe_errcode[BINLOG_STMT_UNSAFE_COUNT] =
{
ER_BINLOG_UNSAFE_LIMIT,
ER_BINLOG_UNSAFE_INSERT_DELAYED,
ER_BINLOG_UNSAFE_SYSTEM_TABLE,
ER_BINLOG_UNSAFE_TWO_AUTOINC_COLUMNS,
ER_BINLOG_UNSAFE_UDF,
ER_BINLOG_UNSAFE_SYSTEM_VARIABLE,
ER_BINLOG_UNSAFE_SYSTEM_FUNCTION
};
/* Longest standard keyword name */ /* Longest standard keyword name */
#define TOCK_NAME_LENGTH 24 #define TOCK_NAME_LENGTH 24
......
...@@ -1099,6 +1099,11 @@ public: ...@@ -1099,6 +1099,11 @@ public:
static const int BINLOG_STMT_UNSAFE_ALL_FLAGS= static const int BINLOG_STMT_UNSAFE_ALL_FLAGS=
((1 << BINLOG_STMT_UNSAFE_COUNT) - 1); ((1 << BINLOG_STMT_UNSAFE_COUNT) - 1);
/**
Maps elements of enum_binlog_stmt_unsafe to error codes.
*/
static const int binlog_stmt_unsafe_errcode[BINLOG_STMT_UNSAFE_COUNT];
/** /**
Determine if this statement is marked as unsafe. Determine if this statement is marked as unsafe.
......
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