1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

MWL#182: Explain running statements

- Implement new approach to testing (the DBUG_EXECUTE_IF variant)
- add an 'evalp' mysqltest command that is like 'eval' except that
  it prints the original query.
- Fix select_describe() not to change join_tab[i]->type
- More tests
This commit is contained in:
Sergey Petrunya
2011-09-24 21:56:42 +04:00
parent d9045bce1d
commit 203bbfe569
7 changed files with 141 additions and 53 deletions

View File

@ -75,6 +75,8 @@
#define QUERY_SEND_FLAG 1 #define QUERY_SEND_FLAG 1
#define QUERY_REAP_FLAG 2 #define QUERY_REAP_FLAG 2
#define QUERY_PRINT_ORIGINAL_FLAG 4
#ifndef HAVE_SETENV #ifndef HAVE_SETENV
static int setenv(const char *name, const char *value, int overwrite); static int setenv(const char *name, const char *value, int overwrite);
#endif #endif
@ -289,6 +291,7 @@ enum enum_commands {
Q_SEND, Q_REAP, Q_SEND, Q_REAP,
Q_DIRTY_CLOSE, Q_REPLACE, Q_REPLACE_COLUMN, 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_RPL_PROBE, Q_ENABLE_RPL_PARSE,
Q_DISABLE_RPL_PARSE, Q_EVAL_RESULT, Q_DISABLE_RPL_PARSE, Q_EVAL_RESULT,
Q_ENABLE_QUERY_LOG, Q_DISABLE_QUERY_LOG, Q_ENABLE_QUERY_LOG, Q_DISABLE_QUERY_LOG,
@ -353,6 +356,7 @@ const char *command_names[]=
"replace_column", "replace_column",
"ping", "ping",
"eval", "eval",
"evalp",
"rpl_probe", "rpl_probe",
"enable_rpl_parse", "enable_rpl_parse",
"disable_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 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); init_dynamic_string(&eval_query, "", command->query_len+256, 1024);
do_eval(&eval_query, command->query, command->end, FALSE); do_eval(&eval_query, command->query, command->end, FALSE);
@ -7564,11 +7569,21 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
*/ */
if (!disable_query_log && (flags & QUERY_SEND_FLAG)) 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, delimiter, delimiter_length);
dynstr_append_mem(ds, "\n", 1); 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 Write the command to the result file before we execute the query
This is needed to be able to analyse the log if something goes This is needed to be able to analyse the log if something goes
@ -8420,6 +8435,7 @@ int main(int argc, char **argv)
case Q_EVAL_RESULT: case Q_EVAL_RESULT:
die("'eval_result' command is deprecated"); die("'eval_result' command is deprecated");
case Q_EVAL: case Q_EVAL:
case Q_EVALP:
case Q_QUERY_VERTICAL: case Q_QUERY_VERTICAL:
case Q_QUERY_HORIZONTAL: case Q_QUERY_HORIZONTAL:
if (command->query == command->query_buf) if (command->query == command->query_buf)
@ -8447,6 +8463,9 @@ int main(int argc, char **argv)
flags= QUERY_REAP_FLAG; flags= QUERY_REAP_FLAG;
} }
if (command->type == Q_EVALP)
flags |= QUERY_PRINT_ORIGINAL_FLAG;
/* Check for special property for this query */ /* Check for special property for this query */
display_result_vertically|= (command->type == Q_QUERY_VERTICAL); display_result_vertically|= (command->type == Q_QUERY_VERTICAL);

View File

