From 497d86276f4b67191d58d491ab294dc06d6f606a Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Mon, 27 Aug 2018 08:12:59 -0700 Subject: [PATCH] MDEV-17017 Explain for query using derived table specified with a table value constructor shows wrong number of rows This is another attempt to fix this bug. The previous patch did not take into account that a transformation for ALL/ANY subqueries could be applied to the materialized table that wrapped the table value constructor used as a specification of the subselect used an ALL/ANY subquery. In this case the result of the derived table used a sink of the class select_subselect rather than of the class select_unit. Thus the previous fix could cause memory overwrites when running EXPLAIN for queries with table value constructors in ALL/ANY subselects. --- mysql-test/main/table_value_constr.test | 2 -- sql/sql_class.h | 5 ++--- sql/sql_lex.cc | 6 +++--- sql/table.cc | 2 +- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/mysql-test/main/table_value_constr.test b/mysql-test/main/table_value_constr.test index 5df40d1047c14..0dd0a7a04b0db 100644 --- a/mysql-test/main/table_value_constr.test +++ b/mysql-test/main/table_value_constr.test @@ -1123,5 +1123,3 @@ PREPARE stmt FROM "SELECT * FROM (VALUES(1 + 1,2,'abc')) t"; EXECUTE stmt; EXECUTE stmt; DEALLOCATE PREPARE stmt; - - diff --git a/sql/sql_class.h b/sql/sql_class.h index faae443e7a08a..026ef4d1118ff 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -4956,7 +4956,8 @@ class select_result :public select_result_sink SELECT_LEX_UNIT *unit; /* Something used only by the parser: */ public: - select_result(THD *thd_arg): select_result_sink(thd_arg) {} + ha_rows est_records; /* estimated number of records in the result */ + select_result(THD *thd_arg): select_result_sink(thd_arg), est_records(0) {} void set_unit(SELECT_LEX_UNIT *unit_arg) { unit= unit_arg; } virtual ~select_result() {}; /** @@ -5528,7 +5529,6 @@ class select_unit :public select_result_interceptor TMP_TABLE_PARAM tmp_table_param; int write_err; /* Error code from the last send_data->ha_write_row call. */ TABLE *table; - ha_rows records; select_unit(THD *thd_arg): select_result_interceptor(thd_arg), @@ -5566,7 +5566,6 @@ class select_unit :public select_result_interceptor curr_sel= UINT_MAX; step= UNION_TYPE; write_err= 0; - records= 0; } void change_select(); }; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 7d88a6cab4bb8..1b1031d440bb6 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -4678,18 +4678,18 @@ void SELECT_LEX::increase_derived_records(ha_rows records) return; } - select_unit *result= (select_unit*)unit->result; + select_result *result= unit->result; switch (linkage) { case INTERSECT_TYPE: // result of intersect can't be more then one of components - set_if_smaller(result->records, records); + set_if_smaller(result->est_records, records); case EXCEPT_TYPE: // in worse case none of record will be removed break; default: // usual UNION - result->records+= records; + result->est_records+= records; break; } } diff --git a/sql/table.cc b/sql/table.cc index 627f6159979d9..4aef9aad4fc10 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -8334,7 +8334,7 @@ int TABLE_LIST::fetch_number_of_rows() } if (is_materialized_derived() && !fill_me) { - table->file->stats.records= ((select_unit*)(get_unit()->result))->records; + table->file->stats.records= get_unit()->result->est_records; set_if_bigger(table->file->stats.records, 2); table->used_stat_records= table->file->stats.records; }