summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/main/temp_table.result12
-rw-r--r--mysql-test/main/temp_table.test16
-rw-r--r--mysql-test/suite/rpl/disabled.def1
-rw-r--r--mysql-test/suite/rpl/r/rpl_binlog_dup_entry.result29
-rw-r--r--mysql-test/suite/rpl/r/rpl_row_mysqlbinlog.result8
-rw-r--r--mysql-test/suite/rpl/t/rpl_binlog_dup_entry.test72
-rw-r--r--mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test3
-rw-r--r--sql/handler.cc4
-rw-r--r--sql/handler.h6
-rw-r--r--sql/sql_base.cc8
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();
}
}