diff options
author | Oleg Smirnov <olernov@gmail.com> | 2022-03-27 11:58:27 +0700 |
---|---|---|
committer | Sergei Petrunia <sergey@mariadb.com> | 2022-04-29 10:48:25 +0300 |
commit | 02c3babdec0c931c6983863bff129114f750bd22 (patch) | |
tree | 6340356ad6be55b8c80000d99f4b0ca333f22afa | |
parent | a0475cb9ca2b98d5c95f021e6d8c57dcba238397 (diff) | |
download | mariadb-git-02c3babdec0c931c6983863bff129114f750bd22.tar.gz |
MDEV-28124 Server crashes in Explain_aggr_filesort::print_json_members
SHOW EXPLAIN/ANALYZE FORMAT=JSON tries to access items that have already been
freed by a call to free_items() during THD::cleanup_after_query().
The solution is to disallow APC calls including SHOW EXPLAIN/ANALYZE
just before the call to free_items().
-rw-r--r-- | mysql-test/main/show_analyze.result | 14 | ||||
-rw-r--r-- | mysql-test/main/show_analyze.test | 21 | ||||
-rw-r--r-- | mysql-test/main/show_analyze_json.result | 14 | ||||
-rw-r--r-- | mysql-test/main/show_analyze_json.test | 22 | ||||
-rw-r--r-- | mysql-test/main/show_explain.result | 14 | ||||
-rw-r--r-- | mysql-test/main/show_explain.test | 20 | ||||
-rw-r--r-- | mysql-test/main/show_explain_json.result | 14 | ||||
-rw-r--r-- | mysql-test/main/show_explain_json.test | 20 | ||||
-rw-r--r-- | mysql-test/suite/perfschema/r/nesting.result | 38 | ||||
-rw-r--r-- | sql/item.cc | 36 | ||||
-rw-r--r-- | sql/item.h | 67 | ||||
-rw-r--r-- | sql/item_func.cc | 7 | ||||
-rw-r--r-- | sql/item_subselect.cc | 16 | ||||
-rw-r--r-- | sql/item_sum.cc | 16 | ||||
-rw-r--r-- | sql/my_apc.cc | 3 | ||||
-rw-r--r-- | sql/sql_class.cc | 3 | ||||
-rw-r--r-- | sql/sql_explain.cc | 10 | ||||
-rw-r--r-- | sql/sql_explain.h | 2 | ||||
-rw-r--r-- | sql/sql_parse.cc | 5 | ||||
-rw-r--r-- | sql/sql_select.cc | 41 | ||||
-rw-r--r-- | sql/sql_select.h | 1 | ||||
-rw-r--r-- | sql/sql_window.cc | 6 |
22 files changed, 303 insertions, 87 deletions
diff --git a/mysql-test/main/show_analyze.result b/mysql-test/main/show_analyze.result index e307edcccf8..8f50bb4d970 100644 --- a/mysql-test/main/show_analyze.result +++ b/mysql-test/main/show_analyze.result @@ -373,6 +373,20 @@ a 9 SET debug_dbug=@old_debug; drop table t0,t1; +# +# MDEV-28124: Server crashes in Explain_aggr_filesort::print_json_members +# upon SHOW ANALYZE/EXPLAIN FORMAT=JSON +# +connection con1; +set @show_explain_probe_query= 'SELECT count(*) - count(*) FROM sys.waits_by_user_by_latency'; +set debug_dbug='+d,log_slow_statement_end'; +SELECT count(*) - count(*) FROM sys.waits_by_user_by_latency; +connection default; +SHOW ANALYZE FOR $thr2; +ERROR HY000: Target is not executing an operation with a query plan +connection con1; +count(*) - count(*) +0 # End connection default; disconnect con1; diff --git a/mysql-test/main/show_analyze.test b/mysql-test/main/show_analyze.test index 01e86945461..e4e16bb6159 100644 --- a/mysql-test/main/show_analyze.test +++ b/mysql-test/main/show_analyze.test @@ -326,6 +326,27 @@ SET debug_dbug=@old_debug; drop table t0,t1; + +--echo # +--echo # MDEV-28124: Server crashes in Explain_aggr_filesort::print_json_members +--echo # upon SHOW ANALYZE/EXPLAIN FORMAT=JSON +--echo # + +let $wait_condition= select State='show_explain_trap' from information_schema.processlist where id=$thr2; +connection con1; +set @show_explain_probe_query= 'SELECT count(*) - count(*) FROM sys.waits_by_user_by_latency'; +set debug_dbug='+d,log_slow_statement_end'; + +# Statement guarantees to produce 0 on every run +send SELECT count(*) - count(*) FROM sys.waits_by_user_by_latency; +connection default; +--source include/wait_condition.inc +--error ER_TARGET_NOT_EXPLAINABLE +evalp SHOW ANALYZE FOR $thr2; + +connection con1; +reap; + --echo # End connection default; disconnect con1; diff --git a/mysql-test/main/show_analyze_json.result b/mysql-test/main/show_analyze_json.result index 574fe73f20c..5b34d8f0952 100644 --- a/mysql-test/main/show_analyze_json.result +++ b/mysql-test/main/show_analyze_json.result @@ -1222,6 +1222,20 @@ a 9 SET debug_dbug=@old_debug; drop table t0,t1; +# +# MDEV-28124: Server crashes in Explain_aggr_filesort::print_json_members +# upon SHOW ANALYZE/EXPLAIN FORMAT=JSON +# +connection con1; +set @show_explain_probe_query= 'SELECT count(*) - count(*) FROM sys.waits_by_user_by_latency'; +set debug_dbug='+d,log_slow_statement_end'; +SELECT count(*) - count(*) FROM sys.waits_by_user_by_latency; +connection default; +SHOW ANALYZE FORMAT=JSON FOR $thr2; +ERROR HY000: Target is not executing an operation with a query plan +connection con1; +count(*) - count(*) +0 # End connection default; disconnect con1; diff --git a/mysql-test/main/show_analyze_json.test b/mysql-test/main/show_analyze_json.test index bd12247ae16..18eea8c7a9a 100644 --- a/mysql-test/main/show_analyze_json.test +++ b/mysql-test/main/show_analyze_json.test @@ -360,8 +360,28 @@ connection con1; reap; SET debug_dbug=@old_debug; - drop table t0,t1; + +--echo # +--echo # MDEV-28124: Server crashes in Explain_aggr_filesort::print_json_members +--echo # upon SHOW ANALYZE/EXPLAIN FORMAT=JSON +--echo # + +let $wait_condition= select State='show_explain_trap' from information_schema.processlist where id=$thr2; +connection con1; +set @show_explain_probe_query= 'SELECT count(*) - count(*) FROM sys.waits_by_user_by_latency'; +set debug_dbug='+d,log_slow_statement_end'; + +# Statement guarantees to produce 0 on every run +send SELECT count(*) - count(*) FROM sys.waits_by_user_by_latency; +connection default; +--source include/wait_condition.inc +--error ER_TARGET_NOT_EXPLAINABLE +evalp SHOW ANALYZE FORMAT=JSON FOR $thr2; + +connection con1; +reap; + --echo # End connection default; disconnect con1; diff --git a/mysql-test/main/show_explain.result b/mysql-test/main/show_explain.result index 345fa928601..35a528aff4e 100644 --- a/mysql-test/main/show_explain.result +++ b/mysql-test/main/show_explain.result @@ -1421,6 +1421,20 @@ kill query $thr2; connection con1; ERROR 70100: Query execution was interrupted drop table t0,t1,t2; +# +# MDEV-28124: Server crashes in Explain_aggr_filesort::print_json_members +# upon SHOW ANALYZE/EXPLAIN FORMAT=JSON +# +connection con1; +set @show_explain_probe_query= 'SELECT count(*) - count(*) FROM sys.waits_by_user_by_latency'; +set debug_dbug='+d,log_slow_statement_end'; +SELECT count(*) - count(*) FROM sys.waits_by_user_by_latency; +connection default; +SHOW EXPLAIN FOR $thr2; +ERROR HY000: Target is not executing an operation with a query plan +connection con1; +count(*) - count(*) +0 # End connection default; disconnect con1; diff --git a/mysql-test/main/show_explain.test b/mysql-test/main/show_explain.test index 36654e7bd9e..47073628ca7 100644 --- a/mysql-test/main/show_explain.test +++ b/mysql-test/main/show_explain.test @@ -1304,6 +1304,26 @@ reap; drop table t0,t1,t2; +--echo # +--echo # MDEV-28124: Server crashes in Explain_aggr_filesort::print_json_members +--echo # upon SHOW ANALYZE/EXPLAIN FORMAT=JSON +--echo # + +let $wait_condition= select State='show_explain_trap' from information_schema.processlist where id=$thr2; +connection con1; +set @show_explain_probe_query= 'SELECT count(*) - count(*) FROM sys.waits_by_user_by_latency'; +set debug_dbug='+d,log_slow_statement_end'; + +# Statement guarantees to produce 0 on every run +send SELECT count(*) - count(*) FROM sys.waits_by_user_by_latency; +connection default; +--source include/wait_condition.inc +--error ER_TARGET_NOT_EXPLAINABLE +evalp SHOW EXPLAIN FOR $thr2; + +connection con1; +reap; + --echo # End connection default; disconnect con1; diff --git a/mysql-test/main/show_explain_json.result b/mysql-test/main/show_explain_json.result index 191b41cea01..4713d8194f0 100644 --- a/mysql-test/main/show_explain_json.result +++ b/mysql-test/main/show_explain_json.result @@ -1288,6 +1288,20 @@ set names default; drop table if exists t0,t1,t2; Warnings: Note 1051 Unknown table 'test.t2' +# +# MDEV-28124: Server crashes in Explain_aggr_filesort::print_json_members +# upon SHOW ANALYZE/EXPLAIN FORMAT=JSON +# +connection con1; +set @show_explain_probe_query= 'SELECT count(*) - count(*) FROM sys.waits_by_user_by_latency'; +set debug_dbug='+d,log_slow_statement_end'; +SELECT count(*) - count(*) FROM sys.waits_by_user_by_latency; +connection default; +SHOW EXPLAIN FORMAT=JSON FOR $thr2; +ERROR HY000: Target is not executing an operation with a query plan +connection con1; +count(*) - count(*) +0 # End connection default; disconnect con1; diff --git a/mysql-test/main/show_explain_json.test b/mysql-test/main/show_explain_json.test index 23cfc9b1d6f..3799ff7ec04 100644 --- a/mysql-test/main/show_explain_json.test +++ b/mysql-test/main/show_explain_json.test @@ -470,6 +470,26 @@ set names default; drop table if exists t0,t1,t2; +--echo # +--echo # MDEV-28124: Server crashes in Explain_aggr_filesort::print_json_members +--echo # upon SHOW ANALYZE/EXPLAIN FORMAT=JSON +--echo # + +let $wait_condition= select State='show_explain_trap' from information_schema.processlist where id=$thr2; +connection con1; +set @show_explain_probe_query= 'SELECT count(*) - count(*) FROM sys.waits_by_user_by_latency'; +set debug_dbug='+d,log_slow_statement_end'; + +# Statement guarantees to produce 0 on every run +send SELECT count(*) - count(*) FROM sys.waits_by_user_by_latency; +connection default; +--source include/wait_condition.inc +--error ER_TARGET_NOT_EXPLAINABLE +evalp SHOW EXPLAIN FORMAT=JSON FOR $thr2; + +connection con1; +reap; + --echo # End connection default; disconnect con1; diff --git a/mysql-test/suite/perfschema/r/nesting.result b/mysql-test/suite/perfschema/r/nesting.result index ba655d3c329..5fe515e2662 100644 --- a/mysql-test/suite/perfschema/r/nesting.result +++ b/mysql-test/suite/perfschema/r/nesting.result @@ -131,9 +131,9 @@ relative_event_id relative_end_event_id event_name comment nesting_event_type re 14 14 stage/sql/Commit (stage) STATEMENT 0 15 15 stage/sql/closing tables (stage) STATEMENT 0 16 16 stage/sql/Starting cleanup (stage) STATEMENT 0 -17 17 stage/sql/Freeing items (stage) STATEMENT 0 -18 18 wait/io/socket/sql/client_connection send STATEMENT 0 -19 19 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STATEMENT 0 +17 18 stage/sql/Freeing items (stage) STATEMENT 0 +18 18 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 17 +19 19 wait/io/socket/sql/client_connection send STATEMENT 0 20 21 stage/sql/Reset for next command (stage) STATEMENT 0 21 21 wait/synch/mutex/sql/THD::LOCK_thd_data lock STAGE 20 22 22 wait/synch/mutex/sql/THD::LOCK_thd_data lock STATEMENT 0 @@ -155,9 +155,9 @@ relative_event_id relative_end_event_id event_name comment nesting_event_type re 38 38 stage/sql/Commit (stage) STATEMENT 24 39 39 stage/sql/closing tables (stage) STATEMENT 24 40 40 stage/sql/Starting cleanup (stage) STATEMENT 24 -41 41 stage/sql/Freeing items (stage) STATEMENT 24 -42 42 wait/io/socket/sql/client_connection send STATEMENT 24 -43 43 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STATEMENT 24 +41 42 stage/sql/Freeing items (stage) STATEMENT 24 +42 42 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 41 +43 43 wait/io/socket/sql/client_connection send STATEMENT 24 44 45 stage/sql/Reset for next command (stage) STATEMENT 24 45 45 wait/synch/mutex/sql/THD::LOCK_thd_data lock STAGE 44 46 46 wait/synch/mutex/sql/THD::LOCK_thd_data lock STATEMENT 24 @@ -179,9 +179,9 @@ relative_event_id relative_end_event_id event_name comment nesting_event_type re 62 62 stage/sql/Commit (stage) STATEMENT 48 63 63 stage/sql/closing tables (stage) STATEMENT 48 64 64 stage/sql/Starting cleanup (stage) STATEMENT 48 -65 65 stage/sql/Freeing items (stage) STATEMENT 48 -66 66 wait/io/socket/sql/client_connection send STATEMENT 48 -67 67 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STATEMENT 48 +65 66 stage/sql/Freeing items (stage) STATEMENT 48 +66 66 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 65 +67 67 wait/io/socket/sql/client_connection send STATEMENT 48 68 69 stage/sql/Reset for next command (stage) STATEMENT 48 69 69 wait/synch/mutex/sql/THD::LOCK_thd_data lock STAGE 68 70 70 wait/synch/mutex/sql/THD::LOCK_thd_data lock STATEMENT 48 @@ -207,8 +207,8 @@ select "With a third part to make things complete" as payload NULL NULL 88 88 stage/sql/closing tables (stage) STATEMENT 72 89 89 stage/sql/Starting cleanup (stage) STATEMENT 72 90 92 stage/sql/Freeing items (stage) STATEMENT 72 -91 91 wait/io/socket/sql/client_connection send STAGE 90 -92 92 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 90 +91 91 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 90 +92 92 wait/io/socket/sql/client_connection send STAGE 90 93 110 statement/sql/select select "And this is the second part of a multi query" as payload; select "With a third part to make things complete" as payload NULL NULL 94 96 stage/sql/starting (stage) STATEMENT 93 @@ -226,8 +226,8 @@ select "With a third part to make things complete" as payload NULL NULL 106 106 stage/sql/closing tables (stage) STATEMENT 93 107 107 stage/sql/Starting cleanup (stage) STATEMENT 93 108 110 stage/sql/Freeing items (stage) STATEMENT 93 -109 109 wait/io/socket/sql/client_connection send STAGE 108 -110 110 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 108 +109 109 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 108 +110 110 wait/io/socket/sql/client_connection send STAGE 108 111 129 statement/sql/select select "With a third part to make things complete" as payload NULL NULL 112 113 stage/sql/starting (stage) STATEMENT 111 113 113 wait/synch/mutex/sql/THD::LOCK_thd_data lock STAGE 112 @@ -242,9 +242,9 @@ select "With a third part to make things complete" as payload NULL NULL 122 122 stage/sql/Commit (stage) STATEMENT 111 123 123 stage/sql/closing tables (stage) STATEMENT 111 124 124 stage/sql/Starting cleanup (stage) STATEMENT 111 -125 125 stage/sql/Freeing items (stage) STATEMENT 111 -126 126 wait/io/socket/sql/client_connection send STATEMENT 111 -127 127 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STATEMENT 111 +125 126 stage/sql/Freeing items (stage) STATEMENT 111 +126 126 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 125 +127 127 wait/io/socket/sql/client_connection send STATEMENT 111 128 129 stage/sql/Reset for next command (stage) STATEMENT 111 129 129 wait/synch/mutex/sql/THD::LOCK_thd_data lock STAGE 128 130 130 wait/synch/mutex/sql/THD::LOCK_thd_data lock STATEMENT 111 @@ -266,9 +266,9 @@ select "With a third part to make things complete" as payload NULL NULL 146 146 stage/sql/Commit (stage) STATEMENT 132 147 147 stage/sql/closing tables (stage) STATEMENT 132 148 148 stage/sql/Starting cleanup (stage) STATEMENT 132 -149 149 stage/sql/Freeing items (stage) STATEMENT 132 -150 150 wait/io/socket/sql/client_connection send STATEMENT 132 -151 151 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STATEMENT 132 +149 150 stage/sql/Freeing items (stage) STATEMENT 132 +150 150 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 149 +151 151 wait/io/socket/sql/client_connection send STATEMENT 132 152 153 stage/sql/Reset for next command (stage) STATEMENT 132 153 153 wait/synch/mutex/sql/THD::LOCK_thd_data lock STAGE 152 disconnect con1; diff --git a/sql/item.cc b/sql/item.cc index 7c9aa662609..339dc0f3d37 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3060,8 +3060,7 @@ Item_field::Item_field(THD *thd, Name_resolution_context *context_arg, Field *f) :Item_ident(thd, context_arg, f->table->s->db, Lex_cstring_strlen(*f->table_name), f->field_name), - item_equal(0), - have_privileges(NO_ACL), any_privileges(0) + item_equal(0), have_privileges(NO_ACL), any_privileges(0) { /* We always need to provide Item_field with a fully qualified field @@ -3134,7 +3133,7 @@ void Item_field::set_field(Field *field_par) { field=result_field=field_par; // for easy coding with fields set_maybe_null(field->maybe_null()); - Type_std_attributes::set(field_par->type_std_attributes()); + Type_std_attributes::set(field_par->type_std_attributes()); table_name= Lex_cstring_strlen(*field_par->table_name); field_name= field_par->field_name; db_name= field_par->table->s->db; @@ -3142,7 +3141,10 @@ void Item_field::set_field(Field *field_par) base_flags|= item_base_t::FIXED; if (field->table->s->tmp_table == SYSTEM_TMP_TABLE) + { any_privileges= 0; + refers_to_temp_table= true; + } } @@ -3620,9 +3622,12 @@ void Item_field::fix_after_pullout(st_select_lex *new_parent, Item **ref, Item *Item_field::get_tmp_table_item(THD *thd) { - Item_field *new_item= new (thd->mem_root) Item_temptable_field(thd, this); + Item_field *new_item= new (thd->mem_root) Item_field(thd, this); if (new_item) + { new_item->field= new_item->result_field; + new_item->set_refers_to_temp_table(true); + } return new_item; } @@ -3632,6 +3637,11 @@ longlong Item_field::val_int_endpoint(bool left_endp, bool *incl_endp) return null_value? LONGLONG_MIN : res; } +void Item_field::set_refers_to_temp_table(bool value) +{ + refers_to_temp_table= value; +} + bool Item_basic_value::eq(const Item *item, bool binary_cmp) const { @@ -6275,6 +6285,7 @@ void Item_field::cleanup() field= 0; item_equal= NULL; null_value= FALSE; + refers_to_temp_table= FALSE; DBUG_VOID_RETURN; } @@ -7821,21 +7832,15 @@ Item_direct_view_ref::grouping_field_transformer_for_where(THD *thd, void Item_field::print(String *str, enum_query_type query_type) { - if (field && field->table->const_table && + if (!refers_to_temp_table && field && field->table->const_table && !(query_type & (QT_NO_DATA_EXPANSION | QT_VIEW_INTERNAL))) { print_value(str); return; } - Item_ident::print(str, query_type); -} - - -void Item_temptable_field::print(String *str, enum_query_type query_type) -{ /* Item_ident doesn't have references to the underlying Field/TABLE objects, - so it's ok to use the following: + so it's safe to use the following even for a temporary table: */ Item_ident::print(str, query_type); } @@ -9101,7 +9106,12 @@ int Item_cache_wrapper::save_in_field(Field *to, bool no_conversions) Item* Item_cache_wrapper::get_tmp_table_item(THD *thd) { if (!orig_item->with_sum_func() && !orig_item->const_item()) - return new (thd->mem_root) Item_temptable_field(thd, result_field); + { + auto item_field= new (thd->mem_root) Item_field(thd, result_field); + if (item_field) + item_field->set_refers_to_temp_table(true); + return item_field; + } return copy_or_same(thd); } diff --git a/sql/item.h b/sql/item.h index af357d2407f..4ef0e1b93b2 100644 --- a/sql/item.h +++ b/sql/item.h @@ -3529,6 +3529,32 @@ public: privilege_t have_privileges; /* field need any privileges (for VIEW creation) */ bool any_privileges; + +private: + /* + Setting this member to TRUE (via set_refers_to_temp_table()) + ensures print() function continues to work even if the table + has been dropped. + + We need this for "ANALYZE statement" feature. Query execution has + these steps: + 1. Run the query. + 2. Cleanup starts. Temporary tables are destroyed + 3. print "ANALYZE statement" output, if needed + 4. Call close_thread_table() for regular tables. + + Step #4 is done after step #3, so "ANALYZE stmt" has no problem printing + Item_field objects that refer to regular tables. + + However, Step #3 is done after Step #2. Attempt to print Item_field objects + that refer to temporary tables will cause access to freed memory. + + To resolve this, we use refers_to_temp_table member to refer to items + in temporary (work) tables. + */ + bool refers_to_temp_table= false; + +public: Item_field(THD *thd, Name_resolution_context *context_arg, const LEX_CSTRING &db_arg, const LEX_CSTRING &table_name_arg, const LEX_CSTRING &field_name_arg); @@ -3753,6 +3779,7 @@ public: return field->table->pos_in_table_list->outer_join; } bool check_index_dependence(void *arg) override; + void set_refers_to_temp_table(bool value); friend class Item_default_value; friend class Item_insert_value; friend class st_select_lex_unit; @@ -3791,46 +3818,6 @@ public: }; -/* - @brief - Item_temptable_field is the same as Item_field, except that print() - continues to work even if the table has been dropped. - - @detail - - We need this item for "ANALYZE statement" feature. Query execution has - these steps: - - 1. Run the query. - 2. Cleanup starts. Temporary tables are destroyed - 3. print "ANALYZE statement" output, if needed - 4. Call close_thread_table() for regular tables. - - Step #4 is done after step #3, so "ANALYZE stmt" has no problem printing - Item_field objects that refer to regular tables. - - However, Step #3 is done after Step #2. Attempt to print Item_field objects - that refer to temporary tables will cause access to freed memory. - - To resolve this, we use Item_temptable_field to refer to items in temporary - (work) tables. -*/ - -class Item_temptable_field :public Item_field -{ -public: - Item_temptable_field(THD *thd, Name_resolution_context *context_arg, Field *field) - : Item_field(thd, context_arg, field) {} - - Item_temptable_field(THD *thd, Field *field) - : Item_field(thd, field) {} - - Item_temptable_field(THD *thd, Item_field *item) : Item_field(thd, item) {}; - - void print(String *str, enum_query_type query_type) override; -}; - - class Item_null :public Item_basic_constant { public: diff --git a/sql/item_func.cc b/sql/item_func.cc index 250393bf2fc..f25dffdfd02 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -734,7 +734,12 @@ void Item_func::signal_divide_by_null() Item *Item_func::get_tmp_table_item(THD *thd) { if (!with_sum_func() && !const_item()) - return new (thd->mem_root) Item_temptable_field(thd, result_field); + { + auto item_field= new (thd->mem_root) Item_field(thd, result_field); + if (item_field) + item_field->set_refers_to_temp_table(true); + return item_field; + } return copy_or_same(thd); } diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index e4bbe475212..de31c82abf4 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1068,7 +1068,13 @@ bool Item_subselect::const_item() const Item *Item_subselect::get_tmp_table_item(THD *thd_arg) { if (!with_sum_func() && !const_item()) - return new (thd->mem_root) Item_temptable_field(thd_arg, result_field); + { + auto item_field= + new (thd->mem_root) Item_field(thd_arg, result_field); + if (item_field) + item_field->set_refers_to_temp_table(true); + return item_field; + } return copy_or_same(thd_arg); } @@ -5324,10 +5330,12 @@ bool subselect_hash_sj_engine::make_semi_join_conds() /* New equi-join condition for the current column. */ Item_func_eq *eq_cond; /* Item for the corresponding field from the materialized temp table. */ - Item_field *right_col_item; + Item_field *right_col_item= new (thd->mem_root) + Item_field(thd, context, tmp_table->field[i]); + if (right_col_item) + right_col_item->set_refers_to_temp_table(true); - if (!(right_col_item= new (thd->mem_root) - Item_temptable_field(thd, context, tmp_table->field[i])) || + if (!right_col_item || !(eq_cond= new (thd->mem_root) Item_func_eq(thd, item_in->left_expr->element_index(i), right_col_item)) || diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 70567160b9b..109a0f883e8 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -552,10 +552,18 @@ Item *Item_sum::get_tmp_table_item(THD *thd) Item *arg= sum_item->args[i]; if (!arg->const_item()) { - if (arg->type() == Item::FIELD_ITEM) - ((Item_field*) arg)->field= result_field_tmp++; - else - sum_item->args[i]= new (thd->mem_root) Item_temptable_field(thd, result_field_tmp++); + if (arg->type() == Item::FIELD_ITEM) + { + ((Item_field*) arg)->field= result_field_tmp++; + } + else + { + auto item_field= + new (thd->mem_root) Item_field(thd, result_field_tmp++); + if (item_field) + item_field->set_refers_to_temp_table(true); + sum_item->args[i]= item_field; + } } } } diff --git a/sql/my_apc.cc b/sql/my_apc.cc index e0feabab8e2..cef00c0a738 100644 --- a/sql/my_apc.cc +++ b/sql/my_apc.cc @@ -186,6 +186,9 @@ bool Apc_target::make_apc_call(THD *caller_thd, Apc_call *call, } else { +#ifndef DBUG_OFF + n_calls_processed++; +#endif mysql_mutex_unlock(LOCK_thd_kill_ptr); } return res; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 27875e3837b..07d5510648e 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2242,6 +2242,9 @@ void THD::cleanup_after_query() thd_progress_end(this); + if (lex && lex->explain) + lex->explain->notify_item_objects_about_to_be_freed(); + /* Reset rand_used so that detection of calls to rand() will save random seeds if needed by the slave. diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc index 914b83fc667..d8f46be870e 100644 --- a/sql/sql_explain.cc +++ b/sql/sql_explain.cc @@ -159,6 +159,16 @@ void Explain_query::query_plan_ready() apc_enabled= true; } + +void Explain_query::notify_item_objects_about_to_be_freed() +{ + if (apc_enabled) + { + thd->apc_target.disable(); + apc_enabled= false; + } +} + /* Send EXPLAIN output to the client. */ diff --git a/sql/sql_explain.h b/sql/sql_explain.h index f908e2e4221..f00d6bcf029 100644 --- a/sql/sql_explain.h +++ b/sql/sql_explain.h @@ -486,6 +486,8 @@ public: void query_plan_ready(); + void notify_item_objects_about_to_be_freed(); + MEM_ROOT *mem_root; Explain_update *get_upd_del_plan() { return upd_del_plan; } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b7b5d0492ab..2c34fb0a586 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2575,6 +2575,11 @@ void log_slow_statement(THD *thd) end: delete_explain_query(thd->lex); + DBUG_EXECUTE_IF("log_slow_statement_end", + if (dbug_user_var_equals_str(thd, "show_explain_probe_query", + thd->query())) + dbug_serve_apcs(thd, 1); + ); DBUG_VOID_RETURN; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index f4e065cf11a..0b4798e86c0 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -363,6 +363,33 @@ bool dbug_user_var_equals_int(THD *thd, const char *name, int value) } return FALSE; } + +/* + Debugging : check if @name= value, comparing as string + + Intended usage : + + DBUG_EXECUTE_IF("log_slow_statement_end", + if (dbug_user_var_equals_str(thd, "show_explain_probe_query", + thd->query())) + dbug_serve_apcs(thd, 1); + ); +*/ + +bool dbug_user_var_equals_str(THD *thd, const char *name, const char* value) +{ + user_var_entry *var; + LEX_CSTRING varname= {name, strlen(name)}; + if ((var= get_variable(&thd->user_vars, &varname, FALSE))) + { + bool null_value; + String str; + auto var_value= var->val_str(&null_value, &str, 10)->ptr(); + if (!null_value && !strncmp(var_value, value, strlen(value))) + return TRUE; + } + return FALSE; +} #endif /* DBUG_OFF */ /* @@ -18958,8 +18985,9 @@ bool Create_tmp_table::add_fields(THD *thd, thd->mem_root= mem_root_save; if (!(tmp_item= new (thd->mem_root) - Item_temptable_field(thd, new_field))) + Item_field(thd, new_field))) goto err; + ((Item_field*) tmp_item)->set_refers_to_temp_table(true); arg= sum_item->set_arg(i, thd, tmp_item); thd->mem_root= &table->mem_root; @@ -26056,9 +26084,10 @@ change_to_use_tmp_fields(THD *thd, Ref_ptr_array ref_pointer_array, */ Item_func_set_user_var* suv= new (thd->mem_root) Item_func_set_user_var(thd, (Item_func_set_user_var*) item); - Item_field *new_field= new (thd->mem_root) Item_temptable_field(thd, field); + Item_field *new_field= new (thd->mem_root) Item_field(thd, field); if (!suv || !new_field) DBUG_RETURN(true); // Fatal error + new_field->set_refers_to_temp_table(true); List<Item> list; list.push_back(new_field, thd->mem_root); suv->set_arguments(thd, list); @@ -26070,9 +26099,15 @@ change_to_use_tmp_fields(THD *thd, Ref_ptr_array ref_pointer_array, else if ((field= item->get_tmp_table_field())) { if (item->type() == Item::SUM_FUNC_ITEM && field->table->group) + { item_field= ((Item_sum*) item)->result_item(thd, field); + } else - item_field= (Item *) new (thd->mem_root) Item_temptable_field(thd, field); + { + item_field= (Item*) new (thd->mem_root) Item_field(thd, field); + if (item_field) + ((Item_field*) item_field)->set_refers_to_temp_table(true); + } if (!item_field) DBUG_RETURN(true); // Fatal error diff --git a/sql/sql_select.h b/sql/sql_select.h index a8081b8d6e3..e6f63b465f6 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -2478,4 +2478,5 @@ void propagate_new_equalities(THD *thd, Item *cond, COND_EQUAL *inherited, bool *is_simplifiable_cond); +bool dbug_user_var_equals_str(THD *thd, const char *name, const char *value); #endif /* SQL_SELECT_INCLUDED */ diff --git a/sql/sql_window.cc b/sql/sql_window.cc index 17920519b41..e50a17333e8 100644 --- a/sql/sql_window.cc +++ b/sql/sql_window.cc @@ -3075,8 +3075,10 @@ bool Window_funcs_sort::setup(THD *thd, SQL_SELECT *sel, */ ORDER *order= (ORDER *)alloc_root(thd->mem_root, sizeof(ORDER)); memset(order, 0, sizeof(*order)); - Item *item= new (thd->mem_root) Item_temptable_field(thd, - join_tab->table->field[0]); + Item_field *item= + new (thd->mem_root) Item_field(thd, join_tab->table->field[0]); + if (item) + item->set_refers_to_temp_table(true); order->item= (Item **)alloc_root(thd->mem_root, 2 * sizeof(Item *)); order->item[1]= NULL; order->item[0]= item; |