diff options
-rw-r--r-- | client/mysqltest.cc | 25 | ||||
-rw-r--r-- | mysql-test/r/show_explain.result | 43 | ||||
-rw-r--r-- | mysql-test/t/show_explain.test | 65 | ||||
-rw-r--r-- | sql/my_apc.cc | 8 | ||||
-rw-r--r-- | sql/my_apc.h | 6 | ||||
-rw-r--r-- | sql/mysql_priv.h | 4 | ||||
-rw-r--r-- | sql/sql_select.cc | 43 |
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 && |