mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03: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:
committed by
Sergei Petrunia
parent
a0475cb9ca
commit
02c3babdec
@@ -373,6 +373,20 @@ a
|
|||||||
9
|
9
|
||||||
SET debug_dbug=@old_debug;
|
SET debug_dbug=@old_debug;
|
||||||
drop table t0,t1;
|
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
|
# End
|
||||||
connection default;
|
connection default;
|
||||||
disconnect con1;
|
disconnect con1;
|
||||||
|
@@ -326,6 +326,27 @@ SET debug_dbug=@old_debug;
|
|||||||
|
|
||||||
|
|
||||||
drop table t0,t1;
|
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
|
--echo # End
|
||||||
connection default;
|
connection default;
|
||||||
disconnect con1;
|
disconnect con1;
|
||||||
|
@@ -1222,6 +1222,20 @@ a
|
|||||||
9
|
9
|
||||||
SET debug_dbug=@old_debug;
|
SET debug_dbug=@old_debug;
|
||||||
drop table t0,t1;
|
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
|
# End
|
||||||
connection default;
|
connection default;
|
||||||
disconnect con1;
|
disconnect con1;
|
||||||
|
@@ -360,8 +360,28 @@ connection con1;
|
|||||||
reap;
|
reap;
|
||||||
SET debug_dbug=@old_debug;
|
SET debug_dbug=@old_debug;
|
||||||
|
|
||||||
|
|
||||||
drop table t0,t1;
|
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
|
--echo # End
|
||||||
connection default;
|
connection default;
|
||||||
disconnect con1;
|
disconnect con1;
|
||||||
|
@@ -1421,6 +1421,20 @@ kill query $thr2;
|
|||||||
connection con1;
|
connection con1;
|
||||||
ERROR 70100: Query execution was interrupted
|
ERROR 70100: Query execution was interrupted
|
||||||
drop table t0,t1,t2;
|
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
|
# End
|
||||||
connection default;
|
connection default;
|
||||||
disconnect con1;
|
disconnect con1;
|
||||||
|
@@ -1304,6 +1304,26 @@ reap;
|
|||||||
|
|
||||||
drop table t0,t1,t2;
|
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
|
--echo # End
|
||||||
connection default;
|
connection default;
|
||||||
disconnect con1;
|
disconnect con1;
|
||||||
|
@@ -1288,6 +1288,20 @@ set names default;
|
|||||||
drop table if exists t0,t1,t2;
|
drop table if exists t0,t1,t2;
|
||||||
Warnings:
|
Warnings:
|
||||||
Note 1051 Unknown table 'test.t2'
|
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
|
# End
|
||||||
connection default;
|
connection default;
|
||||||
disconnect con1;
|
disconnect con1;
|
||||||
|
@@ -470,6 +470,26 @@ set names default;
|
|||||||
|
|
||||||
drop table if exists t0,t1,t2;
|
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
|
--echo # End
|
||||||
connection default;
|
connection default;
|
||||||
disconnect con1;
|
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
|
14 14 stage/sql/Commit (stage) STATEMENT 0
|
||||||
15 15 stage/sql/closing tables (stage) STATEMENT 0
|
15 15 stage/sql/closing tables (stage) STATEMENT 0
|
||||||
16 16 stage/sql/Starting cleanup (stage) STATEMENT 0
|
16 16 stage/sql/Starting cleanup (stage) STATEMENT 0
|
||||||
17 17 stage/sql/Freeing items (stage) STATEMENT 0
|
17 18 stage/sql/Freeing items (stage) STATEMENT 0
|
||||||
18 18 wait/io/socket/sql/client_connection send STATEMENT 0
|
18 18 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 17
|
||||||
19 19 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STATEMENT 0
|
19 19 wait/io/socket/sql/client_connection send STATEMENT 0
|
||||||
20 21 stage/sql/Reset for next command (stage) 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
|
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
|
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
|
38 38 stage/sql/Commit (stage) STATEMENT 24
|
||||||
39 39 stage/sql/closing tables (stage) STATEMENT 24
|
39 39 stage/sql/closing tables (stage) STATEMENT 24
|
||||||
40 40 stage/sql/Starting cleanup (stage) STATEMENT 24
|
40 40 stage/sql/Starting cleanup (stage) STATEMENT 24
|
||||||
41 41 stage/sql/Freeing items (stage) STATEMENT 24
|
41 42 stage/sql/Freeing items (stage) STATEMENT 24
|
||||||
42 42 wait/io/socket/sql/client_connection send STATEMENT 24
|
42 42 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 41
|
||||||
43 43 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STATEMENT 24
|
43 43 wait/io/socket/sql/client_connection send STATEMENT 24
|
||||||
44 45 stage/sql/Reset for next command (stage) 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
|
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
|
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
|
62 62 stage/sql/Commit (stage) STATEMENT 48
|
||||||
63 63 stage/sql/closing tables (stage) STATEMENT 48
|
63 63 stage/sql/closing tables (stage) STATEMENT 48
|
||||||
64 64 stage/sql/Starting cleanup (stage) STATEMENT 48
|
64 64 stage/sql/Starting cleanup (stage) STATEMENT 48
|
||||||
65 65 stage/sql/Freeing items (stage) STATEMENT 48
|
65 66 stage/sql/Freeing items (stage) STATEMENT 48
|
||||||
66 66 wait/io/socket/sql/client_connection send STATEMENT 48
|
66 66 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 65
|
||||||
67 67 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STATEMENT 48
|
67 67 wait/io/socket/sql/client_connection send STATEMENT 48
|
||||||
68 69 stage/sql/Reset for next command (stage) 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
|
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
|
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
|
88 88 stage/sql/closing tables (stage) STATEMENT 72
|
||||||
89 89 stage/sql/Starting cleanup (stage) STATEMENT 72
|
89 89 stage/sql/Starting cleanup (stage) STATEMENT 72
|
||||||
90 92 stage/sql/Freeing items (stage) STATEMENT 72
|
90 92 stage/sql/Freeing items (stage) STATEMENT 72
|
||||||
91 91 wait/io/socket/sql/client_connection send STAGE 90
|
91 91 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 90
|
||||||
92 92 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;
|
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
|
select "With a third part to make things complete" as payload NULL NULL
|
||||||
94 96 stage/sql/starting (stage) STATEMENT 93
|
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
|
106 106 stage/sql/closing tables (stage) STATEMENT 93
|
||||||
107 107 stage/sql/Starting cleanup (stage) STATEMENT 93
|
107 107 stage/sql/Starting cleanup (stage) STATEMENT 93
|
||||||
108 110 stage/sql/Freeing items (stage) STATEMENT 93
|
108 110 stage/sql/Freeing items (stage) STATEMENT 93
|
||||||
109 109 wait/io/socket/sql/client_connection send STAGE 108
|
109 109 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 108
|
||||||
110 110 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
|
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
|
112 113 stage/sql/starting (stage) STATEMENT 111
|
||||||
113 113 wait/synch/mutex/sql/THD::LOCK_thd_data lock STAGE 112
|
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
|
122 122 stage/sql/Commit (stage) STATEMENT 111
|
||||||
123 123 stage/sql/closing tables (stage) STATEMENT 111
|
123 123 stage/sql/closing tables (stage) STATEMENT 111
|
||||||
124 124 stage/sql/Starting cleanup (stage) STATEMENT 111
|
124 124 stage/sql/Starting cleanup (stage) STATEMENT 111
|
||||||
125 125 stage/sql/Freeing items (stage) STATEMENT 111
|
125 126 stage/sql/Freeing items (stage) STATEMENT 111
|
||||||
126 126 wait/io/socket/sql/client_connection send STATEMENT 111
|
126 126 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 125
|
||||||
127 127 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STATEMENT 111
|
127 127 wait/io/socket/sql/client_connection send STATEMENT 111
|
||||||
128 129 stage/sql/Reset for next command (stage) 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
|
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
|
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
|
146 146 stage/sql/Commit (stage) STATEMENT 132
|
||||||
147 147 stage/sql/closing tables (stage) STATEMENT 132
|
147 147 stage/sql/closing tables (stage) STATEMENT 132
|
||||||
148 148 stage/sql/Starting cleanup (stage) STATEMENT 132
|
148 148 stage/sql/Starting cleanup (stage) STATEMENT 132
|
||||||
149 149 stage/sql/Freeing items (stage) STATEMENT 132
|
149 150 stage/sql/Freeing items (stage) STATEMENT 132
|
||||||
150 150 wait/io/socket/sql/client_connection send STATEMENT 132
|
150 150 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 149
|
||||||
151 151 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STATEMENT 132
|
151 151 wait/io/socket/sql/client_connection send STATEMENT 132
|
||||||
152 153 stage/sql/Reset for next command (stage) 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
|
153 153 wait/synch/mutex/sql/THD::LOCK_thd_data lock STAGE 152
|
||||||
disconnect con1;
|
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)
|
Field *f)
|
||||||
:Item_ident(thd, context_arg, f->table->s->db,
|
:Item_ident(thd, context_arg, f->table->s->db,
|
||||||
Lex_cstring_strlen(*f->table_name), f->field_name),
|
Lex_cstring_strlen(*f->table_name), f->field_name),
|
||||||
item_equal(0),
|
item_equal(0), have_privileges(NO_ACL), any_privileges(0)
|
||||||
have_privileges(NO_ACL), any_privileges(0)
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
We always need to provide Item_field with a fully qualified field
|
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
|
field=result_field=field_par; // for easy coding with fields
|
||||||
set_maybe_null(field->maybe_null());
|
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);
|
table_name= Lex_cstring_strlen(*field_par->table_name);
|
||||||
field_name= field_par->field_name;
|
field_name= field_par->field_name;
|
||||||
db_name= field_par->table->s->db;
|
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;
|
base_flags|= item_base_t::FIXED;
|
||||||
if (field->table->s->tmp_table == SYSTEM_TMP_TABLE)
|
if (field->table->s->tmp_table == SYSTEM_TMP_TABLE)
|
||||||
|
{
|
||||||
any_privileges= 0;
|
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 *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)
|
if (new_item)
|
||||||
|
{
|
||||||
new_item->field= new_item->result_field;
|
new_item->field= new_item->result_field;
|
||||||
|
new_item->set_refers_to_temp_table(true);
|
||||||
|
}
|
||||||
return new_item;
|
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;
|
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
|
bool Item_basic_value::eq(const Item *item, bool binary_cmp) const
|
||||||
{
|
{
|
||||||
@@ -6275,6 +6285,7 @@ void Item_field::cleanup()
|
|||||||
field= 0;
|
field= 0;
|
||||||
item_equal= NULL;
|
item_equal= NULL;
|
||||||
null_value= FALSE;
|
null_value= FALSE;
|
||||||
|
refers_to_temp_table= FALSE;
|
||||||
DBUG_VOID_RETURN;
|
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)
|
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)))
|
!(query_type & (QT_NO_DATA_EXPANSION | QT_VIEW_INTERNAL)))
|
||||||
{
|
{
|
||||||
print_value(str);
|
print_value(str);
|
||||||
return;
|
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,
|
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);
|
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)
|
Item* Item_cache_wrapper::get_tmp_table_item(THD *thd)
|
||||||
{
|
{
|
||||||
if (!orig_item->with_sum_func() && !orig_item->const_item())
|
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);
|
return copy_or_same(thd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
67
sql/item.h
67
sql/item.h
@@ -3529,6 +3529,32 @@ public:
|
|||||||
privilege_t have_privileges;
|
privilege_t have_privileges;
|
||||||
/* field need any privileges (for VIEW creation) */
|
/* field need any privileges (for VIEW creation) */
|
||||||
bool any_privileges;
|
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,
|
Item_field(THD *thd, Name_resolution_context *context_arg,
|
||||||
const LEX_CSTRING &db_arg, const LEX_CSTRING &table_name_arg,
|
const LEX_CSTRING &db_arg, const LEX_CSTRING &table_name_arg,
|
||||||
const LEX_CSTRING &field_name_arg);
|
const LEX_CSTRING &field_name_arg);
|
||||||
@@ -3753,6 +3779,7 @@ public:
|
|||||||
return field->table->pos_in_table_list->outer_join;
|
return field->table->pos_in_table_list->outer_join;
|
||||||
}
|
}
|
||||||
bool check_index_dependence(void *arg) override;
|
bool check_index_dependence(void *arg) override;
|
||||||
|
void set_refers_to_temp_table(bool value);
|
||||||
friend class Item_default_value;
|
friend class Item_default_value;
|
||||||
friend class Item_insert_value;
|
friend class Item_insert_value;
|
||||||
friend class st_select_lex_unit;
|
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
|
class Item_null :public Item_basic_constant
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@@ -734,7 +734,12 @@ void Item_func::signal_divide_by_null()
|
|||||||
Item *Item_func::get_tmp_table_item(THD *thd)
|
Item *Item_func::get_tmp_table_item(THD *thd)
|
||||||
{
|
{
|
||||||
if (!with_sum_func() && !const_item())
|
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);
|
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)
|
Item *Item_subselect::get_tmp_table_item(THD *thd_arg)
|
||||||
{
|
{
|
||||||
if (!with_sum_func() && !const_item())
|
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);
|
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. */
|
/* New equi-join condition for the current column. */
|
||||||
Item_func_eq *eq_cond;
|
Item_func_eq *eq_cond;
|
||||||
/* Item for the corresponding field from the materialized temp table. */
|
/* 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)
|
if (!right_col_item ||
|
||||||
Item_temptable_field(thd, context, tmp_table->field[i])) ||
|
|
||||||
!(eq_cond= new (thd->mem_root)
|
!(eq_cond= new (thd->mem_root)
|
||||||
Item_func_eq(thd, item_in->left_expr->element_index(i),
|
Item_func_eq(thd, item_in->left_expr->element_index(i),
|
||||||
right_col_item)) ||
|
right_col_item)) ||
|
||||||
|
@@ -552,10 +552,18 @@ Item *Item_sum::get_tmp_table_item(THD *thd)
|
|||||||
Item *arg= sum_item->args[i];
|
Item *arg= sum_item->args[i];
|
||||||
if (!arg->const_item())
|
if (!arg->const_item())
|
||||||
{
|
{
|
||||||
if (arg->type() == Item::FIELD_ITEM)
|
if (arg->type() == Item::FIELD_ITEM)
|
||||||
((Item_field*) arg)->field= result_field_tmp++;
|
{
|
||||||
else
|
((Item_field*) arg)->field= result_field_tmp++;
|
||||||
sum_item->args[i]= new (thd->mem_root) Item_temptable_field(thd, 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
|
else
|
||||||
{
|
{
|
||||||
|
#ifndef DBUG_OFF
|
||||||
|
n_calls_processed++;
|
||||||
|
#endif
|
||||||
mysql_mutex_unlock(LOCK_thd_kill_ptr);
|
mysql_mutex_unlock(LOCK_thd_kill_ptr);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
@@ -2242,6 +2242,9 @@ void THD::cleanup_after_query()
|
|||||||
|
|
||||||
thd_progress_end(this);
|
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
|
Reset rand_used so that detection of calls to rand() will save random
|
||||||
seeds if needed by the slave.
|
seeds if needed by the slave.
|
||||||
|
@@ -159,6 +159,16 @@ void Explain_query::query_plan_ready()
|
|||||||
apc_enabled= true;
|
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.
|
Send EXPLAIN output to the client.
|
||||||
*/
|
*/
|
||||||
|
@@ -486,6 +486,8 @@ public:
|
|||||||
|
|
||||||
void query_plan_ready();
|
void query_plan_ready();
|
||||||
|
|
||||||
|
void notify_item_objects_about_to_be_freed();
|
||||||
|
|
||||||
MEM_ROOT *mem_root;
|
MEM_ROOT *mem_root;
|
||||||
|
|
||||||
Explain_update *get_upd_del_plan() { return upd_del_plan; }
|
Explain_update *get_upd_del_plan() { return upd_del_plan; }
|
||||||
|
@@ -2575,6 +2575,11 @@ void log_slow_statement(THD *thd)
|
|||||||
|
|
||||||
end:
|
end:
|
||||||
delete_explain_query(thd->lex);
|
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;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -363,6 +363,33 @@ bool dbug_user_var_equals_int(THD *thd, const char *name, int value)
|
|||||||
}
|
}
|
||||||
return FALSE;
|
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 */
|
#endif /* DBUG_OFF */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -18958,8 +18985,9 @@ bool Create_tmp_table::add_fields(THD *thd,
|
|||||||
|
|
||||||
thd->mem_root= mem_root_save;
|
thd->mem_root= mem_root_save;
|
||||||
if (!(tmp_item= new (thd->mem_root)
|
if (!(tmp_item= new (thd->mem_root)
|
||||||
Item_temptable_field(thd, new_field)))
|
Item_field(thd, new_field)))
|
||||||
goto err;
|
goto err;
|
||||||
|
((Item_field*) tmp_item)->set_refers_to_temp_table(true);
|
||||||
arg= sum_item->set_arg(i, thd, tmp_item);
|
arg= sum_item->set_arg(i, thd, tmp_item);
|
||||||
thd->mem_root= &table->mem_root;
|
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=
|
Item_func_set_user_var* suv=
|
||||||
new (thd->mem_root) Item_func_set_user_var(thd, (Item_func_set_user_var*) item);
|
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)
|
if (!suv || !new_field)
|
||||||
DBUG_RETURN(true); // Fatal error
|
DBUG_RETURN(true); // Fatal error
|
||||||
|
new_field->set_refers_to_temp_table(true);
|
||||||
List<Item> list;
|
List<Item> list;
|
||||||
list.push_back(new_field, thd->mem_root);
|
list.push_back(new_field, thd->mem_root);
|
||||||
suv->set_arguments(thd, list);
|
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()))
|
else if ((field= item->get_tmp_table_field()))
|
||||||
{
|
{
|
||||||
if (item->type() == Item::SUM_FUNC_ITEM && field->table->group)
|
if (item->type() == Item::SUM_FUNC_ITEM && field->table->group)
|
||||||
|
{
|
||||||
item_field= ((Item_sum*) item)->result_item(thd, field);
|
item_field= ((Item_sum*) item)->result_item(thd, field);
|
||||||
|
}
|
||||||
else
|
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)
|
if (!item_field)
|
||||||
DBUG_RETURN(true); // Fatal error
|
DBUG_RETURN(true); // Fatal error
|
||||||
|
|
||||||
|
@@ -2478,4 +2478,5 @@ void propagate_new_equalities(THD *thd, Item *cond,
|
|||||||
COND_EQUAL *inherited,
|
COND_EQUAL *inherited,
|
||||||
bool *is_simplifiable_cond);
|
bool *is_simplifiable_cond);
|
||||||
|
|
||||||
|
bool dbug_user_var_equals_str(THD *thd, const char *name, const char *value);
|
||||||
#endif /* SQL_SELECT_INCLUDED */
|
#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));
|
ORDER *order= (ORDER *)alloc_root(thd->mem_root, sizeof(ORDER));
|
||||||
memset(order, 0, sizeof(*order));
|
memset(order, 0, sizeof(*order));
|
||||||
Item *item= new (thd->mem_root) Item_temptable_field(thd,
|
Item_field *item=
|
||||||
join_tab->table->field[0]);
|
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= (Item **)alloc_root(thd->mem_root, 2 * sizeof(Item *));
|
||||||
order->item[1]= NULL;
|
order->item[1]= NULL;
|
||||||
order->item[0]= item;
|
order->item[0]= item;
|
||||||
|
Reference in New Issue
Block a user