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
98a8642f
Commit
98a8642f
authored
Oct 07, 2013
by
Sergey Petrunya
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MDEV-3798: EXPLAIN UPDATE/DELETE
- Add support for EXPLAIN INSERT.
parent
69393db3
Changes
11
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
201 additions
and
62 deletions
+201
-62
mysql-test/r/explain_non_select.result
mysql-test/r/explain_non_select.result
+17
-0
mysql-test/t/explain_non_select.test
mysql-test/t/explain_non_select.test
+15
-0
sql/sp_head.cc
sql/sp_head.cc
+4
-0
sql/sql_delete.cc
sql/sql_delete.cc
+1
-13
sql/sql_explain.cc
sql/sql_explain.cc
+54
-5
sql/sql_explain.h
sql/sql_explain.h
+41
-7
sql/sql_insert.cc
sql/sql_insert.cc
+46
-1
sql/sql_parse.cc
sql/sql_parse.cc
+2
-16
sql/sql_select.cc
sql/sql_select.cc
+17
-5
sql/sql_select.h
sql/sql_select.h
+1
-1
sql/sql_update.cc
sql/sql_update.cc
+3
-14
No files found.
mysql-test/r/explain_non_select.result
View file @
98a8642f
...
...
@@ -181,3 +181,20 @@ explain partitions update t1 set b=12345 where a in (32,33);
id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No matching rows after partition pruning
drop table t1;
#
# Tests for EXPLAIN INSERT ... VALUES
#
create table t1 (a int, key(a));
explain insert into t1 values (1),(2),(3);
id select_type table type possible_keys key key_len ref rows Extra
1 INSERT t1 ALL NULL NULL NULL NULL NULL NULL
insert into t1 values (1),(2),(3);
create table t2 (a int, b int);
explain insert into t2 values
(10, 1+(select max(a) from t1)),
(11, 1+(select max(a+1) from t1));
id select_type table type possible_keys key key_len ref rows Extra
1 INSERT t2 ALL NULL NULL NULL NULL NULL NULL
3 SUBQUERY t1 index NULL a 5 NULL 3 Using index
2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
drop table t1,t2;
mysql-test/t/explain_non_select.test
View file @
98a8642f
...
...
@@ -155,3 +155,18 @@ explain partitions delete from t1 where a in (32,33);
explain
partitions
update
t1
set
b
=
12345
where
a
in
(
32
,
33
);
drop
table
t1
;
--
echo
#
--
echo
# Tests for EXPLAIN INSERT ... VALUES
--
echo
#
create
table
t1
(
a
int
,
key
(
a
));
explain
insert
into
t1
values
(
1
),(
2
),(
3
);
insert
into
t1
values
(
1
),(
2
),(
3
);
create
table
t2
(
a
int
,
b
int
);
explain
insert
into
t2
values
(
10
,
1
+
(
select
max
(
a
)
from
t1
)),
(
11
,
1
+
(
select
max
(
a
+
1
)
from
t1
));
drop
table
t1
,
t2
;
sql/sp_head.cc
View file @
98a8642f
...
...
@@ -328,6 +328,10 @@ sp_get_flags_for_command(LEX *lex)
}
case
SQLCOM_UPDATE
:
case
SQLCOM_UPDATE_MULTI
:
case
SQLCOM_INSERT
:
case
SQLCOM_REPLACE
:
case
SQLCOM_REPLACE_SELECT
:
case
SQLCOM_INSERT_SELECT
:
{
if
(
!
lex
->
describe
)
flags
=
0
;
...
...
sql/sql_delete.cc
View file @
98a8642f
...
...
@@ -680,19 +680,7 @@ cleanup:
/* Special exits */
exit_without_my_ok:
query_plan
.
save_explain_data
(
thd
->
lex
->
explain
);
select_send
*
result2
;
if
(
!
(
result2
=
new
select_send
()))
return
1
;
/* purecov: inspected */
List
<
Item
>
dummy
;
/* note: looked in 5.6 and they too use a dummy list like this */
result2
->
prepare
(
dummy
,
&
thd
->
lex
->
unit
);
thd
->
send_explain_fields
(
result2
);
int
err2
=
thd
->
lex
->
explain
->
print_explain
(
result2
,
thd
->
lex
->
describe
);
if
(
err2
)
result2
->
abort_result_set
();
else
result2
->
send_eof
();
int
err2
=
thd
->
lex
->
explain
->
send_explain
(
thd
);
delete
select
;
free_underlaid_joins
(
thd
,
select_lex
);
...
...
sql/sql_explain.cc
View file @
98a8642f
...
...
@@ -22,9 +22,8 @@
#include "sql_select.h"
Explain_query
::
Explain_query
()
Explain_query
::
Explain_query
()
:
upd_del_plan
(
NULL
),
insert_plan
(
NULL
)
{
upd_del_plan
=
NULL
;
operations
=
0
;
}
...
...
@@ -32,6 +31,7 @@ Explain_query::Explain_query()
Explain_query
::~
Explain_query
()
{
delete
upd_del_plan
;
delete
insert_plan
;
uint
i
;
for
(
i
=
0
;
i
<
unions
.
elements
();
i
++
)
delete
unions
.
at
(
i
);
...
...
@@ -100,6 +100,29 @@ void Explain_query::add_node(Explain_node *node)
}
/*
Send EXPLAIN output to the client.
*/
int
Explain_query
::
send_explain
(
THD
*
thd
)
{
select_result
*
result
;
LEX
*
lex
=
thd
->
lex
;
if
(
!
(
result
=
new
select_send
())
||
thd
->
send_explain_fields
(
result
))
return
1
;
int
res
;
if
((
res
=
print_explain
(
result
,
lex
->
describe
)))
result
->
abort_result_set
();
else
result
->
send_eof
();
return
res
;
}
/*
The main entry point to print EXPLAIN of the entire query
*/
...
...
@@ -112,6 +135,11 @@ int Explain_query::print_explain(select_result_sink *output,
upd_del_plan
->
print_explain
(
this
,
output
,
explain_flags
);
return
0
;
}
else
if
(
insert_plan
)
{
insert_plan
->
print_explain
(
this
,
output
,
explain_flags
);
return
0
;
}
else
{
/* Start printing from node with id=1 */
...
...
@@ -681,7 +709,7 @@ const char * Explain_quick_select::get_name_by_type()
return
"sort_intersect"
;
default:
DBUG_ASSERT
(
0
);
return
"
Oops
"
;
return
"
unknown quick select type
"
;
}
}
...
...
@@ -809,13 +837,34 @@ int Explain_update::print_explain(Explain_query *query,
key_str
.
length
()
?
key_str
.
c_ptr
()
:
NULL
,
key_len_str
.
length
()
?
key_len_str
.
c_ptr
()
:
NULL
,
NULL
,
/* 'ref' is always NULL in single-table EXPLAIN DELETE */
rows
,
&
rows
,
extra_str
.
c_ptr
());
return
print_explain_for_children
(
query
,
output
,
explain_flags
);
}
int
Explain_insert
::
print_explain
(
Explain_query
*
query
,
select_result_sink
*
output
,
uint8
explain_flags
)
{
const
char
*
select_type
=
"INSERT"
;
print_explain_row
(
output
,
explain_flags
,
1
,
/* id */
select_type
,
table_name
.
c_ptr
(),
NULL
,
// partitions
JT_ALL
,
NULL
,
// possible_keys
NULL
,
// key
NULL
,
// key_len
NULL
,
// ref
NULL
,
// rows
NULL
);
return
print_explain_for_children
(
query
,
output
,
explain_flags
);
}
void
delete_explain_query
(
LEX
*
lex
)
{
delete
lex
->
explain
;
...
...
sql/sql_explain.h
View file @
98a8642f
...
...
@@ -37,10 +37,16 @@ class Explain_query;
class
Explain_node
:
public
Sql_alloc
{
public:
enum
explain_node_type
{
EXPLAIN_UNION
,
EXPLAIN_SELECT
,
EXPLAIN_UPDATE
,
EXPLAIN_DELETE
};
virtual
enum
explain_node_type
get_type
()
=
0
;
enum
explain_node_type
{
EXPLAIN_UNION
,
EXPLAIN_SELECT
,
EXPLAIN_UPDATE
,
EXPLAIN_DELETE
,
EXPLAIN_INSERT
};
virtual
enum
explain_node_type
get_type
()
=
0
;
virtual
int
get_select_id
()
=
0
;
/*
...
...
@@ -172,8 +178,10 @@ public:
bool
using_filesort
;
};
class
Explain_delete
;
class
Explain_update
;
class
Explain_delete
;
class
Explain_insert
;
/*
Explain structure for a query (i.e. a statement).
...
...
@@ -229,14 +237,20 @@ public:
/* Explain_delete inherits from Explain_update */
Explain_update
*
upd_del_plan
;
/* Query "plan" for INSERTs */
Explain_insert
*
insert_plan
;
/* Produce a tabular EXPLAIN output */
int
print_explain
(
select_result_sink
*
output
,
uint8
explain_flags
);
/* Send tabular EXPLAIN to the client */
int
send_explain
(
THD
*
thd
);
/* Return tabular EXPLAIN output as a text string */
bool
print_explain_str
(
THD
*
thd
,
String
*
out_str
);
/* If true, at least part of EXPLAIN can be printed */
bool
have_query_plan
()
{
return
upd_del_plan
!=
NULL
||
get_node
(
1
)
!=
NULL
;
}
bool
have_query_plan
()
{
return
insert_plan
||
upd_del_plan
||
get_node
(
1
)
!=
NULL
;
}
MEM_ROOT
*
mem_root
;
private:
Dynamic_array
<
Explain_union
*>
unions
;
...
...
@@ -445,7 +459,7 @@ private:
/*
Query Plan Footprint
for single-table UPDATE.
EXPLAIN structure
for single-table UPDATE.
This is similar to Explain_table_access, except that it is more restrictive.
Also, it can have UPDATE operation options, but currently there aren't any.
...
...
@@ -483,7 +497,27 @@ public:
/*
Explain data of a single-table DELETE.
EXPLAIN data structure for an INSERT.
At the moment this doesn't do much as we don't really have any query plans
for INSERT statements.
*/
class
Explain_insert
:
public
Explain_node
{
public:
StringBuffer
<
64
>
table_name
;
enum
explain_node_type
get_type
()
{
return
EXPLAIN_INSERT
;
}
int
get_select_id
()
{
return
1
;
/* always root */
}
int
print_explain
(
Explain_query
*
query
,
select_result_sink
*
output
,
uint8
explain_flags
);
};
/*
EXPLAIN data of a single-table DELETE.
*/
class
Explain_delete
:
public
Explain_update
...
...
sql/sql_insert.cc
View file @
98a8642f
...
...
@@ -644,6 +644,36 @@ create_insert_stmt_from_insert_delayed(THD *thd, String *buf)
}
static
void
save_insert_query_plan
(
THD
*
thd
,
TABLE_LIST
*
table_list
)
{
Explain_insert
*
explain
=
new
Explain_insert
;
explain
->
table_name
.
append
(
table_list
->
table
->
alias
);
thd
->
lex
->
explain
->
insert_plan
=
explain
;
/* See Update_plan::updating_a_view for details */
bool
skip
=
test
(
table_list
->
view
);
/* Save subquery children */
for
(
SELECT_LEX_UNIT
*
unit
=
thd
->
lex
->
select_lex
.
first_inner_unit
();
unit
;
unit
=
unit
->
next_unit
())
{
if
(
skip
)
{
skip
=
false
;
continue
;
}
/*
Table elimination doesn't work for INSERTS, but let's still have this
here for consistency
*/
if
(
!
(
unit
->
item
&&
unit
->
item
->
eliminated
))
explain
->
add_child
(
unit
->
first_select
()
->
select_number
);
}
}
/**
INSERT statement implementation
...
...
@@ -660,6 +690,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
enum_duplicates
duplic
,
bool
ignore
)
{
bool
retval
=
true
;
int
error
,
res
;
bool
transactional_table
,
joins_freed
=
FALSE
;
bool
changed
;
...
...
@@ -781,6 +812,17 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
/* Restore the current context. */
ctx_state
.
restore_state
(
context
,
table_list
);
if
(
thd
->
lex
->
unit
.
first_select
()
->
optimize_unflattened_subqueries
(
false
))
{
goto
abort
;
}
save_insert_query_plan
(
thd
,
table_list
);
if
(
thd
->
lex
->
describe
)
{
retval
=
0
;
goto
exit_without_my_ok
;
}
/*
Fill in the given fields and dump it to the table file
*/
...
...
@@ -1128,16 +1170,19 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
DBUG_RETURN
(
FALSE
);
abort:
exit_without_my_ok:
#ifndef EMBEDDED_LIBRARY
if
(
lock_type
==
TL_WRITE_DELAYED
)
end_delayed_insert
(
thd
);
#endif
if
(
table
!=
NULL
)
table
->
file
->
ha_release_auto_increment
();
retval
=
thd
->
lex
->
explain
->
send_explain
(
thd
);
if
(
!
joins_freed
)
free_underlaid_joins
(
thd
,
&
thd
->
lex
->
select_lex
);
thd
->
abort_on_warning
=
0
;
DBUG_RETURN
(
TRUE
);
DBUG_RETURN
(
retval
);
}
...
...
sql/sql_parse.cc
View file @
98a8642f
...
...
@@ -3245,14 +3245,7 @@ end_with_restore_list:
}
if
(
!
res
&&
explain
)
{
select_result
*
result
=
new
select_send
();
LEX
*
lex
=
thd
->
lex
;
if
(
thd
->
send_explain_fields
(
result
)
||
lex
->
explain
->
print_explain
(
result
,
lex
->
describe
)
||
result
->
send_eof
())
res
=
1
;
}
res
=
thd
->
lex
->
explain
->
send_explain
(
thd
);
/* revert changes for SP */
MYSQL_INSERT_SELECT_DONE
(
res
,
(
ulong
)
thd
->
get_row_count_func
());
...
...
@@ -3341,14 +3334,7 @@ end_with_restore_list:
else
{
if
(
explain
)
{
select_result
*
result
=
new
select_send
();
LEX
*
lex
=
thd
->
lex
;
if
(
thd
->
send_explain_fields
(
result
)
||
lex
->
explain
->
print_explain
(
result
,
lex
->
describe
)
||
result
->
send_eof
())
res
=
1
;
}
res
=
thd
->
lex
->
explain
->
send_explain
(
thd
);
}
delete
result
;
}
...
...
sql/sql_select.cc
View file @
98a8642f
...
...
@@ -22238,7 +22238,10 @@ int print_explain_message_line(select_result_sink *result,
if
(
options
&
DESCRIBE_EXTENDED
)
item_list
.
push_back
(
item_null
);
if
(
message
)
item_list
.
push_back
(
new
Item_string
(
message
,
strlen
(
message
),
cs
));
else
item_list
.
push_back
(
item_null
);
if
(
result
->
send_data
(
item_list
))
return
1
;
...
...
@@ -22292,7 +22295,7 @@ int print_explain_row(select_result_sink *result,
const
char
*
index
,
const
char
*
key_len
,
const
char
*
ref
,
ha_rows
rows
,
ha_rows
*
rows
,
const
char
*
extra
)
{
const
CHARSET_INFO
*
cs
=
system_charset_info
;
...
...
@@ -22337,15 +22340,24 @@ int print_explain_row(select_result_sink *result,
item_list
.
push_back
(
item
);
/* 'rows' */
item_list
.
push_back
(
new
Item_int
(
rows
,
if
(
rows
)
{
item_list
.
push_back
(
new
Item_int
(
*
rows
,
MY_INT64_NUM_DECIMAL_DIGITS
));
}
else
item_list
.
push_back
(
item_null
);
/* 'filtered' */
const
double
filtered
=
100.0
;
if
(
options
&
DESCRIBE_EXTENDED
)
item_list
.
push_back
(
new
Item_float
(
filtered
,
2
));
/* 'Extra' */
if
(
extra
)
item_list
.
push_back
(
new
Item_string
(
extra
,
strlen
(
extra
),
cs
));
else
item_list
.
push_back
(
item_null
);
if
(
result
->
send_data
(
item_list
))
return
1
;
...
...
sql/sql_select.h
View file @
98a8642f
...
...
@@ -1865,7 +1865,7 @@ int print_explain_row(select_result_sink *result,
const
char
*
index
,
const
char
*
key_len
,
const
char
*
ref
,
ha_rows
rows
,
ha_rows
*
rows
,
const
char
*
extra
);
void
make_possible_keys_line
(
TABLE
*
table
,
key_map
possible_keys
,
String
*
line
);
...
...
sql/sql_update.cc
View file @
98a8642f
...
...
@@ -948,7 +948,7 @@ int mysql_update(THD *thd,
if
(
!
transactional_table
&&
updated
>
0
)
thd
->
transaction
.
stmt
.
modified_non_trans_table
=
TRUE
;
thd
->
apc_target
.
disable
();
//psergey-todo.
thd
->
apc_target
.
disable
();
apc_target_enabled
=
false
;
end_read_record
(
&
info
);
delete
select
;
...
...
@@ -1036,18 +1036,7 @@ exit_without_my_ok:
DBUG_ASSERT
(
!
apc_target_enabled
);
query_plan
.
save_explain_data
(
thd
->
lex
->
explain
);
select_send
*
result
;
if
(
!
(
result
=
new
select_send
()))
return
1
;
/* purecov: inspected */
List
<
Item
>
dummy
;
/* note: looked in 5.6 and they too use a dummy list like this */
result
->
prepare
(
dummy
,
&
thd
->
lex
->
unit
);
thd
->
send_explain_fields
(
result
);
int
err2
=
thd
->
lex
->
explain
->
print_explain
(
result
,
thd
->
lex
->
describe
);
if
(
err2
)
result
->
abort_result_set
();
else
result
->
send_eof
();
int
err2
=
thd
->
lex
->
explain
->
send_explain
(
thd
);
delete
select
;
free_underlaid_joins
(
thd
,
select_lex
);
...
...
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