revision-id: 18db45ff3553b6830ec1f72941301472abb3e706 (mariadb-10.3.26-135-g18db45ff355) parent(s): 75c01f39b1b4a6d27d36d075f8baab9bdda7cc7e author: Sergei Petrunia committer: Sergei Petrunia timestamp: 2021-04-23 16:00:29 +0300 message: MDEV-21603: Long WHERE IN mariadb 10.3.22 crash I_S tables and SHOW COMMANDS use special logic for creating and populating temp.tables, e.g. table creation is delayed. The code attempted to apply the same logic for the IN-to-SELECT temptable, which resulted in an attempt to read from not-yet-created temptable and crash. Fix this by restricting use of I_S table logic only to I_S tables. --- mysql-test/main/information_schema2.result | 12 ++++++++++++ mysql-test/main/information_schema2.test | 13 +++++++++++++ sql/sql_base.cc | 1 - sql/sql_class.h | 12 ++++++++++-- sql/sql_derived.cc | 8 +++++--- sql/sql_prepare.cc | 2 +- 6 files changed, 41 insertions(+), 7 deletions(-) diff --git a/mysql-test/main/information_schema2.result b/mysql-test/main/information_schema2.result index e23e81b885c..0f24ca3f264 100644 --- a/mysql-test/main/information_schema2.result +++ b/mysql-test/main/information_schema2.result @@ -18,3 +18,15 @@ t2 t3 t4 drop table t1, t2, t3, t4; +# +# MDEV-21603: Long WHERE IN mariadb 10.3.22 crash +# +connect con1,localhost,root,,; +set @@in_predicate_conversion_threshold=10; +use mysql; +show tables where tables_in_mysql in ('1','2','3','4','5','6','7','8','9','boom'); +Tables_in_mysql +show fields from user where Field in ('1','2','3','4','5','6','7','8','9','boom'); +Field Type Null Key Default Extra +disconnect con1; +connection default; diff --git a/mysql-test/main/information_schema2.test b/mysql-test/main/information_schema2.test index d2fa3da2b5f..d0cfeefa31a 100644 --- a/mysql-test/main/information_schema2.test +++ b/mysql-test/main/information_schema2.test @@ -17,3 +17,16 @@ create table t4 AS select table_name from information_schema.TABLES where table_ delete from t4 where table_name not in (select table_name from information_schema.TABLES where table_schema = database() and table_type = 'BASE TABLE'); select * from t4 order by table_name; drop table t1, t2, t3, t4; + +--echo # +--echo # MDEV-21603: Long WHERE IN mariadb 10.3.22 crash +--echo # +connect (con1,localhost,root,,); + +set @@in_predicate_conversion_threshold=10; +use mysql; +show tables where tables_in_mysql in ('1','2','3','4','5','6','7','8','9','boom'); +show fields from user where Field in ('1','2','3','4','5','6','7','8','9','boom'); + +disconnect con1; +connection default; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 0b17032da8f..4e5b32ce1e5 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -5187,7 +5187,6 @@ bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags, uint counter; MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint(); DBUG_ENTER("open_normal_and_derived_tables"); - DBUG_ASSERT(!thd->fill_derived_tables()); if (open_tables(thd, &tables, &counter, flags, &prelocking_strategy) || mysql_handle_derived(thd->lex, dt_phases)) goto end; diff --git a/sql/sql_class.h b/sql/sql_class.h index 5ab93de7957..9d19e25f44f 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3636,9 +3636,17 @@ class THD :public Statement, { return server_status & SERVER_STATUS_IN_TRANS; } - inline bool fill_derived_tables() + inline bool fill_derived_table(TABLE_LIST *tl) { - return !stmt_arena->is_stmt_prepare() && !lex->only_view_structure(); + /* + Do not fill derived table when + 1. running a PREPARE command + 2. this is a SHOW command and the table is a temp.table representing + the I_S table. + */ + return !stmt_arena->is_stmt_prepare() && // (1) + !(lex->only_view_structure() && tl->schema_table_reformed); // (2) + } inline bool fill_information_schema_tables() { diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 50b0178c6c9..33cb6a50710 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -85,14 +85,16 @@ mysql_handle_derived(LEX *lex, uint phases) break; if (!(phases & phase_flag)) continue; - if (phase_flag >= DT_CREATE && !thd->fill_derived_tables()) - break; for (SELECT_LEX *sl= lex->all_selects_list; sl && !res; sl= sl->next_select_in_list()) { TABLE_LIST *cursor= sl->get_table_list(); + + if (phase_flag >= DT_CREATE && !thd->fill_derived_table(cursor)) + break; + sl->changed_elements|= TOUCHED_SEL_DERIVED; /* DT_MERGE_FOR_INSERT is not needed for views/derived tables inside @@ -193,7 +195,7 @@ mysql_handle_single_derived(LEX *lex, TABLE_LIST *derived, uint phases) if (phase_flag != DT_PREPARE && !(allowed_phases & phase_flag)) continue; - if (phase_flag >= DT_CREATE && !thd->fill_derived_tables()) + if (phase_flag >= DT_CREATE && !thd->fill_derived_table(derived)) break; if ((res= (*processors[phase])(lex->thd, lex, derived))) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 9775e99afdd..357c1334ee2 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1452,7 +1452,7 @@ static int mysql_test_update(Prepared_statement *stmt, } /* - thd->fill_derived_tables() is false here for sure (because it is + thd->fill_derived_table(table_list) is false here for sure (because it is preparation of PS, so we even do not check it). */ if (table_list->handle_derived(thd->lex, DT_MERGE_FOR_INSERT))