diff --git a/mysql-test/suite/binlog/r/binlog_bug38839.result b/mysql-test/suite/binlog/r/binlog_bug38839.result new file mode 100644 index 0000000000000..d68652f54bb93 --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_bug38839.result @@ -0,0 +1,11 @@ +SET sql_mode=''; +CREATE TEMPORARY TABLE t ENGINE=MyISAM AS SELECT @a AS c; +INSERT INTO t VALUES (0xABB0); +SET autocommit=OFF; +CREATE TABLE t (c INT PRIMARY KEY) ENGINE=MyISAM SELECT * FROM t FOR UPDATE; +ERROR 23000: Duplicate entry '0' for key 'PRIMARY' +SET autocommit=ON; +DROP TEMPORARY TABLE IF EXISTS t; +DROP TABLE IF EXISTS t; +Warnings: +Note 1051 Unknown table 'test.t' diff --git a/mysql-test/suite/binlog/t/binlog_bug38839.test b/mysql-test/suite/binlog/t/binlog_bug38839.test new file mode 100644 index 0000000000000..7e5923c10d44d --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_bug38839.test @@ -0,0 +1,17 @@ +# Test case for MDEV-38839 +# Assertion `(thd->state_flags & Open_tables_state::BACKUPS_AVAIL) || +# !thd->has_pending_row_events()' failed in close_thread_tables +# on CREATE TABLE ... SELECT * FROM temp_table FOR UPDATE in MIXED binlog mode + +--source include/have_log_bin.inc +--source include/have_binlog_format_mixed.inc + +SET sql_mode=''; +CREATE TEMPORARY TABLE t ENGINE=MyISAM AS SELECT @a AS c; +INSERT INTO t VALUES (0xABB0); +SET autocommit=OFF; +--error ER_DUP_ENTRY +CREATE TABLE t (c INT PRIMARY KEY) ENGINE=MyISAM SELECT * FROM t FOR UPDATE; +SET autocommit=ON; +DROP TEMPORARY TABLE IF EXISTS t; +DROP TABLE IF EXISTS t; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 42723fb6caf62..cd126a31d1807 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -7130,7 +7130,7 @@ int THD::decide_logging_format(TABLE_LIST *tables) } } - if (tbl->lock_type >= TL_FIRST_WRITE) + if (tbl->updating) { bool trans; if (prev_write_table && prev_write_table->file->ht != @@ -7147,12 +7147,29 @@ int THD::decide_logging_format(TABLE_LIST *tables) trans= table->file->has_transactions(); - if (share->tmp_table) - lex->set_stmt_accessed_table(trans ? LEX::STMT_WRITES_TEMP_TRANS_TABLE : - LEX::STMT_WRITES_TEMP_NON_TRANS_TABLE); - else - lex->set_stmt_accessed_table(trans ? LEX::STMT_WRITES_TRANS_TABLE : - LEX::STMT_WRITES_NON_TRANS_TABLE); + /* + For SELECT ... FOR UPDATE, tbl->updating is false because the + table is only locked for reading, not actually being modified. + MyISAM has no row-level locking so FOR UPDATE escalates to + TL_WRITE, but this does not mean the table is being written to. + Sequences are an exception: even though tbl->updating is false + for SELECT NEXT VALUE FOR s, the sequence table is genuinely + modified internally, which is indicated by tbl->sequence. + Only set the write flag when the table is actually being written + to (tbl->updating) or is a sequence (tbl->sequence), to avoid + incorrectly setting MODIFIED_NON_TRANS_TABLE which would block + binlog_truncate_trx_cache() in MIXED mode and cause an assertion + in close_thread_tables(). + */ + // if (tbl->updating || tbl->sequence) + // { + if (share->tmp_table) + lex->set_stmt_accessed_table(trans ? LEX::STMT_WRITES_TEMP_TRANS_TABLE : + LEX::STMT_WRITES_TEMP_NON_TRANS_TABLE); + else + lex->set_stmt_accessed_table(trans ? LEX::STMT_WRITES_TRANS_TABLE : + LEX::STMT_WRITES_NON_TRANS_TABLE); + // } flags_write_all_set &= flags; flags_write_some_set |= flags; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 5dbd26c406e06..48a2cdfd9337d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -8185,6 +8185,11 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, if (!ptr->table_name.str) DBUG_RETURN(0); // EOM + if (ptr->sequence) + { + ptr->updating= true; + } + /* check that used name is unique. Sequences are ignored */ if (lock_type != TL_IGNORE && !ptr->sequence) { diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 310d5e9784f16..6d7f6e19ef3c5 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -10913,6 +10913,7 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db, if (online) { table_list->lock_type= TL_READ; + table_list->updating = false; } enum_tx_isolation iso_level_initial= thd->tx_isolation;