Commit 34e9a4c1 authored by Sergey Petrunya's avatar Sergey Petrunya

Merge of recent changes in MWL#182 in 5.3 with {Merge of MWL#182 with 5.5}

parents dfbd777f 483ae4bf
This diff is collapsed.
......@@ -4,7 +4,8 @@
--source include/have_debug.inc
--disable_warnings
drop table if exists t0, t1;
drop table if exists t0, t1, t2, t3, t4;
drop view if exists v1;
--enable_warnings
#
......@@ -196,12 +197,308 @@ reap;
# TODO: explain in the parent subuqery when the un-correlated child has been
# run (and have done irreversible cleanups)
# ^^ Is this at all possible after 5.3?
# Maybe, for 5.3 try this:
# - run before/after the parent has invoked child's optimization
# - run after materialization
--echo # Try to do SHOW EXPLAIN for a query that runs a SET command:
--echo # I've found experimentally that select_id==2 here...
--echo #
set @show_explain_probe_select_id=2;
set debug_dbug='d,show_explain_probe_join_exec_start';
send set @foo= (select max(a) from t0 where sin(a) >0);
connection default;
--source include/wait_condition.inc
--error ER_ERROR_WHEN_EXECUTING_COMMAND
evalp show explain for $thr2;
connection con1;
reap;
--echo #
--echo # Attempt SHOW EXPLAIN for an UPDATE
--echo #
create table t2 as select a as a, a as dummy from t0 limit 2;
set @show_explain_probe_select_id=2;
set debug_dbug='d,show_explain_probe_join_exec_start';
send update t2 set dummy=0 where (select max(a) from t0 where t2.a + t0.a <3) >3 ;
connection default;
--source include/wait_condition.inc
--error ER_ERROR_WHEN_EXECUTING_COMMAND
evalp show explain for $thr2;
--error ER_ERROR_WHEN_EXECUTING_COMMAND
evalp show explain for $thr2;
connection con1;
reap;
drop table t2;
--echo #
--echo # Attempt SHOW EXPLAIN for a DELETE
--echo #
create table t2 as select a as a, a as dummy from t0 limit 2;
set @show_explain_probe_select_id=2;
set debug_dbug='d,show_explain_probe_join_exec_start';
send delete from t2 where (select max(a) from t0 where t2.a + t0.a <3) >3 ;
connection default;
--source include/wait_condition.inc
--error ER_ERROR_WHEN_EXECUTING_COMMAND
evalp show explain for $thr2;
--error ER_ERROR_WHEN_EXECUTING_COMMAND
evalp show explain for $thr2;
connection con1;
reap;
drop table t2;
--echo #
--echo # Multiple SHOW EXPLAIN calls for one select
--echo #
create table t2 as select a as a, a as dummy from t0 limit 3;
set @show_explain_probe_select_id=2;
set debug_dbug='d,show_explain_probe_join_exec_start';
send select t2.a, ((select max(a) from t0 where t2.a + t0.a <3) >3) as SUBQ from t2;
connection default;
--source include/wait_condition.inc
evalp show explain for $thr2;
evalp show explain for $thr2;
evalp show explain for $thr2;
connection con1;
reap;
drop table t2;
--echo #
--echo # SHOW EXPLAIN for SELECT ... ORDER BY with "Using filesort"
--echo #
explain select * from t0 order by a;
set debug_dbug='d,show_explain_probe_join_exec_start';
set @show_explain_probe_select_id=1;
send select * from t0 order by a;
connection default;
--source include/wait_condition.inc
evalp show explain for $thr2;
connection con1;
reap;
--echo #
--echo # SHOW EXPLAIN for SELECT ... with "Using temporary"
--echo #
connection default;
explain select distinct a from t0;
connection con1;
set debug_dbug='d,show_explain_probe_join_exec_start';
set @show_explain_probe_select_id=1;
send select distinct a from t0;
connection default;
--source include/wait_condition.inc
evalp show explain for $thr2;
connection con1;
reap;
--echo #
--echo # SHOW EXPLAIN for SELECT ... with "Using temporary; Using filesort"
--echo #
connection default;
explain select distinct a from t0;
connection con1;
set debug_dbug='d,show_explain_probe_join_exec_start';
set @show_explain_probe_select_id=1;
send select distinct a from t0;
connection default;
--source include/wait_condition.inc
evalp show explain for $thr2;
connection con1;
reap;
set debug_dbug='';
--echo #
--echo # MDEV-238: SHOW EXPLAIN: Server crashes in JOIN::print_explain with FROM subquery and GROUP BY
--echo #
CREATE TABLE t2 ( a INT );
INSERT INTO t2 VALUES (1),(2),(1),(4),(2);
explain SELECT alias.a FROM t2, ( SELECT * FROM t2 ) AS alias GROUP BY alias.a;
# TODO: hit JOIN::optimize for non-select commands: UPDATE/DELETE, SET.
set debug_dbug='d,show_explain_in_find_all_keys';
send SELECT alias.a FROM t2, ( SELECT * FROM t2 ) AS alias GROUP BY alias.a;
connection default;
--source include/wait_condition.inc
--echo # NOTE: current code will not show "Using join buffer":
evalp show explain for $thr2;
connection con1;
reap;
set debug_dbug='';
DROP TABLE t2;
--echo #
--echo # MDEV-239: Assertion `field_types == 0 ... ' failed in Protocol_text::store(double, uint32, String*) with
--echo # SHOW EXPLAIN over EXPLAIN EXTENDED
--echo #
CREATE TABLE t2 (a INT);
INSERT INTO t2 VALUES (1),(2),(1),(4),(2);
EXPLAIN EXTENDED SELECT alias.a FROM t2, ( SELECT * FROM t2 ) AS alias GROUP BY alias.a ;
set @show_explain_probe_select_id=1;
set debug_dbug='d,show_explain_probe_join_exec_end';
send EXPLAIN EXTENDED SELECT alias.a FROM t2, ( SELECT * FROM t2 ) AS alias GROUP BY alias.a ;
connection default;
--source include/wait_condition.inc
evalp show explain for $thr2;
connection con1;
reap;
set debug_dbug='';
DROP TABLE t2;
--echo #
--echo # MDEV-240: SHOW EXPLAIN: Assertion `this->optimized == 2' failed in
--echo # JOIN::print_explain on query with a JOIN, TEMPTABLE view,
--echo #
CREATE TABLE t3 (a INT);
CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t3;
INSERT INTO t3 VALUES (8);
CREATE TABLE t2 (b INT);
INSERT INTO t2 VALUES (4),(5),(6),(7),(8),(9);
explain SELECT * FROM v1, t2;
set @show_explain_probe_select_id=2;
set debug_dbug='d,show_explain_probe_join_exec_end';
send SELECT * FROM v1, t2;
connection default;
--source include/wait_condition.inc
evalp show explain for $thr2;
connection con1;
reap;
set debug_dbug='';
DROP VIEW v1;
DROP TABLE t2, t3;
--echo #
--echo # MDEV-267: SHOW EXPLAIN: Server crashes in JOIN::print_explain on most of queries
--echo #
set @show_explain_probe_select_id=1;
set debug_dbug='d,show_explain_probe_join_exec_end';
send select sleep(1);
connection default;
--source include/wait_condition.inc
evalp show explain for $thr2;
connection con1;
reap;
set debug_dbug='';
--echo #
--echo # Same as above, but try another reason for JOIN to be degenerate
--echo #
set @show_explain_probe_select_id=1;
set debug_dbug='d,show_explain_probe_join_exec_end';
send select * from t0 where 1>10;
connection default;
--source include/wait_condition.inc
evalp show explain for $thr2;
connection con1;
reap;
set debug_dbug='';
--echo #
--echo # Same as above, but try another reason for JOIN to be degenerate (2)
--echo #
create table t3(a int primary key);
insert into t3 select a from t0;
set @show_explain_probe_select_id=1;
set debug_dbug='d,show_explain_probe_join_exec_end';
send select * from t0,t3 where t3.a=112233;
connection default;
--source include/wait_condition.inc
evalp show explain for $thr2;
connection con1;
reap;
set debug_dbug='';
drop table t3;
--echo #
--echo # MDEV-270: SHOW EXPLAIN: server crashes in JOIN::print_explain on a query with
--echo # select tables optimized away
--echo #
CREATE TABLE t2 (pk INT PRIMARY KEY, a INT ) ENGINE=MyISAM;
INSERT INTO t2 VALUES
(1,4),(2,62),(3,7),(4,1),(5,0),(6,7),(7,7),(8,1),(9,7),(10,1),
(11,5),(12,2),(13,0),(14,1),(15,8),(16,1),(17,1),(18,9),(19,1),(20,5) ;
explain SELECT * FROM t2 WHERE a =
(SELECT MAX(a) FROM t2
WHERE pk= (SELECT MAX(pk) FROM t2 WHERE pk = 3)
);
set @show_explain_probe_select_id=2;
set debug_dbug='d,show_explain_probe_do_select';
send SELECT * FROM t2 WHERE a =
(SELECT MAX(a) FROM t2
WHERE pk= (SELECT MAX(pk) FROM t2 WHERE pk = 3)
);
connection default;
--source include/wait_condition.inc
evalp show explain for $thr2;
connection con1;
reap;
set debug_dbug='';
drop table t2;
--echo #
--echo # MDEV-273: SHOW EXPLAIN: server crashes in JOIN::print_explain on a query with impossible WHERE
--echo #
CREATE TABLE t2 (a1 INT, KEY(a1)) ENGINE=MyISAM;
INSERT INTO t2 VALUES
(4),(6),(7),(1),(0),(7),(7),(1),(7),(1),
(5),(2),(0),(1),(8),(1),(1),(9),(1),(5);
CREATE TABLE t3 (b1 INT) ENGINE=MyISAM;
INSERT INTO t3 VALUES
(4),(5),(8),(4),(8),(2),(9),(6),(4),(8),
(3),(5),(9),(6),(8),(3),(2),(6),(3),(1),
(4),(3),(1),(7),(0),(0),(9),(5),(9),(0),
(2),(2),(5),(9),(1),(4),(8),(6),(5),(5),
(1),(7),(2),(8),(9),(3),(2),(6),(6),(5),
(4),(3),(2),(7),(4),(6),(0),(8),(5),(8),
(2),(9),(7),(5),(7),(0),(4),(3),(1),(0),
(6),(2),(8),(3),(7),(3),(5),(5),(1),(2),
(1),(7),(1),(9),(9),(8),(3);
CREATE TABLE t4 (c1 INT) ENGINE=MyISAM;
EXPLAIN
SELECT count(*) FROM t2, t3
WHERE a1 < ALL (
SELECT a1 FROM t2
WHERE a1 IN ( SELECT a1 FROM t2, t4 )
);
set @show_explain_probe_select_id=1;
set debug_dbug='d,show_explain_probe_do_select';
send
SELECT count(*) FROM t2, t3
WHERE a1 < ALL (
SELECT a1 FROM t2
WHERE a1 IN ( SELECT a1 FROM t2, t4 )
);
connection default;
--source include/wait_condition.inc
evalp show explain for $thr2;
connection con1;
reap;
set debug_dbug='';
drop table t2, t3, t4;
## TODO: Test this: multiple SHOW EXPLAIN calls in course of running of one select
##
## TODO: Test this: have several SHOW EXPLAIN requests be queued up for a
## thread and served together.
......
......@@ -502,7 +502,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
my_off_t record;
TABLE *sort_form;
THD *thd= current_thd;
volatile killed_state *killed= &thd->killed;
//volatile killed_state *killed= &thd->killed;
handler *file;
MY_BITMAP *save_read_set, *save_write_set, *save_vcol_set;
uchar *next_sort_key= sort_keys_buf;
......@@ -523,6 +523,11 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
if (flag)
ref_pos= &file->ref[0];
next_pos=ref_pos;
DBUG_EXECUTE_IF("show_explain_in_find_all_keys",
dbug_serve_apcs(thd, 1);
);
if (!quick_select)
{
next_pos=(uchar*) 0; /* Find records in sequence */
......@@ -586,7 +591,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
break;
}
if (*killed)
if (thd->check_killed())
{
DBUG_PRINT("info",("Sort killed by user"));
if (!quick_select)
......@@ -1231,18 +1236,20 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
void *first_cmp_arg;
element_count dupl_count= 0;
uchar *src;
killed_state not_killable;
/* killed_state not_killable; */
uchar *unique_buff= param->unique_buff;
volatile killed_state *killed= &current_thd->killed;
/* volatile killed_state *killed= &current_thd->killed; */
const bool killable= !param->not_killable;
THD* const thd=current_thd;
DBUG_ENTER("merge_buffers");
status_var_increment(current_thd->status_var.filesort_merge_passes);
current_thd->query_plan_fsort_passes++;
if (param->not_killable)
status_var_increment(thd->status_var.filesort_merge_passes);
thd->query_plan_fsort_passes++;
/*if (param->not_killable)
{
killed= &not_killable;
not_killable= NOT_KILLED;
}
}*/
error=0;
rec_length= param->rec_length;
......@@ -1320,7 +1327,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
while (queue.elements > 1)
{
if (*killed)
if (killable && thd->check_killed())
{
error= 1; goto err; /* purecov: inspected */
}
......
......@@ -4725,6 +4725,7 @@ int subselect_hash_sj_engine::exec()
thd->lex->current_select= materialize_engine->select_lex;
/* The subquery should be optimized, and materialized only once. */
DBUG_ASSERT(materialize_join->optimized && !is_materialized);
materialize_join->exec();
if ((res= test(materialize_join->error || thd->is_fatal_error ||
thd->is_error())))
......
......@@ -25,6 +25,14 @@
*/
/*
Initialize the target.
@note
Initialization must be done prior to enabling/disabling the target, or making
any call requests to it.
Initial state after initialization is 'disabled'.
*/
void Apc_target::init()
{
// todo: should use my_pthread_... functions instead?
......@@ -37,6 +45,9 @@ void Apc_target::init()
}
/*
Destroy the target. The target must be disabled when this call is made.
*/
void Apc_target::destroy()
{
DBUG_ASSERT(!enabled);
......@@ -44,6 +55,9 @@ void Apc_target::destroy()
}
/*
Enter ther state where the target is available for serving APC requests
*/
void Apc_target::enable()
{
pthread_mutex_lock(&LOCK_apc_queue);
......@@ -52,6 +66,13 @@ void Apc_target::enable()
}
/*
Make the target unavailable for serving APC requests.
@note
This call will serve all requests that were already enqueued
*/
void Apc_target::disable()
{
bool process= FALSE;
......@@ -63,6 +84,9 @@ void Apc_target::disable()
process_apc_requests();
}
/* (internal) Put request into the request list */
void Apc_target::enqueue_request(Call_request *qe)
{
//call_queue_size++;
......@@ -82,6 +106,13 @@ void Apc_target::enqueue_request(Call_request *qe)
}
}
/*
(internal) Remove given request from the request queue.
The request is not necessarily first in the queue.
*/
void Apc_target::dequeue_request(Call_request *qe)
{
//call_queue_size--;
......@@ -100,8 +131,10 @@ void Apc_target::dequeue_request(Call_request *qe)
/*
Make an apc call in another thread. The caller is responsible so
that we're not calling to ourselves.
Make an APC (Async Procedure Call) in another thread.
The caller is responsible for making sure he's not calling an Apc_target
that is serviced by the same thread it is called from.
psergey-todo: Should waits here be KILLable? (it seems one needs
to use thd->enter_cond() calls to be killable)
......@@ -120,7 +153,7 @@ bool Apc_target::make_apc_call(apc_func_t func, void *func_arg,
Call_request apc_request;
apc_request.func= func;
apc_request.func_arg= func_arg;
apc_request.done= FALSE;
apc_request.processed= FALSE;
(void)pthread_cond_init(&apc_request.COND_request, NULL);
(void)pthread_mutex_init(&apc_request.LOCK_request, MY_MUTEX_INIT_SLOW);
pthread_mutex_lock(&apc_request.LOCK_request);
......@@ -134,19 +167,19 @@ bool Apc_target::make_apc_call(apc_func_t func, void *func_arg,
int wait_res= 0;
/* todo: how about processing other errors here? */
while (!apc_request.done && (wait_res != ETIMEDOUT))
while (!apc_request.processed && (wait_res != ETIMEDOUT))
{
wait_res= pthread_cond_timedwait(&apc_request.COND_request,
&apc_request.LOCK_request, &abstime);
}
if (!apc_request.done)
if (!apc_request.processed)
{
/* We timed out */
apc_request.done= TRUE;
/* The wait has timed out. Remove the request from the queue */
apc_request.processed= TRUE;
*timed_out= TRUE;
pthread_mutex_unlock(&apc_request.LOCK_request);
//psergey-todo: "Whoa rare event" refers to this part, right? put a comment.
pthread_mutex_lock(&LOCK_apc_queue);
dequeue_request(&apc_request);
pthread_mutex_unlock(&LOCK_apc_queue);
......@@ -172,7 +205,8 @@ bool Apc_target::make_apc_call(apc_func_t func, void *func_arg,
/*
Process all APC requests
Process all APC requests.
This should be called periodically by the APC target thread.
*/
void Apc_target::process_apc_requests()
......@@ -191,7 +225,7 @@ void Apc_target::process_apc_requests()
request->what="seen by process_apc_requests";
pthread_mutex_lock(&request->LOCK_request);
if (request->done)
if (request->processed)
{
/*
We can get here when
......@@ -215,7 +249,7 @@ void Apc_target::process_apc_requests()
*/
request->what="dequeued by process_apc_requests";
dequeue_request(request);
request->done= TRUE;
request->processed= TRUE;
pthread_mutex_unlock(&LOCK_apc_queue);
......
......@@ -3,9 +3,18 @@
*/
/*
Design
- Mutex-guarded request queue (it belongs to the target), which can be enabled/
disabled (when empty).
Interface
~~~~~~~~~
(
- This is an APC request queue
- We assume there is a particular owner thread which periodically calls
process_apc_requests() to serve the call requests.
- Other threads can post call requests, and block until they are exectued.
)
Implementation
~~~~~~~~~~~~~~
- The target has a mutex-guarded request queue.
- After the request has been put into queue, the requestor waits for request
to be satisfied. The worker satisifes the request and signals the
......@@ -21,31 +30,11 @@ public:
Apc_target() : enabled(0), apc_calls(NULL) /*, call_queue_size(0)*/ {}
~Apc_target() { DBUG_ASSERT(!enabled && !apc_calls);}
/*
Initialize the target. This must be called before anything else. Right
after initialization, the target is disabled.
*/
void init();
/*
Destroy the target. The target must be disabled when this call is made.
*/
void destroy();
/*
Enter into state where this target will be serving APC requests
*/
void enable();
/*
Leave the state where we could serve APC requests (will serve all already
enqueued requests)
*/
void disable();
/*
This should be called periodically to serve observation requests.
*/
void process_apc_requests();
typedef void (*apc_func_t)(void *arg);
......@@ -68,18 +57,32 @@ public:
#endif
private:
class Call_request;
/*
Non-zero value means we're enabled. It's an int, not bool, because one can
call enable() N times (and then needs to call disable() N times before the
target is really disabled)
*/
int enabled;
/*
Circular, double-linked list of all enqueued call requests.
We use this structure, because we
- process requests sequentially
- a thread that has posted a request may time out (or be KILLed) and
cancel the request, which means we'll need to remove its request at
arbitrary point in time.
*/
Call_request *apc_calls;
pthread_mutex_t LOCK_apc_queue;
pthread_mutex_t LOCK_apc_queue;
class Call_request
{
public:
apc_func_t func;
void *func_arg;
bool done;
apc_func_t func; /* Function to call */
void *func_arg; /* Argument to pass it */
bool processed;
pthread_mutex_t LOCK_request;
pthread_cond_t COND_request;
......@@ -87,13 +90,15 @@ private:
Call_request *next;
Call_request *prev;
const char *what;
const char *what; /* State of the request */
};
void enqueue_request(Call_request *qe);
void dequeue_request(Call_request *qe);
/* return the first call request in queue, or NULL if there are none enqueued */
Call_request *get_first_in_queue()
{
{
return apc_calls;
}
};
......
......@@ -2015,6 +2015,11 @@ int THD::send_explain_fields(select_result *result)
}
/*
Populate the provided field_list with EXPLAIN output columns.
this->lex->describe has the EXPLAIN flags
*/
void THD::make_explain_field_list(List<Item> &field_list)
{
Item *item;
......@@ -3280,13 +3285,20 @@ void Show_explain_request::get_explain_data(void *arg)
//TODO: change mem_root to point to request_thd->mem_root.
// Actually, change the ARENA, because we're going to allocate items!
Query_arena backup_arena;
req->target_thd->set_n_backup_active_arena((Query_arena*)req->request_thd,
&backup_arena);
req->target_thd->lex->unit.print_explain(req->explain_buf);
THD *target_thd= req->target_thd;
req->target_thd->restore_active_arena((Query_arena*)req->request_thd,
target_thd->set_n_backup_active_arena((Query_arena*)req->request_thd,
&backup_arena);
req->query_str.copy(target_thd->query(),
target_thd->query_length(),
&my_charset_bin);
if (target_thd->lex->unit.print_explain(req->explain_buf, 0 /* explain flags */))
req->failed_to_produce= TRUE;
target_thd->restore_active_arena((Query_arena*)req->request_thd,
&backup_arena);
}
......
......@@ -1528,8 +1528,12 @@ public:
THD *target_thd;
THD *request_thd;
bool failed_to_produce;
select_result_explain_buffer *explain_buf;
String query_str;
static void get_explain_data(void *arg);
};
......
......@@ -2236,7 +2236,7 @@ enum_nested_loop_state JOIN_CACHE::join_matching_records(bool skip_last)
while (!(error= join_tab_scan->next()))
{
if (join->thd->killed)
if (join->thd->check_killed())
{
/* The user has aborted the execution of the query */
join->thd->send_kill_message();
......@@ -2506,7 +2506,7 @@ enum_nested_loop_state JOIN_CACHE::join_null_complements(bool skip_last)
for ( ; cnt; cnt--)
{
if (join->thd->killed)
if (join->thd->check_killed())
{
/* The user has aborted the execution of the query */
join->thd->send_kill_message();
......@@ -3356,7 +3356,7 @@ int JOIN_TAB_SCAN::next()
update_virtual_fields(thd, table);
while (!err && select && (skip_rc= select->skip_record(thd)) <= 0)
{
if (thd->killed || skip_rc < 0)
if (thd->check_killed() || skip_rc < 0)
return 1;
/*
Move to the next record if the last retrieved record does not
......
......@@ -3831,6 +3831,7 @@ void SELECT_LEX::update_used_tables()
/**
Set the EXPLAIN type for this subquery.
psergey-todo: comments about
*/
void st_select_lex::set_explain_type(bool on_the_fly)
......@@ -4072,16 +4073,32 @@ int print_explain_message_line(select_result_sink *result,
const char *message);
int st_select_lex::print_explain(select_result_sink *output)
int st_select_lex::print_explain(select_result_sink *output,
uint8 explain_flags)
{
int res;
if (join && join->have_query_plan == JOIN::QEP_AVAILABLE)
{
res= join->print_explain(output, TRUE,
FALSE, // need_tmp_table,
FALSE, // bool need_order,
FALSE, // bool distinct,
NULL); //const char *message
/*
There is a number of reasons join can be marked as degenerate, so all
three conditions below can happen simultaneously, or individually:
*/
if (!join->table_count || !join->tables_list || join->zero_result_cause)
{
/* It's a degenerate join */
const char *cause= join->zero_result_cause ? join-> zero_result_cause :
"No tables used";
res= join->print_explain(output, explain_flags, TRUE, FALSE, FALSE,
FALSE, cause);
}
else
{
res= join->print_explain(output, explain_flags, TRUE,
join->need_tmp, // need_tmp_table
(join->order != 0 && !join->skip_sort_order), // bool need_order
join->select_distinct, // bool distinct
NULL); //const char *message
}
if (res)
goto err;
......@@ -4095,7 +4112,7 @@ int st_select_lex::print_explain(select_result_sink *output)
*/
if (!(unit->item && unit->item->eliminated))
{
unit->print_explain(output);
unit->print_explain(output, explain_flags);
}
}
}
......@@ -4119,14 +4136,24 @@ err:
}
int st_select_lex_unit::print_explain(select_result_sink *output)
int st_select_lex_unit::print_explain(select_result_sink *output,
uint8 explain_flags)
{
int res= 0;
SELECT_LEX *first= first_select();
if (first && !first->next_select() && !first->join)
{
/*
If there is only one child, 'first', and it has join==NULL, emit "not in
EXPLAIN state" error.
*/
return 1;
}
for (SELECT_LEX *sl= first; sl; sl= sl->next_select())
{
if ((res= sl->print_explain(output)))
if ((res= sl->print_explain(output, explain_flags)))
break;
}
......@@ -4136,7 +4163,7 @@ int st_select_lex_unit::print_explain(select_result_sink *output)
if (fake_select_lex && !fake_select_lex->join)
{
res= print_fake_select_lex_join(output, TRUE /* on the fly */,
fake_select_lex, 0 /* flags */);
fake_select_lex, explain_flags);
}
return res;
}
......
......@@ -718,7 +718,7 @@ public:
friend int subselect_union_engine::exec();
List<Item> *get_unit_column_types();
int print_explain(select_result_sink *output);
int print_explain(select_result_sink *output, uint8 explain_flags);
};
typedef class st_select_lex_unit SELECT_LEX_UNIT;
......@@ -1039,7 +1039,7 @@ public:
bool save_prep_leaf_tables(THD *thd);
bool is_merged_child_of(st_select_lex *ancestor);
int print_explain(select_result_sink *output);
int print_explain(select_result_sink *output, uint8 explain_flags);
/*
For MODE_ONLY_FULL_GROUP_BY we need to maintain two flags:
- Non-aggregated fields are used in this select.
......
This diff is collapsed.
......@@ -896,6 +896,20 @@ protected:
public:
JOIN_TAB *join_tab, **best_ref;
/*
For "Using temporary+Using filesort" queries, JOIN::join_tab can point to
either:
1. array of join tabs describing how to run the select, or
2. array of single join tab describing read from the temporary table.
SHOW EXPLAIN code needs to read/show #1. This is why two next members are
there for saving it.
*/
JOIN_TAB *table_access_tabs;
uint top_table_access_tabs_count;
JOIN_TAB **map2table; ///< mapping between table indexes and JOIN_TABs
JOIN_TAB *join_tab_save; ///< saved join_tab for subquery reexecution
......@@ -1161,7 +1175,11 @@ public:
const char *zero_result_cause; ///< not 0 if exec must return zero result
bool union_part; ///< this subselect is part of union
bool optimized; ///< flag to avoid double optimization in EXPLAIN
enum join_optimization_state { NOT_OPTIMIZED=0,
OPTIMIZATION_IN_PROGRESS=1,
OPTIMIZATION_DONE=2};
bool optimized; ///< flag to avoid double optimization in EXPLAIN
bool initialized; ///< flag to avoid double init_execution calls
enum { QEP_NOT_PRESENT_YET, QEP_AVAILABLE, QEP_DELETED} have_query_plan;
......@@ -1393,7 +1411,8 @@ public:
return (unit->item && unit->item->is_in_predicate());
}
int print_explain(select_result_sink *result, bool on_the_fly,
int print_explain(select_result_sink *result, uint8 explain_flags,
bool on_the_fly,
bool need_tmp_table, bool need_order,
bool distinct,const char *message);
private:
......
......@@ -2062,16 +2062,33 @@ void mysqld_show_explain(THD *thd, ulong thread_id)
explain_req.explain_buf= explain_buf;
explain_req.target_thd= tmp;
explain_req.request_thd= thd;
explain_req.failed_to_produce= FALSE;
bres= tmp->apc_target.make_apc_call(Show_explain_request::get_explain_data,
(void*)&explain_req,
timeout_sec, &timed_out);
if (bres)
if (bres || explain_req.failed_to_produce)
{
/* TODO not enabled or time out */
my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0),
"SHOW EXPLAIN",
"Target is not running EXPLAINable command");
if (timed_out)
{
my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0),
"SHOW EXPLAIN",
"Timeout");
}
else
{
my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0),
"SHOW EXPLAIN",
"Target is not running EXPLAINable command");
}
bres= TRUE;
}
else
{
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_YES, explain_req.query_str.c_ptr_safe());
}
mysql_mutex_unlock(&tmp->LOCK_thd_data);
if (!bres)
......
......@@ -1106,7 +1106,12 @@ public:
See TABLE_LIST::process_index_hints().
*/
bool force_index_group;
bool distinct,const_table,no_rows, used_for_duplicate_elimination;
/*
TRUE<=> this table was created with create_tmp_table(... distinct=TRUE..)
call
*/
bool distinct;
bool const_table,no_rows, used_for_duplicate_elimination;
/**
If set, the optimizer has found that row retrieval should access index
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment