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:
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
# 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;
|
||||
select get_lock('optimizer_done', 10);
|
||||
send select count(*) from t1 where a < 100000 and sleep(a*0 + release_lock('optimizer_done') +1);
|
||||
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;
|
||||
set debug='d,show_explain_probe_1';
|
||||
send select count(*) from t1 where a < 100000;
|
||||
|
||||
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;
|
||||
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
|
||||
##
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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 &&
|
||||
|
Reference in New Issue
Block a user