summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/show_explain.result48
-rw-r--r--mysql-test/t/show_explain.test58
-rw-r--r--sql/my_apc.cc32
-rw-r--r--sql/my_apc.h6
-rw-r--r--sql/mysqld.cc2
-rw-r--r--sql/share/errmsg-utf8.txt8
-rw-r--r--sql/sql_class.cc51
-rw-r--r--sql/sql_class.h36
-rw-r--r--sql/sql_parse.cc6
-rw-r--r--sql/sql_show.cc95
-rw-r--r--sql/sql_show.h25
-rw-r--r--unittest/sql/my_apc-t.cc18
12 files changed, 201 insertions, 184 deletions
diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result
index e5659bdf4ac..2851e775280 100644
--- a/mysql-test/r/show_explain.result
+++ b/mysql-test/r/show_explain.result
@@ -10,11 +10,11 @@ alter table t1 add key(a), add key(b);
show explain for 2*1000*1000*1000;
ERROR HY000: Unknown thread id: 2000000000
show explain for (select max(a) from t0);
-ERROR 42000: This version of MariaDB doesn't yet support 'Usage of subqueries or stored function calls as part of this statement'
+ERROR HY000: You may only use constant expressions in this statement
show explain for $thr2;
-ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command
+ERROR HY000: Target is not running an EXPLAINable command
show explain for $thr1;
-ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command
+ERROR HY000: Target is not running an EXPLAINable command
set @show_explain_probe_select_id=1;
set debug_dbug='d,show_explain_probe_join_exec_start';
select count(*) from t1 where a < 100000;
@@ -153,7 +153,7 @@ set @show_explain_probe_select_id=1;
set debug_dbug='d,show_explain_probe_join_exec_end';
select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1;
show explain for $thr2;
-ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command
+ERROR HY000: Target is not running an EXPLAINable command
a (select max(a) from t0 b where b.a+a.a<10)
0 9
# Try to do SHOW EXPLAIN for a query that runs a SET command:
@@ -163,7 +163,7 @@ set @show_explain_probe_select_id=2;
set debug_dbug='d,show_explain_probe_join_exec_start';
set @foo= (select max(a) from t0 where sin(a) >0);
show explain for $thr2;
-ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command
+ERROR HY000: Target is not running an EXPLAINable command
#
# Attempt SHOW EXPLAIN for an UPDATE
#
@@ -172,9 +172,9 @@ set @show_explain_probe_select_id=2;
set debug_dbug='d,show_explain_probe_join_exec_start';
update t2 set dummy=0 where (select max(a) from t0 where t2.a + t0.a <3) >3 ;
show explain for $thr2;
-ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command
+ERROR HY000: Target is not running an EXPLAINable command
show explain for $thr2;
-ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command
+ERROR HY000: Target is not running an EXPLAINable command
drop table t2;
#
# Attempt SHOW EXPLAIN for a DELETE
@@ -184,9 +184,9 @@ set @show_explain_probe_select_id=2;
set debug_dbug='d,show_explain_probe_join_exec_start';
delete from t2 where (select max(a) from t0 where t2.a + t0.a <3) >3 ;
show explain for $thr2;
-ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command
+ERROR HY000: Target is not running an EXPLAINable command
show explain for $thr2;
-ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command
+ERROR HY000: Target is not running an EXPLAINable command
drop table t2;
#
# Multiple SHOW EXPLAIN calls for one select
@@ -308,7 +308,7 @@ SELECT alias.a FROM t2, ( SELECT * FROM t2 ) AS alias GROUP BY alias.a;
# FIXED by "conservative assumptions about when QEP is available" fix:
# NOTE: current code will not show "Using join buffer":
show explain for $thr2;
-ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command
+ERROR HY000: Target is not running an EXPLAINable command
a
1
2
@@ -361,7 +361,7 @@ set @show_explain_probe_select_id=2;
set debug_dbug='d,show_explain_probe_join_exec_end';
SELECT * FROM v1, t2;
show explain for $thr2;
-ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command
+ERROR HY000: Target is not running an EXPLAINable command
a b
8 4
8 5
@@ -393,7 +393,7 @@ set @show_explain_probe_select_id=1;
set debug_dbug='d,show_explain_probe_join_exec_end';
select * from t0 where 1>10;
show explain for $thr2;
-ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command
+ERROR HY000: Target is not running an EXPLAINable command
a
set debug_dbug='';
#
@@ -405,7 +405,7 @@ set @show_explain_probe_select_id=1;
set debug_dbug='d,show_explain_probe_join_exec_end';
select * from t0,t3 where t3.a=112233;
show explain for $thr2;
-ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command
+ERROR HY000: Target is not running an EXPLAINable command
a a
set debug_dbug='';
drop table t3;
@@ -510,7 +510,7 @@ set @show_explain_probe_select_id=1;
set debug_dbug='d,show_explain_probe_join_exec_end';
SELECT * FROM t2 WHERE (5, 78) IN (SELECT `a1`, MAX(`a1`) FROM t2 GROUP BY `a1`);
show explain for $thr2;
-ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command
+ERROR HY000: Target is not running an EXPLAINable command
pk a1
set debug_dbug='';
DROP TABLE t2;
@@ -732,6 +732,7 @@ drop table t1,t3,t4;
# ---------- SHOW EXPLAIN and permissions -----------------
#
grant ALL on test.* to test2@localhost;
+grant super on *.* to test2@localhost;
#
# First, make sure that user 'test2' cannot do SHOW EXPLAIN on us
#
@@ -739,7 +740,7 @@ set @show_explain_probe_select_id=1;
set debug_dbug='d,show_explain_probe_join_exec_start';
select * from t0 where a < 3;
show explain for $thr2;
-ERROR 42000: Access denied; you need (at least one of) the PROCESSLIST privilege(s) for this operation
+ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation
show explain for $thr2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t0 ALL NULL NULL NULL NULL 10 Using where
@@ -751,11 +752,20 @@ a
2
set debug_dbug='';
#
-# Unfortunately, our test setup doesn't allow to check that test2
-# can do SHOW EXPLAIN on his own queries. This is because SET debug_dbug
-# requires SUPER privilege. Giving SUPER to test2 will make the test
-# meaningless
+# Check that user test2 can do SHOW EXPLAIN on its own queries
#
+set @show_explain_probe_select_id=1;
+set debug_dbug='d,show_explain_probe_join_exec_start';
+select * from t0 where a < 3;
+show explain for $thr_con2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ALL NULL NULL NULL NULL 10 Using where
+Warnings:
+Note 1003 select * from t0 where a < 3
+a
+0
+1
+2
#
# Now, grant test2 a PROCESSLIST permission, and see that he's able to observe us
#
diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test
index 6d4ddd79104..2cb3ab6924a 100644
--- a/mysql-test/t/show_explain.test
+++ b/mysql-test/t/show_explain.test
@@ -45,7 +45,7 @@ alter table t1 add key(a), add key(b);
--error ER_NO_SUCH_THREAD
show explain for 2*1000*1000*1000;
---error ER_NOT_SUPPORTED_YET
+--error ER_SET_CONSTANTS_ONLY
show explain for (select max(a) from t0);
#
@@ -58,11 +58,11 @@ let $thr2=`select connection_id()`;
connection default;
# SHOW EXPLAIN FOR <idle thread>
---error ER_ERROR_WHEN_EXECUTING_COMMAND
+--error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2;
# SHOW EXPLAIN FOR <ourselves>
---error ER_ERROR_WHEN_EXECUTING_COMMAND
+--error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr1;
let $wait_condition= select State='show_explain_trap' from information_schema.processlist where id=$thr2;
@@ -192,7 +192,7 @@ set debug_dbug='d,show_explain_probe_join_exec_end';
send select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1;
connection default;
--source include/wait_condition.inc
---error ER_ERROR_WHEN_EXECUTING_COMMAND
+--error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2;
connection con1;
reap;
@@ -212,7 +212,7 @@ set debug_dbug='d,show_explain_probe_join_exec_start';
send set @foo= (select max(a) from t0 where sin(a) >0);
connection default;
--source include/wait_condition.inc
---error ER_ERROR_WHEN_EXECUTING_COMMAND
+--error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2;
connection con1;
reap;
@@ -226,9 +226,9 @@ set debug_dbug='d,show_explain_probe_join_exec_start';
send update t2 set dummy=0 where (select max(a) from t0 where t2.a + t0.a <3) >3 ;
connection default;
--source include/wait_condition.inc
---error ER_ERROR_WHEN_EXECUTING_COMMAND
+--error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2;
---error ER_ERROR_WHEN_EXECUTING_COMMAND
+--error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2;
connection con1;
reap;
@@ -243,9 +243,9 @@ set debug_dbug='d,show_explain_probe_join_exec_start';
send delete from t2 where (select max(a) from t0 where t2.a + t0.a <3) >3 ;
connection default;
--source include/wait_condition.inc
---error ER_ERROR_WHEN_EXECUTING_COMMAND
+--error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2;
---error ER_ERROR_WHEN_EXECUTING_COMMAND
+--error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2;
connection con1;
reap;
@@ -329,7 +329,7 @@ connection default;
--source include/wait_condition.inc
--echo # FIXED by "conservative assumptions about when QEP is available" fix:
--echo # NOTE: current code will not show "Using join buffer":
---error ER_ERROR_WHEN_EXECUTING_COMMAND
+--error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2;
connection con1;
reap;
@@ -378,7 +378,7 @@ send SELECT * FROM v1, t2;
connection default;
--source include/wait_condition.inc
---error ER_ERROR_WHEN_EXECUTING_COMMAND
+--error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2;
connection con1;
reap;
@@ -408,7 +408,7 @@ set debug_dbug='d,show_explain_probe_join_exec_end';
send select * from t0 where 1>10;
connection default;
--source include/wait_condition.inc
---error ER_ERROR_WHEN_EXECUTING_COMMAND
+--error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2;
connection con1;
reap;
@@ -424,7 +424,7 @@ set debug_dbug='d,show_explain_probe_join_exec_end';
send select * from t0,t3 where t3.a=112233;
connection default;
--source include/wait_condition.inc
---error ER_ERROR_WHEN_EXECUTING_COMMAND
+--error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2;
connection con1;
reap;
@@ -520,7 +520,7 @@ send
SELECT * FROM t2 WHERE (5, 78) IN (SELECT `a1`, MAX(`a1`) FROM t2 GROUP BY `a1`);
connection default;
--source include/wait_condition.inc
---error ER_ERROR_WHEN_EXECUTING_COMMAND
+--error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2;
connection con1;
reap;
@@ -734,6 +734,8 @@ drop table t1,t3,t4;
--echo #
grant ALL on test.* to test2@localhost;
+# Give the user SUPER privilege so it can set debug_dbug variable.
+grant super on *.* to test2@localhost;
connect (con2, localhost, test2,,);
connection con1;
@@ -760,12 +762,32 @@ reap;
set debug_dbug='';
--echo #
---echo # Unfortunately, our test setup doesn't allow to check that test2
---echo # can do SHOW EXPLAIN on his own queries. This is because SET debug_dbug
---echo # requires SUPER privilege. Giving SUPER to test2 will make the test
---echo # meaningless
+--echo # Check that user test2 can do SHOW EXPLAIN on its own queries
--echo #
+connect (con3, localhost, test2,,);
+connection con2;
+let $thr_con2=`select connection_id()`;
+set @show_explain_probe_select_id=1;
+set debug_dbug='d,show_explain_probe_join_exec_start';
+send
+select * from t0 where a < 3;
+
+connection con1;
+let $save_wait_condition= $wait_condition;
+let $wait_condition= select State='show_explain_trap' from information_schema.processlist where id=$thr_con2;
+--source include/wait_condition.inc
+
+connection con3;
+evalp show explain for $thr_con2;
+
+connection con2;
+reap;
+
+connection con1;
+
+disconnect con3;
+let $wait_condition= $save_wait_condition;
--echo #
--echo # Now, grant test2 a PROCESSLIST permission, and see that he's able to observe us
--echo #
diff --git a/sql/my_apc.cc b/sql/my_apc.cc
index 8551c0187a4..4d0042510ae 100644
--- a/sql/my_apc.cc
+++ b/sql/my_apc.cc
@@ -24,35 +24,6 @@
/* For standalone testing of APC system, see unittest/sql/my_apc-t.cc */
-#ifndef MY_APC_STANDALONE
-
-ST_FIELD_INFO show_explain_fields_info[]=
-{
- /* field_name, length, type, value, field_flags, old_name*/
- {"id", 3, MYSQL_TYPE_LONGLONG, 0 /*value*/, MY_I_S_MAYBE_NULL, "id",
- SKIP_OPEN_TABLE},
- {"select_type", 19, MYSQL_TYPE_STRING, 0 /*value*/, 0, "select_type",
- SKIP_OPEN_TABLE},
- {"table", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0 /*value*/, MY_I_S_MAYBE_NULL,
- "table", SKIP_OPEN_TABLE},
- {"type", 10, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, "type", SKIP_OPEN_TABLE},
- {"possible_keys", NAME_CHAR_LEN*MAX_KEY, MYSQL_TYPE_STRING, 0/*value*/,
- MY_I_S_MAYBE_NULL, "possible_keys", SKIP_OPEN_TABLE},
- {"key", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0/*value*/, MY_I_S_MAYBE_NULL,
- "key", SKIP_OPEN_TABLE},
- {"key_len", NAME_CHAR_LEN*MAX_KEY, MYSQL_TYPE_STRING, 0/*value*/,
- MY_I_S_MAYBE_NULL, "key_len", SKIP_OPEN_TABLE},
- {"ref", NAME_CHAR_LEN*MAX_REF_PARTS, MYSQL_TYPE_STRING, 0/*value*/,
- MY_I_S_MAYBE_NULL, "ref", SKIP_OPEN_TABLE},
- {"rows", 10, MYSQL_TYPE_LONGLONG, 0/*value*/, MY_I_S_MAYBE_NULL, "rows",
- SKIP_OPEN_TABLE},
- {"Extra", 255, MYSQL_TYPE_STRING, 0/*value*/, 0 /*flags*/, "Extra",
- SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
-};
-
-
-#endif
/*
Initialize the target.
@@ -266,9 +237,6 @@ bool Apc_target::make_apc_call(THD *caller_thd, Apc_call *call,
void Apc_target::process_apc_requests()
{
- if (!get_first_in_queue())
- return;
-
while (1)
{
Call_request *request;
diff --git a/sql/my_apc.h b/sql/my_apc.h
index 5473600bae6..7f19809c082 100644
--- a/sql/my_apc.h
+++ b/sql/my_apc.h
@@ -1,3 +1,5 @@
+#ifndef INCLUDES_MY_APC_H
+#define INCLUDES_MY_APC_H
/*
Copyright (c) 2011 - 2012, Monty Program Ab
@@ -93,7 +95,7 @@ private:
We use this structure, because we
- process requests sequentially: requests are added at the end of the
list and removed from the front. With circular list, we can keep one
- pointer.
+ pointer, and access both front an back of the list with it.
- a thread that has posted a request may time out (or be KILLed) and
cancel the request, which means we need a fast request-removal
operation.
@@ -132,3 +134,5 @@ private:
void init_show_explain_psi_keys(void);
#endif
+#endif //INCLUDES_MY_APC_H
+
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 54b5b95afaf..7123bf03cdf 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -3909,8 +3909,8 @@ static int init_thread_environment()
sp_cache_init();
#ifdef HAVE_EVENT_SCHEDULER
Events::init_mutexes();
- init_show_explain_psi_keys();
#endif
+ init_show_explain_psi_keys();
/* Parameter for threads created for connections */
(void) pthread_attr_init(&connection_attrib);
(void) pthread_attr_setdetachstate(&connection_attrib,
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 140220dfa9c..6e58a70412d 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -4345,13 +4345,13 @@ ER_TOO_MANY_USER_CONNECTIONS 42000
ER_SET_CONSTANTS_ONLY
dan "Du må kun bruge konstantudtryk med SET"
nla "U mag alleen constante expressies gebruiken bij SET"
- eng "You may only use constant expressions with SET"
+ eng "You may only use constant expressions in this statement"
est "Ainult konstantsed suurused on lubatud SET klauslis"
fre "Seules les expressions constantes sont autorisées avec SET"
- ger "Bei SET dürfen nur konstante Ausdrücke verwendet werden"
+ ger "Bei diesem Befehl dürfen nur konstante Ausdrücke verwendet werden"
ita "Si possono usare solo espressioni costanti con SET"
por "Você pode usar apenas expressões constantes com SET"
- rus "Вы можете использовать в SET только константные выражения"
+ rus "С этой командой вы можете использовать только константные выражения"
serbian "Možete upotrebiti samo konstantan iskaz sa komandom 'SET'"
spa "Tu solo debes usar expresiones constantes con SET"
swe "Man kan endast använda konstantuttryck med SET"
@@ -6582,3 +6582,5 @@ ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION
eng "Cannot modify @@session.skip_replication inside a stored function or trigger"
ER_QUERY_EXCEEDED_ROWS_EXAMINED_LIMIT
eng "Query execution was interrupted. The query examined at least %llu rows, which exceeds LIMIT ROWS EXAMINED (%llu). The query result may be incomplete."
+ER_TARGET_NOT_EXPLAINABLE
+ eng "Target is not running an EXPLAINable command"
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 414b1ba3f7f..d6e09b6c59a 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -2295,15 +2295,6 @@ int select_send::send_data(List<Item> &items)
}
-int select_result_explain_buffer::send_data(List<Item> &items)
-{
- fill_record(thd, dst_table->field, items, TRUE, FALSE);
- if ((dst_table->file->ha_write_tmp_row(dst_table->record[0])))
- return 1;
- return 0;
-}
-
-
bool select_send::send_eof()
{
/*
@@ -3233,43 +3224,6 @@ void THD::restore_active_arena(Query_arena *set, Query_arena *backup)
DBUG_VOID_RETURN;
}
-
-/*
- Produce EXPLAIN data.
-
- This function is APC-scheduled to be run in the context of the thread that
- we're producing EXPLAIN for.
-*/
-
-void Show_explain_request::call_in_target_thread()
-{
- Query_arena backup_arena;
- bool printed_anything= FALSE;
-
- /*
- Change the arena because JOIN::print_explain and co. are going to allocate
- items. Let them allocate them on our arena.
- */
- target_thd->set_n_backup_active_arena((Query_arena*)request_thd,
- &backup_arena);
-
- query_str.copy(target_thd->query(),
- target_thd->query_length(),
- &my_charset_bin);
-
- if (target_thd->lex->unit.print_explain(explain_buf, 0 /* explain flags*/,
- &printed_anything))
- {
- failed_to_produce= TRUE;
- }
-
- if (!printed_anything)
- failed_to_produce= TRUE;
-
- target_thd->restore_active_arena((Query_arena*)request_thd, &backup_arena);
-}
-
-
Statement::~Statement()
{
}
@@ -3832,6 +3786,7 @@ void THD::restore_backup_open_tables_state(Open_tables_backup *backup)
@retval 1 the user thread has been killed
This is used to signal a storage engine if it should be killed.
+ See also THD::check_killed().
*/
extern "C" int thd_killed(const MYSQL_THD thd)
@@ -3839,6 +3794,10 @@ extern "C" int thd_killed(const MYSQL_THD thd)
if (!thd)
thd= current_thd;
+ Apc_target *apc_target= (Apc_target*)&thd->apc_target;
+ if (apc_target->have_apc_requests())
+ apc_target->process_apc_requests();
+
if (!(thd->killed & KILL_HARD_BIT))
return 0;
return thd->killed;
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 50e445fe9c4..86797a8608b 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1520,39 +1520,7 @@ private:
extern "C" void my_message_sql(uint error, const char *str, myf MyFlags);
-class select_result_explain_buffer;
-
-
-/*
- SHOW EXPLAIN request object.
-
- The thread that runs SHOW EXPLAIN statement creates a Show_explain_request
- object R, and then schedules APC call of
- Show_explain_request::call((void*)&R).
-
-*/
-
-class Show_explain_request : public Apc_target::Apc_call
-{
-public:
- THD *target_thd; /* thd that we're running SHOW EXPLAIN for */
- THD *request_thd; /* thd that run SHOW EXPLAIN command */
-
- /* If true, there was some error when producing EXPLAIN output. */
- bool failed_to_produce;
-
- /* SHOW EXPLAIN will be stored here */
- select_result_explain_buffer *explain_buf;
-
- /* Query that we've got SHOW EXPLAIN for */
- String query_str;
-
- /* Overloaded virtual function */
- void call_in_target_thread();
-};
-
class THD;
-void mysqld_show_explain(THD *thd, const char *calling_user, ulong thread_id);
#ifndef DBUG_OFF
void dbug_serve_apcs(THD *thd, int n_calls);
#endif
@@ -2222,6 +2190,7 @@ public:
*/
killed_state volatile killed;
+ /* See also thd_killed() */
inline bool check_killed()
{
if (killed)
@@ -2438,7 +2407,8 @@ public:
Allows this thread to serve as a target for others to schedule Async
Procedure Calls on.
- It's possible to schedule arbitrary C++ function calls. Currently, only
+ It's possible to schedule any code to be executed this way, by
+ inheriting from the Apc_call object. Currently, only
Show_explain_request uses this.
*/
Apc_target apc_target;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 3a6bb4909f2..2bdc7952d73 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2155,9 +2155,9 @@ mysql_execute_command(THD *thd)
*/
if (lex->sroutines.records || lex->query_tables->next_global)
{
- my_error(ER_NOT_SUPPORTED_YET, MYF(0), "Usage of subqueries or stored "
- "function calls as part of this statement");
- break;
+ my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY),
+ MYF(0));
+ goto error;
}
Item **it= &(lex->show_explain_for_thread);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index dc5f32b5728..94463b8293c 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1999,8 +1999,50 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
}
-static
-const char *target_not_explainable_cmd="Target is not running EXPLAINable command";
+/*
+ Produce EXPLAIN data.
+
+ This function is APC-scheduled to be run in the context of the thread that
+ we're producing EXPLAIN for.
+*/
+
+void Show_explain_request::call_in_target_thread()
+{
+ Query_arena backup_arena;
+ bool printed_anything= FALSE;
+
+ /*
+ Change the arena because JOIN::print_explain and co. are going to allocate
+ items. Let them allocate them on our arena.
+ */
+ target_thd->set_n_backup_active_arena((Query_arena*)request_thd,
+ &backup_arena);
+
+ query_str.copy(target_thd->query(),
+ target_thd->query_length(),
+ &my_charset_bin);
+
+ if (target_thd->lex->unit.print_explain(explain_buf, 0 /* explain flags*/,
+ &printed_anything))
+ {
+ failed_to_produce= TRUE;
+ }
+
+ if (!printed_anything)
+ failed_to_produce= TRUE;
+
+ target_thd->restore_active_arena((Query_arena*)request_thd, &backup_arena);
+}
+
+
+int select_result_explain_buffer::send_data(List<Item> &items)
+{
+ fill_record(thd, dst_table->field, items, TRUE, FALSE);
+ if ((dst_table->file->ha_write_tmp_row(dst_table->record[0])))
+ return 1;
+ return 0;
+}
+
/*
Store the SHOW EXPLAIN output in the temporary table.
@@ -2048,7 +2090,7 @@ int fill_show_explain(THD *thd, TABLE_LIST *table, COND *cond)
if (calling_user && (!tmp_sctx->user || strcmp(calling_user,
tmp_sctx->user)))
{
- my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "PROCESSLIST");
+ my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "PROCESS");
mysql_mutex_unlock(&tmp->LOCK_thd_data);
DBUG_RETURN(1);
}
@@ -2056,8 +2098,7 @@ int fill_show_explain(THD *thd, TABLE_LIST *table, COND *cond)
if (tmp == thd)
{
mysql_mutex_unlock(&tmp->LOCK_thd_data);
- my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0), "SHOW EXPLAIN",
- target_not_explainable_cmd);
+ my_error(ER_TARGET_NOT_EXPLAINABLE, MYF(0));
DBUG_RETURN(1);
}
@@ -2084,21 +2125,12 @@ int fill_show_explain(THD *thd, TABLE_LIST *table, COND *cond)
if (bres || explain_req.failed_to_produce)
{
if (thd->killed)
- {
thd->send_kill_message();
- }
- else
- if (timed_out)
- {
- my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0),
- "SHOW EXPLAIN",
- "Timeout");
- }
+ else if (timed_out)
+ my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0));
else
- {
- my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0),
- "SHOW EXPLAIN", target_not_explainable_cmd);
- }
+ my_error(ER_TARGET_NOT_EXPLAINABLE, MYF(0));
+
bres= TRUE;
}
else
@@ -8427,7 +8459,32 @@ ST_FIELD_INFO keycache_fields_info[]=
};
-extern ST_FIELD_INFO show_explain_fields_info[];
+ST_FIELD_INFO show_explain_fields_info[]=
+{
+ /* field_name, length, type, value, field_flags, old_name*/
+ {"id", 3, MYSQL_TYPE_LONGLONG, 0 /*value*/, MY_I_S_MAYBE_NULL, "id",
+ SKIP_OPEN_TABLE},
+ {"select_type", 19, MYSQL_TYPE_STRING, 0 /*value*/, 0, "select_type",
+ SKIP_OPEN_TABLE},
+ {"table", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0 /*value*/, MY_I_S_MAYBE_NULL,
+ "table", SKIP_OPEN_TABLE},
+ {"type", 10, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, "type", SKIP_OPEN_TABLE},
+ {"possible_keys", NAME_CHAR_LEN*MAX_KEY, MYSQL_TYPE_STRING, 0/*value*/,
+ MY_I_S_MAYBE_NULL, "possible_keys", SKIP_OPEN_TABLE},
+ {"key", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0/*value*/, MY_I_S_MAYBE_NULL,
+ "key", SKIP_OPEN_TABLE},
+ {"key_len", NAME_CHAR_LEN*MAX_KEY, MYSQL_TYPE_STRING, 0/*value*/,
+ MY_I_S_MAYBE_NULL, "key_len", SKIP_OPEN_TABLE},
+ {"ref", NAME_CHAR_LEN*MAX_REF_PARTS, MYSQL_TYPE_STRING, 0/*value*/,
+ MY_I_S_MAYBE_NULL, "ref", SKIP_OPEN_TABLE},
+ {"rows", 10, MYSQL_TYPE_LONGLONG, 0/*value*/, MY_I_S_MAYBE_NULL, "rows",
+ SKIP_OPEN_TABLE},
+ {"Extra", 255, MYSQL_TYPE_STRING, 0/*value*/, 0 /*flags*/, "Extra",
+ SKIP_OPEN_TABLE},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+};
+
+
/*
Description of ST_FIELD_INFO in table.h
diff --git a/sql/sql_show.h b/sql/sql_show.h
index 8ad9327c08c..6ccb6e03872 100644
--- a/sql/sql_show.h
+++ b/sql/sql_show.h
@@ -19,6 +19,7 @@
#include "sql_list.h" /* List */
#include "handler.h" /* enum_schema_tables */
#include "table.h" /* enum_schema_table_state */
+#include "my_apc.h"
/* Forward declarations */
class JOIN;
@@ -132,4 +133,28 @@ enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table);
/* These functions were under INNODB_COMPATIBILITY_HOOKS */
int get_quote_char_for_identifier(THD *thd, const char *name, uint length);
+class select_result_explain_buffer;
+/*
+ SHOW EXPLAIN request object.
+*/
+
+class Show_explain_request : public Apc_target::Apc_call
+{
+public:
+ THD *target_thd; /* thd that we're running SHOW EXPLAIN for */
+ THD *request_thd; /* thd that run SHOW EXPLAIN command */
+
+ /* If true, there was some error when producing EXPLAIN output. */
+ bool failed_to_produce;
+
+ /* SHOW EXPLAIN will be stored here */
+ select_result_explain_buffer *explain_buf;
+
+ /* Query that we've got SHOW EXPLAIN for */
+ String query_str;
+
+ /* Overloaded virtual function */
+ void call_in_target_thread();
+};
+
#endif /* SQL_SHOW_H */
diff --git a/unittest/sql/my_apc-t.cc b/unittest/sql/my_apc-t.cc
index 3b837b4700e..8b599198302 100644
--- a/unittest/sql/my_apc-t.cc
+++ b/unittest/sql/my_apc-t.cc
@@ -90,7 +90,7 @@ void *test_apc_service_thread(void *ptr)
apc_target.init(&target_mutex);
apc_target.enable();
started= TRUE;
- fprintf(stderr, "# test_apc_service_thread started\n");
+ diag("test_apc_service_thread started");
while (!service_should_exit)
{
//apc_target.disable();
@@ -137,7 +137,7 @@ public:
void *test_apc_requestor_thread(void *ptr)
{
my_thread_init();
- fprintf(stderr, "# test_apc_requestor_thread started\n");
+ diag("test_apc_requestor_thread started");
THD my_thd;
while (!requestors_should_exit)
@@ -159,7 +159,7 @@ void *test_apc_requestor_thread(void *ptr)
if (dst_value != 0)
{
- fprintf(stderr, "APC was done even though return value says it wasnt!\n");
+ diag("APC was done even though return value says it wasnt!");
have_errors= true;
}
}
@@ -167,13 +167,13 @@ void *test_apc_requestor_thread(void *ptr)
{
if (dst_value != src_value)
{
- fprintf(stderr, "APC was not done even though return value says it was!\n");
+ diag("APC was not done even though return value says it was!");
have_errors= true;
}
}
//my_sleep(300);
}
- fprintf(stderr, "# test_apc_requestor_thread exiting\n");
+ diag("test_apc_requestor_thread exiting");
my_thread_end();
return NULL;
}
@@ -204,20 +204,20 @@ int main(int args, char **argv)
for (i = 0; i < 15; i++)
{
my_sleep(500*1000);
- fprintf(stderr, "# %d APCs served %d missed\n", apcs_served, apcs_missed);
+ diag("%d APCs served %d missed", apcs_served, apcs_missed);
}
- fprintf(stderr, "# Shutting down requestors\n");
+ diag("Shutting down requestors");
requestors_should_exit= TRUE;
for (i = 0; i < N_THREADS; i++)
pthread_join(request_thr[i], NULL);
- fprintf(stderr, "# Shutting down service\n");
+ diag("Shutting down service");
service_should_exit= TRUE;
pthread_join(service_thr, NULL);
mysql_mutex_destroy(&apc_counters_mutex);
- fprintf(stderr, "# Done.\n");
+ diag("Done");
my_thread_end();
my_thread_global_end();