Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mariadb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
34e9a4c1
Commit
34e9a4c1
authored
May 17, 2012
by
Sergey Petrunya
Browse files
Options
Browse Files
Download
Plain Diff
Merge of recent changes in MWL#182 in 5.3 with {Merge of MWL#182 with 5.5}
parents
dfbd777f
483ae4bf
Changes
15
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
942 additions
and
125 deletions
+942
-125
mysql-test/r/show_explain.result
mysql-test/r/show_explain.result
+383
-2
mysql-test/t/show_explain.test
mysql-test/t/show_explain.test
+301
-4
sql/filesort.cc
sql/filesort.cc
+16
-9
sql/item_subselect.cc
sql/item_subselect.cc
+1
-0
sql/my_apc.cc
sql/my_apc.cc
+45
-11
sql/my_apc.h
sql/my_apc.h
+34
-29
sql/sql_class.cc
sql/sql_class.cc
+17
-5
sql/sql_class.h
sql/sql_class.h
+4
-0
sql/sql_join_cache.cc
sql/sql_join_cache.cc
+3
-3
sql/sql_lex.cc
sql/sql_lex.cc
+37
-10
sql/sql_lex.h
sql/sql_lex.h
+2
-2
sql/sql_select.cc
sql/sql_select.cc
+51
-43
sql/sql_select.h
sql/sql_select.h
+21
-2
sql/sql_show.cc
sql/sql_show.cc
+21
-4
sql/table.h
sql/table.h
+6
-1
No files found.
mysql-test/r/show_explain.result
View file @
34e9a4c1
This diff is collapsed.
Click to expand it.
mysql-test/t/show_explain.test
View file @
34e9a4c1
...
...
@@ -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.
...
...
sql/filesort.cc
View file @
34e9a4c1
...
...
@@ -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= ¤t_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= ¬_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 */
}
...
...
sql/item_subselect.cc
View file @
34e9a4c1
...
...
@@ -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
())))
...
...
sql/my_apc.cc
View file @
34e9a4c1
...
...
@@ -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
);
...
...
sql/my_apc.h
View file @
34e9a4c1
...
...
@@ -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
;
}
};
...
...
sql/sql_class.cc
View file @
34e9a4c1
...
...
@@ -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
);
}
...
...
sql/sql_class.h
View file @
34e9a4c1
...
...
@@ -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
);
};
...
...
sql/sql_join_cache.cc
View file @
34e9a4c1
...
...
@@ -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
...
...
sql/sql_lex.cc
View file @
34e9a4c1
...
...
@@ -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
;
}
...
...
sql/sql_lex.h
View file @
34e9a4c1
...
...
@@ -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.
...
...
sql/sql_select.cc
View file @
34e9a4c1
This diff is collapsed.
Click to expand it.
sql/sql_select.h
View file @
34e9a4c1
...
...
@@ -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:
...
...
sql/sql_show.cc
View file @
34e9a4c1
...
...
@@ -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
)
...
...
sql/table.h
View file @
34e9a4c1
...
...
@@ -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
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment