diff options
author | Oleg Smirnov <olernov@gmail.com> | 2023-01-29 19:39:14 +0700 |
---|---|---|
committer | Oleg Smirnov <olernov@gmail.com> | 2023-04-19 17:08:29 +0700 |
commit | 135f877f278d4e85cf8ecb83385b5631cb20229d (patch) | |
tree | ea6a78f52701104fc08246ceda172a35657b2328 | |
parent | 2e1c532bd2d9f9a35559e54f66d33c81e33009b1 (diff) | |
download | mariadb-git-bb-10.4-mdev-30143.tar.gz |
MDEV-30143 Segfault on select query using index for group-by and filesortbb-10.4-mdev-30143
The problem was trying to access JOIN_TAB::select which is set to NULL
when using the filesort. The correct way is accessing either
JOIN_TAB::select or JOIN_TAB::filesort->select depending on whether
the filesort is used.
This commit introduces member function JOIN_TAB::get_sql_select()
encapsulating that check so the code duplication is eliminated
-rw-r--r-- | mysql-test/main/group_min_max_innodb.result | 22 | ||||
-rw-r--r-- | mysql-test/main/group_min_max_innodb.test | 23 | ||||
-rw-r--r-- | sql/sql_select.cc | 6 | ||||
-rw-r--r-- | sql/sql_select.h | 9 |
4 files changed, 54 insertions, 6 deletions
diff --git a/mysql-test/main/group_min_max_innodb.result b/mysql-test/main/group_min_max_innodb.result index 3586ad5237f..a2b06b0481b 100644 --- a/mysql-test/main/group_min_max_innodb.result +++ b/mysql-test/main/group_min_max_innodb.result @@ -308,6 +308,28 @@ NULL bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb NULL aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa NULL aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa drop table t1,t2; +# +# MDEV-30143: Segfault on select query using index for group-by and filesort +# +CREATE TABLE t1 (a varchar(35), b varchar(4)) ENGINE=InnoDB; +INSERT INTO t1 VALUES +('Albania','AXA'),('Australia','AUS'),('American Samoa','AMSA'),('Bahamas','BS'); +CREATE TABLE t2 (a varchar(4), b varchar(50), PRIMARY KEY (b,a), KEY (a)) ENGINE=InnoDB; +INSERT INTO t2 VALUES +('BERM','African Methodist Episcopal'),('AUS','Anglican'),('BERM','Anglican'),('BS','Anglican'),('BS','Baptist'),('BS','Methodist'); +EXPLAIN SELECT t1.a +FROM (SELECT a FROM t2 GROUP BY a ORDER BY COUNT(DISTINCT b) LIMIT 1) dt +JOIN t1 ON dt.a=t1.b; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY <derived2> ALL NULL NULL NULL NULL # +1 PRIMARY t1 ALL NULL NULL NULL NULL # Using where; Using join buffer (flat, BNL join) +2 DERIVED t2 range a a 58 NULL # Using index for group-by (scanning); Using temporary; Using filesort +SELECT t1.a +FROM (SELECT a FROM t2 GROUP BY a ORDER BY COUNT(DISTINCT b) LIMIT 1) dt +JOIN t1 ON dt.a=t1.b; +a +Australia +DROP TABLES t1, t2; set global innodb_stats_persistent= @innodb_stats_persistent_save; set global innodb_stats_persistent_sample_pages= @innodb_stats_persistent_sample_pages_save; diff --git a/mysql-test/main/group_min_max_innodb.test b/mysql-test/main/group_min_max_innodb.test index 87a6e320887..fcecbec41b3 100644 --- a/mysql-test/main/group_min_max_innodb.test +++ b/mysql-test/main/group_min_max_innodb.test @@ -251,7 +251,28 @@ insert into t2 values (1,repeat("a",1000)),(2,repeat("a",1000)),(3,repeat("b",10 SELECT GROUP_CONCAT(t1.language_id SEPARATOR ',') AS `translation_resources`, `d`.`serialized_c` FROM t2 AS `d` LEFT JOIN t1 ON `d`.`voter_id` = t1.`voter_id` GROUP BY `d`.`voter_id` ORDER BY 10-d.voter_id+RAND()*0; drop table t1,t2; + +--echo # +--echo # MDEV-30143: Segfault on select query using index for group-by and filesort +--echo # +CREATE TABLE t1 (a varchar(35), b varchar(4)) ENGINE=InnoDB; +INSERT INTO t1 VALUES +('Albania','AXA'),('Australia','AUS'),('American Samoa','AMSA'),('Bahamas','BS'); + +CREATE TABLE t2 (a varchar(4), b varchar(50), PRIMARY KEY (b,a), KEY (a)) ENGINE=InnoDB; +INSERT INTO t2 VALUES +('BERM','African Methodist Episcopal'),('AUS','Anglican'),('BERM','Anglican'),('BS','Anglican'),('BS','Baptist'),('BS','Methodist'); + +let query= +SELECT t1.a +FROM (SELECT a FROM t2 GROUP BY a ORDER BY COUNT(DISTINCT b) LIMIT 1) dt +JOIN t1 ON dt.a=t1.b; +--replace_column 9 # +eval EXPLAIN $query; +eval $query; + +DROP TABLES t1, t2; + set global innodb_stats_persistent= @innodb_stats_persistent_save; set global innodb_stats_persistent_sample_pages= @innodb_stats_persistent_sample_pages_save; - diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0651c1d58bd..0048d36d2ea 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8100,6 +8100,7 @@ best_access_path(JOIN *join, if ((records >= s->found_records || best > s->read_time) && // (1) !(best_key && best_key->key == MAX_KEY) && // (2) !(s->quick && best_key && s->quick->index == best_key->key && // (2) + s->table->quick_keys.is_set(best_key->key) && // (2) best_max_key_part >= s->table->quick_key_parts[best_key->key]) &&// (2) !((s->table->file->ha_table_flags() & HA_TABLE_SCAN_ON_INDEX) && // (3) ! s->table->covering_keys.is_clear_all() && best_key && !s->quick) &&// (3) @@ -13761,7 +13762,7 @@ double JOIN_TAB::scan_time() ha_rows JOIN_TAB::get_examined_rows() { double examined_rows; - SQL_SELECT *sel= filesort? filesort->select : this->select; + const SQL_SELECT *sel= get_sql_select(); if (sel && sel->quick && use_quick != 2) examined_rows= (double)sel->quick->records; @@ -26770,13 +26771,12 @@ bool JOIN_TAB::save_explain_data(Explain_table_access *eta, eta->key.clear(); eta->quick_info= NULL; - SQL_SELECT *tab_select; /* We assume that if this table does pre-sorting, then it doesn't do filtering with SQL_SELECT. */ DBUG_ASSERT(!(select && filesort)); - tab_select= (filesort)? filesort->select : select; + const SQL_SELECT *tab_select= get_sql_select(); if (filesort) { diff --git a/sql/sql_select.h b/sql/sql_select.h index 0dfecc98a48..a438f29bd23 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -535,14 +535,19 @@ typedef struct st_join_table { void cleanup(); inline bool is_using_loose_index_scan() { - const SQL_SELECT *sel= filesort ? filesort->select : select; + const SQL_SELECT *sel= get_sql_select(); return (sel && sel->quick && (sel->quick->get_type() == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)); } bool is_using_agg_loose_index_scan () { + const SQL_SELECT *sel= get_sql_select(); return (is_using_loose_index_scan() && - ((QUICK_GROUP_MIN_MAX_SELECT *)select->quick)->is_agg_distinct()); + ((QUICK_GROUP_MIN_MAX_SELECT *)sel->quick)->is_agg_distinct()); + } + const SQL_SELECT *get_sql_select() + { + return filesort ? filesort->select : select; } bool is_inner_table_of_semi_join_with_first_match() { |