Details
-
Bug
-
Status: Approved (View Workflow)
-
Major
-
Resolution: Unresolved
-
N/A
-
None
Description
The symptom looks like
rpl.create_or_replace_mix2 'mix' w5 [ fail ]
|
Test ended at 2025-09-17 16:45:27
|
|
CURRENT_TEST: rpl.create_or_replace_mix2
|
mysqltest: In included file "/home/buildbot/aarch64-centos-stream10/build/mysql-test/suite/rpl/t/create_or_replace.inc":
|
included from /home/buildbot/aarch64-centos-stream10/build/mysql-test/suite/rpl/t/create_or_replace_mix2.test at line 7:
|
At line 142: failed in 'select master_pos_wait('master-bin.000001', 4538, 300, '')': 2013: Lost connection to server during query
|
...
|
create table t2 select * from t9;
|
...
|
sql/opt_hints.cc:939(hint_table_state(THD const*, TABLE_LIST const*, opt_hints_enum, bool))[0xaaaaeb38c500]
|
sql/sql_select.cc:2541(JOIN::optimize_inner())[0xaaaaeb21b150]
|
sql/sql_select.cc:2023(JOIN::optimize())[0xaaaaeb21bddc]
|
sql/sql_select.cc:5388(mysql_select(THD*, TABLE_LIST*, List<Item>&, Item*, unsigned int, st_order*, st_order*, Item*, st_order*, unsigned long long, select_result*, st_select_lex_unit*, st_select_lex*))[0xaaaaeb21bed4]
|
sql/sql_select.cc:634(handle_select(THD*, LEX*, select_result*, unsigned long long))[0xaaaaeb21c538]
|
sql/sql_table.cc:13952(Sql_cmd_create_table_like::execute(THD*))[0xaaaaeb25854c]
|
sql/sql_parse.cc:5861(mysql_execute_command(THD*, bool))[0xaaaaeb1b156c]
|
sql/sql_parse.cc:7895(mysql_parse(THD*, char*, unsigned int, Parser_state*))[0xaaaaeb1b50d4]
|
sql/log_event_server.cc:2092(Query_log_event::do_apply_event(rpl_group_info*, char const*, unsigned int))[0xaaaaeb53185c]
|
sql/log_event.cc:3986(Log_event::apply_event(rpl_group_info*))[0xaaaaeb524e80]
|
sql/slave.cc:3615(apply_event_and_update_pos_apply(Log_event*, THD*, rpl_group_info*, int))[0xaaaaeb106df8]
|
in other words, it crashes in the slave thread here:
bool hint_table_state(const THD *thd, const TABLE_LIST *table_list, |
opt_hints_enum type_arg, bool fallback_value) |
{
|
if (table_list->opt_hints_qb) |
because table_list is NULL. It comes from
bool hint_table_state(const THD *thd, const TABLE *table, |
opt_hints_enum type_arg,
|
bool fallback_value) |
{
|
return hint_table_state(thd, table->pos_in_table_list, type_arg, |
fallback_value);
|
}
|
And table->pos_in_table_list becomes NULL because of
@@ -869,6 +953,7 @@ void THD::mark_tmp_table_as_free_for_reuse(TABLE *table)
|
table->mark_as_not_binlogged();
|
}
|
|
+ table->pos_in_table_list= NULL;
|
table->query_id= 0;
|
table->file->ha_reset(); |
which was added in
commit f024fe7885b
|
Author: Nikita Malyavin <nikita.malyavin@mariadb.com>
|
Date: Fri Feb 7 01:34:56 2025 +0100
|
|
MDEV-35915 Implement Global temporary tables
|
But this does not look like the actual problem. THD::mark_tmp_table_as_free_for_reuse() is invoked because the offending statement
CREATE t2 SELECT * FROM t9 |
is executed as CREATE OR REPLACE, the table t2 exists and create_table_impl() does
if (options.or_replace()) |
{
|
(void) delete_statistics_for_table(thd, &db, &table_name); |
delete_statistics_for_table() in turn, creates a separate transation, deletes statistics, commits that transaction using
thd->commit_whole_transaction_and_close_tables();
|
and restores the original transaction. commit_whole_transaction_and_close_tables() invokes THD::mark_tmp_table_as_free_for_reuse(), which looks certainly wrong here, because the temporary table t9 is definitely not "free for reuse" it'll be used in SELECT part of this very statement.
Consider the following test case:
create table t2 (a int); |
create temporary table t9 (a int); |
insert t9 values (1); |
create or replace table t2 select * from t9 |
The code path is almost the same, but there's no crash here. Because "creating a separate transaction" includes saving and resetting the list of temporary tables in the THD. So THD::mark_tmp_table_as_free_for_reuse() only affects temporary tables in that separate transaction. Specifically,
start_new_trans new_trans(thd);
|
does in THD::reset_open_tables_state()
temporary_tables= 0;
|
But
bool THD::has_temporary_tables() |
{
|
DBUG_ENTER("THD::has_temporary_tables"); |
bool result; |
#ifdef HAVE_REPLICATION
|
if (rgi_slave) |
{
|
mysql_mutex_lock(&rgi_slave->rli->data_lock);
|
result= rgi_slave->rli->save_temporary_tables &&
|
!rgi_slave->rli->save_temporary_tables->is_empty();
|
mysql_mutex_unlock(&rgi_slave->rli->data_lock);
|
}
|
else |
#endif
|
{
|
result= has_thd_temporary_tables();
|
}
|
DBUG_RETURN(result);
|
}
|
that is, in the slave thread, temporary tables are in rgi_slave->rli->save_temporary_tables, not in thd->temporary_tables. Meaning, on the master, new_trans(thd) correctly saves the state, creates a clean one, and later restores the old state. But on the slave it doesn't.
That is, perhaps, it has to be fixed not only in GTT branch, but much earlier.
Attachments
Issue Links
- relates to
-
MDEV-35915 Implement Global temporary tables
-
- In Testing
-
-
MDEV-36106 New-style hints: [NO_]DERIVED_CONDITION_PUSHDOWN, [NO_]MERGE
-
- Closed
-
-
MDEV-22447 SIGSEGV in Item::val_uint on EXPLAIN, UBSAN: member call on null pointer of type 'struct Item' in handle_select
-
- Stalled
-
-
MDEV-37394 SIGSEGV in handler::ha_external_lock on CREATE GTT ... ENGINE=INNODB SELECT, ASAN heap-use-after-free in unlock_external
-
- Closed
-