mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 02:05:57 +01:00
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().
This commit is contained in:
parent
a0475cb9ca
commit
02c3babdec
22 changed files with 303 additions and 87 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
36
sql/item.cc
36
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);
|
||||
}
|
||||
|
||||
|
|
67
sql/item.h
67
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:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)) ||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue