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:
Oleg Smirnov 2022-03-27 11:58:27 +07:00 committed by Sergei Petrunia
parent a0475cb9ca
commit 02c3babdec
22 changed files with 303 additions and 87 deletions

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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);
}

View file

@ -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:

View file

@ -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);
}

View file

@ -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)) ||

View file

@ -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;
}
}
}
}

View file

@ -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;

View file

@ -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.

View file

@ -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.
*/

View file

@ -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; }

View file

@ -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;
}

View file

@ -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

View file

@ -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 */

View file

@ -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;