@ -3,24 +3,37 @@ create table t0 (a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1 (a int); create table t1 (a int);
insert into t1 select A.a + 10*B.a + 100*C.a from t0 A, t0 B, t0 C; 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; show explain for 2*1000*1000*1000;
ERROR HY000: Unknown thread id: 2000000000 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 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 ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command
select get_lock('optimizer_done', 10); set debug='d,show_explain_probe_1';
get_lock('optimizer_done', 10) select count(*) from t1 where a < 100000;
1 show explain for $thr2;
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
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 1000 Using where 1 SIMPLE t1 index a a 5 NULL 1000 Using where; Using index
select release_lock('optimizer_done'); count(*)
release_lock('optimizer_done') 1000
1 set debug='d,show_explain_probe_1';
kill query thr2 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; drop table t0,t1;

View File

@ -9,6 +9,9 @@ create table t0 (a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1 (a int); create table t1 (a int);
insert into t1 select A.a + 10*B.a + 100*C.a from t0 A, t0 B, t0 C; 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 # 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 --error ER_NO_SUCH_THREAD
show explain for 2*1000*1000*1000; 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 # Setup two threads and their ids
#
let $thr1=`select connection_id()`; let $thr1=`select connection_id()`;
connect (con1, localhost, root,,); connect (con1, localhost, root,,);
connection con1; connection con1;
@ -24,36 +32,47 @@ let $thr2=`select connection_id()`;
connection default; connection default;
# SHOW EXPLAIN FOR <idle thread> # SHOW EXPLAIN FOR <idle thread>
echo SHOW explain for thr2;
--disable_query_log
--error ER_ERROR_WHEN_EXECUTING_COMMAND --error ER_ERROR_WHEN_EXECUTING_COMMAND
eval show explain for $thr2; evalp show explain for $thr2;
--enable_query_log
# SHOW EXPLAIN FOR <ourselves> # SHOW EXPLAIN FOR <ourselves>
echo SHOW explain for thr1;
--disable_query_log
--error ER_ERROR_WHEN_EXECUTING_COMMAND --error ER_ERROR_WHEN_EXECUTING_COMMAND
eval show explain for $thr1; evalp show explain for $thr1;
--enable_query_log
# SHOW EXPLAIN FOR <running thread> let $wait_condition= select State='show_explain_trap' from information_schema.processlist where id=$thr2;
#
# Test SHOW EXPLAIN for simple queries
#
connection con1; connection con1;
select get_lock('optimizer_done', 10); set debug='d,show_explain_probe_1';
send select count(*) from t1 where a < 100000 and sleep(a*0 + release_lock('optimizer_done') +1); send select count(*) from t1 where a < 100000;
connection default;
select get_lock('optimizer_done', 100); connection default;
echo SHOW explain for thr2; --source include/wait_condition.inc
--disable_query_log evalp show explain for $thr2;
eval show explain for $thr2; connection con1;
--enable_query_log reap;
select release_lock('optimizer_done');
--disable_query_log
eval kill query $thr2; set debug='d,show_explain_probe_1';
--enable_query_log send select max(c) from t1 where a < 10;
echo kill query thr2; connection default;
--source include/wait_condition.inc
evalp show explain for $thr2;
connection con1;
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;
--source include/wait_condition.inc
evalp show explain for $thr2;
connection con1;
reap;
#insert into t1 values ('one'),('two'),('three');
## TODO: Test this: multiple SHOW EXPLAIN calls in course of running of one select ## TODO: Test this: multiple SHOW EXPLAIN calls in course of running of one select
## ##

View File

@ -29,6 +29,10 @@ void Apc_target::init()
// todo: should use my_pthread_... functions instead? // todo: should use my_pthread_... functions instead?
DBUG_ASSERT(!enabled); DBUG_ASSERT(!enabled);
(void)pthread_mutex_init(&LOCK_apc_queue, MY_MUTEX_INIT_SLOW); (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->func(request->func_arg);
request->what="func called by process_apc_requests"; request->what="func called by process_apc_requests";
#ifndef DBUG_OFF
n_calls_processed++;
#endif
pthread_cond_signal(&request->COND_request); pthread_cond_signal(&request->COND_request);
pthread_mutex_unlock(&request->LOCK_request); pthread_mutex_unlock(&request->LOCK_request);

View File

@ -62,13 +62,17 @@ public:
bool make_apc_call(apc_func_t func, void *func_arg, bool make_apc_call(apc_func_t func, void *func_arg,
int timeout_sec, bool *timed_out); int timeout_sec, bool *timed_out);
#ifndef DBUG_OFF
int n_calls_processed;
//int call_queue_size;
#endif
private: private:
class Call_request; class Call_request;
int enabled; int enabled;
Call_request *apc_calls; Call_request *apc_calls;
pthread_mutex_t LOCK_apc_queue; pthread_mutex_t LOCK_apc_queue;
//int call_queue_size;
class Call_request class Call_request
{ {

View File

@ -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, int format_number(uint inputflag,uint max_length,char * pos,uint length,
char * *errpos); char * *errpos);
#ifndef DBUG_OFF
void dbug_serve_apcs(THD *thd, int n_calls);
#endif
/* table.cc */ /* table.cc */
TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key, TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key,
uint key_length); uint key_length);

View File

@ -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 *first_depth_first_tab(JOIN* join);
JOIN_TAB *next_depth_first_tab(JOIN* join, JOIN_TAB* tab); 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. This handles SELECT with and without UNION.
*/ */
@ -2048,6 +2067,8 @@ void JOIN::exec_inner()
int tmp_error; int tmp_error;
DBUG_ENTER("JOIN::exec"); DBUG_ENTER("JOIN::exec");
DBUG_EXECUTE_IF("show_explain_probe_1", dbug_serve_apcs(thd, 1););
thd_proc_info(thd, "executing"); thd_proc_info(thd, "executing");
error= 0; error= 0;
if (procedure) if (procedure)
@ -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) else if (join->select_lex == join->unit->fake_select_lex)
{ {
//if (!join->select_lex->type)
if (on_the_fly) if (on_the_fly)
join->select_lex->set_explain_type(on_the_fly); //psergey 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; join->select_lex->type;
item_list.push_back(new Item_string(stype, strlen(stype), cs)); 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) && if ((tab->type == JT_ALL || tab->type == JT_HASH) &&
tab->select && tab->select->quick) 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_INDEX_INTERSECT) ||
(quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT) || (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT) ||
(quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION)) (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 else
tab->type= tab->type == JT_ALL ? JT_RANGE : JT_HASH_RANGE; tab_type= tab->type == JT_ALL ? JT_RANGE : JT_HASH_RANGE;
} }
/* table */ /* table */
@ -20620,8 +20641,8 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly,
#endif #endif
} }
/* "type" column */ /* "type" column */
item_list.push_back(new Item_string(join_type_str[tab->type], item_list.push_back(new Item_string(join_type_str[tab_type],
strlen(join_type_str[tab->type]), strlen(join_type_str[tab_type]),
cs)); cs));
/* Build "possible_keys" value and add it to item_list */ /* Build "possible_keys" value and add it to item_list */
if (!tab->keys.is_clear_all()) 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); item_list.push_back(item_null);
/* Build "key", "key_len", and "ref" values and add them to item_list */ /* 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_info= table->key_info+tab->index;
key_len= key_info->key_length; 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(':'); tmp2.append(':');
tmp3.append(':'); tmp3.append(':');
} }
if (tab->type == JT_HASH_NEXT) if (tab_type == JT_HASH_NEXT)
{ {
register uint length; register uint length;
key_info= table->key_info+tab->index; 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)); item_list.push_back(new Item_string(tmp3.ptr(),tmp3.length(),cs));
else else
item_list.push_back(item_null); 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)); item_list.push_back(new Item_string(tmp4.ptr(),tmp4.length(),cs));
else else
item_list.push_back(item_null); 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; ha_rows examined_rows;
if (tab->select && tab->select->quick) if (tab->select && tab->select->quick)
examined_rows= tab->select->quick->records; 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) if (tab->limit)
examined_rows= 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. */ /* Build "Extra" field and add it to item_list. */
key_read=table->key_read; 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)) table->covering_keys.is_set(tab->index))
key_read=1; key_read=1;
if (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT && if (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT &&