summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergey Petrunya <psergey@askmonty.org>2012-07-17 21:52:08 +0400
committerSergey Petrunya <psergey@askmonty.org>2012-07-17 21:52:08 +0400
commit2368f8895d10a3d883a6a0ffe33b2b222caf7f1a (patch)
tree1f674b38702d87f5b13bbb587c8939bc842e9926 /sql
parenta49b4c970fe582919d89109e0cc3ebe2558269cd (diff)
downloadmariadb-git-2368f8895d10a3d883a6a0ffe33b2b222caf7f1a.tar.gz
MWL#182: Explain running statements
- Address feedback from the second code review.
Diffstat (limited to 'sql')
-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
9 files changed, 123 insertions, 138 deletions
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 */