diff --git a/mysql-test/main/sp_sync.result b/mysql-test/main/sp_sync.result index d6c170712a7..270822d79bb 100644 --- a/mysql-test/main/sp_sync.result +++ b/mysql-test/main/sp_sync.result @@ -117,3 +117,35 @@ ERROR 42000: Unknown database 's1' connection default; disconnect con3; SET DEBUG_SYNC = 'RESET'; +# +# MDEV-26048 Table 'test._test_new' doesn't exist when add trigger (use pt-osc) +# +create table t1 (x int); +create procedure sp() +begin +declare a int default 1; +while a <= 2 do +set debug_sync= concat("now wait_for created_", a); +insert into t1 values(a); +set debug_sync= "now signal inserted"; +set a= a + 1; +end while; +end$$ +connect con1,localhost,root,,test; +call sp(); +connection default; +create table t2 (y int); +create trigger tr1 after delete on t1 for each row delete from t2; +set debug_sync= "now signal created_1"; +set debug_sync= "now wait_for inserted"; +create trigger tr2 after insert on t1 for each row insert t2 values (0); +set debug_sync= "now signal created_2"; +connection con1; +disconnect con1; +connection default; +drop trigger tr1; +drop trigger tr2; +drop table t2; +drop procedure sp; +drop table t1; +set debug_sync= "reset"; diff --git a/mysql-test/main/sp_sync.test b/mysql-test/main/sp_sync.test index a5682fc572f..1cb44e74caf 100644 --- a/mysql-test/main/sp_sync.test +++ b/mysql-test/main/sp_sync.test @@ -168,3 +168,49 @@ SET DEBUG_SYNC = 'RESET'; # Check that all connections opened by test cases in this file are really # gone so execution of other tests won't be affected by their presence. --source include/wait_until_count_sessions.inc + +--echo # +--echo # MDEV-26048 Table 'test._test_new' doesn't exist when add trigger (use pt-osc) +--echo # +create table t1 (x int); + +--delimiter $$ +# Note: it's important to do INSERT in a loop as +# the bug reproduces only on the same statetement +# (has_prelocking_list depends on it) +create procedure sp() +begin + declare a int default 1; + while a <= 2 do + set debug_sync= concat("now wait_for created_", a); + insert into t1 values(a); + set debug_sync= "now signal inserted"; + set a= a + 1; + end while; +end$$ +--delimiter ; + +--connect (con1,localhost,root,,test) +send call sp(); +--connection default + +create table t2 (y int); +create trigger tr1 after delete on t1 for each row delete from t2; +set debug_sync= "now signal created_1"; +set debug_sync= "now wait_for inserted"; +create trigger tr2 after insert on t1 for each row insert t2 values (0); +set debug_sync= "now signal created_2"; + +--connection con1 +--reap + +--disconnect con1 +--connection default +drop trigger tr1; +drop trigger tr2; +drop table t2; +drop procedure sp; +drop table t1; +set debug_sync= "reset"; + +# End of 10.11 tests diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 926da91ae0b..37ecb468c35 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -3572,6 +3572,8 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, We've already entered/left prelocked mode with this statement. Attach the list of tables that need to be prelocked and mark m_lex as having such list attached. + + TODO: DBUG_ASSERT(prelocking_tables); */ *lex_query_tables_own_last= prelocking_tables; m_lex->mark_as_requiring_prelocking(lex_query_tables_own_last); diff --git a/sql/sp_head.h b/sql/sp_head.h index 1f48603eafe..38a3e93a8a4 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -1269,7 +1269,8 @@ class sp_lex_keeper public: sp_lex_keeper(LEX *lex, bool lex_resp) - : m_lex(lex), m_lex_resp(lex_resp), + : m_lex(lex), m_lex_resp(lex_resp), + prelocking_tables(NULL), lex_query_tables_own_last(NULL) { lex->sp_lex_in_use= TRUE; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index f9b19d8bb9b..8b20d37f18a 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3709,7 +3709,12 @@ bool extend_table_list(THD *thd, TABLE_LIST *tables, &need_prelocking); if (need_prelocking && ! lex->requires_prelocking()) + { + /* + TODO: DBUG_ASSERT(save_query_tables_last != lex->query_tables_last); + */ lex->mark_as_requiring_prelocking(save_query_tables_last); + } } return error; } @@ -4912,14 +4917,10 @@ bool DML_prelocking_strategy::handle_table(THD *thd, if (table_list->trg_event_map) { - if (table->triggers) - { - *need_prelocking= TRUE; - - if (table->triggers-> - add_tables_and_routines_for_triggers(thd, prelocking_ctx, table_list)) - return TRUE; - } + Table_triggers_list *tr= table->triggers; + if (tr && tr->add_tables_and_routines_for_triggers(thd, prelocking_ctx, + table_list, need_prelocking)) + return true; if (prepare_fk_prelocking_list(thd, prelocking_ctx, table_list, need_prelocking, diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 06ba5d75afc..c04863d2cc1 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -2532,7 +2532,8 @@ bool Table_triggers_list:: add_tables_and_routines_for_triggers(THD *thd, Query_tables_list *prelocking_ctx, - TABLE_LIST *table_list) + TABLE_LIST *table_list, + bool *need_prelocking) { DBUG_ASSERT(static_cast(table_list->lock_type) >= static_cast(TL_FIRST_WRITE)); @@ -2552,6 +2553,8 @@ add_tables_and_routines_for_triggers(THD *thd, if (unlikely(!triggers->body)) // Parse error continue; + *need_prelocking= true; + MDL_key key(MDL_key::TRIGGER, trigger->m_db.str, trigger->m_name.str); if (sp_add_used_routine(prelocking_ctx, diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h index 872dc7c3c32..144ce235690 100644 --- a/sql/sql_trigger.h +++ b/sql/sql_trigger.h @@ -309,7 +309,8 @@ public: bool add_tables_and_routines_for_triggers(THD *thd, Query_tables_list *prelocking_ctx, - TABLE_LIST *table_list); + TABLE_LIST *table_list, + bool *need_prelocking); Field **nullable_fields() { return record0_field; } void clear_extra_null_bitmap()