From ef9e3e73ed52e55842e6ba40dfa94a78fb06cbee Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Tue, 11 Jun 2024 16:20:00 +0300 Subject: [PATCH] MDEV-30651: Assertion `sel->quick' in make_range_rowid_filters (Variant for 10.6: return error code from SQL_SELECT::test_quick_select) The optimizer deals with Rowid Filters this way: 1. First, range optimizer is invoked. It saves information about all potential range accesses. 2. A query plan is chosen. Suppose, it uses a Rowid Filter on index $IDX. 3. JOIN::make_range_rowid_filters() calls the range optimizer again to create a quick select on index $IDX which will be used to populate the rowid filter. The problem: KILL command catches the query in step #3. Quick Select is not created which causes a crash. Fixed by checking if query was killed. --- .../include/rowid_filter_debug_kill.inc | 28 +++++++++++++++++++ .../main/rowid_filter_innodb_debug.result | 18 ++++++++++++ .../main/rowid_filter_myisam_debug.result | 18 ++++++++++++ sql/opt_range.cc | 9 ++++++ sql/sql_select.cc | 7 +++-- 5 files changed, 77 insertions(+), 3 deletions(-) diff --git a/mysql-test/include/rowid_filter_debug_kill.inc b/mysql-test/include/rowid_filter_debug_kill.inc index 513efed8a4c..45b44b246d2 100644 --- a/mysql-test/include/rowid_filter_debug_kill.inc +++ b/mysql-test/include/rowid_filter_debug_kill.inc @@ -55,5 +55,33 @@ disconnect con1; reap; set debug_sync='RESET'; +--echo # +--echo # MDEV-30651: SIGSEGV in st_join_table::save_explain_data and +--echo # Assertion `sel->quick' failed in make_range_rowid_filters +--echo # + +--echo # Reusing table t2 and t3 from previous test +let $target_id= `select connection_id()`; + +set debug_sync='in_forced_range_optimize SIGNAL ready1 WAIT_FOR go1'; +send +explain +select * from t2, t3 +where + t3.key1=t2.a and t3.key2 in (2,3); + +connect (con1, localhost, root,,); +set debug_sync='now WAIT_FOR ready1'; +evalp kill query $target_id; +set debug_sync='now SIGNAL go1'; + +connection default; +disconnect con1; + +--error ER_QUERY_INTERRUPTED +reap; +set debug_sync='RESET'; + + drop table t2,t3; --source include/wait_until_count_sessions.inc diff --git a/mysql-test/main/rowid_filter_innodb_debug.result b/mysql-test/main/rowid_filter_innodb_debug.result index f82b29aa1e6..4fdf53cb2b0 100644 --- a/mysql-test/main/rowid_filter_innodb_debug.result +++ b/mysql-test/main/rowid_filter_innodb_debug.result @@ -46,5 +46,23 @@ connection default; disconnect con1; ERROR 70100: Query execution was interrupted set debug_sync='RESET'; +# +# MDEV-30651: SIGSEGV in st_join_table::save_explain_data and +# Assertion `sel->quick' failed in make_range_rowid_filters +# +# Reusing table t2 and t3 from previous test +set debug_sync='in_forced_range_optimize SIGNAL ready1 WAIT_FOR go1'; +explain +select * from t2, t3 +where +t3.key1=t2.a and t3.key2 in (2,3); +connect con1, localhost, root,,; +set debug_sync='now WAIT_FOR ready1'; +kill query $target_id; +set debug_sync='now SIGNAL go1'; +connection default; +disconnect con1; +ERROR 70100: Query execution was interrupted +set debug_sync='RESET'; drop table t2,t3; set default_storage_engine=default; diff --git a/mysql-test/main/rowid_filter_myisam_debug.result b/mysql-test/main/rowid_filter_myisam_debug.result index 75a8fad6947..175e054af2a 100644 --- a/mysql-test/main/rowid_filter_myisam_debug.result +++ b/mysql-test/main/rowid_filter_myisam_debug.result @@ -45,4 +45,22 @@ connection default; disconnect con1; ERROR 70100: Query execution was interrupted set debug_sync='RESET'; +# +# MDEV-30651: SIGSEGV in st_join_table::save_explain_data and +# Assertion `sel->quick' failed in make_range_rowid_filters +# +# Reusing table t2 and t3 from previous test +set debug_sync='in_forced_range_optimize SIGNAL ready1 WAIT_FOR go1'; +explain +select * from t2, t3 +where +t3.key1=t2.a and t3.key2 in (2,3); +connect con1, localhost, root,,; +set debug_sync='now WAIT_FOR ready1'; +kill query $target_id; +set debug_sync='now SIGNAL go1'; +connection default; +disconnect con1; +ERROR 70100: Query execution was interrupted +set debug_sync='RESET'; drop table t2,t3; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 9c47639596d..ea0a0d70807 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2720,7 +2720,10 @@ SQL_SELECT::test_quick_select(THD *thd, only_single_index_range_scan= 1; if (head->force_index || force_quick_range) + { + DEBUG_SYNC(thd, "in_forced_range_optimize"); scan_time= read_time= DBL_MAX; + } else { scan_time= rows2double(records) / TIME_FOR_COMPARE; @@ -3117,6 +3120,12 @@ SQL_SELECT::test_quick_select(THD *thd, free_root(&alloc,MYF(0)); // Return memory & allocator thd->mem_root= param.old_root; thd->no_errors=0; + if (thd->killed || thd->is_error()) + { + delete quick; + quick= NULL; + returnval= ERROR; + } } DBUG_EXECUTE("info", print_quick(quick, &needed_reg);); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9b103a7f2ea..e195ab31564 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1987,6 +1987,7 @@ bool JOIN::make_range_rowid_filters() tab->table->force_index= force_index_save; if (rc == SQL_SELECT::ERROR || thd->is_error()) { + delete sel; DBUG_RETURN(true); /* Fatal error */ } /* @@ -2012,8 +2013,6 @@ bool JOIN::make_range_rowid_filters() continue; } no_filter: - if (sel->quick) - delete sel->quick; delete sel; } @@ -2031,7 +2030,9 @@ bool JOIN::make_range_rowid_filters() rowid container employed by the filter. On success it lets the table engine know that what rowid filter will be used when accessing the table rows. - @retval false always + @retval + false OK + true Error, query should abort */ bool