Commit 02fc237a authored by Alfranio Correia's avatar Alfranio Correia

BUG#50479 DDL stmt on row-only/stmt-only tables generate spurious binlog_format

errors
            
In the fix of BUG#39934 in 5.1-rep+3, errors are generated when
binlog_format=row and a statement modifies a table restricted to
statement-logging (ER_BINLOG_ROW_MODE_AND_STMT_ENGINE); or if
binlog_format=statement and a statement modifies a table restricted to
row-logging (ER_BINLOG_STMT_MODE_AND_ROW_ENGINE).
            
However, some DDL statements that lock tables (e.g. ALTER TABLE,
CREATE INDEX and CREATE TRIGGER) were causing spurious errors,
although no row might be inserted into the binary log.
            
To fix the problem, we tagged statements that may generate
rows into the binary log and thence the warning messages are
only printed out when the appropriate conditions hold and rows
might be changed.
parent 4ede1aa2
......@@ -8,14 +8,14 @@ INSERT INTO t1b VALUES (1,1), (1,2), (2,1), (2,2);
INSERT INTO t1m VALUES (1,1), (1,2), (2,1), (2,2);
UPDATE t1m, t1b SET m = 2, b = 3 WHERE n = c;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
The last event before the COMMIT is use `test`; UPDATE t1m, t1b SET m = 2, b = 3 WHERE n = c
*** Please look in binlog_multi_engine.test if you have a diff here ****
START TRANSACTION;
INSERT INTO t1n VALUES (1,1), (1,2), (2,1), (2,2);
UPDATE t1m, t1n SET m = 2, e = 3 WHERE n = f;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
UPDATE t1n, t1b SET e = 2, b = 3 WHERE f = c;
COMMIT;
TRUNCATE t1m;
......
SET @old_binlog_format= @@global.binlog_format;
INSTALL PLUGIN example SONAME 'ha_example.so';
################################################################################
# Verifies if ER_BINLOG_STMT_MODE_AND_ROW_ENGINE happens by setting the binlog
# format to STATEMENT and the transaction isolation level to READ COMMITTED as
# such changes force Innodb to accept changes in the row format.
#
# When CREATE TABLE, ALTER TABLE, CREATE INDEX and CREATE TRIGGER are executed
# any error should be triggered.
#
# In contrast, CREATE TABLE ... SELECT should trigger the following error:
# ER_BINLOG_STMT_MODE_AND_ROW_ENGINE.
################################################################################
SET binlog_format = STATEMENT;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
CREATE TABLE t_row (a VARCHAR(100)) ENGINE = InnoDB;
ALTER TABLE t_row ADD COLUMN b INT;
CREATE TRIGGER trig_row BEFORE INSERT ON t_row FOR EACH ROW INSERT INTO t_stmt VALUES (1);
CREATE INDEX i ON t_row(a);
CREATE TABLE t_row_new ENGINE = InnoDB SELECT * FROM t_row;
ERROR HY000: Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-based logging. InnoDB is limited to row-logging when transaction isolation level is READ COMMITTED or READ UNCOMMITTED.
DROP TABLE t_row;
################################################################################
# Verifies if ER_BINLOG_ROW_MODE_AND_STMT_ENGINE happens by setting the binlog
# format to ROW and using a engine, i.e. EXAMPLE, that only supports STATEMENT.
#
# When CREATE TABLE, ALTER TABLE, CREATE INDEX and CREATE TRIGGER are executed
# the error ER_BINLOG_ROW_MODE_AND_STMT_ENGINE is not triggered. Note that other
# errors are triggered due to restrictions in the engine.
#
# In contrast, CREATE TABLE ... SELECT should trigger the following error:
# ER_BINLOG_ROW_MODE_AND_STMT_ENGINE.
################################################################################
SET binlog_format = ROW;
CREATE TABLE t_stmt (a VARCHAR(100)) ENGINE = EXAMPLE;
ALTER TABLE t_stmt ADD COLUMN b INT;
ERROR 42000: This version of MySQL doesn't yet support 'ALTER TABLE'
CREATE TRIGGER trig_stmt BEFORE INSERT ON t_stmt FOR EACH ROW INSERT INTO t_stmt VALUES (1);
CREATE INDEX i ON t_stmt(a);
ERROR 42000: Too many key parts specified; max 0 parts allowed
CREATE TABLE t_stmt_new ENGINE = EXAMPLE SELECT * FROM t_stmt;
ERROR HY000: Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = ROW and at least one table uses a storage engine limited to statement-based logging.
DROP TABLE t_stmt;
################################################################################
# CLEAN UP #
################################################################################
UNINSTALL PLUGIN example;
SET @@global.binlog_format = @old_binlog_format;
SET @@session.binlog_format = @old_binlog_format;
......@@ -8,7 +8,7 @@ begin;
insert into t1 values(1);
insert into t2 select * from t1;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
commit;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
......@@ -23,7 +23,7 @@ begin;
insert into t1 values(2);
insert into t2 select * from t1;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
rollback;
Warnings:
Warning 1196 Some non-transactional changed tables couldn't be rolled back
......@@ -42,7 +42,7 @@ savepoint my_savepoint;
insert into t1 values(4);
insert into t2 select * from t1;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
rollback to savepoint my_savepoint;
Warnings:
Warning 1196 Some non-transactional changed tables couldn't be rolled back
......@@ -65,7 +65,7 @@ savepoint my_savepoint;
insert into t1 values(6);
insert into t2 select * from t1;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
rollback to savepoint my_savepoint;
Warnings:
Warning 1196 Some non-transactional changed tables couldn't be rolled back
......@@ -95,7 +95,7 @@ begin;
insert into t1 values(8);
insert into t2 select * from t1;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
select get_lock("a",10);
get_lock("a",10)
1
......@@ -111,7 +111,7 @@ reset master;
insert into t1 values(9);
insert into t2 select * from t1;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # BEGIN
......@@ -127,7 +127,7 @@ insert into t1 values(10);
begin;
insert into t2 select * from t1;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # BEGIN
......@@ -246,7 +246,7 @@ Warning 1196 Some non-transactional changed tables couldn't be rolled back
create table t0 (n int);
insert t0 select * from t1;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
set autocommit=1;
insert into t0 select GET_LOCK("lock1",null);
Warnings:
......@@ -432,7 +432,7 @@ begin;
insert into t1 values(8);
insert into t2 select * from t1;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
select get_lock("a",10);
get_lock("a",10)
1
......
################################################################################
# BUG#50479 DDL stmt on row-only/stmt-only tables generate spurious
# binlog_format errors
#
# In the fix of BUG#39934 in 5.1-rep+3, errors are generated when
# binlog_format=row and a statement modifies a table restricted to
# statement-logging (ER_BINLOG_ROW_MODE_AND_STMT_ENGINE); or if
# binlog_format=statement and a statement modifies a table limited to
# row-logging (ER_BINLOG_STMT_MODE_AND_ROW_ENGINE).
#
# In this test case, we check if some DDL statements that lock tables do not
# trigger errors as they do not generate rows events and as such are harmless
# from the point of view of conflicts between the engine's supported logging
# format and the value of binlog_format.
#
# In particular, we check if:
# 1 - ALTER TABLE, CREATE INDEX and CREATE TRIGGER do not generate either
# ER_BINLOG_STMT_MODE_AND_ROW_ENGINE or ER_BINLOG_STMT_MODE_AND_ROW_ENGINE
#
# 2 - CREATE TABLE ... SELECT generates an error because the command can
# generate row events but CREATE TABLE without SELECT does not generate
# an error.
################################################################################
--source include/have_innodb.inc
--source include/have_example_plugin.inc
--source include/have_log_bin.inc
SET @old_binlog_format= @@global.binlog_format;
INSTALL PLUGIN example SONAME 'ha_example.so';
--echo ################################################################################
--echo # Verifies if ER_BINLOG_STMT_MODE_AND_ROW_ENGINE happens by setting the binlog
--echo # format to STATEMENT and the transaction isolation level to READ COMMITTED as
--echo # such changes force Innodb to accept changes in the row format.
--echo #
--echo # When CREATE TABLE, ALTER TABLE, CREATE INDEX and CREATE TRIGGER are executed
--echo # any error should be triggered.
--echo #
--echo # In contrast, CREATE TABLE ... SELECT should trigger the following error:
--echo # ER_BINLOG_STMT_MODE_AND_ROW_ENGINE.
--echo ################################################################################
SET binlog_format = STATEMENT;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
CREATE TABLE t_row (a VARCHAR(100)) ENGINE = InnoDB;
ALTER TABLE t_row ADD COLUMN b INT;
CREATE TRIGGER trig_row BEFORE INSERT ON t_row FOR EACH ROW INSERT INTO t_stmt VALUES (1);
CREATE INDEX i ON t_row(a);
--error ER_BINLOG_STMT_MODE_AND_ROW_ENGINE
CREATE TABLE t_row_new ENGINE = InnoDB SELECT * FROM t_row;
DROP TABLE t_row;
--echo
--echo
--echo ################################################################################
--echo # Verifies if ER_BINLOG_ROW_MODE_AND_STMT_ENGINE happens by setting the binlog
--echo # format to ROW and using a engine, i.e. EXAMPLE, that only supports STATEMENT.
--echo #
--echo # When CREATE TABLE, ALTER TABLE, CREATE INDEX and CREATE TRIGGER are executed
--echo # the error ER_BINLOG_ROW_MODE_AND_STMT_ENGINE is not triggered. Note that other
--echo # errors are triggered due to restrictions in the engine.
--echo #
--echo # In contrast, CREATE TABLE ... SELECT should trigger the following error:
--echo # ER_BINLOG_ROW_MODE_AND_STMT_ENGINE.
--echo ################################################################################
SET binlog_format = ROW;
CREATE TABLE t_stmt (a VARCHAR(100)) ENGINE = EXAMPLE;
--error ER_NOT_SUPPORTED_YET
ALTER TABLE t_stmt ADD COLUMN b INT;
CREATE TRIGGER trig_stmt BEFORE INSERT ON t_stmt FOR EACH ROW INSERT INTO t_stmt VALUES (1);
--error ER_TOO_MANY_KEY_PARTS
CREATE INDEX i ON t_stmt(a);
--error ER_BINLOG_ROW_MODE_AND_STMT_ENGINE
CREATE TABLE t_stmt_new ENGINE = EXAMPLE SELECT * FROM t_stmt;
DROP TABLE t_stmt;
--echo
--echo
--echo ################################################################################
--echo # CLEAN UP #
--echo ################################################################################
UNINSTALL PLUGIN example;
SET @@global.binlog_format = @old_binlog_format;
SET @@session.binlog_format = @old_binlog_format;
......@@ -9,12 +9,12 @@ INSERT INTO t1 VALUES (1,1), (1,2), (2,1), (2,2);
INSERT INTO t2 VALUES (1,1), (1,2), (2,1), (2,2);
UPDATE t1, t2 SET m = 2, b = 3 WHERE n = c;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
START TRANSACTION;
INSERT INTO t3 VALUES (1,1), (1,2), (2,1), (2,2);
UPDATE t1, t3 SET m = 2, e = 3 WHERE n = f;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
UPDATE t3, t2 SET e = 2, b = 3 WHERE f = c;
COMMIT;
show binlog events from <binlog_start>;
......
......@@ -22,7 +22,7 @@ SET AUTOCOMMIT = 1;
BEGIN;
UPDATE t SET f = 'yellow 2' WHERE i = 3;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
SET AUTOCOMMIT = 1;
BEGIN;
UPDATE t SET f = 'magenta 2' WHERE f = 'red';
......@@ -51,7 +51,7 @@ SET AUTOCOMMIT = 1;
BEGIN;
UPDATE t SET f = 'gray 2' WHERE i = 3;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
SET AUTOCOMMIT = 1;
BEGIN;
UPDATE t SET f = 'dark blue 2' WHERE f = 'red';
......@@ -77,7 +77,7 @@ master-bin.000001 # Xid # # COMMIT /* XID */
SET AUTOCOMMIT = 0;
UPDATE t SET f = 'yellow 1' WHERE i = 3;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
SET AUTOCOMMIT = 0;
UPDATE t SET f = 'magenta 1' WHERE f = 'red';
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
......@@ -104,7 +104,7 @@ master-bin.000001 # Query # # ROLLBACK
SET AUTOCOMMIT = 0;
UPDATE t SET f = 'gray 1' WHERE i = 3;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
SET AUTOCOMMIT = 0;
UPDATE t SET f = 'dark blue 1' WHERE f = 'red';
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
......
......@@ -53,7 +53,7 @@ set @@global.debug="+d,stop_slave_middle_group";
set @@global.debug="+d,incomplete_group_in_relay_log";
update tm as t1, ti as t2 set t1.a=t1.a * 2, t2.a=t2.a * 2;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
SELECT "Fatal error: ... The slave SQL is stopped, leaving the current group of events unfinished with a non-transaction table changed. If the group consists solely of Row-based events, you can try restarting the slave with --slave-exec-mode=IDEMPOTENT, which ignores duplicate key, key not found, and similar errors (see documentation for details)." AS Last_SQL_Error, @check as `true`;
Last_SQL_Error true
Fatal error: ... The slave SQL is stopped, leaving the current group of events unfinished with a non-transaction table changed. If the group consists solely of Row-based events, you can try restarting the slave with --slave-exec-mode=IDEMPOTENT, which ignores duplicate key, key not found, and similar errors (see documentation for details). 1
......
......@@ -24,7 +24,7 @@ INSERT INTO t_innodb_temp VALUES(1);
BEGIN;
INSERT INTO t_myisam SELECT * FROM t_myisam_temp;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
INSERT INTO t_innodb SELECT * FROM t_myisam_temp;
INSERT INTO t_innodb SELECT * FROM t_innodb_temp;
ROLLBACK;
......@@ -33,7 +33,7 @@ Warning 1196 Some non-transactional changed tables couldn't be rolled back
BEGIN;
INSERT INTO t_myisam SELECT * FROM t_innodb_temp;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
INSERT INTO t_innodb SELECT * FROM t_myisam_temp;
INSERT INTO t_innodb SELECT * FROM t_innodb_temp;
ROLLBACK;
......
......@@ -43,11 +43,11 @@ SELECT * FROM t /* Should be empty */;
a
* Modify both row-only and stmt-only table
CREATE TRIGGER trig_2 AFTER INSERT ON t_stmt FOR EACH ROW BEGIN INSERT INTO t_row VALUES(1); END;
ERROR HY000: Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = ROW and at least one table uses a storage engine limited to statement-based logging.
INSERT INTO t_stmt VALUES (1);
ERROR HY000: Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = ROW and at least one table uses a storage engine limited to statement-based logging.
ERROR HY000: Cannot execute statement: impossible to write to binary log since both row-incapable engines and statement-incapable engines are involved.
SELECT * FROM t_stmt /* should be empty */;
a
DROP TRIGGER trig_2;
* Stmt-only table and binlog_format=row
INSERT INTO t_stmt VALUES (1);
ERROR HY000: Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = ROW and at least one table uses a storage engine limited to statement-based logging.
......
......@@ -97,11 +97,11 @@ SELECT * FROM t_self_logging /* Should be empty */;
SELECT * FROM t /* Should be empty */;
--echo * Modify both row-only and stmt-only table
--error ER_BINLOG_ROW_MODE_AND_STMT_ENGINE
--eval CREATE TRIGGER trig_2 AFTER INSERT ON t_stmt FOR EACH ROW BEGIN INSERT INTO t_row VALUES(1); END
--error ER_BINLOG_ROW_MODE_AND_STMT_ENGINE
--error ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE
INSERT INTO t_stmt VALUES (1);
SELECT * FROM t_stmt /* should be empty */;
DROP TRIGGER trig_2;
--echo * Stmt-only table and binlog_format=row
--error ER_BINLOG_ROW_MODE_AND_STMT_ENGINE
......
......@@ -2465,95 +2465,62 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
else
time_zone_len= 0;
LEX *lex= thd->lex;
/*
In what follows, we decide whether to write to the binary log or to use a
cache.
TRUE defines that either a trx-cache or stmt-cache must be used
and wrapped by a BEGIN...COMMIT. Otherwise, the statement will
be written directly to the binary log without being wrapped by
a BEGIN...COMMIT.
Note that a cache will not be used if the parameter direct is
TRUE.
*/
LEX *lex= thd->lex;
bool implicit_commit= FALSE;
bool force_trans= FALSE;
bool use_cache= FALSE;
/*
TRUE defines that the trx-cache must be used and by consequence
the use_cache is TRUE.
Note that a cache will not be used if the parameter direct is
TRUE.
*/
bool trx_cache= FALSE;
cache_type= Log_event::EVENT_INVALID_CACHE;
switch (lex->sql_command)
{
case SQLCOM_ALTER_DB:
case SQLCOM_CREATE_FUNCTION:
case SQLCOM_DROP_FUNCTION:
case SQLCOM_DROP_PROCEDURE:
case SQLCOM_INSTALL_PLUGIN:
case SQLCOM_UNINSTALL_PLUGIN:
case SQLCOM_ALTER_TABLESPACE:
implicit_commit= TRUE;
break;
case SQLCOM_DROP_TABLE:
force_trans= lex->drop_temporary && thd->in_multi_stmt_transaction_mode();
implicit_commit= !force_trans;
break;
case SQLCOM_ALTER_TABLE:
use_cache= trx_cache= (lex->drop_temporary &&
thd->in_multi_stmt_transaction_mode());
break;
case SQLCOM_CREATE_TABLE:
force_trans= (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
thd->in_multi_stmt_transaction_mode();
implicit_commit= !force_trans &&
!(lex->select_lex.item_list.elements &&
thd->is_current_stmt_binlog_format_row());
use_cache= trx_cache=
((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
thd->in_multi_stmt_transaction_mode()) ||
(lex->select_lex.item_list.elements &&
thd->is_current_stmt_binlog_format_row());
break;
case SQLCOM_SET_OPTION:
implicit_commit= (lex->autocommit ? TRUE : FALSE);
break;
/*
Replace what follows after CF_AUTO_COMMIT_TRANS is backported by:
default:
implicit_commit= ((sql_command_flags[lex->sql_command] &
CF_AUTO_COMMIT_TRANS));
use_cache= trx_cache= (lex->autocommit ? FALSE : TRUE);
break;
*/
case SQLCOM_CREATE_INDEX:
case SQLCOM_TRUNCATE:
case SQLCOM_CREATE_DB:
case SQLCOM_DROP_DB:
case SQLCOM_ALTER_DB_UPGRADE:
case SQLCOM_RENAME_TABLE:
case SQLCOM_DROP_INDEX:
case SQLCOM_CREATE_VIEW:
case SQLCOM_DROP_VIEW:
case SQLCOM_CREATE_TRIGGER:
case SQLCOM_DROP_TRIGGER:
case SQLCOM_CREATE_EVENT:
case SQLCOM_ALTER_EVENT:
case SQLCOM_DROP_EVENT:
case SQLCOM_REPAIR:
case SQLCOM_OPTIMIZE:
case SQLCOM_ANALYZE:
case SQLCOM_CREATE_USER:
case SQLCOM_DROP_USER:
case SQLCOM_RENAME_USER:
case SQLCOM_REVOKE_ALL:
case SQLCOM_REVOKE:
case SQLCOM_GRANT:
case SQLCOM_CREATE_PROCEDURE:
case SQLCOM_CREATE_SPFUNCTION:
case SQLCOM_ALTER_PROCEDURE:
case SQLCOM_ALTER_FUNCTION:
case SQLCOM_ASSIGN_TO_KEYCACHE:
case SQLCOM_PRELOAD_KEYS:
case SQLCOM_FLUSH:
case SQLCOM_RESET:
case SQLCOM_CHECK:
implicit_commit= TRUE;
case SQLCOM_RELEASE_SAVEPOINT:
case SQLCOM_ROLLBACK_TO_SAVEPOINT:
case SQLCOM_SAVEPOINT:
use_cache= trx_cache= TRUE;
break;
default:
implicit_commit= FALSE;
use_cache= sqlcom_can_generate_row_events(thd);
break;
}
if (implicit_commit || direct)
if (!use_cache || direct)
{
cache_type= Log_event::EVENT_NO_CACHE;
}
else
{
cache_type= ((using_trans || stmt_has_updated_trans_table(thd) ||
force_trans || thd->thread_temporary_used)
cache_type= ((using_trans || stmt_has_updated_trans_table(thd)
|| trx_cache || thd->thread_temporary_used)
? Log_event::EVENT_TRANSACTIONAL_CACHE :
Log_event::EVENT_STMT_CACHE);
}
......
......@@ -6335,7 +6335,7 @@ ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE
eng "Mixing self-logging and non-self-logging engines in a statement is unsafe."
ER_BINLOG_UNSAFE_MIXED_STATEMENT
eng "Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe."
eng "Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them."
ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN
eng "Cannot modify @@session.sql_log_bin inside a transaction"
......@@ -6343,4 +6343,3 @@ ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN
ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN
eng "Cannot change the sql_log_bin inside a stored function or trigger"
......@@ -3192,6 +3192,11 @@ extern "C" bool thd_binlog_filter_ok(const MYSQL_THD thd)
{
return binlog_filter->db_ok(thd->db);
}
extern "C" bool thd_sqlcom_can_generate_row_events(const MYSQL_THD thd)
{
return sqlcom_can_generate_row_events(thd);
}
#endif // INNODB_COMPATIBILITY_HOOKS */
/****************************************************************************
......@@ -3917,7 +3922,8 @@ int THD::decide_logging_format(TABLE_LIST *tables)
*/
my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE), MYF(0));
}
else if (variables.binlog_format == BINLOG_FORMAT_ROW)
else if (variables.binlog_format == BINLOG_FORMAT_ROW &&
sqlcom_can_generate_row_events(this))
{
/*
2. Error: Cannot modify table that uses a storage engine
......@@ -3955,7 +3961,8 @@ int THD::decide_logging_format(TABLE_LIST *tables)
*/
my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_MODE), MYF(0));
}
else if ((flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0)
else if ((flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0 &&
sqlcom_can_generate_row_events(this))
{
/*
5. Error: Cannot modify table that uses a storage engine
......
......@@ -3619,6 +3619,12 @@ public:
*/
#define CF_PROTECT_AGAINST_GRL (1U << 10)
/**
Identifies statements that may generate row events
and that may end up in the binary log.
*/
#define CF_CAN_GENERATE_ROW_EVENTS (1U << 11)
/* Bits in server_command_flags */
/**
......
......@@ -247,8 +247,19 @@ void init_update_queries(void)
/* Initialize the sql command flags array. */
memset(sql_command_flags, 0, sizeof(sql_command_flags));
/*
In general, DDL statements do not generate row events and do not go
through a cache before being written to the binary log. However, the
CREATE TABLE...SELECT is an exception because it may generate row
events. For that reason, the SQLCOM_CREATE_TABLE which represents
a CREATE TABLE, including the CREATE TABLE...SELECT, has the
CF_CAN_GENERATE_ROW_EVENTS flag. The distinction between a regular
CREATE TABLE and the CREATE TABLE...SELECT is made in other parts of
the code, in particular in the Query_log_event's constructor.
*/
sql_command_flags[SQLCOM_CREATE_TABLE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_AUTO_COMMIT_TRANS | CF_PROTECT_AGAINST_GRL;
CF_AUTO_COMMIT_TRANS | CF_PROTECT_AGAINST_GRL |
CF_CAN_GENERATE_ROW_EVENTS;
sql_command_flags[SQLCOM_CREATE_INDEX]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_ALTER_TABLE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND |
CF_AUTO_COMMIT_TRANS | CF_PROTECT_AGAINST_GRL;
......@@ -256,7 +267,8 @@ void init_update_queries(void)
CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_DROP_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_LOAD]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_PROTECT_AGAINST_GRL;
CF_PROTECT_AGAINST_GRL |
CF_CAN_GENERATE_ROW_EVENTS;
sql_command_flags[SQLCOM_CREATE_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_DROP_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_ALTER_DB_UPGRADE]= CF_AUTO_COMMIT_TRANS;
......@@ -275,22 +287,32 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_DROP_TRIGGER]= CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_UPDATE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_PROTECT_AGAINST_GRL;
CF_PROTECT_AGAINST_GRL |
CF_CAN_GENERATE_ROW_EVENTS;
sql_command_flags[SQLCOM_UPDATE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_PROTECT_AGAINST_GRL;
CF_PROTECT_AGAINST_GRL |
CF_CAN_GENERATE_ROW_EVENTS;
sql_command_flags[SQLCOM_INSERT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_PROTECT_AGAINST_GRL;
CF_PROTECT_AGAINST_GRL |
CF_CAN_GENERATE_ROW_EVENTS;
sql_command_flags[SQLCOM_INSERT_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_PROTECT_AGAINST_GRL;
CF_PROTECT_AGAINST_GRL |
CF_CAN_GENERATE_ROW_EVENTS;
sql_command_flags[SQLCOM_DELETE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_PROTECT_AGAINST_GRL;
CF_PROTECT_AGAINST_GRL |
CF_CAN_GENERATE_ROW_EVENTS;
sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_PROTECT_AGAINST_GRL;
sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE;
sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE;
sql_command_flags[SQLCOM_SELECT]= CF_REEXECUTION_FRAGILE;
CF_PROTECT_AGAINST_GRL |
CF_CAN_GENERATE_ROW_EVENTS;
sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS;
sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS;
sql_command_flags[SQLCOM_SELECT]= CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS;
sql_command_flags[SQLCOM_SET_OPTION]= CF_REEXECUTION_FRAGILE | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_DO]= CF_REEXECUTION_FRAGILE;
sql_command_flags[SQLCOM_DO]= CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS;
sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
sql_command_flags[SQLCOM_SHOW_STATUS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
......@@ -365,7 +387,9 @@ void init_update_queries(void)
last called (or executed) statement is preserved.
See mysql_execute_command() for how CF_ROW_COUNT is used.
*/
sql_command_flags[SQLCOM_CALL]= CF_REEXECUTION_FRAGILE;
sql_command_flags[SQLCOM_CALL]= CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS;
sql_command_flags[SQLCOM_EXECUTE]= CF_CAN_GENERATE_ROW_EVENTS;
/*
The following admin table operations are allowed
......@@ -390,7 +414,12 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_CHECK]= CF_AUTO_COMMIT_TRANS;
}
bool sqlcom_can_generate_row_events(const THD *thd)
{
return (sql_command_flags[thd->lex->sql_command] &
CF_CAN_GENERATE_ROW_EVENTS);
}
bool is_update_query(enum enum_sql_command command)
{
DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
......
......@@ -79,6 +79,7 @@ bool check_host_name(LEX_STRING *str);
bool check_identifier_name(LEX_STRING *str, uint max_char_length,
uint err_code, const char *param_for_err_msg);
bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length);
bool sqlcom_can_generate_row_events(const THD *thd);
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);
......
......@@ -8608,7 +8608,9 @@ ha_innobase::external_lock(
if (lock_type == F_WRLCK
&& !(table_flags() & HA_BINLOG_STMT_CAPABLE)
&& thd_binlog_format(thd) == BINLOG_FORMAT_STMT
&& thd_binlog_filter_ok(thd)) {
&& thd_binlog_filter_ok(thd)
&& thd_sqlcom_can_generate_row_events(thd))
{
int skip = 0;
/* used by test case */
DBUG_EXECUTE_IF("no_innodb_binlog_errors", skip = 1;);
......
......@@ -281,6 +281,13 @@ void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all);
*/
bool thd_binlog_filter_ok(const MYSQL_THD thd);
#endif /* MYSQL_VERSION_ID > 50140 */
/**
Check if the query may generate row changes which
may end up in the binary.
@param thd Thread handle
@return 1 the query may generate row changes, 0 otherwise.
*/
bool thd_sqlcom_can_generate_row_events(const MYSQL_THD thd);
}
typedef struct trx_struct trx_t;
......
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