summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOleg Smirnov <olernov@gmail.com>2022-03-27 11:58:27 +0700
committerSergei Petrunia <sergey@mariadb.com>2022-04-29 10:48:25 +0300
commit02c3babdec0c931c6983863bff129114f750bd22 (patch)
tree6340356ad6be55b8c80000d99f4b0ca333f22afa
parenta0475cb9ca2b98d5c95f021e6d8c57dcba238397 (diff)
downloadmariadb-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.result14
-rw-r--r--mysql-test/main/show_analyze.test21
-rw-r--r--mysql-test/main/show_analyze_json.result14
-rw-r--r--mysql-test/main/show_analyze_json.test22
-rw-r--r--mysql-test/main/show_explain.result14
-rw-r--r--mysql-test/main/show_explain.test20
-rw-r--r--mysql-test/main/show_explain_json.result14
-rw-r--r--mysql-test/main/show_explain_json.test20
-rw-r--r--mysql-test/suite/perfschema/r/nesting.result38
-rw-r--r--sql/item.cc36
-rw-r--r--sql/item.h67
-rw-r--r--sql/item_func.cc7
-rw-r--r--sql/item_subselect.cc16
-rw-r--r--sql/item_sum.cc16
-rw-r--r--sql/my_apc.cc3
-rw-r--r--sql/sql_class.cc3
-rw-r--r--sql/sql_explain.cc10
-rw-r--r--sql/sql_explain.h2
-rw-r--r--sql/sql_parse.cc5
-rw-r--r--sql/sql_select.cc41
-rw-r--r--sql/sql_select.h1
-rw-r--r--sql/sql_window.cc6
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;