summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/mysqltest.cc25
-rw-r--r--mysql-test/r/show_explain.result43
-rw-r--r--mysql-test/t/show_explain.test65
-rw-r--r--sql/my_apc.cc8
-rw-r--r--sql/my_apc.h6
-rw-r--r--sql/mysql_priv.h4
-rw-r--r--sql/sql_select.cc43
7 files changed, 141 insertions, 53 deletions
diff --git a/client/mysqltest.cc b/client/mysqltest.cc
index a3689a7b757..d33db945aee 100644
--- a/client/mysqltest.cc
+++ b/client/mysqltest.cc
@@ -75,6 +75,8 @@
#define QUERY_SEND_FLAG 1
#define QUERY_REAP_FLAG 2
+#define QUERY_PRINT_ORIGINAL_FLAG 4
+
#ifndef HAVE_SETENV
static int setenv(const char *name, const char *value, int overwrite);
#endif
@@ -288,7 +290,8 @@ enum enum_commands {
Q_ERROR,
Q_SEND, Q_REAP,
Q_DIRTY_CLOSE, Q_REPLACE, Q_REPLACE_COLUMN,
- Q_PING, Q_EVAL,
+ Q_PING, Q_EVAL,
+ Q_EVALP,
Q_RPL_PROBE, Q_ENABLE_RPL_PARSE,
Q_DISABLE_RPL_PARSE, Q_EVAL_RESULT,
Q_ENABLE_QUERY_LOG, Q_DISABLE_QUERY_LOG,
@@ -353,6 +356,7 @@ const char *command_names[]=
"replace_column",
"ping",
"eval",
+ "evalp",
"rpl_probe",
"enable_rpl_parse",
"disable_rpl_parse",
@@ -7532,7 +7536,8 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
/*
Evaluate query if this is an eval command
*/
- if (command->type == Q_EVAL || command->type == Q_SEND_EVAL)
+ if (command->type == Q_EVAL || command->type == Q_SEND_EVAL ||
+ command->type == Q_EVALP)
{
init_dynamic_string(&eval_query, "", command->query_len+256, 1024);
do_eval(&eval_query, command->query, command->end, FALSE);
@@ -7564,10 +7569,20 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
*/
if (!disable_query_log && (flags & QUERY_SEND_FLAG))
{
- replace_dynstr_append_mem(ds, query, query_len);
+ char *print_query= query;
+ int print_len= query_len;
+ if (flags & QUERY_PRINT_ORIGINAL_FLAG)
+ {
+ print_query= command->query;
+ print_len= command->end - command->query;
+ }
+ replace_dynstr_append_mem(ds, print_query, print_len);
dynstr_append_mem(ds, delimiter, delimiter_length);
dynstr_append_mem(ds, "\n", 1);
}
+
+ /* We're done with this flag */
+ flags &= ~QUERY_PRINT_ORIGINAL_FLAG;
/*
Write the command to the result file before we execute the query
@@ -8420,6 +8435,7 @@ int main(int argc, char **argv)
case Q_EVAL_RESULT:
die("'eval_result' command is deprecated");
case Q_EVAL:
+ case Q_EVALP:
case Q_QUERY_VERTICAL:
case Q_QUERY_HORIZONTAL:
if (command->query == command->query_buf)
@@ -8447,6 +8463,9 @@ int main(int argc, char **argv)
flags= QUERY_REAP_FLAG;
}
+ if (command->type == Q_EVALP)
+ flags |= QUERY_PRINT_ORIGINAL_FLAG;
+
/* Check for special property for this query */
display_result_vertically|= (command->type == Q_QUERY_VERTICAL);
diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result
index 4ff89069c5c..6a142e676fa 100644
--- a/mysql-test/r/show_explain.result
+++ b/mysql-test/r/show_explain.result
@@ -3,24 +3,37 @@ create table t0 (a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1 (a int);
insert into t1 select A.a + 10*B.a + 100*C.a from t0 A, t0 B, t0 C;
+alter table t1 add b int, add c int, add filler char(32);
+update t1 set b=a, c=a, filler='fooo';
+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 thr2
+show explain for (select max(a) from t0);
+ERROR 42000: This version of MySQL doesn't yet support 'Usage of subqueries or stored function calls as part of this statement'
+show explain for $thr2;
ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command
-SHOW explain for thr1
+show explain for $thr1;
ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command
-select get_lock('optimizer_done', 10);
-get_lock('optimizer_done', 10)
-1
-select count(*) from t1 where a < 100000 and sleep(a*0 + release_lock('optimizer_done') +1);
-select get_lock('optimizer_done', 100);
-get_lock('optimizer_done', 100)
-1
-SHOW explain for thr2
+set debug='d,show_explain_probe_1';
+select count(*) from t1 where a < 100000;
+show explain for $thr2;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ALL NULL NULL NULL NULL 1000 Using where
-select release_lock('optimizer_done');
-release_lock('optimizer_done')
-1
-kill query thr2
+1 SIMPLE t1 index a a 5 NULL 1000 Using where; Using index
+count(*)
+1000
+set debug='d,show_explain_probe_1';
+select max(c) from t1 where a < 10;
+show explain for $thr2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 5 NULL 10 Using where
+max(c)
+9
+set optimizer_switch='index_condition_pushdown=on,mrr=on,mrr_sort_keys=on';
+set debug='d,show_explain_probe_1';
+explain select max(c) from t1 where a < 10;
+show explain for $thr2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 5 NULL 10 Using index condition; Rowid-ordered scan
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 5 NULL 10 Using index condition; Rowid-ordered scan
drop table t0,t1;
diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test
index fc83613ae0e..1ee66e3ca2c 100644
--- a/mysql-test/t/show_explain.test
+++ b/mysql-test/t/show_explain.test
@@ -9,6 +9,9 @@ create table t0 (a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1 (a int);
insert into t1 select A.a + 10*B.a + 100*C.a from t0 A, t0 B, t0 C;
+alter table t1 add b int, add c int, add filler char(32);
+update t1 set b=a, c=a, filler='fooo';
+alter table t1 add key(a), add key(b);
#
# Try killing a non-existent thread
@@ -16,7 +19,12 @@ insert into t1 select A.a + 10*B.a + 100*C.a from t0 A, t0 B, t0 C;
--error ER_NO_SUCH_THREAD
show explain for 2*1000*1000*1000;
+--error ER_NOT_SUPPORTED_YET
+show explain for (select max(a) from t0);
+
+#
# Setup two threads and their ids
+#
let $thr1=`select connection_id()`;
connect (con1, localhost, root,,);
connection con1;
@@ -24,36 +32,47 @@ let $thr2=`select connection_id()`;
connection default;
# SHOW EXPLAIN FOR <idle thread>
-echo SHOW explain for thr2;
---disable_query_log
--error ER_ERROR_WHEN_EXECUTING_COMMAND
-eval show explain for $thr2;
---enable_query_log
+evalp show explain for $thr2;
# SHOW EXPLAIN FOR <ourselves>
-echo SHOW explain for thr1;
---disable_query_log
--error ER_ERROR_WHEN_EXECUTING_COMMAND
-eval show explain for $thr1;
---enable_query_log
+evalp show explain for $thr1;
+
+let $wait_condition= select State='show_explain_trap' from information_schema.processlist where id=$thr2;
+
+#
+# Test SHOW EXPLAIN for simple queries
+#
+connection con1;
+set debug='d,show_explain_probe_1';
+send select count(*) from t1 where a < 100000;
-# SHOW EXPLAIN FOR <running thread>
+connection default;
+--source include/wait_condition.inc
+evalp show explain for $thr2;
+connection con1;
+reap;
+
+
+set debug='d,show_explain_probe_1';
+send select max(c) from t1 where a < 10;
+connection default;
+--source include/wait_condition.inc
+evalp show explain for $thr2;
connection con1;
-select get_lock('optimizer_done', 10);
-send select count(*) from t1 where a < 100000 and sleep(a*0 + release_lock('optimizer_done') +1);
+reap;
+
+# We can catch EXPLAIN, too.
+set optimizer_switch='index_condition_pushdown=on,mrr=on,mrr_sort_keys=on';
+set debug='d,show_explain_probe_1';
+send explain select max(c) from t1 where a < 10;
connection default;
-select get_lock('optimizer_done', 100);
-echo SHOW explain for thr2;
---disable_query_log
-eval show explain for $thr2;
---enable_query_log
-select release_lock('optimizer_done');
---disable_query_log
-eval kill query $thr2;
---enable_query_log
-echo kill query thr2;
-
-#insert into t1 values ('one'),('two'),('three');
+--source include/wait_condition.inc
+evalp show explain for $thr2;
+connection con1;
+reap;
+
## TODO: Test this: multiple SHOW EXPLAIN calls in course of running of one select
##
diff --git a/sql/my_apc.cc b/sql/my_apc.cc
index 754b7880c42..91559483b1f 100644
--- a/sql/my_apc.cc
+++ b/sql/my_apc.cc
@@ -29,6 +29,10 @@ void Apc_target::init()
// todo: should use my_pthread_... functions instead?
DBUG_ASSERT(!enabled);
(void)pthread_mutex_init(&LOCK_apc_queue, MY_MUTEX_INIT_SLOW);
+
+#ifndef DBUG_OFF
+ n_calls_processed= 0;
+#endif
}
@@ -217,6 +221,10 @@ void Apc_target::process_apc_requests()
request->func(request->func_arg);
request->what="func called by process_apc_requests";
+#ifndef DBUG_OFF
+ n_calls_processed++;
+#endif
+
pthread_cond_signal(&request->COND_request);
pthread_mutex_unlock(&request->LOCK_request);
diff --git a/sql/my_apc.h b/sql/my_apc.h
index 3783bd28f54..3906aa24408 100644
--- a/sql/my_apc.h
+++ b/sql/my_apc.h
@@ -62,13 +62,17 @@ public:
bool make_apc_call(apc_func_t func, void *func_arg,
int timeout_sec, bool *timed_out);
+#ifndef DBUG_OFF
+ int n_calls_processed;
+ //int call_queue_size;
+#endif
private:
class Call_request;
int enabled;
Call_request *apc_calls;
pthread_mutex_t LOCK_apc_queue;
- //int call_queue_size;
+
class Call_request
{
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index a19cca31d1c..e20702b497d 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -2404,6 +2404,10 @@ int rea_create_table(THD *thd, const char *path,
int format_number(uint inputflag,uint max_length,char * pos,uint length,
char * *errpos);
+#ifndef DBUG_OFF
+void dbug_serve_apcs(THD *thd, int n_calls);
+#endif
+
/* table.cc */
TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key,
uint key_length);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 2a895bb2798..355b33fa353 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -245,6 +245,25 @@ Item_equal *find_item_equal(COND_EQUAL *cond_equal, Field *field,
JOIN_TAB *first_depth_first_tab(JOIN* join);
JOIN_TAB *next_depth_first_tab(JOIN* join, JOIN_TAB* tab);
+#ifndef DBUG_OFF
+// psergey:
+void dbug_serve_apcs(THD *thd, int n_calls)
+{
+ // TODO how do we signal that we're SHOW-EXPLAIN-READY?
+ const char *save_proc_info= thd->proc_info;
+ thd_proc_info(thd, "show_explain_trap");
+
+ int n_apcs= thd->apc_target.n_calls_processed + n_calls;
+ while (thd->apc_target.n_calls_processed < n_apcs)
+ {
+ my_sleep(300);
+ if (thd->check_killed())
+ break;
+ }
+ thd_proc_info(thd, save_proc_info);
+}
+#endif
+
/**
This handles SELECT with and without UNION.
*/
@@ -2047,6 +2066,8 @@ void JOIN::exec_inner()
List<Item> *columns_list= &fields_list;
int tmp_error;
DBUG_ENTER("JOIN::exec");
+
+ DBUG_EXECUTE_IF("show_explain_probe_1", dbug_serve_apcs(thd, 1););
thd_proc_info(thd, "executing");
error= 0;
@@ -20430,7 +20451,6 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly,
}
else if (join->select_lex == join->unit->fake_select_lex)
{
- //if (!join->select_lex->type)
if (on_the_fly)
join->select_lex->set_explain_type(on_the_fly); //psergey
/*
@@ -20561,6 +20581,7 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly,
join->select_lex->type;
item_list.push_back(new Item_string(stype, strlen(stype), cs));
+ enum join_type tab_type= tab->type;
if ((tab->type == JT_ALL || tab->type == JT_HASH) &&
tab->select && tab->select->quick)
{
@@ -20569,9 +20590,9 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly,
(quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT) ||
(quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT) ||
(quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION))
- tab->type= tab->type == JT_ALL ? JT_INDEX_MERGE : JT_HASH_INDEX_MERGE;
+ tab_type= tab->type == JT_ALL ? JT_INDEX_MERGE : JT_HASH_INDEX_MERGE;
else
- tab->type= tab->type == JT_ALL ? JT_RANGE : JT_HASH_RANGE;
+ tab_type= tab->type == JT_ALL ? JT_RANGE : JT_HASH_RANGE;
}
/* table */
@@ -20620,8 +20641,8 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly,
#endif
}
/* "type" column */
- item_list.push_back(new Item_string(join_type_str[tab->type],
- strlen(join_type_str[tab->type]),
+ item_list.push_back(new Item_string(join_type_str[tab_type],
+ strlen(join_type_str[tab_type]),
cs));
/* Build "possible_keys" value and add it to item_list */
if (!tab->keys.is_clear_all())
@@ -20645,7 +20666,7 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly,
item_list.push_back(item_null);
/* Build "key", "key_len", and "ref" values and add them to item_list */
- if (tab->type == JT_NEXT)
+ if (tab_type == JT_NEXT)
{
key_info= table->key_info+tab->index;
key_len= key_info->key_length;
@@ -20674,12 +20695,12 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly,
}
}
}
- if (is_hj && tab->type != JT_HASH)
+ if (is_hj && tab_type != JT_HASH)
{
tmp2.append(':');
tmp3.append(':');
}
- if (tab->type == JT_HASH_NEXT)
+ if (tab_type == JT_HASH_NEXT)
{
register uint length;
key_info= table->key_info+tab->index;
@@ -20701,7 +20722,7 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly,
item_list.push_back(new Item_string(tmp3.ptr(),tmp3.length(),cs));
else
item_list.push_back(item_null);
- if (key_info && tab->type != JT_NEXT)
+ if (key_info && tab_type != JT_NEXT)
item_list.push_back(new Item_string(tmp4.ptr(),tmp4.length(),cs));
else
item_list.push_back(item_null);
@@ -20754,7 +20775,7 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly,
ha_rows examined_rows;
if (tab->select && tab->select->quick)
examined_rows= tab->select->quick->records;
- else if (tab->type == JT_NEXT || tab->type == JT_ALL || is_hj)
+ else if (tab_type == JT_NEXT || tab_type == JT_ALL || is_hj)
{
if (tab->limit)
examined_rows= tab->limit;
@@ -20793,7 +20814,7 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly,
/* Build "Extra" field and add it to item_list. */
key_read=table->key_read;
- if ((tab->type == JT_NEXT || tab->type == JT_CONST) &&
+ if ((tab_type == JT_NEXT || tab_type == JT_CONST) &&
table->covering_keys.is_set(tab->index))
key_read=1;
if (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT &&