diff options
-rw-r--r-- | mysql-test/main/temp_table.result | 12 | ||||
-rw-r--r-- | mysql-test/main/temp_table.test | 16 | ||||
-rw-r--r-- | mysql-test/suite/rpl/disabled.def | 1 | ||||
-rw-r--r-- | mysql-test/suite/rpl/r/rpl_binlog_dup_entry.result | 29 | ||||
-rw-r--r-- | mysql-test/suite/rpl/r/rpl_row_mysqlbinlog.result | 8 | ||||
-rw-r--r-- | mysql-test/suite/rpl/t/rpl_binlog_dup_entry.test | 72 | ||||
-rw-r--r-- | mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test | 3 | ||||
-rw-r--r-- | sql/handler.cc | 4 | ||||
-rw-r--r-- | sql/handler.h | 6 | ||||
-rw-r--r-- | sql/sql_base.cc | 8 |
10 files changed, 150 insertions, 9 deletions
diff --git a/mysql-test/main/temp_table.result b/mysql-test/main/temp_table.result index 5de86e47fb1..69f3b8e5155 100644 --- a/mysql-test/main/temp_table.result +++ b/mysql-test/main/temp_table.result @@ -572,3 +572,15 @@ LOCK TABLES t2 WRITE; TRUNCATE TABLE t1; UNLOCK TABLES; DROP TABLE t1, t2; +# +# MDEV-19449 1030: Got error 168 "Unknown (generic) error from engine" +# for valid TRUNCATE (temporary) TABLE +# +CREATE TEMPORARY TABLE t1 (col1 BIGINT) ENGINE = InnoDB; +INSERT INTO t1 (no_such_col) SELECT * FROM t1; +ERROR 42S22: Unknown column 'no_such_col' in 'field list' +TRUNCATE TABLE t1; +ALTER TABLE t1 CHANGE no_such_col1 col1 BIGINT NULL; +ERROR 42S22: Unknown column 'no_such_col1' in 't1' +TRUNCATE TABLE t1; +DROP TEMPORARY TABLE t1; diff --git a/mysql-test/main/temp_table.test b/mysql-test/main/temp_table.test index a1e61b31a82..bd3bba34f89 100644 --- a/mysql-test/main/temp_table.test +++ b/mysql-test/main/temp_table.test @@ -623,3 +623,19 @@ TRUNCATE TABLE t1; UNLOCK TABLES; DROP TABLE t1, t2; + +--echo # +--echo # MDEV-19449 1030: Got error 168 "Unknown (generic) error from engine" +--echo # for valid TRUNCATE (temporary) TABLE +--echo # + +CREATE TEMPORARY TABLE t1 (col1 BIGINT) ENGINE = InnoDB; +--error ER_BAD_FIELD_ERROR +INSERT INTO t1 (no_such_col) SELECT * FROM t1; +TRUNCATE TABLE t1; +--error ER_BAD_FIELD_ERROR +ALTER TABLE t1 CHANGE no_such_col1 col1 BIGINT NULL; +# This would wrongly try to re-truncate the old copy of the table that +# was not dropped during the first TRUNCATE due to extra table handles. +TRUNCATE TABLE t1; +DROP TEMPORARY TABLE t1; diff --git a/mysql-test/suite/rpl/disabled.def b/mysql-test/suite/rpl/disabled.def index d4617398c64..772713aeb4e 100644 --- a/mysql-test/suite/rpl/disabled.def +++ b/mysql-test/suite/rpl/disabled.def @@ -15,7 +15,6 @@ rpl_get_master_version_and_clock : Bug#11766137 Jan 05 2011 joro Valgrind warnin rpl_partition_archive : MDEV-5077 2013-09-27 svoj Cannot exchange partition with archive table rpl_row_binlog_max_cache_size : MDEV-11092 rpl_blackhole : MDEV-11094 -rpl_row_mysqlbinlog : MDEV-11095 rpl_row_index_choice : MDEV-11666 rpl_parallel2 : fails after MDEV-16172 rpl_semi_sync_after_sync : fails after MDEV-16172 diff --git a/mysql-test/suite/rpl/r/rpl_binlog_dup_entry.result b/mysql-test/suite/rpl/r/rpl_binlog_dup_entry.result new file mode 100644 index 00000000000..108a65df07f --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_binlog_dup_entry.result @@ -0,0 +1,29 @@ +include/master-slave.inc +[connection master] +CREATE TABLE t1 (id mediumint(8) unsigned NOT NULL AUTO_INCREMENT, someLabel varchar(30) NOT NULL, flag tinyint(1) NOT NULL DEFAULT 0, PRIMARY KEY (id)) Engine=MyISAM; +CREATE TABLE t2 (id mediumint(8) unsigned NOT NULL AUTO_INCREMENT, data varchar(30) NOT NULL, status tinyint(1) NOT NULL, PRIMARY KEY (id)) Engine=MyISAM; +CREATE TABLE t3 (id mediumint(8) unsigned NOT NULL AUTO_INCREMENT, t1id mediumint(8) unsigned NOT NULL, flag tinyint(1) NOT NULL DEFAULT 0, status tinyint(1) NOT NULL DEFAULT 0, PRIMARY KEY (id)) Engine=MyISAM; +INSERT INTO t1 ( id, someLabel, flag ) VALUES ( 1, 'ABC', 0 ); +CREATE OR REPLACE TRIGGER doNothing +BEFORE UPDATE ON t1 +FOR EACH ROW +BEGIN +IF +new.someLabel != old.someLabel +THEN +UPDATE t3 SET t3.flag = 0; +END IF; +END| +FLUSH LOGS; +LOCK TABLES t1 WRITE, t2 WRITE; +INSERT INTO t2 (data, status) VALUES ('1', 4); +UPDATE t1 SET flag = 1 WHERE id = 1; +INSERT INTO t2 (data, status) VALUES ('2', 4); +UNLOCK TABLES; +connection slave; +include/diff_tables.inc [master:t1, slave:t1] +include/diff_tables.inc [master:t2, slave:t2] +include/diff_tables.inc [master:t3, slave:t3] +connection master; +DROP TABLE t1, t2, t3; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/rpl_row_mysqlbinlog.result b/mysql-test/suite/rpl/r/rpl_row_mysqlbinlog.result index b86743507d8..42d7fc39b5c 100644 --- a/mysql-test/suite/rpl/r/rpl_row_mysqlbinlog.result +++ b/mysql-test/suite/rpl/r/rpl_row_mysqlbinlog.result @@ -169,7 +169,7 @@ use `test`/*!*/; SET TIMESTAMP=1000000000/*!*/; SET @@session.pseudo_thread_id=999999999/*!*/; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/; -SET @@session.sql_mode=1342177280/*!*/; +SET @@session.sql_mode=1411383296/*!*/; SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; /*!\C latin1 *//*!*/; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/; @@ -192,7 +192,7 @@ use `test`/*!*/; SET TIMESTAMP=1000000000/*!*/; SET @@session.pseudo_thread_id=999999999/*!*/; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/; -SET @@session.sql_mode=1342177280/*!*/; +SET @@session.sql_mode=1411383296/*!*/; SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; /*!\C latin1 *//*!*/; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/; @@ -307,7 +307,7 @@ use `test`/*!*/; SET TIMESTAMP=1000000000/*!*/; SET @@session.pseudo_thread_id=999999999/*!*/; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/; -SET @@session.sql_mode=1342177280/*!*/; +SET @@session.sql_mode=1411383296/*!*/; SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; /*!\C latin1 *//*!*/; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/; @@ -336,7 +336,7 @@ use `test`/*!*/; SET TIMESTAMP=1000000000/*!*/; SET @@session.pseudo_thread_id=999999999/*!*/; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/; -SET @@session.sql_mode=1342177280/*!*/; +SET @@session.sql_mode=1411383296/*!*/; SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; /*!\C latin1 *//*!*/; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/; diff --git a/mysql-test/suite/rpl/t/rpl_binlog_dup_entry.test b/mysql-test/suite/rpl/t/rpl_binlog_dup_entry.test new file mode 100644 index 00000000000..869c715f407 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_binlog_dup_entry.test @@ -0,0 +1,72 @@ +# ==== Purpose ==== +# +# Test verifies that there are no duplicate entries in binlog (i.e a safe +# statement which follows an unsafe statement gets logged in both row format +# and statement format resulting in duplicate entry) when binlog-format=MIXED +# and LOCK TABLES are enabled. +# +# ==== Implementation ==== +# +# Steps: +# 1 - Create three tables t1,t2 and t3 with AUTO_INCREMENT on. +# 2 - Create a trigger on table t3, so that trigger execution results in +# unsafe statement. Note query that modifies autoinc column in +# sub-statement can make the master and slave inconsistent. Hence they +# are logged in row format. +# 3 - Lock tables t1,t2 and t3. +# 4 - Execute an unsafe update which modifies tables t1 and t3. But since t2 +# table is also locked its table map event also gets written into the +# binary log during the execution of update. +# 5 - Execute a safe DML operation using table 't2' and verify that master +# doesn't report any assert. +# 6 - Ensure that slave is in sync with master and data is consistent. +# +# ==== References ==== +# +# MDEV-19158: MariaDB 10.2.22 is writing duplicate entries into binary log + +--source include/have_binlog_format_mixed.inc +--source include/master-slave.inc + +CREATE TABLE t1 (id mediumint(8) unsigned NOT NULL AUTO_INCREMENT, someLabel varchar(30) NOT NULL, flag tinyint(1) NOT NULL DEFAULT 0, PRIMARY KEY (id)) Engine=MyISAM; +CREATE TABLE t2 (id mediumint(8) unsigned NOT NULL AUTO_INCREMENT, data varchar(30) NOT NULL, status tinyint(1) NOT NULL, PRIMARY KEY (id)) Engine=MyISAM; +CREATE TABLE t3 (id mediumint(8) unsigned NOT NULL AUTO_INCREMENT, t1id mediumint(8) unsigned NOT NULL, flag tinyint(1) NOT NULL DEFAULT 0, status tinyint(1) NOT NULL DEFAULT 0, PRIMARY KEY (id)) Engine=MyISAM; + +INSERT INTO t1 ( id, someLabel, flag ) VALUES ( 1, 'ABC', 0 ); + +DELIMITER |; + +CREATE OR REPLACE TRIGGER doNothing +BEFORE UPDATE ON t1 +FOR EACH ROW + BEGIN + IF + new.someLabel != old.someLabel + THEN + UPDATE t3 SET t3.flag = 0; + END IF; + END| + +DELIMITER ;| + +FLUSH LOGS; + +LOCK TABLES t1 WRITE, t2 WRITE; +INSERT INTO t2 (data, status) VALUES ('1', 4); +UPDATE t1 SET flag = 1 WHERE id = 1; +INSERT INTO t2 (data, status) VALUES ('2', 4); +UNLOCK TABLES; + +sync_slave_with_master; + +let $diff_tables= master:t1, slave:t1; +--source include/diff_tables.inc +let $diff_tables= master:t2, slave:t2; +--source include/diff_tables.inc +let $diff_tables= master:t3, slave:t3; +--source include/diff_tables.inc + +--connection master +DROP TABLE t1, t2, t3; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test b/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test index 678679f0cf1..a249043fa19 100644 --- a/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test +++ b/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test @@ -151,8 +151,7 @@ remove_file $MYSQLTEST_VARDIR/tmp/master.sql; --exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ --stop-position=$stop_position --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 --echo --- Test 4 Second Remote test -- ---exec $MYSQL_BINLOG --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 > $MYSQLTEST_VARDIR/tmp/remote.sql ---exec $MYSQL_BINLOG --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000002 >> $MYSQLTEST_VARDIR/tmp/remote.sql +--exec $MYSQL_BINLOG --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT --to-last-log master-bin.000001 > $MYSQLTEST_VARDIR/tmp/remote.sql # Now that we have our file, lets get rid of the current database. # Cleanup the master and the slave and try to recreate. diff --git a/sql/handler.cc b/sql/handler.cc index 4716223d95b..3e1cbc117a9 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6394,8 +6394,8 @@ int handler::ha_reset() table->default_column_bitmaps(); pushed_cond= NULL; tracker= NULL; - mark_trx_read_write_done= check_table_binlog_row_based_done= - check_table_binlog_row_based_result= 0; + mark_trx_read_write_done= 0; + clear_cached_table_binlog_row_based_flag(); /* Reset information about pushed engine conditions */ cancel_pushed_idx_cond(); /* Reset information about pushed index conditions */ diff --git a/sql/handler.h b/sql/handler.h index 786e8170122..1c336e7e35f 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -4372,6 +4372,12 @@ protected: public: bool check_table_binlog_row_based(bool binlog_row); + inline void clear_cached_table_binlog_row_based_flag() + { + check_table_binlog_row_based_done= 0; + check_table_binlog_row_based_result= 0; + } +private: /* Cache result to avoid extra calls */ inline void mark_trx_read_write() { diff --git a/sql/sql_base.cc b/sql/sql_base.cc index b0f388c4e95..d61eb86890d 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -586,6 +586,12 @@ bool close_cached_connection_tables(THD *thd, LEX_CSTRING *connection) Marks all tables in the list which were used by current substatement (they are marked by its query_id) as free for reuse. + Clear 'check_table_binlog_row_based_done' flag. For tables which were used + by current substatement the flag is cleared as part of 'ha_reset()' call. + For the rest of the open tables not used by current substament if this + flag is enabled as part of current substatement execution, clear the flag + explicitly. + NOTE The reason we reset query_id is that it's not enough to just test if table->query_id != thd->query_id to know if a table is in use. @@ -607,6 +613,8 @@ static void mark_used_tables_as_free_for_reuse(THD *thd, TABLE *table) table->query_id= 0; table->file->ha_reset(); } + else if (table->file->check_table_binlog_row_based_done) + table->file->clear_cached_table_binlog_row_based_flag(); } } |