summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libmysqld/CMakeLists.txt1
-rw-r--r--mysql-test/disabled.def2
-rw-r--r--mysql-test/include/explain_non_select.inc833
-rw-r--r--mysql-test/include/explain_utils.inc161
-rw-r--r--mysql-test/r/derived_opt.result4
-rw-r--r--mysql-test/r/derived_view.result14
-rw-r--r--mysql-test/r/explain_non_select.result221
-rw-r--r--mysql-test/r/explain_slowquerylog.result41
-rw-r--r--mysql-test/r/grant_explain_non_select.result178
-rw-r--r--mysql-test/r/limit_rows_examined.result2
-rw-r--r--mysql-test/r/myisam_explain_non_select_all.result2907
-rw-r--r--mysql-test/r/mysqld--help.result2
-rw-r--r--mysql-test/r/selectivity.result4
-rw-r--r--mysql-test/r/selectivity_innodb.result4
-rw-r--r--mysql-test/r/show_explain.result113
-rw-r--r--mysql-test/r/show_explain_non_select.result44
-rw-r--r--mysql-test/r/subselect.result14
-rw-r--r--mysql-test/r/subselect2.result4
-rw-r--r--mysql-test/r/subselect3.result2
-rw-r--r--mysql-test/r/subselect3_jcl6.result2
-rw-r--r--mysql-test/r/subselect4.result16
-rw-r--r--mysql-test/r/subselect_exists_to_in.result14
-rw-r--r--mysql-test/r/subselect_no_mat.result14
-rw-r--r--mysql-test/r/subselect_no_opts.result14
-rw-r--r--mysql-test/r/subselect_no_scache.result14
-rw-r--r--mysql-test/r/subselect_no_semijoin.result14
-rw-r--r--mysql-test/r/subselect_sj.result6
-rw-r--r--mysql-test/r/subselect_sj_jcl6.result6
-rw-r--r--mysql-test/r/table_elim.result24
-rw-r--r--mysql-test/r/view.result6
-rw-r--r--mysql-test/suite/sys_vars/r/log_slow_verbosity_basic.result28
-rw-r--r--mysql-test/suite/sys_vars/t/log_slow_verbosity_basic.test16
-rw-r--r--mysql-test/t/explain_non_select.test200
-rw-r--r--mysql-test/t/explain_slowquerylog-master.opt1
-rw-r--r--mysql-test/t/explain_slowquerylog.test49
-rw-r--r--mysql-test/t/grant_explain_non_select.test258
-rw-r--r--mysql-test/t/myisam_explain_non_select_all.test21
-rw-r--r--mysql-test/t/show_explain.test60
-rw-r--r--mysql-test/t/show_explain_non_select.test78
-rw-r--r--sql/CMakeLists.txt1
-rw-r--r--sql/log.cc9
-rw-r--r--sql/log_event.cc1
-rw-r--r--sql/log_event_old.cc1
-rw-r--r--sql/log_slow.h1
-rw-r--r--sql/my_apc.cc1
-rw-r--r--sql/my_apc.h2
-rw-r--r--sql/opt_range.cc140
-rw-r--r--sql/opt_range.h30
-rw-r--r--sql/sp_head.cc27
-rw-r--r--sql/sql_array.h18
-rw-r--r--sql/sql_class.cc1
-rw-r--r--sql/sql_class.h29
-rw-r--r--sql/sql_delete.cc247
-rw-r--r--sql/sql_explain.cc954
-rw-r--r--sql/sql_explain.h550
-rw-r--r--sql/sql_insert.cc49
-rw-r--r--sql/sql_join_cache.cc43
-rw-r--r--sql/sql_join_cache.h7
-rw-r--r--sql/sql_lex.cc164
-rw-r--r--sql/sql_lex.h106
-rw-r--r--sql/sql_parse.cc115
-rw-r--r--sql/sql_prepare.cc16
-rw-r--r--sql/sql_select.cc750
-rw-r--r--sql/sql_select.h54
-rw-r--r--sql/sql_show.cc84
-rw-r--r--sql/sql_string.h32
-rw-r--r--sql/sql_union.cc9
-rw-r--r--sql/sql_update.cc121
-rw-r--r--sql/sql_view.cc3
-rw-r--r--sql/sql_yacc.yy11
-rw-r--r--sql/sys_vars.cc5
-rwxr-xr-xsupport-files/build-tags2
72 files changed, 8289 insertions, 686 deletions
diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt
index 874428d456c..1f8db33994e 100644
--- a/libmysqld/CMakeLists.txt
+++ b/libmysqld/CMakeLists.txt
@@ -102,6 +102,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
../sql/sql_expression_cache.cc
../sql/my_apc.cc ../sql/my_apc.h
../sql/rpl_gtid.cc
+ ../sql/sql_explain.cc ../sql/sql_explain.h
../sql/compat56.cc
../sql/table_cache.cc
${GEN_SOURCES}
diff --git a/mysql-test/disabled.def b/mysql-test/disabled.def
index 6d84b8ce0f4..e5fa24786e1 100644
--- a/mysql-test/disabled.def
+++ b/mysql-test/disabled.def
@@ -16,7 +16,7 @@ read_many_rows_innodb : Bug#11748886 2010-11-15 mattiasj report already exist
archive-big : Bug#11817185 2011-03-10 Anitha Disabled since this leads to timeout on Solaris Sparc
log_tables-big : Bug#11756699 2010-11-15 mattiasj report already exists
mysql_embedded : Bug#12561297 2011-05-14 Anitha Dependent on PB2 changes - eventum#41836
+#show_explain : Psergey: random timeout in range-checked-for-each record query.
ssl_crl_clients_valid : broken upstream
ssl_crl : broken upstream
ssl_crl_clrpath : broken upstream
-show_explain : Psergey: random timeout in range-checked-for-each record query.
diff --git a/mysql-test/include/explain_non_select.inc b/mysql-test/include/explain_non_select.inc
new file mode 100644
index 00000000000..a0f86e744b0
--- /dev/null
+++ b/mysql-test/include/explain_non_select.inc
@@ -0,0 +1,833 @@
+# This file is a collection of regression and coverage tests
+# for WL#4897: Add EXPLAIN INSERT/UPDATE/DELETE.
+
+-- disable_query_log
+-- disable_result_log
+# SET GLOBAL innodb_stats_persistent=0;
+-- enable_result_log
+-- enable_query_log
+
+# set end_markers_in_json=on;
+
+--echo #1
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+--let $query = UPDATE t1 SET a = 10 WHERE a < 10
+--let $select = SELECT * FROM t1 WHERE a < 10
+--source include/explain_utils.inc
+DROP TABLE t1;
+
+--echo #2
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+--let $query = DELETE FROM t1 WHERE a < 10
+--let $select = SELECT * FROM t1 WHERE a < 10
+--source include/explain_utils.inc
+DROP TABLE t1;
+
+--echo #3
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+--let $query = DELETE FROM t1 USING t1 WHERE a = 1
+--let $select = SELECT * FROM t1 WHERE a = 1
+--source include/explain_utils.inc
+DROP TABLE t1;
+
+--echo #4
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TABLE t2 (b INT);
+INSERT INTO t2 VALUES (1), (2), (3);
+--let $query = UPDATE t1, t2 SET t1.a = 10 WHERE t1.a = 1
+--let $select = SELECT * FROM t1, t2 WHERE t1.a = 1
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #5
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TABLE t2 (b INT);
+INSERT INTO t2 VALUES (1), (2), (3);
+--let $query = UPDATE t1 t11, (SELECT * FROM t2) t12 SET t11.a = 10 WHERE t11.a = 1
+--let $select = SELECT * FROM t1 t11, (SELECT * FROM t2) t12 WHERE t11.a = 1
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #6
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TABLE t2 (b INT);
+INSERT INTO t2 VALUES (1), (2), (3);
+--let $query = UPDATE t1 SET a = 10 WHERE 1 IN (SELECT 1 FROM t2 WHERE t2.b < 3)
+--let $select = SELECT * FROM t1 WHERE 1 IN (SELECT 1 FROM t2 WHERE t2.b < 3)
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #7
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TABLE t2 (b INT);
+INSERT INTO t2 VALUES (1), (2), (3);
+--let $query = UPDATE t1 SET a = 10 WHERE a IN (SELECT b FROM t2 WHERE t1.a < 3)
+--let $select = SELECT * FROM t1 WHERE a IN (SELECT b FROM t2 WHERE t1.a < 3)
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #7
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TABLE t2 (b INT);
+INSERT INTO t2 VALUES (1), (2), (3);
+--let $query = UPDATE t1, t2 SET a = 10 WHERE a IN (SELECT b FROM t2 WHERE t2.b < 3)
+--let $select = SELECT * FROM t1, t2 WHERE a IN (SELECT b FROM t2 WHERE t2.b < 3)
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #8
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TABLE t2 (b INT);
+INSERT INTO t2 VALUES (1), (2), (3);
+--let $query = UPDATE t1 t11, (SELECT * FROM t2) t12 SET t11.a = t11.a + 10
+--let $select = SELECT * FROM t1 t11, (SELECT * FROM t2) t12
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #9
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TABLE t2 (b INT);
+INSERT INTO t2 VALUES (1), (2), (3);
+--let $query = UPDATE t1 t11, (SELECT 1 FROM DUAL) t12 SET t11.a = t11.a + 10
+--let $select = SELECT * FROM t1 t11, (SELECT 1 FROM DUAL) t12
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #10
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TABLE t2 (b INT);
+INSERT INTO t2 VALUES (1), (2), (3);
+--let $query = UPDATE t1 t11, (SELECT * FROM t2) t12 SET t11.a = 10 WHERE t11.a > 1
+--let $select = SELECT * FROM t1 t11, (SELECT * FROM t2) t12 WHERE t11.a > 1
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #11
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+--let $query = DELETE FROM t1 WHERE a > 1 LIMIT 1
+--let $select = SELECT * FROM t1 WHERE a > 1 LIMIT 1
+--source include/explain_utils.inc
+DROP TABLE t1;
+
+--echo #12
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+--let $query = DELETE FROM t1 WHERE 0
+--let $select = SELECT * FROM t1 WHERE 0
+--source include/explain_utils.inc
+DROP TABLE t1;
+
+--echo #13
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+--let $query = DELETE FROM t1 USING t1 WHERE 0
+--let $select = SELECT * FROM t1 WHERE 0
+--source include/explain_utils.inc
+DROP TABLE t1;
+
+--echo #14
+CREATE TABLE t1 (a INT, b INT, UNIQUE KEY (a), KEY (b));
+INSERT INTO t1 VALUES (3, 3), (7, 7);
+--let $query = DELETE FROM t1 WHERE a = 3
+--let $select = SELECT * FROM t1 WHERE a = 3
+--source include/explain_utils.inc
+DROP TABLE t1;
+
+--echo #15
+CREATE TABLE t1 (a INT, b INT, UNIQUE KEY (a), KEY (b));
+INSERT INTO t1 VALUES (3, 3), (7, 7);
+--let $query = DELETE FROM t1 WHERE a < 3
+--let $select = SELECT * FROM t1 WHERE a < 3
+--source include/explain_utils.inc
+DROP TABLE t1;
+
+--echo #16
+CREATE TABLE t1 ( a int PRIMARY KEY );
+--let $query = DELETE FROM t1 WHERE t1.a > 0 ORDER BY t1.a
+--let $select = SELECT * FROM t1 WHERE t1.a > 0 ORDER BY t1.a
+--source include/explain_utils.inc
+INSERT INTO t1 VALUES (1), (2), (3);
+--let $query = DELETE FROM t1 WHERE t1.a > 0 ORDER BY t1.a
+--let $select = SELECT * FROM t1 WHERE t1.a > 0 ORDER BY t1.a
+--source include/explain_utils.inc
+DROP TABLE t1;
+
+--echo #17
+CREATE TABLE t1(a INT PRIMARY KEY);
+INSERT INTO t1 VALUES (4),(3),(1),(2);
+--let $query = DELETE FROM t1 WHERE (@a:= a) ORDER BY a LIMIT 1
+--let $select = SELECT * FROM t1 WHERE (@a:= a) ORDER BY a LIMIT 1
+--source include/explain_utils.inc
+DROP TABLE t1;
+
+--echo #18
+CREATE TABLE t1 (a DATE, b TIME, c INT, KEY c(c), KEY b(b), KEY a(a));
+INSERT INTO t1 VALUES (), (), (), (), (), (), (), (), (), ();
+UPDATE t1 SET a = c, b = c;
+--let $query = DELETE FROM t1 ORDER BY a ASC, b ASC LIMIT 1
+--let $select = SELECT * FROM t1 ORDER BY a ASC, b ASC LIMIT 1
+--source include/explain_utils.inc
+DROP TABLE t1;
+
+--echo #19
+CREATE TABLE t1 (a1 INT NOT NULL, b1 INT NOT NULL);
+CREATE TABLE t2 (a2 INT NOT NULL, b2 INT NOT NULL, PRIMARY KEY (a2,b2));
+CREATE TABLE t3 (a3 INT NOT NULL, b3 INT NOT NULL, PRIMARY KEY (a3,b3));
+INSERT INTO t1 VALUES (1,1), (2,1), (1,3);
+INSERT INTO t2 VALUES (1,1), (2,2), (3,3);
+INSERT INTO t3 VALUES (1,1), (2,1), (1,3);
+--let $query = DELETE t1,t2,t3 FROM t1,t2,t3 WHERE a1=a2 AND b2=a3 AND b1=b3
+--let $select = SELECT * FROM t1,t2,t3 WHERE a1=a2 AND b2=a3 AND b1=b3
+--source include/explain_utils.inc
+DROP TABLE t1, t2, t3;
+
+--echo #20
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TABLE t2 (a INT);
+INSERT INTO t2 VALUES (1), (2), (3);
+--let $query = UPDATE t1 SET a = 10 WHERE a IN (SELECT a FROM t2)
+--let $select = SELECT * FROM t1 WHERE a IN (SELECT a FROM t2)
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #21
+CREATE TABLE t1 (a1 INT);
+INSERT INTO t1 VALUES (1), (2), (3), (4), (5);
+CREATE TABLE t2 (a2 VARCHAR(10));
+INSERT INTO t2 VALUES (1), (2), (3), (4), (5);
+SET @save_optimizer_switch= @@optimizer_switch;
+--disable_query_log
+if (`select locate('semijoin', @@optimizer_switch) > 0`)
+{
+ SET @@optimizer_switch= 'semijoin=off';
+}
+--enable_query_log
+--let $query = DELETE FROM t1 WHERE a1 IN (SELECT a2 FROM t2 WHERE a2 > 2)
+--let $select = SELECT * FROM t1 WHERE a1 IN (SELECT a2 FROM t2 WHERE a2 > 2)
+--source include/explain_utils.inc
+SET @@optimizer_switch= @save_optimizer_switch;
+TRUNCATE t1;
+INSERT INTO t1 VALUES (1), (2), (3), (4), (5);
+--let $query = DELETE FROM t1 WHERE a1 IN (SELECT a2 FROM t2 WHERE a2 > 2)
+--let $select = SELECT * FROM t1 WHERE a1 IN (SELECT a2 FROM t2 WHERE a2 > 2)
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #22
+CREATE TABLE t1 (i INT, j INT);
+INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5);
+--let $query = UPDATE t1 SET i = 10
+--let $select = SELECT * FROM t1
+--source include/explain_utils.inc
+DROP TABLE t1;
+
+--echo #23
+CREATE TABLE t1 (i INT, j INT);
+INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5);
+--let $query = DELETE FROM t1
+--let $select = SELECT * FROM t1
+--source include/explain_utils.inc
+DROP TABLE t1;
+
+--echo #24
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+ (20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+ (30),(31),(32),(33),(34),(35);
+CREATE TABLE t2(a INT, b INT, c INT, d INT, INDEX(a, b, c));
+INSERT INTO t2 (a, b, c) SELECT i, i, i FROM t1;
+INSERT INTO t2 (a, b, c) SELECT t1.i, t1.i, t1.i FROM t1, t1 x1, t1 x2;
+--let $query = DELETE FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+--let $select = SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+--let $no_rows = 1
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #25
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TABLE t2 (i INT);
+--let $query = INSERT INTO t2 SELECT * FROM t1
+--let $select = SELECT * FROM t1
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #26
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TABLE t2 (i INT);
+--let $query = REPLACE INTO t2 SELECT * FROM t1
+--let $select = SELECT * FROM t1
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #27
+CREATE TABLE t1 (i INT);
+--let $query = INSERT INTO t1 SET i = 10
+--source include/explain_utils.inc
+DROP TABLE t1;
+
+--echo #28
+CREATE TABLE t1 (i INT);
+--let $query = REPLACE INTO t1 SET i = 10
+--source include/explain_utils.inc
+DROP TABLE t1;
+
+--echo #29
+CREATE TABLE t1 (a INT, i INT PRIMARY KEY);
+INSERT INTO t1 (i) VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+ (20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+ (30),(31),(32),(33),(34),(35);
+--let $query = DELETE FROM t1 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5
+--let $select = SELECT * FROM t1 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5
+--source include/explain_utils.inc
+DROP TABLE t1;
+
+--echo #30
+CREATE TABLE t1(a INT, i CHAR(2), INDEX(i(1)));
+INSERT INTO t1 (i) VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+ (20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+ (30),(31),(32),(33),(34),(35);
+--let $query = DELETE FROM t1 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5
+--let $select = SELECT * FROM t1 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5
+--source include/explain_utils.inc
+DROP TABLE t1;
+
+--echo #31
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 (i) VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+ (20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+ (30),(31),(32),(33),(34),(35);
+CREATE TABLE t2(a INT, b INT, c INT, d INT, INDEX(a, b, c));
+INSERT INTO t2 (a, b, c) SELECT i, i, i FROM t1;
+--let $query = DELETE FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+--let $select = SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #32
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 (i) VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+ (20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+ (30),(31),(32),(33),(34),(35);
+CREATE TABLE t2(a INT, b INT, c INT, d INT, INDEX(a, b, c));
+INSERT INTO t2 (a, b, c) SELECT i, i, i FROM t1;
+INSERT INTO t2 (a, b, c) SELECT t1.i, t1.i, t1.i FROM t1, t1 x1, t1 x2;
+--let $query = DELETE FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+--let $select = SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+--let $no_rows = 1
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #33
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 (i) VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+ (20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+ (30),(31),(32),(33),(34),(35);
+CREATE TABLE t2 (a CHAR(2), b CHAR(2), c CHAR(2), d CHAR(2), INDEX (a,b(1),c));
+INSERT INTO t2 SELECT i, i, i, i FROM t1;
+--let $query = DELETE FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+--let $select = SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #34
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 (i) VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+ (20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+ (30),(31),(32),(33),(34),(35);
+CREATE TABLE t2 (a CHAR(2), b CHAR(2), c CHAR(2), d CHAR(2), INDEX (a,b,c))
+ ENGINE=HEAP;
+INSERT INTO t2 SELECT i, i, i, i FROM t1;
+--let $query = DELETE FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+--let $select = SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #35
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 (i) VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+ (20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+ (30),(31),(32),(33),(34),(35),(36),(37),(38),(39),
+ (40),(41),(42);
+CREATE TABLE t2 (i INT, key1 INT, key2 INT, INDEX (key1), INDEX (key2));
+INSERT INTO t2 (key1, key2) SELECT i, i FROM t1;
+--let $query = DELETE FROM t2 WHERE key1 < 13 or key2 < 14 ORDER BY key1
+--let $select = SELECT * FROM t2 WHERE key1 < 13 or key2 < 14 ORDER BY key1
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #36
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 (i) VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+ (20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+ (30),(31),(32),(33),(34),(35);
+CREATE TABLE t2(a INT, i INT PRIMARY KEY);
+INSERT INTO t2 (i) SELECT i FROM t1;
+--let $query = DELETE FROM t2 WHERE i > 10 AND i <= 18 ORDER BY i DESC LIMIT 5
+--let $select = SELECT * FROM t2 WHERE i > 10 AND i <= 18 ORDER BY i DESC LIMIT 5
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #37
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 (i) VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+ (20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+ (30),(31),(32),(33),(34),(35);
+CREATE TABLE t2 (a CHAR(2), b CHAR(2), c CHAR(2), INDEX (a, b));
+INSERT INTO t2 SELECT i, i, i FROM t1;
+--let $query = DELETE FROM t2 ORDER BY a, b DESC LIMIT 5
+--let $select = SELECT * FROM t2 ORDER BY a, b DESC LIMIT 5
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #38
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+ (20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+ (30),(31),(32),(33),(34),(35);
+CREATE TABLE t2 (a CHAR(2), b CHAR(2), c INT, INDEX (a, b));
+INSERT INTO t2 (a, b) SELECT i, i FROM t1;
+INSERT INTO t2 (a, b) SELECT t1.i, t1.i FROM t1, t1 x1, t1 x2;
+--let $query = DELETE FROM t2 ORDER BY a DESC, b DESC LIMIT 5
+--let $select = SELECT * FROM t2 ORDER BY a DESC, b DESC LIMIT 5
+--let $no_rows = 1
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #39
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+ (20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+ (30),(31),(32),(33),(34),(35);
+CREATE TABLE t2(a INT, i INT PRIMARY KEY);
+INSERT INTO t2 (i) SELECT i FROM t1;
+--let $query = UPDATE t2 SET a = 10 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5
+--let $select = SELECT * FROM t2 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5
+--let $no_rows = 1
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #40
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+ (20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+ (30),(31),(32),(33),(34),(35);
+CREATE TABLE t2(a INT, i CHAR(2), INDEX(i(1)));
+INSERT INTO t2 (i) SELECT i FROM t1;
+--let $query = UPDATE t2 SET a = 10 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5
+--let $select = SELECT * FROM t2 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #41
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+ (20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+ (30),(31),(32),(33),(34),(35);
+CREATE TABLE t2(a INT, b INT, c INT, d INT, INDEX(a, b, c));
+INSERT INTO t2 (a, b, c) SELECT i, i, i FROM t1;
+--let $query = UPDATE t2 SET d = 10 WHERE b = 10 ORDER BY a, c LIMIT 5
+--let $select = SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #42
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+ (20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+ (30),(31),(32),(33),(34),(35);
+CREATE TABLE t2(a INT, b INT, c INT, d INT, INDEX(a, b, c));
+INSERT INTO t2 (a, b, c) SELECT i, i, i FROM t1;
+INSERT INTO t2 (a, b, c) SELECT t1.i, t1.i, t1.i FROM t1, t1 x1, t1 x2;
+--let $query = UPDATE t2 SET d = 10 WHERE b = 10 ORDER BY a, c LIMIT 5
+--let $select = SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+--let $no_rows = 1
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #43
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+ (20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+ (30),(31),(32),(33),(34),(35);
+CREATE TABLE t2 (a CHAR(2), b CHAR(2), c CHAR(2), d CHAR(2), INDEX (a,b(1),c));
+INSERT INTO t2 SELECT i, i, i, i FROM t1;
+--let $query = UPDATE t2 SET d = 10 WHERE b = 10 ORDER BY a, c LIMIT 5
+--let $select = SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #44
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+ (20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+ (30),(31),(32),(33),(34),(35);
+CREATE TABLE t2 (a CHAR(2), b CHAR(2), c CHAR(2), d CHAR(2), INDEX (a,b,c))
+ ENGINE=HEAP;
+INSERT INTO t2 SELECT i, i, i, i FROM t1;
+--let $query = UPDATE t2 SET d = 10 WHERE b = 10 ORDER BY a, c LIMIT 5
+--let $select = SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #45
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+ (20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+ (30),(31),(32),(33),(34),(35),(36),(37),(38),(39),
+ (40),(41),(42);
+CREATE TABLE t2 (i INT, key1 INT, key2 INT, INDEX (key1), INDEX (key2));
+INSERT INTO t2 (key1, key2) SELECT i, i FROM t1;
+--let $query = UPDATE t2 SET i = 123 WHERE key1 < 13 or key2 < 14 ORDER BY key1
+--let $select = SELECT * FROM t2 WHERE key1 < 13 or key2 < 14 ORDER BY key1
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #46
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+ (20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+ (30),(31),(32),(33),(34),(35);
+CREATE TABLE t2(a INT, i INT PRIMARY KEY);
+INSERT INTO t2 (i) SELECT i FROM t1;
+--let $query = UPDATE t2 SET a = 10 WHERE i > 10 AND i <= 18 ORDER BY i DESC LIMIT 5
+--let $select = SELECT * FROM t2 WHERE i > 10 AND i <= 18 ORDER BY i DESC LIMIT 5
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #47
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+ (20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+ (30),(31),(32),(33),(34),(35);
+CREATE TABLE t2 (a CHAR(2), b CHAR(2), c CHAR(2), INDEX (a, b));
+INSERT INTO t2 SELECT i, i, i FROM t1;
+--let $query = UPDATE t2 SET c = 10 ORDER BY a, b DESC LIMIT 5
+--let $select = SELECT * FROM t2 ORDER BY a, b DESC LIMIT 5
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #48
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+ (20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+ (30),(31),(32),(33),(34),(35);
+CREATE TABLE t2 (a CHAR(2), b CHAR(2), c INT, INDEX (a, b));
+INSERT INTO t2 (a, b) SELECT i, i FROM t1;
+INSERT INTO t2 (a, b) SELECT t1.i, t1.i FROM t1, t1 x1, t1 x2;
+--let $query = UPDATE t2 SET c = 10 ORDER BY a DESC, b DESC LIMIT 5
+--let $select = SELECT * FROM t2 ORDER BY a DESC, b DESC LIMIT 5
+--let $no_rows = 1
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #49
+CREATE TABLE t1 (
+ pk INT NOT NULL AUTO_INCREMENT,
+ c1_idx CHAR(1) DEFAULT 'y',
+ c2 INT,
+ PRIMARY KEY (pk),
+ INDEX c1_idx (c1_idx)
+);
+INSERT INTO t1 VALUES (1,'y',1), (2,'n',2), (3,'y',3), (4,'n',4);
+--let $query = UPDATE t1 SET c2 = 0 WHERE c1_idx = 'y' ORDER BY pk DESC LIMIT 2
+--let $select = SELECT * FROM t1 WHERE c1_idx = 'y' ORDER BY pk DESC LIMIT 2
+--source include/explain_utils.inc
+--let $query = DELETE FROM t1 WHERE c1_idx = 'y' ORDER BY pk DESC LIMIT 2
+--let $select = SELECT * FROM t1 WHERE c1_idx = 'y' ORDER BY pk DESC LIMIT 2
+--source include/explain_utils.inc
+DROP TABLE t1;
+
+--echo #50
+CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY);
+INSERT INTO t1 VALUES (),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),();
+--let $query = UPDATE t1 SET a=a+10 WHERE a > 34
+--let $select = SELECT * FROM t1 WHERE a > 34
+--source include/explain_utils.inc
+DROP TABLE t1;
+
+--echo #51
+CREATE TABLE t1 (c1 INT, c2 INT, c3 INT);
+CREATE TABLE t2 (c1 INT, c2 INT);
+INSERT INTO t1 VALUES (1, 1, 10), (2, 2, 20);
+--let $query = UPDATE t1 LEFT JOIN t2 ON t1.c1 = t2.c1 SET t2.c2 = 10
+--let $select = SELECT * FROM t1 LEFT JOIN t2 ON t1.c1 = t2.c1
+--source include/explain_utils.inc
+--let $query = UPDATE t1 LEFT JOIN t2 ON t1.c1 = t2.c1 SET t2.c2 = 10 WHERE t1.c3 = 10
+--let $select = SELECT * FROM t1 LEFT JOIN t2 ON t1.c1 = t2.c1 WHERE t1.c3 = 10
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #52
+CREATE TABLE t1(f1 INT, f2 INT);
+CREATE TABLE t2(f3 INT, f4 INT);
+CREATE INDEX IDX ON t2(f3);
+INSERT INTO t1 VALUES(1,0),(2,0);
+INSERT INTO t2 VALUES(1,1),(2,2);
+--let $query = UPDATE t1 SET t1.f2=(SELECT MAX(t2.f4) FROM t2 WHERE t2.f3=t1.f1)
+--let $select = SELECT (SELECT MAX(t2.f4) FROM t2 WHERE t2.f3=t1.f1) FROM t1
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+
+--echo #55
+CREATE TABLE t1(a INT);
+INSERT INTO t1 VALUES (1);
+SET @a = NULL;
+EXPLAIN DELETE FROM t1 WHERE (@a:= a);
+if (`SELECT @a IS NOT NULL`) {
+ die Unexpectedly modified user variable;
+}
+DROP TABLE t1;
+
+--echo #56
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+--error ER_BAD_FIELD_ERROR
+ DELETE FROM t1 USING t1 WHERE uknown_column = 12345;
+--error ER_BAD_FIELD_ERROR
+EXPLAIN EXTENDED DELETE FROM t1 USING t1 WHERE uknown_column = 12345;
+DROP TABLE t1;
+
+--echo #57
+CREATE TABLE t1(f1 INT);
+--error ER_BAD_FIELD_ERROR
+EXPLAIN EXTENDED UPDATE t1 SET f2=1 ORDER BY f2;
+--error ER_BAD_FIELD_ERROR
+UPDATE t1 SET f2=1 ORDER BY f2;
+DROP TABLE t1;
+
+--disable_parsing
+--echo #59
+CREATE TABLE t1 ( a INT, KEY( a ) );
+INSERT INTO t1 VALUES (0), (1);
+CREATE VIEW v1 AS SELECT t11.a, t12.a AS b FROM t1 t11, t1 t12;
+SET SESSION sql_safe_updates = 1;
+--error ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE
+EXPLAIN EXTENDED UPDATE IGNORE v1 SET a = 1;
+--error ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE
+UPDATE IGNORE v1 SET a = 1;
+SET SESSION sql_safe_updates = DEFAULT;
+DROP TABLE t1;
+DROP VIEW v1;
+--enable_parsing
+
+--echo #62
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (0), (1);
+CREATE VIEW v1 AS SELECT t11.a, t12.a AS b FROM t1 t11, t1 t12;
+--let $query = UPDATE v1 SET a = 1 WHERE a > 0
+--let $select = SELECT * FROM v1 WHERE a > 0
+--source include/explain_utils.inc
+--let $query = UPDATE t1, v1 SET v1.a = 1 WHERE t1.a = v1.a
+--let $select = SELECT * FROM t1, v1 WHERE t1.a = v1.a
+--source include/explain_utils.inc
+DROP TABLE t1;
+DROP VIEW v1;
+
+--echo #63
+CREATE TABLE t1 (a INT, PRIMARY KEY(a));
+INSERT INTO t1 VALUES (1), (2), (3), (4), (5);
+CREATE VIEW v1 (a) AS SELECT a FROM t1;
+--let $query = DELETE FROM v1 WHERE a < 4
+--let $select = SELECT * FROM v1 WHERE a < 4
+--source include/explain_utils.inc
+DROP TABLE t1;
+DROP VIEW v1;
+
+--echo #64
+CREATE TABLE t1 (a INT, b INT, PRIMARY KEY(a));
+INSERT INTO t1 VALUES (1,2), (2,3), (3,4), (4,5), (5,10);
+CREATE TABLE t2 (x INT);
+INSERT INTO t2 VALUES (1), (2), (3), (4);
+CREATE VIEW v1 (a,c) AS SELECT a, b+1 FROM t1;
+--let $query = DELETE v1 FROM t2, v1 WHERE t2.x = v1.a
+--let $select = SELECT * FROM t2, v1 WHERE t2.x = v1.a
+--source include/explain_utils.inc
+DROP TABLE t1,t2;
+DROP VIEW v1;
+
+--echo #65
+CREATE TABLE t1 (a INT, b INT, PRIMARY KEY(a));
+INSERT INTO t1 VALUES (1,2), (2,3), (3,4), (4,5), (5,10);
+CREATE TABLE t2 (x INT);
+INSERT INTO t2 VALUES (1), (2), (3), (4);
+CREATE VIEW v1 (a,c) AS SELECT a, b+1 FROM t1;
+--let $query = DELETE v1 FROM t2, v1 WHERE t2.x = v1.a
+--let $select = SELECT * FROM t2, v1 WHERE t2.x = v1.a
+--source include/explain_utils.inc
+DROP TABLE t1,t2;
+DROP VIEW v1;
+
+--echo #66
+CREATE TABLE t1 (a INT);
+CREATE VIEW v1 (x) AS SELECT a FROM t1;
+--let $query = INSERT INTO v1 VALUES (10)
+--let $select = SELECT NULL
+--source include/explain_utils.inc
+DROP TABLE t1;
+DROP VIEW v1;
+
+--echo #67
+CREATE TABLE t1 (a INT);
+CREATE TABLE t2 (b INT);
+INSERT INTO t2 VALUES (1), (2), (3);
+CREATE VIEW v1 (x) AS SELECT b FROM t2;
+--let $query = INSERT INTO v1 SELECT * FROM t1
+--let $select = SELECT * FROM t1
+--source include/explain_utils.inc
+DROP TABLE t1, t2;
+DROP VIEW v1;
+
+--echo #68
+CREATE TABLE t1 (i INT);
+EXPLAIN INSERT DELAYED INTO t1 VALUES (1);
+DROP TABLE t1;
+
+--echo #69
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TABLE t2 (b INT);
+INSERT INTO t2 VALUES (1), (2), (3);
+--let $query = UPDATE t1 SET a = 10 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x)
+--let $select = SELECT * FROM t1 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x)
+--source include/explain_utils.inc
+--let $query = UPDATE t1, t2 SET a = 10 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x)
+--let $select = SELECT * FROM t1, t2 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x)
+--source include/explain_utils.inc
+--let $query = UPDATE t1, (SELECT * FROM t2) y SET a = 10 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x)
+--let $select = SELECT * FROM t1, (SELECT * FROM t2) y WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x)
+--source include/explain_utils.inc
+DROP TABLE t1,t2;
+
+--echo #70
+CREATE TABLE t1 (c1 INT KEY);
+CREATE TABLE t2 (c2 INT);
+CREATE TABLE t3 (c3 INT);
+EXPLAIN EXTENDED UPDATE t3 SET c3 = (
+ SELECT COUNT(d1.c1)
+ FROM (
+ SELECT a11.c1 FROM t1 AS a11
+ STRAIGHT_JOIN t2 AS a21 ON a21.c2 = a11.c1
+ JOIN t1 AS a12 ON a12.c1 = a11.c1
+ ) d1
+);
+
+DROP TABLE t1, t2, t3;
+
+--disable_parsing
+--echo #71
+#
+# Bug: after EXPLAIN bulk INSERT...SELECT and bulk INSERT...SELECT
+# to a # MyISAM table the SELECT query may fail with the
+# "1030: Got error 124 from storage engine" error message.
+#
+CREATE TABLE t1 (c1 INT NOT NULL, c2 INT NOT NULL, INDEX i1(c1));
+INSERT INTO t1 VALUES (1,0),(2,0),(3,0),(4,0),(5,0),(6,0),(7,0),(8,0);
+--disable_query_log
+let $1=7;
+SET @d=8;
+while ($1) {
+ eval INSERT INTO t1 SELECT c1 + @d, c2 + @d FROM t1;
+ eval SET @d = @d*2;
+ dec $1;
+}
+--enable_query_log
+CREATE TABLE t2 LIKE t1;
+
+# replace "rows" column for InnoDB
+--replace_column 9 X
+EXPLAIN INSERT INTO t2 SELECT * FROM t1;
+INSERT INTO t2 SELECT * FROM t1;
+--disable_result_log
+SELECT * FROM t1 LEFT JOIN t2 ON t1.c1 = t2.c1;
+--enable_result_log
+
+DROP TABLE t1, t2;
+--enable_parsing
+
+--echo #73
+
+CREATE TABLE t1 (id INT);
+CREATE TABLE t2 (id INT);
+INSERT INTO t1 VALUES (1), (2);
+
+EXPLAIN SELECT * FROM t1 LEFT JOIN t2 USING(id) GROUP BY t1.id;
+
+DROP TABLE t1,t2;
+
+--echo #74
+
+CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1), (2), (3), (4), (5);
+
+--echo # used key is modified & Using temporary
+
+--let $query = UPDATE t1 SET a=a+1 WHERE a>10
+--let $select = SELECT a t1 FROM t1 WHERE a>10
+--source include/explain_utils.inc
+
+--echo # used key is modified & Using filesort
+
+--let $query = UPDATE t1 SET a=a+1 WHERE a>10 ORDER BY a+20
+--let $select = SELECT a t1 FROM t1 WHERE a>10 ORDER BY a+20
+--source include/explain_utils.inc
+
+DROP TABLE t1;
+
+--echo #
+--echo # Bug #12949629: CLIENT LOSES CONNECTION AFTER EXECUTING A PROCEDURE WITH
+--echo # EXPLAIN UPDATE/DEL/INS
+--echo #
+
+CREATE TABLE t1 (i INT);
+CREATE TABLE t2 (i INT);
+
+--delimiter |
+CREATE PROCEDURE p1() BEGIN EXPLAIN INSERT INTO t1 VALUES (1);END|
+CREATE PROCEDURE p2() BEGIN INSERT INTO t1 VALUES (1);END|
+CREATE PROCEDURE p3() BEGIN EXPLAIN INSERT INTO t1 SELECT 1;END|
+CREATE PROCEDURE p4() BEGIN INSERT INTO t1 SELECT 1;END|
+CREATE PROCEDURE p5() BEGIN EXPLAIN REPLACE INTO t1 VALUES (1);END|
+CREATE PROCEDURE p6() BEGIN REPLACE INTO t1 VALUES (1);END|
+CREATE PROCEDURE p7() BEGIN EXPLAIN REPLACE INTO t1 SELECT 1;END|
+CREATE PROCEDURE p8() BEGIN REPLACE INTO t1 SELECT 1;END|
+CREATE PROCEDURE p9() BEGIN EXPLAIN UPDATE t1 SET i = 10;END|
+CREATE PROCEDURE p10() BEGIN UPDATE t1 SET i = 10;END|
+CREATE PROCEDURE p11() BEGIN EXPLAIN UPDATE t1,t2 SET t1.i = 10 WHERE t1.i = t2.i ;END|
+CREATE PROCEDURE p12() BEGIN UPDATE t1,t2 SET t1.i = 10 WHERE t1.i = t2.i ;END|
+CREATE PROCEDURE p13() BEGIN EXPLAIN DELETE FROM t1;END|
+CREATE PROCEDURE p14() BEGIN DELETE FROM t1;END|
+CREATE PROCEDURE p15() BEGIN EXPLAIN DELETE FROM t1 USING t1;END|
+CREATE PROCEDURE p16() BEGIN DELETE FROM t1 USING t1;END|
+--delimiter ;
+
+let $i=16;
+while($i) {
+ eval CALL p$i();
+ eval DROP PROCEDURE p$i;
+ dec $i;
+}
+
+DROP TABLE t1, t2;
+
+--echo #
+
+-- disable_query_log
+-- disable_result_log
+# SET GLOBAL innodb_stats_persistent=default;
+-- enable_result_log
+-- enable_query_log
diff --git a/mysql-test/include/explain_utils.inc b/mysql-test/include/explain_utils.inc
new file mode 100644
index 00000000000..505798e432a
--- /dev/null
+++ b/mysql-test/include/explain_utils.inc
@@ -0,0 +1,161 @@
+# This file is a collection of utility tests
+# for WL#4897: Add EXPLAIN INSERT/UPDATE/DELETE.
+#
+# Since MTR doesn't have functions, we use this file instead
+# including it many times.
+#
+# Parameters:
+#
+# $query: INSERT/REPLACE/UPDATE/DELETE query to explain
+# NOTE: this file resets this variable
+#
+# $select: may be empty; the SELECT query similar to $query
+# We use it to compare:
+# 1) table data before and after EXPLAIN $query evaluation;
+# 2) EXPLAIN $query and EXPLAIN $select output and
+# handler/filesort statistics
+# NOTE: this file resets this variable
+# $innodb: take $no_rows parameter into account if not 0;
+# $no_rows: filter out "rows" and "filtered" columns of EXPLAIN if not 0;
+# it may be necessary for InnoDB tables since InnoDB's table row
+# counter can't return precise and repeatable values;
+# NOTE: ANALYZE TABLE doesn't help
+# NOTE: this file resets this variable
+
+--echo #
+--echo # query: $query
+--echo # select: $select
+--echo #
+
+if ($select) {
+--disable_query_log
+--eval $select INTO OUTFILE '$MYSQLTEST_VARDIR/tmp/before_explain.txt'
+--enable_query_log
+}
+
+if ($innodb) {
+ if ($no_rows) {
+--replace_column 9 X
+ }
+}
+--eval EXPLAIN $query
+if (`SELECT ROW_COUNT() > 0`) {
+--echo # Erroneous query: EXPLAIN $query
+--die Unexpected ROW_COUNT() <> 0
+}
+
+FLUSH STATUS;
+FLUSH TABLES;
+if ($innodb) {
+ if ($no_rows) {
+--replace_column 9 X 10 X
+ }
+}
+--eval EXPLAIN EXTENDED $query
+if (`SELECT ROW_COUNT() > 0`) {
+--echo # Erroneous query: EXPLAIN EXTENDED $query
+--die Unexpected ROW_COUNT() <> 0
+}
+--echo # Status of EXPLAIN EXTENDED query
+--disable_query_log
+SHOW STATUS WHERE (Variable_name LIKE 'Sort%' OR
+ Variable_name LIKE 'Handler_read_%' OR
+ Variable_name = 'Handler_write' OR
+ Variable_name = 'Handler_update' OR
+ Variable_name = 'Handler_delete') AND Value <> 0;
+--enable_query_log
+
+if ($json) {
+if ($innodb) {
+ if ($no_rows) {
+--replace_regex /"rows": [0-9]+/"rows": "X"/ /"filtered": [0-9.]+/"filtered": "X"/
+ }
+}
+--eval EXPLAIN FORMAT=JSON $query;
+if ($validation) {
+--disable_query_log
+--replace_result $MASTER_MYSOCK MASTER_MYSOCK
+--exec $MYSQL -S $MASTER_MYSOCK -u root -r test -e "EXPLAIN FORMAT=JSON $query;" > $MYSQLTEST_VARDIR/tmp/explain.json
+--replace_regex /[-]*// /FILE.[\/\\:_\.0-9A-Za-z]*/Validation:/
+--exec python $MYSQL_TEST_DIR/suite/opt_trace/validate_json.py $MYSQLTEST_VARDIR/tmp/explain.json
+--remove_file '$MYSQLTEST_VARDIR/tmp/explain.json'
+--enable_query_log
+}
+}
+
+if ($select) {
+FLUSH STATUS;
+FLUSH TABLES;
+if ($innodb) {
+ if ($no_rows) {
+--replace_column 9 X 10 X
+ }
+}
+--eval EXPLAIN EXTENDED $select
+--echo # Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+--disable_query_log
+SHOW STATUS WHERE (Variable_name LIKE 'Sort%' OR
+ Variable_name LIKE 'Handler_read_%' OR
+ Variable_name = 'Handler_write' OR
+ Variable_name = 'Handler_update' OR
+ Variable_name = 'Handler_delete') AND Value <> 0;
+--enable_query_log
+if ($json) {
+if ($innodb) {
+ if ($no_rows) {
+--replace_regex /"rows": [0-9]+/"rows": "X"/ /"filtered": [0-9.]+/"filtered": "X"/
+ }
+}
+--eval EXPLAIN FORMAT=JSON $select;
+if ($validation) {
+--disable_query_log
+--replace_result $MASTER_MYSOCK MASTER_MYSOCK
+--exec $MYSQL -S $MASTER_MYSOCK -u root -r test -e "EXPLAIN FORMAT=JSON $select;" > $MYSQLTEST_VARDIR/tmp/explain.json
+--replace_regex /[-]*// /FILE.[\/\\:_\.0-9A-Za-z]*/Validation:/
+--exec python $MYSQL_TEST_DIR/suite/opt_trace/validate_json.py $MYSQLTEST_VARDIR/tmp/explain.json
+--remove_file '$MYSQLTEST_VARDIR/tmp/explain.json'
+--enable_query_log
+}
+}
+}
+
+--disable_query_log
+
+if ($select) {
+--eval $select INTO OUTFILE '$MYSQLTEST_VARDIR/tmp/after_explain.txt'
+--diff_files '$MYSQLTEST_VARDIR/tmp/before_explain.txt' '$MYSQLTEST_VARDIR/tmp/after_explain.txt'
+--remove_file '$MYSQLTEST_VARDIR/tmp/before_explain.txt'
+--remove_file '$MYSQLTEST_VARDIR/tmp/after_explain.txt'
+}
+
+FLUSH STATUS;
+FLUSH TABLES;
+if ($select) {
+--disable_result_log
+--eval $select
+--enable_result_log
+--echo # Status of "equivalent" SELECT query execution:
+SHOW STATUS WHERE (Variable_name LIKE 'Sort%' OR
+ Variable_name LIKE 'Handler_read_%' OR
+ Variable_name = 'Handler_write' OR
+ Variable_name = 'Handler_update' OR
+ Variable_name = 'Handler_delete') AND Value <> 0;
+}
+
+FLUSH STATUS;
+FLUSH TABLES;
+--eval $query
+--echo # Status of testing query execution:
+SHOW STATUS WHERE (Variable_name LIKE 'Sort%' OR
+ Variable_name LIKE 'Handler_read_%' OR
+ Variable_name = 'Handler_write' OR
+ Variable_name = 'Handler_update' OR
+ Variable_name = 'Handler_delete') AND Value <> 0;
+
+--let $query=
+--let $select=
+--let $no_rows=
+
+--enable_query_log
+
+--echo
diff --git a/mysql-test/r/derived_opt.result b/mysql-test/r/derived_opt.result
index 22e2ab8d676..f5e7393591c 100644
--- a/mysql-test/r/derived_opt.result
+++ b/mysql-test/r/derived_opt.result
@@ -109,8 +109,8 @@ count(*)
2
explain select count(*) from t1 INNER JOIN (SELECT A.E1, A.E2, A.E3 FROM t1 AS A WHERE A.E3 = (SELECT MAX(B.E3) FROM t1 AS B WHERE A.E2 = B.E2)) AS THEMAX ON t1.E1 = THEMAX.E2 AND t1.E1 = t1.E2;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE A ALL NULL NULL NULL NULL 2 Using where
-1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.A.E2 1 Using where
+1 PRIMARY A ALL NULL NULL NULL NULL 2 Using where
+1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.A.E2 1 Using where
3 DEPENDENT SUBQUERY B ALL NULL NULL NULL NULL 2 Using where
drop table t1;
create table t1 (a int);
diff --git a/mysql-test/r/derived_view.result b/mysql-test/r/derived_view.result
index 3438579d97e..c0daabc148f 100644
--- a/mysql-test/r/derived_view.result
+++ b/mysql-test/r/derived_view.result
@@ -386,7 +386,7 @@ materialized derived in merged derived
explain extended select * from (select * from
(select * from t1 where f1 < 7 group by f1) tt where f1 > 2) zz;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE <derived3> ALL NULL NULL NULL NULL 11 100.00 Using where
+1 PRIMARY <derived3> ALL NULL NULL NULL NULL 11 100.00 Using where
3 DERIVED t1 ALL NULL NULL NULL NULL 11 100.00 Using where; Using temporary; Using filesort
Warnings:
Note 1003 select `tt`.`f1` AS `f1`,`tt`.`f11` AS `f11` from (select `test`.`t1`.`f1` AS `f1`,`test`.`t1`.`f11` AS `f11` from `test`.`t1` where (`test`.`t1`.`f1` < 7) group by `test`.`t1`.`f1`) `tt` where (`tt`.`f1` > 2)
@@ -429,8 +429,8 @@ join
(select * from (select * from t1 where f1 < 7 group by f1) tt where f1 > 2) z
on x.f1 = z.f1;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE <derived3> ALL NULL NULL NULL NULL 11 100.00 Using where
-1 SIMPLE <derived5> ref key0 key0 5 tt.f1 2 100.00
+1 PRIMARY <derived3> ALL NULL NULL NULL NULL 11 100.00 Using where
+1 PRIMARY <derived5> ref key0 key0 5 tt.f1 2 100.00
5 DERIVED t1 ALL NULL NULL NULL NULL 11 100.00 Using where; Using temporary; Using filesort
3 DERIVED t1 ALL NULL NULL NULL NULL 11 100.00 Using where; Using temporary; Using filesort
Warnings:
@@ -522,7 +522,7 @@ materialized view in merged derived
explain extended
select * from ( select * from v1 where f1 < 7) tt;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE <derived3> ALL NULL NULL NULL NULL 11 100.00 Using where
+1 PRIMARY <derived3> ALL NULL NULL NULL NULL 11 100.00 Using where
3 DERIVED t1 ALL NULL NULL NULL NULL 11 100.00 Using temporary; Using filesort
Warnings:
Note 1003 select `v1`.`f1` AS `f1`,`v1`.`f11` AS `f11` from `test`.`v1` where (`v1`.`f1` < 7)
@@ -568,8 +568,8 @@ f1 f11
join of above two
explain extended select * from v6 join v7 on f2=f1;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE t2 ALL NULL NULL NULL NULL 11 100.00 Using where
-1 SIMPLE <derived5> ref key0 key0 5 test.t2.f2 2 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 11 100.00 Using where
+1 PRIMARY <derived5> ref key0 key0 5 test.t2.f2 2 100.00
5 DERIVED t1 ALL NULL NULL NULL NULL 11 100.00 Using temporary; Using filesort
Warnings:
Note 1003 select `test`.`t2`.`f2` AS `f2`,`test`.`t2`.`f22` AS `f22`,`v1`.`f1` AS `f1`,`v1`.`f11` AS `f11` from `test`.`t2` join `test`.`v1` where ((`v1`.`f1` = `test`.`t2`.`f2`) and (`test`.`t2`.`f2` < 7) and (`test`.`t2`.`f2` in (2,3)))
@@ -1220,7 +1220,7 @@ Note 1003 select `test`.`t1`.`b` AS `b` from `test`.`t1` where 0
EXPLAIN EXTENDED
SELECT * FROM (SELECT b FROM v2 WHERE b = 0) t WHERE b;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
+1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
3 DERIVED t1 ALL NULL NULL NULL NULL 5 100.00 Using temporary; Using filesort
Warnings:
Note 1003 select `v2`.`b` AS `b` from `test`.`v2` where 0
diff --git a/mysql-test/r/explain_non_select.result b/mysql-test/r/explain_non_select.result
new file mode 100644
index 00000000000..00ca481147b
--- /dev/null
+++ b/mysql-test/r/explain_non_select.result
@@ -0,0 +1,221 @@
+drop table if exists t0, t1;
+create table t0 (a int) engine=myisam;
+insert into t0 values (1),(2),(3),(4),(5),(6),(7),(8);
+#
+# Tests for single-table DELETE
+#
+explain select * from t0 where a=3;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ALL NULL NULL NULL NULL 8 Using where
+explain delete from t0 where a=3;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ALL NULL NULL NULL NULL 8 Using where
+# DELETE without WHERE is a special case:
+explain delete from t0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL 8 Deleting all rows
+create table t1 (a int, b int, filler char(100), key(a), key(b));
+insert into t1
+select A.a+10*B.a + 10*C.a, A.a+10*B.a + 10*C.a, 'filler'
+from t0 A, t0 B, t0 C;
+# This should use an index, possible_keys=NULL because there is no WHERE
+explain delete from t1 order by a limit 2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL a 5 NULL 2
+# This should use range, possible_keys={a,b}
+explain delete from t1 where a<20 and b < 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a,b a 5 NULL 1 Using where
+# This should use ALL + filesort
+explain delete from t1 order by a+1 limit 2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 512 Using filesort
+# This should use range + using filesort
+explain delete from t1 where a<20 order by b limit 2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 5 NULL 1 Using where; Using filesort
+# Try some subqueries:
+explain delete from t1 where a < (select max(a) from t0);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 range a a 5 NULL 1 Using where
+2 SUBQUERY t0 ALL NULL NULL NULL NULL 8
+explain delete from t1 where a < (select max(a) from t0 where a < t1.b);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 512 Using where
+2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 8 Using where
+#
+# Tests for multi-table DELETE
+#
+explain delete t1 from t0, t1 where t0.a = t1.a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ALL NULL NULL NULL NULL 8 Using where
+1 SIMPLE t1 ref a a 5 test.t0.a 4
+drop table t0, t1;
+# ###################################################################
+# ## EXPLAIN UPDATE tests
+# ###################################################################
+create table t0 (a int) engine=myisam;
+insert into t0 values (1),(2),(3),(4),(5),(6),(7),(8);
+explain update t0 set a=3 where a=4;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ALL NULL NULL NULL NULL 8 Using where
+create table t1 (a int, b int, filler char(100), key(a), key(b));
+insert into t1
+select A.a+10*B.a + 10*C.a, A.a+10*B.a + 10*C.a, 'filler'
+from t0 A, t0 B, t0 C;
+explain update t1 set a=a+1 where 3>4;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
+explain update t1 set a=a+1 where a=3 and a=4;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
+# This should use an index, possible_keys=NULL because there is no WHERE
+explain update t1 set a=a+1 order by a limit 2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 512 Using filesort
+# This should use range, possible_keys={a,b}
+explain update t1 set filler='fooo' where a<20 and b < 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a,b a 5 NULL 1 Using where
+# This should use ALL + filesort
+explain update t1 set filler='fooo' order by a+1 limit 2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 512 Using filesort
+# This should use range + using filesort
+explain update t1 set filler='fooo' where a<20 order by b limit 2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 5 NULL 1 Using where; Using filesort
+# Try some subqueries:
+explain update t1 set filler='fooo' where a < (select max(a) from t0);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 range a a 5 NULL 1 Using where
+2 SUBQUERY t0 ALL NULL NULL NULL NULL 8
+explain update t1 set filler='fooo' where a < (select max(a) from t0 where a < t1.b);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 512 Using where
+2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 8 Using where
+#
+# Tests for multi-table UPDATE
+#
+explain update t0, t1 set t1.a=t1.a+1 where t0.a = t1.a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ALL NULL NULL NULL NULL 8 Using where
+1 SIMPLE t1 ref a a 5 test.t0.a 4
+drop table t0, t1;
+#
+# Try DELETE ... RETURNING ...
+#
+create table t0 (a int);
+insert into t0 values (1),(2),(3),(4);
+explain delete from t0 where a=1 returning a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ALL NULL NULL NULL NULL 4 Using where
+explain delete from t0 returning a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ALL NULL NULL NULL NULL 4
+drop table t0;
+#
+# MDEV-5070 - EXPLAIN INSERT ... SELECT crashes on 10.0-base-explain-slowquerylog
+#
+create table t0 (a int);
+insert into t0 values (1),(2),(3),(4),(5),(6),(7),(8);
+create table t1 (a int);
+explain insert into t1 select * from t0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ALL NULL NULL NULL NULL 8
+explain replace into t1 select * from t0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ALL NULL NULL NULL NULL 8
+drop table t0, t1;
+#
+# MDEV-5067: Valgrind warnings (Invalid read) in QPF_table_access::print_explain
+#
+CREATE TABLE t1 (i INT) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (7),(0),(9);
+SELECT * FROM t1 INNER JOIN ( SELECT DISTINCT * FROM t1 ) AS sq ON (sq.i = t1.i);
+i i
+7 7
+0 0
+9 9
+DROP TABLE t1;
+#
+# MDEV-5093, MDEV-5094: EXPLAIN PARTITIONS and EXPLAIN EXTENDED do not
+# work for EXPLAIN UPDATE.
+#
+create table t1 (i int);
+explain partitions update t1 set i = 3;
+id select_type table partitions type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 0
+create table t2 (a int, b int) partition by hash(a) partitions 5;
+insert into t2 values (0,0),(1,1),(2,2),(3,3),(4,4);
+explain partitions update t2 set b=3 where a in (3,4);
+id select_type table partitions type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 p3,p4 ALL NULL NULL NULL NULL 2 Using where
+explain partitions delete from t2 where a in (3,4);
+id select_type table partitions type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 p3,p4 ALL NULL NULL NULL NULL 2 Using where
+explain extended update t2 set b=3 where a in (3,4);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 2 100.00 Using where
+explain extended delete from t2 where a in (3,4);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 2 100.00 Using where
+drop table t1,t2;
+#
+# Check the special case where partition pruning removed all partitions
+#
+create table t1 (a int, b int)
+partition by range (a) (
+partition p0 values less than (10),
+partition p1 values less than (20),
+partition p2 values less than (30)
+);
+insert into t1 values (9,9), (19,19), (29,29);
+explain partitions select * from t1 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 Impossible WHERE noticed after reading const tables
+explain partitions delete from t1 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
+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;
+#
+# MDEV-5122: "Commands out of sync", "Malformed packet" or client hang up on unique key violation
+#
+drop table if exists t1;
+Warnings:
+Note 1051 Unknown table 'test.t1'
+drop function if exists f1;
+create table t1 (a int, unique(a));
+create function f1(x int)
+returns int
+begin
+insert into t1 values(x),(x);
+return 10;
+end|
+select f1(100);
+ERROR 23000: Duplicate entry '100' for key 'a'
+select 'OK';
+OK
+OK
+drop function f1;
+drop table t1;
diff --git a/mysql-test/r/explain_slowquerylog.result b/mysql-test/r/explain_slowquerylog.result
new file mode 100644
index 00000000000..9d25cf06275
--- /dev/null
+++ b/mysql-test/r/explain_slowquerylog.result
@@ -0,0 +1,41 @@
+drop table if exists t0,t1;
+create table t0 (a int);
+insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+explain select * from t0 where a < 3;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ALL NULL NULL NULL NULL 10 Using where
+#
+# MDEV-5045: Server crashes in QPF_query::print_explain with log_slow_verbosity='query_plan,explain'
+#
+set autocommit=1;
+drop table t0;
+#
+# MDEV-5047 virtual THD::~THD(): Assertion `status_var.memory_used == 0' fails on disconnect
+#
+ALTER TABLE nonexisting ENABLE KEYS;
+ERROR 42S02: Table 'test.nonexisting' doesn't exist
+SHOW WARNINGS;
+Level Code Message
+Error 1146 Table 'test.nonexisting' doesn't exist
+SELECT 1;
+1
+1
+#
+# MDEV-5060 Server crashes on EXPLAIN EXTENDED or EXPLAIN PARTITIONS with explain in slow_log
+#
+EXPLAIN PARTITIONS SELECT 1 ;
+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 tables used
+#
+# MDEV-5106: Server crashes in Explain_union::print_explain on ER_TOO_BIG_SELECT with explain in slow log
+#
+CREATE TABLE t1 (i INT) ENGINE=MyISAM;
+INSERT INTO t1 VALUES
+(1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
+SET max_join_size = 10;
+( SELECT ta.* FROM t1 ta, t1 tb ) UNION ( SELECT * FROM t1 );
+ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay
+SELECT 'Server still alive?' as 'Yes';
+Yes
+Server still alive?
+DROP TABLE t1;
diff --git a/mysql-test/r/grant_explain_non_select.result b/mysql-test/r/grant_explain_non_select.result
new file mode 100644
index 00000000000..85b0ae5c4b4
--- /dev/null
+++ b/mysql-test/r/grant_explain_non_select.result
@@ -0,0 +1,178 @@
+CREATE DATABASE privtest_db;
+CREATE TABLE privtest_db.t1 (a INT);
+CREATE TABLE privtest_db.t2 (a INT);
+INSERT INTO privtest_db.t2 VALUES (1), (2), (3);
+GRANT USAGE ON *.* TO 'privtest'@'localhost';
+GRANT SELECT ON privtest_db.t2 TO 'privtest'@'localhost';
+USE privtest_db;
+EXPLAIN INSERT INTO t1 VALUES (10);
+ERROR 42000: INSERT command denied to user 'privtest'@'localhost' for table 't1'
+INSERT INTO t1 VALUES (10);
+ERROR 42000: INSERT command denied to user 'privtest'@'localhost' for table 't1'
+EXPLAIN INSERT INTO t1 SELECT * FROM t2;
+ERROR 42000: INSERT command denied to user 'privtest'@'localhost' for table 't1'
+INSERT INTO t1 SELECT * FROM t2;
+ERROR 42000: INSERT command denied to user 'privtest'@'localhost' for table 't1'
+GRANT INSERT ON privtest_db.t1 TO 'privtest'@'localhost';
+EXPLAIN INSERT INTO t1 VALUES (10);
+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 (10);
+EXPLAIN INSERT INTO t1 SELECT * FROM t2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3
+INSERT INTO t1 SELECT * FROM t2;
+REVOKE ALL PRIVILEGES ON privtest_db.t1 FROM 'privtest'@'localhost';
+EXPLAIN REPLACE INTO t1 VALUES (10);
+ERROR 42000: INSERT, DELETE command denied to user 'privtest'@'localhost' for table 't1'
+REPLACE INTO t1 VALUES (10);
+ERROR 42000: INSERT, DELETE command denied to user 'privtest'@'localhost' for table 't1'
+EXPLAIN REPLACE INTO t1 SELECT * FROM t2;
+ERROR 42000: INSERT, DELETE command denied to user 'privtest'@'localhost' for table 't1'
+REPLACE INTO t1 SELECT * FROM t2;
+ERROR 42000: INSERT, DELETE command denied to user 'privtest'@'localhost' for table 't1'
+GRANT INSERT ON privtest_db.t1 TO 'privtest'@'localhost';
+EXPLAIN REPLACE INTO t1 VALUES (10);
+ERROR 42000: DELETE command denied to user 'privtest'@'localhost' for table 't1'
+REPLACE INTO t1 VALUES (10);
+ERROR 42000: DELETE command denied to user 'privtest'@'localhost' for table 't1'
+EXPLAIN REPLACE INTO t1 SELECT * FROM t2;
+ERROR 42000: DELETE command denied to user 'privtest'@'localhost' for table 't1'
+REPLACE INTO t1 SELECT * FROM t2;
+ERROR 42000: DELETE command denied to user 'privtest'@'localhost' for table 't1'
+REVOKE INSERT ON privtest_db.t1 FROM 'privtest'@'localhost';
+GRANT DELETE ON privtest_db.t1 TO 'privtest'@'localhost';
+EXPLAIN REPLACE INTO t1 VALUES (10);
+ERROR 42000: INSERT command denied to user 'privtest'@'localhost' for table 't1'
+REPLACE INTO t1 VALUES (10);
+ERROR 42000: INSERT command denied to user 'privtest'@'localhost' for table 't1'
+EXPLAIN REPLACE INTO t1 SELECT * FROM t2;
+ERROR 42000: INSERT command denied to user 'privtest'@'localhost' for table 't1'
+REPLACE INTO t1 SELECT * FROM t2;
+ERROR 42000: INSERT command denied to user 'privtest'@'localhost' for table 't1'
+GRANT INSERT, DELETE ON privtest_db.t1 TO 'privtest'@'localhost';
+EXPLAIN REPLACE INTO t1 VALUES (10);
+id select_type table type possible_keys key key_len ref rows Extra
+1 INSERT t1 ALL NULL NULL NULL NULL NULL NULL
+REPLACE INTO t1 VALUES (10);
+EXPLAIN REPLACE INTO t1 SELECT * FROM t2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3
+REPLACE INTO t1 SELECT * FROM t2;
+REVOKE ALL PRIVILEGES ON privtest_db.t1 FROM 'privtest'@'localhost';
+EXPLAIN UPDATE t1 SET a = a + 1;
+ERROR 42000: UPDATE command denied to user 'privtest'@'localhost' for table 't1'
+UPDATE t1 SET a = a + 1;
+ERROR 42000: UPDATE command denied to user 'privtest'@'localhost' for table 't1'
+EXPLAIN UPDATE t1, t2 SET t1.a = t1.a + 1 WHERE t1.a = t2.a;
+ERROR 42000: SELECT command denied to user 'privtest'@'localhost' for table 't1'
+UPDATE t1, t2 SET t1.a = t1.a + 1 WHERE t1.a = t2.a;
+ERROR 42000: SELECT command denied to user 'privtest'@'localhost' for table 't1'
+GRANT UPDATE ON privtest_db.t1 TO 'privtest'@'localhost';
+EXPLAIN UPDATE t1 SET a = a + 1;
+ERROR 42000: SELECT command denied to user 'privtest'@'localhost' for column 'a' in table 't1'
+UPDATE t1 SET a = a + 1;
+ERROR 42000: SELECT command denied to user 'privtest'@'localhost' for column 'a' in table 't1'
+EXPLAIN UPDATE t1, t2 SET t1.a = t1.a + 1 WHERE t1.a = t2.a;
+ERROR 42000: SELECT command denied to user 'privtest'@'localhost' for column 'a' in table 't1'
+UPDATE t1, t2 SET t1.a = t1.a + 1 WHERE t1.a = t2.a;
+ERROR 42000: SELECT command denied to user 'privtest'@'localhost' for column 'a' in table 't1'
+REVOKE UPDATE ON privtest_db.t1 FROM 'privtest'@'localhost';
+GRANT SELECT ON privtest_db.t1 TO 'privtest'@'localhost';
+EXPLAIN UPDATE t1 SET a = a + 1;
+ERROR 42000: UPDATE command denied to user 'privtest'@'localhost' for table 't1'
+UPDATE t1 SET a = a + 1;
+ERROR 42000: UPDATE command denied to user 'privtest'@'localhost' for table 't1'
+EXPLAIN UPDATE t1, t2 SET t1.a = t1.a + 1 WHERE t1.a = t2.a;
+ERROR 42000: UPDATE command denied to user 'privtest'@'localhost' for table 't1'
+UPDATE t1, t2 SET t1.a = t1.a + 1 WHERE t1.a = t2.a;
+ERROR 42000: UPDATE command denied to user 'privtest'@'localhost' for table 't1'
+GRANT UPDATE, SELECT ON privtest_db.t1 TO 'privtest'@'localhost';
+EXPLAIN UPDATE t1 SET a = a + 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 8
+UPDATE t1 SET a = a + 1;
+EXPLAIN UPDATE t1, t2 SET t1.a = t1.a + 1 WHERE t1.a = t2.a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3
+1 SIMPLE t1 ALL NULL NULL NULL NULL 8 Using where
+UPDATE t1, t2 SET t1.a = t1.a + 1 WHERE t1.a = t2.a;
+REVOKE ALL PRIVILEGES ON privtest_db.t1 FROM 'privtest'@'localhost';
+EXPLAIN DELETE FROM t1 WHERE a = 10;
+ERROR 42000: DELETE command denied to user 'privtest'@'localhost' for table 't1'
+DELETE FROM t1 WHERE a = 10;
+ERROR 42000: DELETE command denied to user 'privtest'@'localhost' for table 't1'
+EXPLAIN DELETE FROM t1 USING t1, t2 WHERE t1.a = t2.a;
+ERROR 42000: SELECT command denied to user 'privtest'@'localhost' for table 't1'
+DELETE FROM t1 USING t1, t2 WHERE t1.a = t2.a;
+ERROR 42000: SELECT command denied to user 'privtest'@'localhost' for table 't1'
+GRANT DELETE ON privtest_db.t1 TO 'privtest'@'localhost';
+EXPLAIN DELETE FROM t1 WHERE a = 10;
+ERROR 42000: SELECT command denied to user 'privtest'@'localhost' for column 'a' in table 't1'
+DELETE FROM t1 WHERE a = 10;
+ERROR 42000: SELECT command denied to user 'privtest'@'localhost' for column 'a' in table 't1'
+EXPLAIN DELETE FROM t1 USING t1, t2 WHERE t1.a = t2.a;
+ERROR 42000: SELECT command denied to user 'privtest'@'localhost' for table 't1'
+DELETE FROM t1 USING t1, t2 WHERE t1.a = t2.a;
+ERROR 42000: SELECT command denied to user 'privtest'@'localhost' for table 't1'
+REVOKE ALL PRIVILEGES ON privtest_db.t1 FROM 'privtest'@'localhost';
+GRANT SELECT ON privtest_db.t1 TO 'privtest'@'localhost';
+EXPLAIN DELETE FROM t1 WHERE a = 10;
+ERROR 42000: DELETE command denied to user 'privtest'@'localhost' for table 't1'
+DELETE FROM t1 WHERE a = 10;
+ERROR 42000: DELETE command denied to user 'privtest'@'localhost' for table 't1'
+EXPLAIN DELETE FROM t1 USING t1, t2 WHERE t1.a = t2.a;
+ERROR 42000: DELETE command denied to user 'privtest'@'localhost' for table 't1'
+DELETE FROM t1 USING t1, t2 WHERE t1.a = t2.a;
+ERROR 42000: DELETE command denied to user 'privtest'@'localhost' for table 't1'
+REVOKE ALL PRIVILEGES ON privtest_db.t1 FROM 'privtest'@'localhost';
+GRANT DELETE, SELECT ON privtest_db.t1 TO 'privtest'@'localhost';
+EXPLAIN DELETE FROM t1 WHERE a = 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 8 Using where
+DELETE FROM t1 WHERE a = 10;
+EXPLAIN DELETE FROM t1 USING t1, t2 WHERE t1.a = t2.a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3
+1 SIMPLE t1 ALL NULL NULL NULL NULL 8 Using where
+DELETE FROM t1 USING t1, t2 WHERE t1.a = t2.a;
+REVOKE ALL PRIVILEGES ON privtest_db.t1 FROM 'privtest'@'localhost';
+CREATE VIEW privtest_db.v1 (a) AS SELECT a FROM privtest_db.t1;
+GRANT SELECT, INSERT, UPDATE, DELETE ON privtest_db.v1 TO 'privtest'@'localhost';
+EXPLAIN SELECT * FROM v1;
+ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table
+SELECT * FROM v1;
+a
+11
+4
+4
+11
+4
+4
+EXPLAIN INSERT INTO v1 VALUES (10);
+ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table
+INSERT INTO v1 VALUES (10);
+EXPLAIN INSERT INTO v1 SELECT * FROM t2;
+ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table
+INSERT INTO v1 SELECT * FROM t2;
+EXPLAIN REPLACE INTO v1 VALUES (10);
+ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table
+REPLACE INTO v1 VALUES (10);
+EXPLAIN REPLACE INTO v1 SELECT * FROM t2;
+ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table
+REPLACE INTO v1 SELECT * FROM t2;
+EXPLAIN UPDATE v1 SET a = a + 1;
+ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table
+UPDATE v1 SET a = a + 1;
+EXPLAIN UPDATE v1, t2 SET v1.a = v1.a + 1 WHERE v1.a = t2.a;
+ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table
+UPDATE v1, t2 SET v1.a = v1.a + 1 WHERE v1.a = t2.a;
+EXPLAIN DELETE FROM v1 WHERE a = 10;
+ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table
+DELETE FROM v1 WHERE a = 10;
+EXPLAIN DELETE FROM v1 USING v1, t2 WHERE v1.a = t2.a;
+ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table
+DELETE FROM v1 USING v1, t2 WHERE v1.a = t2.a;
+DROP USER 'privtest'@localhost;
+USE test;
+DROP DATABASE privtest_db;
diff --git a/mysql-test/r/limit_rows_examined.result b/mysql-test/r/limit_rows_examined.result
index a51798a5883..5dbe01eef4f 100644
--- a/mysql-test/r/limit_rows_examined.result
+++ b/mysql-test/r/limit_rows_examined.result
@@ -439,7 +439,7 @@ from (select * from t1
where c1 IN (select * from t2 where c2 > ' ' LIMIT ROWS EXAMINED 0)) as tmp
LIMIT ROWS EXAMINED 11;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using where
+1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where
3 MATERIALIZED t2 ALL NULL NULL NULL NULL 4 Using where
select *
from (select * from t1
diff --git a/mysql-test/r/myisam_explain_non_select_all.result b/mysql-test/r/myisam_explain_non_select_all.result
new file mode 100644
index 00000000000..86e3ffbff6c
--- /dev/null
+++ b/mysql-test/r/myisam_explain_non_select_all.result
@@ -0,0 +1,2907 @@
+set @save_storage_engine= @@session.default_storage_engine;
+set session default_storage_engine = MyISAM;
+#1
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+#
+# query: UPDATE t1 SET a = 10 WHERE a < 10
+# select: SELECT * FROM t1 WHERE a < 10
+#
+EXPLAIN UPDATE t1 SET a = 10 WHERE a < 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t1 SET a = 10 WHERE a < 10;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE a < 10;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` < 10)
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 4
+# Status of testing query execution:
+Variable_name Value
+Handler_read_rnd_next 4
+Handler_update 3
+
+DROP TABLE t1;
+#2
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+#
+# query: DELETE FROM t1 WHERE a < 10
+# select: SELECT * FROM t1 WHERE a < 10
+#
+EXPLAIN DELETE FROM t1 WHERE a < 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t1 WHERE a < 10;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE a < 10;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` < 10)
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 4
+# Status of testing query execution:
+Variable_name Value
+Handler_delete 3
+Handler_read_rnd_next 4
+
+DROP TABLE t1;
+#3
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+#
+# query: DELETE FROM t1 USING t1 WHERE a = 1
+# select: SELECT * FROM t1 WHERE a = 1
+#
+EXPLAIN DELETE FROM t1 USING t1 WHERE a = 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t1 USING t1 WHERE a = 1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE a = 1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` = 1)
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 4
+# Status of testing query execution:
+Variable_name Value
+Handler_delete 1
+Handler_read_rnd_next 4
+
+DROP TABLE t1;
+#4
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TABLE t2 (b INT);
+INSERT INTO t2 VALUES (1), (2), (3);
+#
+# query: UPDATE t1, t2 SET t1.a = 10 WHERE t1.a = 1
+# select: SELECT * FROM t1, t2 WHERE t1.a = 1
+#
+EXPLAIN UPDATE t1, t2 SET t1.a = 10 WHERE t1.a = 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t1, t2 SET t1.a = 10 WHERE t1.a = 1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1, t2 WHERE t1.a = 1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join)
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t1` join `test`.`t2` where (`test`.`t1`.`a` = 1)
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 8
+# Status of testing query execution:
+Variable_name Value
+Handler_read_rnd_next 8
+Handler_update 1
+
+DROP TABLE t1, t2;
+#5
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TABLE t2 (b INT);
+INSERT INTO t2 VALUES (1), (2), (3);
+#
+# query: UPDATE t1 t11, (SELECT * FROM t2) t12 SET t11.a = 10 WHERE t11.a = 1
+# select: SELECT * FROM t1 t11, (SELECT * FROM t2) t12 WHERE t11.a = 1
+#
+EXPLAIN UPDATE t1 t11, (SELECT * FROM t2) t12 SET t11.a = 10 WHERE t11.a = 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t11 ALL NULL NULL NULL NULL 3 Using where
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3
+2 DERIVED t2 ALL NULL NULL NULL NULL 3
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t1 t11, (SELECT * FROM t2) t12 SET t11.a = 10 WHERE t11.a = 1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t11 ALL NULL NULL NULL NULL 3 100.00 Using where
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3 100.00
+2 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 t11, (SELECT * FROM t2) t12 WHERE t11.a = 1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t11 ALL NULL NULL NULL NULL 3 100.00 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join)
+Warnings:
+Note 1003 select `test`.`t11`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t1` `t11` join `test`.`t2` where (`test`.`t11`.`a` = 1)
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 8
+# Status of testing query execution:
+Variable_name Value
+Handler_read_rnd_next 12
+Handler_update 1
+
+DROP TABLE t1, t2;
+#6
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TABLE t2 (b INT);
+INSERT INTO t2 VALUES (1), (2), (3);
+#
+# query: UPDATE t1 SET a = 10 WHERE 1 IN (SELECT 1 FROM t2 WHERE t2.b < 3)
+# select: SELECT * FROM t1 WHERE 1 IN (SELECT 1 FROM t2 WHERE t2.b < 3)
+#
+EXPLAIN UPDATE t1 SET a = 10 WHERE 1 IN (SELECT 1 FROM t2 WHERE t2.b < 3);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 Using where
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t1 SET a = 10 WHERE 1 IN (SELECT 1 FROM t2 WHERE t2.b < 3);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00 Using where
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+Handler_read_rnd_next 1
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE 1 IN (SELECT 1 FROM t2 WHERE t2.b < 3);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join)
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) where (`test`.`t2`.`b` < 3)
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_key 1
+Handler_read_rnd_next 8
+# Status of testing query execution:
+Variable_name Value
+Handler_read_rnd_next 5
+Handler_update 3
+
+DROP TABLE t1, t2;
+#7
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TABLE t2 (b INT);
+INSERT INTO t2 VALUES (1), (2), (3);
+#
+# query: UPDATE t1 SET a = 10 WHERE a IN (SELECT b FROM t2 WHERE t1.a < 3)
+# select: SELECT * FROM t1 WHERE a IN (SELECT b FROM t2 WHERE t1.a < 3)
+#
+EXPLAIN UPDATE t1 SET a = 10 WHERE a IN (SELECT b FROM t2 WHERE t1.a < 3);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 3 Using where
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t1 SET a = 10 WHERE a IN (SELECT b FROM t2 WHERE t1.a < 3);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00 Using where
+Warnings:
+Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE a IN (SELECT b FROM t2 WHERE t1.a < 3);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where
+1 PRIMARY t2 ALL NULL NULL NULL NULL 3 100.00 Using where; FirstMatch(t1); Using join buffer (flat, BNL join)
+Warnings:
+Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t2`.`b` = `test`.`t1`.`a`) and (`test`.`t1`.`a` < 3))
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 8
+# Status of testing query execution:
+Variable_name Value
+Handler_read_rnd_next 7
+Handler_update 2
+
+DROP TABLE t1, t2;
+#7
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TABLE t2 (b INT);
+INSERT INTO t2 VALUES (1), (2), (3);
+#
+# query: UPDATE t1, t2 SET a = 10 WHERE a IN (SELECT b FROM t2 WHERE t2.b < 3)
+# select: SELECT * FROM t1, t2 WHERE a IN (SELECT b FROM t2 WHERE t2.b < 3)
+#
+EXPLAIN UPDATE t1, t2 SET a = 10 WHERE a IN (SELECT b FROM t2 WHERE t2.b < 3);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
+1 PRIMARY t2 ALL NULL NULL NULL NULL 3
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 Using where
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t1, t2 SET a = 10 WHERE a IN (SELECT b FROM t2 WHERE t2.b < 3);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 3 100.00
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 100.00 Using where
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1, t2 WHERE a IN (SELECT b FROM t2 WHERE t2.b < 3);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join)
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t1` semi join (`test`.`t2`) join `test`.`t2` where ((`test`.`t2`.`b` < 3))
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_key 3
+Handler_read_rnd_next 12
+# Status of testing query execution:
+Variable_name Value
+Handler_read_key 3
+Handler_read_rnd_next 16
+Handler_update 2
+
+DROP TABLE t1, t2;
+#8
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TABLE t2 (b INT);
+INSERT INTO t2 VALUES (1), (2), (3);
+#
+# query: UPDATE t1 t11, (SELECT * FROM t2) t12 SET t11.a = t11.a + 10
+# select: SELECT * FROM t1 t11, (SELECT * FROM t2) t12
+#
+EXPLAIN UPDATE t1 t11, (SELECT * FROM t2) t12 SET t11.a = t11.a + 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t11 ALL NULL NULL NULL NULL 3
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3
+2 DERIVED t2 ALL NULL NULL NULL NULL 3
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t1 t11, (SELECT * FROM t2) t12 SET t11.a = t11.a + 10;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t11 ALL NULL NULL NULL NULL 3 100.00
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3 100.00
+2 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 t11, (SELECT * FROM t2) t12;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t11 ALL NULL NULL NULL NULL 3 100.00
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join)
+Warnings:
+Note 1003 select `test`.`t11`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t1` `t11` join `test`.`t2`
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 8
+# Status of testing query execution:
+Variable_name Value
+Handler_read_rnd 3
+Handler_read_rnd_deleted 1
+Handler_read_rnd_next 24
+Handler_update 3
+
+DROP TABLE t1, t2;
+#9
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TABLE t2 (b INT);
+INSERT INTO t2 VALUES (1), (2), (3);
+#
+# query: UPDATE t1 t11, (SELECT 1 FROM DUAL) t12 SET t11.a = t11.a + 10
+# select: SELECT * FROM t1 t11, (SELECT 1 FROM DUAL) t12
+#
+EXPLAIN UPDATE t1 t11, (SELECT 1 FROM DUAL) t12 SET t11.a = t11.a + 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY <derived2> system NULL NULL NULL NULL 1
+1 PRIMARY t11 ALL NULL NULL NULL NULL 3
+2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t1 t11, (SELECT 1 FROM DUAL) t12 SET t11.a = t11.a + 10;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY <derived2> system NULL NULL NULL NULL 1 100.00
+1 PRIMARY t11 ALL NULL NULL NULL NULL 3 100.00
+2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+Handler_read_rnd_next 1
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 t11, (SELECT 1 FROM DUAL) t12;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY <derived2> system NULL NULL NULL NULL 1 100.00
+1 PRIMARY t11 ALL NULL NULL NULL NULL 3 100.00
+2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select `test`.`t11`.`a` AS `a`,1 AS `1` from `test`.`t1` `t11`
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+Handler_read_rnd_next 1
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 5
+# Status of testing query execution:
+Variable_name Value
+Handler_read_rnd 3
+Handler_read_rnd_next 9
+Handler_update 3
+
+DROP TABLE t1, t2;
+#10
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TABLE t2 (b INT);
+INSERT INTO t2 VALUES (1), (2), (3);
+#
+# query: UPDATE t1 t11, (SELECT * FROM t2) t12 SET t11.a = 10 WHERE t11.a > 1
+# select: SELECT * FROM t1 t11, (SELECT * FROM t2) t12 WHERE t11.a > 1
+#
+EXPLAIN UPDATE t1 t11, (SELECT * FROM t2) t12 SET t11.a = 10 WHERE t11.a > 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t11 ALL NULL NULL NULL NULL 3 Using where
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3
+2 DERIVED t2 ALL NULL NULL NULL NULL 3
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t1 t11, (SELECT * FROM t2) t12 SET t11.a = 10 WHERE t11.a > 1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t11 ALL NULL NULL NULL NULL 3 100.00 Using where
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3 100.00
+2 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 t11, (SELECT * FROM t2) t12 WHERE t11.a > 1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t11 ALL NULL NULL NULL NULL 3 100.00 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join)
+Warnings:
+Note 1003 select `test`.`t11`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t1` `t11` join `test`.`t2` where (`test`.`t11`.`a` > 1)
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 8
+# Status of testing query execution:
+Variable_name Value
+Handler_read_rnd_next 16
+Handler_update 2
+
+DROP TABLE t1, t2;
+#11
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+#
+# query: DELETE FROM t1 WHERE a > 1 LIMIT 1
+# select: SELECT * FROM t1 WHERE a > 1 LIMIT 1
+#
+EXPLAIN DELETE FROM t1 WHERE a > 1 LIMIT 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t1 WHERE a > 1 LIMIT 1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE a > 1 LIMIT 1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` > 1) limit 1
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 2
+# Status of testing query execution:
+Variable_name Value
+Handler_delete 1
+Handler_read_rnd_next 2
+
+DROP TABLE t1;
+#12
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+#
+# query: DELETE FROM t1 WHERE 0
+# select: SELECT * FROM t1 WHERE 0
+#
+EXPLAIN DELETE FROM t1 WHERE 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t1 WHERE 0;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE 0;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where 0
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+# Status of testing query execution:
+Variable_name Value
+
+DROP TABLE t1;
+#13
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+#
+# query: DELETE FROM t1 USING t1 WHERE 0
+# select: SELECT * FROM t1 WHERE 0
+#
+EXPLAIN DELETE FROM t1 USING t1 WHERE 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t1 USING t1 WHERE 0;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE 0;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where 0
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+# Status of testing query execution:
+Variable_name Value
+
+DROP TABLE t1;
+#14
+CREATE TABLE t1 (a INT, b INT, UNIQUE KEY (a), KEY (b));
+INSERT INTO t1 VALUES (3, 3), (7, 7);
+#
+# query: DELETE FROM t1 WHERE a = 3
+# select: SELECT * FROM t1 WHERE a = 3
+#
+EXPLAIN DELETE FROM t1 WHERE a = 3;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 5 NULL 1 Using where
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t1 WHERE a = 3;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 range a a 5 NULL 1 100.00 Using where
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE a = 3;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 const a a 5 const 1 100.00
+Warnings:
+Note 1003 select 3 AS `a`,3 AS `b` from `test`.`t1` where 1
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+Handler_read_key 1
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_key 1
+# Status of testing query execution:
+Variable_name Value
+Handler_delete 1
+Handler_read_key 1
+
+DROP TABLE t1;
+#15
+CREATE TABLE t1 (a INT, b INT, UNIQUE KEY (a), KEY (b));
+INSERT INTO t1 VALUES (3, 3), (7, 7);
+#
+# query: DELETE FROM t1 WHERE a < 3
+# select: SELECT * FROM t1 WHERE a < 3
+#
+EXPLAIN DELETE FROM t1 WHERE a < 3;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 5 NULL 1 Using where
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t1 WHERE a < 3;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 range a a 5 NULL 1 100.00 Using where
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE a < 3;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 range a a 5 NULL 1 100.00 Using index condition
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where (`test`.`t1`.`a` < 3)
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_key 1
+# Status of testing query execution:
+Variable_name Value
+Handler_read_key 1
+
+DROP TABLE t1;
+#16
+CREATE TABLE t1 ( a int PRIMARY KEY );
+#
+# query: DELETE FROM t1 WHERE t1.a > 0 ORDER BY t1.a
+# select: SELECT * FROM t1 WHERE t1.a > 0 ORDER BY t1.a
+#
+EXPLAIN DELETE FROM t1 WHERE t1.a > 0 ORDER BY t1.a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 1 Using where
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t1 WHERE t1.a > 0 ORDER BY t1.a;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 1 100.00 Using where
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE t1.a > 0 ORDER BY t1.a;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+Warnings:
+Note 1003 select NULL AS `a` from `test`.`t1` where 0 order by NULL
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+Handler_read_rnd_next 1
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 1
+# Status of testing query execution:
+Variable_name Value
+Handler_read_key 1
+
+INSERT INTO t1 VALUES (1), (2), (3);
+#
+# query: DELETE FROM t1 WHERE t1.a > 0 ORDER BY t1.a
+# select: SELECT * FROM t1 WHERE t1.a > 0 ORDER BY t1.a
+#
+EXPLAIN DELETE FROM t1 WHERE t1.a > 0 ORDER BY t1.a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 3 Using where
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t1 WHERE t1.a > 0 ORDER BY t1.a;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 3 100.00 Using where
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE t1.a > 0 ORDER BY t1.a;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 3 100.00 Using where; Using index
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` > 0) order by `test`.`t1`.`a`
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_first 1
+Handler_read_next 3
+# Status of testing query execution:
+Variable_name Value
+Handler_delete 3
+Handler_read_key 1
+Handler_read_next 3
+
+DROP TABLE t1;
+#17
+CREATE TABLE t1(a INT PRIMARY KEY);
+INSERT INTO t1 VALUES (4),(3),(1),(2);
+#
+# query: DELETE FROM t1 WHERE (@a:= a) ORDER BY a LIMIT 1
+# select: SELECT * FROM t1 WHERE (@a:= a) ORDER BY a LIMIT 1
+#
+EXPLAIN DELETE FROM t1 WHERE (@a:= a) ORDER BY a LIMIT 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL PRIMARY 4 NULL 1 Using where
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t1 WHERE (@a:= a) ORDER BY a LIMIT 1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 index NULL PRIMARY 4 NULL 1 100.00 Using where
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE (@a:= a) ORDER BY a LIMIT 1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 index NULL PRIMARY 4 NULL 1 100.00 Using where; Using index
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (@a:=`test`.`t1`.`a`) order by `test`.`t1`.`a` limit 1
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_first 1
+# Status of testing query execution:
+Variable_name Value
+Handler_delete 1
+Handler_read_first 1
+
+DROP TABLE t1;
+#18
+CREATE TABLE t1 (a DATE, b TIME, c INT, KEY c(c), KEY b(b), KEY a(a));
+INSERT INTO t1 VALUES (), (), (), (), (), (), (), (), (), ();
+UPDATE t1 SET a = c, b = c;
+#
+# query: DELETE FROM t1 ORDER BY a ASC, b ASC LIMIT 1
+# select: SELECT * FROM t1 ORDER BY a ASC, b ASC LIMIT 1
+#
+EXPLAIN DELETE FROM t1 ORDER BY a ASC, b ASC LIMIT 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 10 Using filesort
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t1 ORDER BY a ASC, b ASC LIMIT 1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 10 100.00 Using filesort
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 ORDER BY a ASC, b ASC LIMIT 1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 10 100.00 Using filesort
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c` from `test`.`t1` order by `test`.`t1`.`a`,`test`.`t1`.`b` limit 1
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 11
+Sort_rows 1
+Sort_scan 1
+# Status of testing query execution:
+Variable_name Value
+Handler_delete 1
+Handler_read_rnd 1
+Handler_read_rnd_next 11
+Sort_rows 10
+Sort_scan 1
+
+DROP TABLE t1;
+#19
+CREATE TABLE t1 (a1 INT NOT NULL, b1 INT NOT NULL);
+CREATE TABLE t2 (a2 INT NOT NULL, b2 INT NOT NULL, PRIMARY KEY (a2,b2));
+CREATE TABLE t3 (a3 INT NOT NULL, b3 INT NOT NULL, PRIMARY KEY (a3,b3));
+INSERT INTO t1 VALUES (1,1), (2,1), (1,3);
+INSERT INTO t2 VALUES (1,1), (2,2), (3,3);
+INSERT INTO t3 VALUES (1,1), (2,1), (1,3);
+#
+# query: DELETE t1,t2,t3 FROM t1,t2,t3 WHERE a1=a2 AND b2=a3 AND b1=b3
+# select: SELECT * FROM t1,t2,t3 WHERE a1=a2 AND b2=a3 AND b1=b3
+#
+EXPLAIN DELETE t1,t2,t3 FROM t1,t2,t3 WHERE a1=a2 AND b2=a3 AND b1=b3;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3
+1 SIMPLE t2 ref PRIMARY PRIMARY 4 test.t1.a1 1
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 8 test.t2.b2,test.t1.b1 1
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE t1,t2,t3 FROM t1,t2,t3 WHERE a1=a2 AND b2=a3 AND b1=b3;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
+1 SIMPLE t2 ref PRIMARY PRIMARY 4 test.t1.a1 1 100.00
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 8 test.t2.b2,test.t1.b1 1 100.00
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1,t2,t3 WHERE a1=a2 AND b2=a3 AND b1=b3;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
+1 SIMPLE t2 ref PRIMARY PRIMARY 4 test.t1.a1 1 100.00 Using index
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 8 test.t2.b2,test.t1.b1 1 100.00 Using index
+Warnings:
+Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`b1` AS `b1`,`test`.`t2`.`a2` AS `a2`,`test`.`t2`.`b2` AS `b2`,`test`.`t3`.`a3` AS `a3`,`test`.`t3`.`b3` AS `b3` from `test`.`t1` join `test`.`t2` join `test`.`t3` where ((`test`.`t2`.`a2` = `test`.`t1`.`a1`) and (`test`.`t3`.`a3` = `test`.`t2`.`b2`) and (`test`.`t3`.`b3` = `test`.`t1`.`b1`))
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_key 6
+Handler_read_next 3
+Handler_read_rnd_next 4
+# Status of testing query execution:
+Variable_name Value
+Handler_delete 8
+Handler_read_key 6
+Handler_read_next 3
+Handler_read_rnd 5
+Handler_read_rnd_next 4
+
+DROP TABLE t1, t2, t3;
+#20
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TABLE t2 (a INT);
+INSERT INTO t2 VALUES (1), (2), (3);
+#
+# query: UPDATE t1 SET a = 10 WHERE a IN (SELECT a FROM t2)
+# select: SELECT * FROM t1 WHERE a IN (SELECT a FROM t2)
+#
+EXPLAIN UPDATE t1 SET a = 10 WHERE a IN (SELECT a FROM t2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 3 Using where
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t1 SET a = 10 WHERE a IN (SELECT a FROM t2);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00 Using where
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE a IN (SELECT a FROM t2);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 100.00
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) where 1
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_key 3
+Handler_read_rnd_next 8
+# Status of testing query execution:
+Variable_name Value
+Handler_read_rnd_next 10
+Handler_update 3
+
+DROP TABLE t1, t2;
+#21
+CREATE TABLE t1 (a1 INT);
+INSERT INTO t1 VALUES (1), (2), (3), (4), (5);
+CREATE TABLE t2 (a2 VARCHAR(10));
+INSERT INTO t2 VALUES (1), (2), (3), (4), (5);
+SET @save_optimizer_switch= @@optimizer_switch;
+#
+# query: DELETE FROM t1 WHERE a1 IN (SELECT a2 FROM t2 WHERE a2 > 2)
+# select: SELECT * FROM t1 WHERE a1 IN (SELECT a2 FROM t2 WHERE a2 > 2)
+#
+EXPLAIN DELETE FROM t1 WHERE a1 IN (SELECT a2 FROM t2 WHERE a2 > 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 Using where
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 5 Using where
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t1 WHERE a1 IN (SELECT a2 FROM t2 WHERE a2 > 2);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 100.00 Using where
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 Using where
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE a1 IN (SELECT a2 FROM t2 WHERE a2 > 2);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 100.00 Using where
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t1`.`a1` AS `a1` from `test`.`t1` where <expr_cache><`test`.`t1`.`a1`>(<in_optimizer>(`test`.`t1`.`a1`,<exists>(select `test`.`t2`.`a2` from `test`.`t2` where ((`test`.`t2`.`a2` > 2) and (<cache>(`test`.`t1`.`a1`) = `test`.`t2`.`a2`)))))
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_key 5
+Handler_read_rnd_next 30
+# Status of testing query execution:
+Variable_name Value
+Handler_delete 3
+Handler_read_rnd_next 30
+
+SET @@optimizer_switch= @save_optimizer_switch;
+TRUNCATE t1;
+INSERT INTO t1 VALUES (1), (2), (3), (4), (5);
+#
+# query: DELETE FROM t1 WHERE a1 IN (SELECT a2 FROM t2 WHERE a2 > 2)
+# select: SELECT * FROM t1 WHERE a1 IN (SELECT a2 FROM t2 WHERE a2 > 2)
+#
+EXPLAIN DELETE FROM t1 WHERE a1 IN (SELECT a2 FROM t2 WHERE a2 > 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 Using where
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 5 Using where
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t1 WHERE a1 IN (SELECT a2 FROM t2 WHERE a2 > 2);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 100.00 Using where
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 Using where
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE a1 IN (SELECT a2 FROM t2 WHERE a2 > 2);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 5 100.00 Using where; FirstMatch(t1); Using join buffer (flat, BNL join)
+Warnings:
+Note 1003 select `test`.`t1`.`a1` AS `a1` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t2`.`a2` > 2) and (`test`.`t1`.`a1` = `test`.`t2`.`a2`))
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 12
+# Status of testing query execution:
+Variable_name Value
+Handler_delete 3
+Handler_read_rnd_next 30
+
+DROP TABLE t1, t2;
+#22
+CREATE TABLE t1 (i INT, j INT);
+INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5);
+#
+# query: UPDATE t1 SET i = 10
+# select: SELECT * FROM t1
+#
+EXPLAIN UPDATE t1 SET i = 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t1 SET i = 10;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00
+Warnings:
+Note 1003 select `test`.`t1`.`i` AS `i`,`test`.`t1`.`j` AS `j` from `test`.`t1`
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 6
+# Status of testing query execution:
+Variable_name Value
+Handler_read_rnd_next 6
+Handler_update 5
+
+DROP TABLE t1;
+#23
+CREATE TABLE t1 (i INT, j INT);
+INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5);
+#
+# query: DELETE FROM t1
+# select: SELECT * FROM t1
+#
+EXPLAIN DELETE FROM t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL 5 Deleting all rows
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL 5 NULL Deleting all rows
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00
+Warnings:
+Note 1003 select `test`.`t1`.`i` AS `i`,`test`.`t1`.`j` AS `j` from `test`.`t1`
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 6
+# Status of testing query execution:
+Variable_name Value
+
+DROP TABLE t1;
+#24
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+(30),(31),(32),(33),(34),(35);
+CREATE TABLE t2(a INT, b INT, c INT, d INT, INDEX(a, b, c));
+INSERT INTO t2 (a, b, c) SELECT i, i, i FROM t1;
+INSERT INTO t2 (a, b, c) SELECT t1.i, t1.i, t1.i FROM t1, t1 x1, t1 x2;
+#
+# query: DELETE FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+# select: SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+#
+EXPLAIN DELETE FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 index NULL a 15 NULL 5 Using where
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 index NULL a 15 NULL 5 100.00 Using where
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 index NULL a 15 NULL 5 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` where (`test`.`t2`.`b` = 10) order by `test`.`t2`.`a`,`test`.`t2`.`c` limit 5
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_first 1
+Handler_read_next 4
+# Status of testing query execution:
+Variable_name Value
+Handler_delete 5
+Handler_read_first 1
+Handler_read_next 4
+
+DROP TABLE t1, t2;
+#25
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TABLE t2 (i INT);
+#
+# query: INSERT INTO t2 SELECT * FROM t1
+# select: SELECT * FROM t1
+#
+EXPLAIN INSERT INTO t2 SELECT * FROM t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED INSERT INTO t2 SELECT * FROM t1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
+Warnings:
+Note 1003 select `test`.`t1`.`i` AS `i` from `test`.`t1`
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 4
+# Status of testing query execution:
+Variable_name Value
+Handler_read_rnd_next 4
+Handler_write 3
+
+DROP TABLE t1, t2;
+#26
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TABLE t2 (i INT);
+#
+# query: REPLACE INTO t2 SELECT * FROM t1
+# select: SELECT * FROM t1
+#
+EXPLAIN REPLACE INTO t2 SELECT * FROM t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED REPLACE INTO t2 SELECT * FROM t1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
+Warnings:
+Note 1003 select `test`.`t1`.`i` AS `i` from `test`.`t1`
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 4
+# Status of testing query execution:
+Variable_name Value
+Handler_read_rnd_next 4
+Handler_write 3
+
+DROP TABLE t1, t2;
+#27
+CREATE TABLE t1 (i INT);
+#
+# query: INSERT INTO t1 SET i = 10
+# select:
+#
+EXPLAIN INSERT INTO t1 SET i = 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 INSERT t1 ALL NULL NULL NULL NULL NULL NULL
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED INSERT INTO t1 SET i = 10;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 INSERT t1 ALL NULL NULL NULL NULL NULL 100.00 NULL
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+# Status of testing query execution:
+Variable_name Value
+Handler_write 1
+
+DROP TABLE t1;
+#28
+CREATE TABLE t1 (i INT);
+#
+# query: REPLACE INTO t1 SET i = 10
+# select:
+#
+EXPLAIN REPLACE INTO t1 SET i = 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 INSERT t1 ALL NULL NULL NULL NULL NULL NULL
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED REPLACE INTO t1 SET i = 10;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 INSERT t1 ALL NULL NULL NULL NULL NULL 100.00 NULL
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+# Status of testing query execution:
+Variable_name Value
+Handler_write 1
+
+DROP TABLE t1;
+#29
+CREATE TABLE t1 (a INT, i INT PRIMARY KEY);
+INSERT INTO t1 (i) VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+(30),(31),(32),(33),(34),(35);
+#
+# query: DELETE FROM t1 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5
+# select: SELECT * FROM t1 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5
+#
+EXPLAIN DELETE FROM t1 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 8 Using where
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t1 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 8 100.00 Using where
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 8 100.00 Using index condition
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`i` AS `i` from `test`.`t1` where ((`test`.`t1`.`i` > 10) and (`test`.`t1`.`i` <= 18)) order by `test`.`t1`.`i` limit 5
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_key 1
+Handler_read_next 4
+# Status of testing query execution:
+Variable_name Value
+Handler_delete 5
+Handler_read_key 1
+Handler_read_next 4
+
+DROP TABLE t1;
+#30
+CREATE TABLE t1(a INT, i CHAR(2), INDEX(i(1)));
+INSERT INTO t1 (i) VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+(30),(31),(32),(33),(34),(35);
+#
+# query: DELETE FROM t1 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5
+# select: SELECT * FROM t1 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5
+#
+EXPLAIN DELETE FROM t1 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 26 Using where; Using filesort
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t1 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL i NULL NULL NULL 26 100.00 Using where; Using filesort
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`i` AS `i` from `test`.`t1` where ((`test`.`t1`.`i` > 10) and (`test`.`t1`.`i` <= 18)) order by `test`.`t1`.`i` limit 5
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 27
+Sort_rows 5
+Sort_scan 1
+# Status of testing query execution:
+Variable_name Value
+Handler_delete 5
+Handler_read_rnd 5
+Handler_read_rnd_next 27
+Sort_rows 8
+Sort_scan 1
+
+DROP TABLE t1;
+#31
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 (i) VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+(30),(31),(32),(33),(34),(35);
+CREATE TABLE t2(a INT, b INT, c INT, d INT, INDEX(a, b, c));
+INSERT INTO t2 (a, b, c) SELECT i, i, i FROM t1;
+#
+# query: DELETE FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+# select: SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+#
+EXPLAIN DELETE FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 Using where; Using filesort
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` where (`test`.`t2`.`b` = 10) order by `test`.`t2`.`a`,`test`.`t2`.`c` limit 5
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 27
+Sort_rows 1
+Sort_scan 1
+# Status of testing query execution:
+Variable_name Value
+Handler_delete 1
+Handler_read_rnd 1
+Handler_read_rnd_next 27
+Sort_rows 1
+Sort_scan 1
+
+DROP TABLE t1, t2;
+#32
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 (i) VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+(30),(31),(32),(33),(34),(35);
+CREATE TABLE t2(a INT, b INT, c INT, d INT, INDEX(a, b, c));
+INSERT INTO t2 (a, b, c) SELECT i, i, i FROM t1;
+INSERT INTO t2 (a, b, c) SELECT t1.i, t1.i, t1.i FROM t1, t1 x1, t1 x2;
+#
+# query: DELETE FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+# select: SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+#
+EXPLAIN DELETE FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 index NULL a 15 NULL 5 Using where
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 index NULL a 15 NULL 5 100.00 Using where
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 index NULL a 15 NULL 5 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` where (`test`.`t2`.`b` = 10) order by `test`.`t2`.`a`,`test`.`t2`.`c` limit 5
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_first 1
+Handler_read_next 4
+# Status of testing query execution:
+Variable_name Value
+Handler_delete 5
+Handler_read_first 1
+Handler_read_next 4
+
+DROP TABLE t1, t2;
+#33
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 (i) VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+(30),(31),(32),(33),(34),(35);
+CREATE TABLE t2 (a CHAR(2), b CHAR(2), c CHAR(2), d CHAR(2), INDEX (a,b(1),c));
+INSERT INTO t2 SELECT i, i, i, i FROM t1;
+#
+# query: DELETE FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+# select: SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+#
+EXPLAIN DELETE FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 Using where; Using filesort
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` where (`test`.`t2`.`b` = 10) order by `test`.`t2`.`a`,`test`.`t2`.`c` limit 5
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 27
+Sort_rows 1
+Sort_scan 1
+# Status of testing query execution:
+Variable_name Value
+Handler_delete 1
+Handler_read_rnd 1
+Handler_read_rnd_next 27
+Sort_rows 1
+Sort_scan 1
+
+DROP TABLE t1, t2;
+#34
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 (i) VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+(30),(31),(32),(33),(34),(35);
+CREATE TABLE t2 (a CHAR(2), b CHAR(2), c CHAR(2), d CHAR(2), INDEX (a,b,c))
+ENGINE=HEAP;
+INSERT INTO t2 SELECT i, i, i, i FROM t1;
+#
+# query: DELETE FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+# select: SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+#
+EXPLAIN DELETE FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 Using where; Using filesort
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` where (`test`.`t2`.`b` = 10) order by `test`.`t2`.`a`,`test`.`t2`.`c` limit 5
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd 1
+Handler_read_rnd_next 27
+Sort_rows 1
+Sort_scan 1
+# Status of testing query execution:
+Variable_name Value
+Handler_delete 1
+Handler_read_rnd 1
+Handler_read_rnd_next 27
+Sort_rows 1
+Sort_scan 1
+
+DROP TABLE t1, t2;
+#35
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 (i) VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+(30),(31),(32),(33),(34),(35),(36),(37),(38),(39),
+(40),(41),(42);
+CREATE TABLE t2 (i INT, key1 INT, key2 INT, INDEX (key1), INDEX (key2));
+INSERT INTO t2 (key1, key2) SELECT i, i FROM t1;
+#
+# query: DELETE FROM t2 WHERE key1 < 13 or key2 < 14 ORDER BY key1
+# select: SELECT * FROM t2 WHERE key1 < 13 or key2 < 14 ORDER BY key1
+#
+EXPLAIN DELETE FROM t2 WHERE key1 < 13 or key2 < 14 ORDER BY key1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 index_merge key1,key2 key1,key2 5,5 NULL 7 Using sort_union(key1,key2); Using where; Using filesort
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t2 WHERE key1 < 13 or key2 < 14 ORDER BY key1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 index_merge key1,key2 key1,key2 5,5 NULL 7 100.00 Using sort_union(key1,key2); Using where; Using filesort
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t2 WHERE key1 < 13 or key2 < 14 ORDER BY key1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 index_merge key1,key2 key1,key2 5,5 NULL 7 100.00 Using sort_union(key1,key2); Using where; Using filesort
+Warnings:
+Note 1003 select `test`.`t2`.`i` AS `i`,`test`.`t2`.`key1` AS `key1`,`test`.`t2`.`key2` AS `key2` from `test`.`t2` where ((`test`.`t2`.`key1` < 13) or (`test`.`t2`.`key2` < 14)) order by `test`.`t2`.`key1`
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_key 2
+Handler_read_next 7
+Handler_read_rnd 4
+Sort_range 1
+Sort_rows 4
+# Status of testing query execution:
+Variable_name Value
+Handler_delete 4
+Handler_read_key 2
+Handler_read_next 7
+Handler_read_rnd 8
+Sort_range 1
+Sort_rows 4
+
+DROP TABLE t1, t2;
+#36
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 (i) VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+(30),(31),(32),(33),(34),(35);
+CREATE TABLE t2(a INT, i INT PRIMARY KEY);
+INSERT INTO t2 (i) SELECT i FROM t1;
+#
+# query: DELETE FROM t2 WHERE i > 10 AND i <= 18 ORDER BY i DESC LIMIT 5
+# select: SELECT * FROM t2 WHERE i > 10 AND i <= 18 ORDER BY i DESC LIMIT 5
+#
+EXPLAIN DELETE FROM t2 WHERE i > 10 AND i <= 18 ORDER BY i DESC LIMIT 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range PRIMARY PRIMARY 4 NULL 8 Using where
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t2 WHERE i > 10 AND i <= 18 ORDER BY i DESC LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 range PRIMARY PRIMARY 4 NULL 8 100.00 Using where
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t2 WHERE i > 10 AND i <= 18 ORDER BY i DESC LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 range PRIMARY PRIMARY 4 NULL 8 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`i` AS `i` from `test`.`t2` where ((`test`.`t2`.`i` > 10) and (`test`.`t2`.`i` <= 18)) order by `test`.`t2`.`i` desc limit 5
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_key 1
+Handler_read_prev 4
+# Status of testing query execution:
+Variable_name Value
+Handler_delete 5
+Handler_read_key 1
+Handler_read_prev 4
+
+DROP TABLE t1, t2;
+#37
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 (i) VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+(30),(31),(32),(33),(34),(35);
+CREATE TABLE t2 (a CHAR(2), b CHAR(2), c CHAR(2), INDEX (a, b));
+INSERT INTO t2 SELECT i, i, i FROM t1;
+#
+# query: DELETE FROM t2 ORDER BY a, b DESC LIMIT 5
+# select: SELECT * FROM t2 ORDER BY a, b DESC LIMIT 5
+#
+EXPLAIN DELETE FROM t2 ORDER BY a, b DESC LIMIT 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 Using filesort
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t2 ORDER BY a, b DESC LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using filesort
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t2 ORDER BY a, b DESC LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using filesort
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` order by `test`.`t2`.`a`,`test`.`t2`.`b` desc limit 5
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 27
+Sort_rows 5
+Sort_scan 1
+# Status of testing query execution:
+Variable_name Value
+Handler_delete 5
+Handler_read_rnd 5
+Handler_read_rnd_next 27
+Sort_rows 26
+Sort_scan 1
+
+DROP TABLE t1, t2;
+#38
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+(30),(31),(32),(33),(34),(35);
+CREATE TABLE t2 (a CHAR(2), b CHAR(2), c INT, INDEX (a, b));
+INSERT INTO t2 (a, b) SELECT i, i FROM t1;
+INSERT INTO t2 (a, b) SELECT t1.i, t1.i FROM t1, t1 x1, t1 x2;
+#
+# query: DELETE FROM t2 ORDER BY a DESC, b DESC LIMIT 5
+# select: SELECT * FROM t2 ORDER BY a DESC, b DESC LIMIT 5
+#
+EXPLAIN DELETE FROM t2 ORDER BY a DESC, b DESC LIMIT 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 index NULL a 6 NULL 5
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t2 ORDER BY a DESC, b DESC LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 index NULL a 6 NULL 5 100.00
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t2 ORDER BY a DESC, b DESC LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 index NULL a 6 NULL 5 100.00
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` order by `test`.`t2`.`a` desc,`test`.`t2`.`b` desc limit 5
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_last 1
+Handler_read_prev 4
+# Status of testing query execution:
+Variable_name Value
+Handler_delete 5
+Handler_read_last 1
+Handler_read_prev 4
+
+DROP TABLE t1, t2;
+#39
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+(30),(31),(32),(33),(34),(35);
+CREATE TABLE t2(a INT, i INT PRIMARY KEY);
+INSERT INTO t2 (i) SELECT i FROM t1;
+#
+# query: UPDATE t2 SET a = 10 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5
+# select: SELECT * FROM t2 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5
+#
+EXPLAIN UPDATE t2 SET a = 10 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range PRIMARY PRIMARY 4 NULL 8 Using where; Using buffer
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t2 SET a = 10 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 range PRIMARY PRIMARY 4 NULL 8 100.00 Using where; Using buffer
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t2 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 range PRIMARY PRIMARY 4 NULL 8 100.00 Using index condition
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`i` AS `i` from `test`.`t2` where ((`test`.`t2`.`i` > 10) and (`test`.`t2`.`i` <= 18)) order by `test`.`t2`.`i` limit 5
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_key 1
+Handler_read_next 4
+# Status of testing query execution:
+Variable_name Value
+Handler_read_key 1
+Handler_read_next 4
+Handler_read_rnd 5
+Handler_update 5
+
+DROP TABLE t1, t2;
+#40
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+(30),(31),(32),(33),(34),(35);
+CREATE TABLE t2(a INT, i CHAR(2), INDEX(i(1)));
+INSERT INTO t2 (i) SELECT i FROM t1;
+#
+# query: UPDATE t2 SET a = 10 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5
+# select: SELECT * FROM t2 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5
+#
+EXPLAIN UPDATE t2 SET a = 10 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 Using where; Using filesort
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t2 SET a = 10 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t2 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL i NULL NULL NULL 26 100.00 Using where; Using filesort
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`i` AS `i` from `test`.`t2` where ((`test`.`t2`.`i` > 10) and (`test`.`t2`.`i` <= 18)) order by `test`.`t2`.`i` limit 5
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 27
+Sort_rows 5
+Sort_scan 1
+# Status of testing query execution:
+Variable_name Value
+Handler_read_rnd 5
+Handler_read_rnd_next 27
+Handler_update 5
+Sort_rows 5
+Sort_scan 1
+
+DROP TABLE t1, t2;
+#41
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+(30),(31),(32),(33),(34),(35);
+CREATE TABLE t2(a INT, b INT, c INT, d INT, INDEX(a, b, c));
+INSERT INTO t2 (a, b, c) SELECT i, i, i FROM t1;
+#
+# query: UPDATE t2 SET d = 10 WHERE b = 10 ORDER BY a, c LIMIT 5
+# select: SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+#
+EXPLAIN UPDATE t2 SET d = 10 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 Using where; Using filesort
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t2 SET d = 10 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` where (`test`.`t2`.`b` = 10) order by `test`.`t2`.`a`,`test`.`t2`.`c` limit 5
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 27
+Sort_rows 1
+Sort_scan 1
+# Status of testing query execution:
+Variable_name Value
+Handler_read_rnd 1
+Handler_read_rnd_next 27
+Handler_update 1
+Sort_rows 1
+Sort_scan 1
+
+DROP TABLE t1, t2;
+#42
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+(30),(31),(32),(33),(34),(35);
+CREATE TABLE t2(a INT, b INT, c INT, d INT, INDEX(a, b, c));
+INSERT INTO t2 (a, b, c) SELECT i, i, i FROM t1;
+INSERT INTO t2 (a, b, c) SELECT t1.i, t1.i, t1.i FROM t1, t1 x1, t1 x2;
+#
+# query: UPDATE t2 SET d = 10 WHERE b = 10 ORDER BY a, c LIMIT 5
+# select: SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+#
+EXPLAIN UPDATE t2 SET d = 10 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 index NULL a 15 NULL 5 Using where; Using buffer
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t2 SET d = 10 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 index NULL a 15 NULL 5 100.00 Using where; Using buffer
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 index NULL a 15 NULL 5 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` where (`test`.`t2`.`b` = 10) order by `test`.`t2`.`a`,`test`.`t2`.`c` limit 5
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_first 1
+Handler_read_next 4
+# Status of testing query execution:
+Variable_name Value
+Handler_read_first 1
+Handler_read_next 4
+Handler_read_rnd 5
+Handler_update 5
+
+DROP TABLE t1, t2;
+#43
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+(30),(31),(32),(33),(34),(35);
+CREATE TABLE t2 (a CHAR(2), b CHAR(2), c CHAR(2), d CHAR(2), INDEX (a,b(1),c));
+INSERT INTO t2 SELECT i, i, i, i FROM t1;
+#
+# query: UPDATE t2 SET d = 10 WHERE b = 10 ORDER BY a, c LIMIT 5
+# select: SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+#
+EXPLAIN UPDATE t2 SET d = 10 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 Using where; Using filesort
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t2 SET d = 10 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` where (`test`.`t2`.`b` = 10) order by `test`.`t2`.`a`,`test`.`t2`.`c` limit 5
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 27
+Sort_rows 1
+Sort_scan 1
+# Status of testing query execution:
+Variable_name Value
+Handler_read_rnd 1
+Handler_read_rnd_next 27
+Sort_rows 1
+Sort_scan 1
+
+DROP TABLE t1, t2;
+#44
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+(30),(31),(32),(33),(34),(35);
+CREATE TABLE t2 (a CHAR(2), b CHAR(2), c CHAR(2), d CHAR(2), INDEX (a,b,c))
+ENGINE=HEAP;
+INSERT INTO t2 SELECT i, i, i, i FROM t1;
+#
+# query: UPDATE t2 SET d = 10 WHERE b = 10 ORDER BY a, c LIMIT 5
+# select: SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5
+#
+EXPLAIN UPDATE t2 SET d = 10 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 Using where; Using filesort
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t2 SET d = 10 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` where (`test`.`t2`.`b` = 10) order by `test`.`t2`.`a`,`test`.`t2`.`c` limit 5
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd 1
+Handler_read_rnd_next 27
+Sort_rows 1
+Sort_scan 1
+# Status of testing query execution:
+Variable_name Value
+Handler_read_rnd 1
+Handler_read_rnd_next 27
+Sort_rows 1
+Sort_scan 1
+
+DROP TABLE t1, t2;
+#45
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+(30),(31),(32),(33),(34),(35),(36),(37),(38),(39),
+(40),(41),(42);
+CREATE TABLE t2 (i INT, key1 INT, key2 INT, INDEX (key1), INDEX (key2));
+INSERT INTO t2 (key1, key2) SELECT i, i FROM t1;
+#
+# query: UPDATE t2 SET i = 123 WHERE key1 < 13 or key2 < 14 ORDER BY key1
+# select: SELECT * FROM t2 WHERE key1 < 13 or key2 < 14 ORDER BY key1
+#
+EXPLAIN UPDATE t2 SET i = 123 WHERE key1 < 13 or key2 < 14 ORDER BY key1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 index_merge key1,key2 key1,key2 5,5 NULL 7 Using sort_union(key1,key2); Using where; Using filesort
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t2 SET i = 123 WHERE key1 < 13 or key2 < 14 ORDER BY key1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 index_merge key1,key2 key1,key2 5,5 NULL 7 100.00 Using sort_union(key1,key2); Using where; Using filesort
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t2 WHERE key1 < 13 or key2 < 14 ORDER BY key1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 index_merge key1,key2 key1,key2 5,5 NULL 7 100.00 Using sort_union(key1,key2); Using where; Using filesort
+Warnings:
+Note 1003 select `test`.`t2`.`i` AS `i`,`test`.`t2`.`key1` AS `key1`,`test`.`t2`.`key2` AS `key2` from `test`.`t2` where ((`test`.`t2`.`key1` < 13) or (`test`.`t2`.`key2` < 14)) order by `test`.`t2`.`key1`
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_key 2
+Handler_read_next 7
+Handler_read_rnd 4
+Sort_range 1
+Sort_rows 4
+# Status of testing query execution:
+Variable_name Value
+Handler_read_key 2
+Handler_read_next 7
+Handler_read_rnd 8
+Handler_update 4
+Sort_range 1
+Sort_rows 4
+
+DROP TABLE t1, t2;
+#46
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+(30),(31),(32),(33),(34),(35);
+CREATE TABLE t2(a INT, i INT PRIMARY KEY);
+INSERT INTO t2 (i) SELECT i FROM t1;
+#
+# query: UPDATE t2 SET a = 10 WHERE i > 10 AND i <= 18 ORDER BY i DESC LIMIT 5
+# select: SELECT * FROM t2 WHERE i > 10 AND i <= 18 ORDER BY i DESC LIMIT 5
+#
+EXPLAIN UPDATE t2 SET a = 10 WHERE i > 10 AND i <= 18 ORDER BY i DESC LIMIT 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range PRIMARY PRIMARY 4 NULL 8 Using where; Using buffer
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t2 SET a = 10 WHERE i > 10 AND i <= 18 ORDER BY i DESC LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 range PRIMARY PRIMARY 4 NULL 8 100.00 Using where; Using buffer
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t2 WHERE i > 10 AND i <= 18 ORDER BY i DESC LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 range PRIMARY PRIMARY 4 NULL 8 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`i` AS `i` from `test`.`t2` where ((`test`.`t2`.`i` > 10) and (`test`.`t2`.`i` <= 18)) order by `test`.`t2`.`i` desc limit 5
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_key 1
+Handler_read_prev 4
+# Status of testing query execution:
+Variable_name Value
+Handler_read_key 1
+Handler_read_prev 4
+Handler_read_rnd 5
+Handler_update 5
+
+DROP TABLE t1, t2;
+#47
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+(30),(31),(32),(33),(34),(35);
+CREATE TABLE t2 (a CHAR(2), b CHAR(2), c CHAR(2), INDEX (a, b));
+INSERT INTO t2 SELECT i, i, i FROM t1;
+#
+# query: UPDATE t2 SET c = 10 ORDER BY a, b DESC LIMIT 5
+# select: SELECT * FROM t2 ORDER BY a, b DESC LIMIT 5
+#
+EXPLAIN UPDATE t2 SET c = 10 ORDER BY a, b DESC LIMIT 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 Using filesort
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t2 SET c = 10 ORDER BY a, b DESC LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using filesort
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t2 ORDER BY a, b DESC LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using filesort
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` order by `test`.`t2`.`a`,`test`.`t2`.`b` desc limit 5
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 27
+Sort_rows 5
+Sort_scan 1
+# Status of testing query execution:
+Variable_name Value
+Handler_read_rnd 5
+Handler_read_rnd_next 27
+Handler_update 4
+Sort_rows 5
+Sort_scan 1
+
+DROP TABLE t1, t2;
+#48
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+(30),(31),(32),(33),(34),(35);
+CREATE TABLE t2 (a CHAR(2), b CHAR(2), c INT, INDEX (a, b));
+INSERT INTO t2 (a, b) SELECT i, i FROM t1;
+INSERT INTO t2 (a, b) SELECT t1.i, t1.i FROM t1, t1 x1, t1 x2;
+#
+# query: UPDATE t2 SET c = 10 ORDER BY a DESC, b DESC LIMIT 5
+# select: SELECT * FROM t2 ORDER BY a DESC, b DESC LIMIT 5
+#
+EXPLAIN UPDATE t2 SET c = 10 ORDER BY a DESC, b DESC LIMIT 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 index NULL a 6 NULL 5 Using buffer
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t2 SET c = 10 ORDER BY a DESC, b DESC LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 index NULL a 6 NULL 5 100.00 Using buffer
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t2 ORDER BY a DESC, b DESC LIMIT 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 index NULL a 6 NULL 5 100.00
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` order by `test`.`t2`.`a` desc,`test`.`t2`.`b` desc limit 5
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_last 1
+Handler_read_prev 4
+# Status of testing query execution:
+Variable_name Value
+Handler_read_last 1
+Handler_read_prev 4
+Handler_read_rnd 5
+Handler_update 5
+
+DROP TABLE t1, t2;
+#49
+CREATE TABLE t1 (
+pk INT NOT NULL AUTO_INCREMENT,
+c1_idx CHAR(1) DEFAULT 'y',
+c2 INT,
+PRIMARY KEY (pk),
+INDEX c1_idx (c1_idx)
+);
+INSERT INTO t1 VALUES (1,'y',1), (2,'n',2), (3,'y',3), (4,'n',4);
+#
+# query: UPDATE t1 SET c2 = 0 WHERE c1_idx = 'y' ORDER BY pk DESC LIMIT 2
+# select: SELECT * FROM t1 WHERE c1_idx = 'y' ORDER BY pk DESC LIMIT 2
+#
+EXPLAIN UPDATE t1 SET c2 = 0 WHERE c1_idx = 'y' ORDER BY pk DESC LIMIT 2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c1_idx c1_idx 2 NULL 2 Using where; Using filesort
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t1 SET c2 = 0 WHERE c1_idx = 'y' ORDER BY pk DESC LIMIT 2;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 range c1_idx c1_idx 2 NULL 2 100.00 Using where; Using filesort
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE c1_idx = 'y' ORDER BY pk DESC LIMIT 2;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ref c1_idx c1_idx 2 const 2 100.00 Using index condition; Using where; Using filesort
+Warnings:
+Note 1003 select `test`.`t1`.`pk` AS `pk`,`test`.`t1`.`c1_idx` AS `c1_idx`,`test`.`t1`.`c2` AS `c2` from `test`.`t1` where (`test`.`t1`.`c1_idx` = 'y') order by `test`.`t1`.`pk` desc limit 2
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_key 1
+Handler_read_next 2
+Sort_range 1
+Sort_rows 2
+# Status of testing query execution:
+Variable_name Value
+Handler_read_key 1
+Handler_read_next 2
+Handler_read_rnd 2
+Handler_update 2
+Sort_range 1
+Sort_rows 2
+
+#
+# query: DELETE FROM t1 WHERE c1_idx = 'y' ORDER BY pk DESC LIMIT 2
+# select: SELECT * FROM t1 WHERE c1_idx = 'y' ORDER BY pk DESC LIMIT 2
+#
+EXPLAIN DELETE FROM t1 WHERE c1_idx = 'y' ORDER BY pk DESC LIMIT 2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c1_idx c1_idx 2 NULL 2 Using where; Using filesort
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM t1 WHERE c1_idx = 'y' ORDER BY pk DESC LIMIT 2;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 range c1_idx c1_idx 2 NULL 2 100.00 Using where; Using filesort
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE c1_idx = 'y' ORDER BY pk DESC LIMIT 2;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ref c1_idx c1_idx 2 const 2 100.00 Using index condition; Using where; Using filesort
+Warnings:
+Note 1003 select `test`.`t1`.`pk` AS `pk`,`test`.`t1`.`c1_idx` AS `c1_idx`,`test`.`t1`.`c2` AS `c2` from `test`.`t1` where (`test`.`t1`.`c1_idx` = 'y') order by `test`.`t1`.`pk` desc limit 2
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_key 1
+Handler_read_next 2
+Sort_range 1
+Sort_rows 2
+# Status of testing query execution:
+Variable_name Value
+Handler_delete 2
+Handler_read_key 1
+Handler_read_next 2
+Handler_read_rnd 2
+Sort_range 1
+Sort_rows 2
+
+DROP TABLE t1;
+#50
+CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY);
+INSERT INTO t1 VALUES (),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),();
+#
+# query: UPDATE t1 SET a=a+10 WHERE a > 34
+# select: SELECT * FROM t1 WHERE a > 34
+#
+EXPLAIN UPDATE t1 SET a=a+10 WHERE a > 34;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 3 Using where; Using buffer
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t1 SET a=a+10 WHERE a > 34;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 3 100.00 Using where; Using buffer
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE a > 34;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 3 100.00 Using where; Using index
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` > 34)
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_key 1
+Handler_read_next 2
+# Status of testing query execution:
+Variable_name Value
+Handler_read_key 1
+Handler_read_next 2
+Handler_read_rnd 2
+Handler_update 2
+
+DROP TABLE t1;
+#51
+CREATE TABLE t1 (c1 INT, c2 INT, c3 INT);
+CREATE TABLE t2 (c1 INT, c2 INT);
+INSERT INTO t1 VALUES (1, 1, 10), (2, 2, 20);
+#
+# query: UPDATE t1 LEFT JOIN t2 ON t1.c1 = t2.c1 SET t2.c2 = 10
+# select: SELECT * FROM t1 LEFT JOIN t2 ON t1.c1 = t2.c1
+#
+EXPLAIN UPDATE t1 LEFT JOIN t2 ON t1.c1 = t2.c1 SET t2.c2 = 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 system NULL NULL NULL NULL 0 const row not found
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t1 LEFT JOIN t2 ON t1.c1 = t2.c1 SET t2.c2 = 10;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 system NULL NULL NULL NULL 0 0.00 const row not found
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+Handler_read_rnd_next 1
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 LEFT JOIN t2 ON t1.c1 = t2.c1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 system NULL NULL NULL NULL 0 0.00 const row not found
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00
+Warnings:
+Note 1003 select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,NULL AS `c1`,NULL AS `c2` from `test`.`t1`
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+Handler_read_rnd_next 1
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 4
+# Status of testing query execution:
+Variable_name Value
+Handler_read_rnd_next 4
+
+#
+# query: UPDATE t1 LEFT JOIN t2 ON t1.c1 = t2.c1 SET t2.c2 = 10 WHERE t1.c3 = 10
+# select: SELECT * FROM t1 LEFT JOIN t2 ON t1.c1 = t2.c1 WHERE t1.c3 = 10
+#
+EXPLAIN UPDATE t1 LEFT JOIN t2 ON t1.c1 = t2.c1 SET t2.c2 = 10 WHERE t1.c3 = 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 system NULL NULL NULL NULL 0 const row not found
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t1 LEFT JOIN t2 ON t1.c1 = t2.c1 SET t2.c2 = 10 WHERE t1.c3 = 10;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 system NULL NULL NULL NULL 0 0.00 const row not found
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+Handler_read_rnd_next 1
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 LEFT JOIN t2 ON t1.c1 = t2.c1 WHERE t1.c3 = 10;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 system NULL NULL NULL NULL 0 0.00 const row not found
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,NULL AS `c1`,NULL AS `c2` from `test`.`t1` where (`test`.`t1`.`c3` = 10)
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+Handler_read_rnd_next 1
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 4
+# Status of testing query execution:
+Variable_name Value
+Handler_read_rnd_next 4
+
+DROP TABLE t1, t2;
+#52
+CREATE TABLE t1(f1 INT, f2 INT);
+CREATE TABLE t2(f3 INT, f4 INT);
+CREATE INDEX IDX ON t2(f3);
+INSERT INTO t1 VALUES(1,0),(2,0);
+INSERT INTO t2 VALUES(1,1),(2,2);
+#
+# query: UPDATE t1 SET t1.f2=(SELECT MAX(t2.f4) FROM t2 WHERE t2.f3=t1.f1)
+# select: SELECT (SELECT MAX(t2.f4) FROM t2 WHERE t2.f3=t1.f1) FROM t1
+#
+EXPLAIN UPDATE t1 SET t1.f2=(SELECT MAX(t2.f4) FROM t2 WHERE t2.f3=t1.f1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2
+2 DEPENDENT SUBQUERY t2 ALL IDX NULL NULL NULL 2 Using where
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t1 SET t1.f2=(SELECT MAX(t2.f4) FROM t2 WHERE t2.f3=t1.f1);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+2 DEPENDENT SUBQUERY t2 ALL IDX NULL NULL NULL 2 100.00 Using where
+Warnings:
+Note 1276 Field or reference 'test.t1.f1' of SELECT #2 was resolved in SELECT #1
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT (SELECT MAX(t2.f4) FROM t2 WHERE t2.f3=t1.f1) FROM t1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+2 DEPENDENT SUBQUERY t2 ALL IDX NULL NULL NULL 2 100.00 Using where
+Warnings:
+Note 1276 Field or reference 'test.t1.f1' of SELECT #2 was resolved in SELECT #1
+Note 1003 select <expr_cache><`test`.`t1`.`f1`>((select max(`test`.`t2`.`f4`) from `test`.`t2` where (`test`.`t2`.`f3` = `test`.`t1`.`f1`))) AS `(SELECT MAX(t2.f4) FROM t2 WHERE t2.f3=t1.f1)` from `test`.`t1`
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_key 2
+Handler_read_rnd_next 9
+# Status of testing query execution:
+Variable_name Value
+Handler_read_rnd_next 9
+Handler_update 2
+
+DROP TABLE t1, t2;
+#55
+CREATE TABLE t1(a INT);
+INSERT INTO t1 VALUES (1);
+SET @a = NULL;
+EXPLAIN DELETE FROM t1 WHERE (@a:= a);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 1 Using where
+DROP TABLE t1;
+#56
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+DELETE FROM t1 USING t1 WHERE uknown_column = 12345;
+ERROR 42S22: Unknown column 'uknown_column' in 'where clause'
+EXPLAIN EXTENDED DELETE FROM t1 USING t1 WHERE uknown_column = 12345;
+ERROR 42S22: Unknown column 'uknown_column' in 'where clause'
+DROP TABLE t1;
+#57
+CREATE TABLE t1(f1 INT);
+EXPLAIN EXTENDED UPDATE t1 SET f2=1 ORDER BY f2;
+ERROR 42S22: Unknown column 'f2' in 'order clause'
+UPDATE t1 SET f2=1 ORDER BY f2;
+ERROR 42S22: Unknown column 'f2' in 'order clause'
+DROP TABLE t1;
+#62
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (0), (1);
+CREATE VIEW v1 AS SELECT t11.a, t12.a AS b FROM t1 t11, t1 t12;
+#
+# query: UPDATE v1 SET a = 1 WHERE a > 0
+# select: SELECT * FROM v1 WHERE a > 0
+#
+EXPLAIN UPDATE v1 SET a = 1 WHERE a > 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t11 ALL NULL NULL NULL NULL 2 Using where
+1 SIMPLE t12 ALL NULL NULL NULL NULL 2
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE v1 SET a = 1 WHERE a > 0;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t11 ALL NULL NULL NULL NULL 2 100.00 Using where
+1 SIMPLE t12 ALL NULL NULL NULL NULL 2 100.00
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM v1 WHERE a > 0;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t11 ALL NULL NULL NULL NULL 2 100.00 Using where
+1 SIMPLE t12 ALL NULL NULL NULL NULL 2 100.00 Using join buffer (flat, BNL join)
+Warnings:
+Note 1003 select `test`.`t11`.`a` AS `a`,`test`.`t12`.`a` AS `b` from `test`.`t1` `t11` join `test`.`t1` `t12` where (`test`.`t11`.`a` > 0)
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 6
+# Status of testing query execution:
+Variable_name Value
+Handler_read_rnd 1
+Handler_read_rnd_deleted 1
+Handler_read_rnd_next 8
+
+#
+# query: UPDATE t1, v1 SET v1.a = 1 WHERE t1.a = v1.a
+# select: SELECT * FROM t1, v1 WHERE t1.a = v1.a
+#
+EXPLAIN UPDATE t1, v1 SET v1.a = 1 WHERE t1.a = v1.a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2
+1 SIMPLE t11 ALL NULL NULL NULL NULL 2 Using where
+1 SIMPLE t12 ALL NULL NULL NULL NULL 2
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t1, v1 SET v1.a = 1 WHERE t1.a = v1.a;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00
+1 SIMPLE t11 ALL NULL NULL NULL NULL 2 100.00 Using where
+1 SIMPLE t12 ALL NULL NULL NULL NULL 2 100.00
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1, v1 WHERE t1.a = v1.a;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00
+1 SIMPLE t11 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (flat, BNL join)
+1 SIMPLE t12 ALL NULL NULL NULL NULL 2 100.00 Using join buffer (incremental, BNL join)
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t11`.`a` AS `a`,`test`.`t12`.`a` AS `b` from `test`.`t1` join `test`.`t1` `t11` join `test`.`t1` `t12` where (`test`.`t11`.`a` = `test`.`t1`.`a`)
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 9
+# Status of testing query execution:
+Variable_name Value
+Handler_read_rnd 2
+Handler_read_rnd_deleted 1
+Handler_read_rnd_next 18
+Handler_update 1
+
+DROP TABLE t1;
+DROP VIEW v1;
+#63
+CREATE TABLE t1 (a INT, PRIMARY KEY(a));
+INSERT INTO t1 VALUES (1), (2), (3), (4), (5);
+CREATE VIEW v1 (a) AS SELECT a FROM t1;
+#
+# query: DELETE FROM v1 WHERE a < 4
+# select: SELECT * FROM v1 WHERE a < 4
+#
+EXPLAIN DELETE FROM v1 WHERE a < 4;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 3 Using where
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE FROM v1 WHERE a < 4;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 3 100.00 Using where
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM v1 WHERE a < 4;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 3 100.00 Using where; Using index
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` < 4)
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_first 1
+Handler_read_next 3
+# Status of testing query execution:
+Variable_name Value
+Handler_delete 3
+Handler_read_first 1
+Handler_read_next 3
+
+DROP TABLE t1;
+DROP VIEW v1;
+#64
+CREATE TABLE t1 (a INT, b INT, PRIMARY KEY(a));
+INSERT INTO t1 VALUES (1,2), (2,3), (3,4), (4,5), (5,10);
+CREATE TABLE t2 (x INT);
+INSERT INTO t2 VALUES (1), (2), (3), (4);
+CREATE VIEW v1 (a,c) AS SELECT a, b+1 FROM t1;
+#
+# query: DELETE v1 FROM t2, v1 WHERE t2.x = v1.a
+# select: SELECT * FROM t2, v1 WHERE t2.x = v1.a
+#
+EXPLAIN DELETE v1 FROM t2, v1 WHERE t2.x = v1.a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 4 Using where
+1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.x 1
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE v1 FROM t2, v1 WHERE t2.x = v1.a;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 4 100.00 Using where
+1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.x 1 100.00
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t2, v1 WHERE t2.x = v1.a;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 4 100.00 Using where
+1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.x 1 100.00
+Warnings:
+Note 1003 select `test`.`t2`.`x` AS `x`,`test`.`t1`.`a` AS `a`,(`test`.`t1`.`b` + 1) AS `c` from `test`.`t2` join `test`.`t1` where (`test`.`t1`.`a` = `test`.`t2`.`x`)
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_key 4
+Handler_read_rnd_next 5
+# Status of testing query execution:
+Variable_name Value
+Handler_delete 4
+Handler_read_key 4
+Handler_read_rnd 4
+Handler_read_rnd_next 5
+
+DROP TABLE t1,t2;
+DROP VIEW v1;
+#65
+CREATE TABLE t1 (a INT, b INT, PRIMARY KEY(a));
+INSERT INTO t1 VALUES (1,2), (2,3), (3,4), (4,5), (5,10);
+CREATE TABLE t2 (x INT);
+INSERT INTO t2 VALUES (1), (2), (3), (4);
+CREATE VIEW v1 (a,c) AS SELECT a, b+1 FROM t1;
+#
+# query: DELETE v1 FROM t2, v1 WHERE t2.x = v1.a
+# select: SELECT * FROM t2, v1 WHERE t2.x = v1.a
+#
+EXPLAIN DELETE v1 FROM t2, v1 WHERE t2.x = v1.a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 4 Using where
+1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.x 1
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED DELETE v1 FROM t2, v1 WHERE t2.x = v1.a;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 4 100.00 Using where
+1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.x 1 100.00
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t2, v1 WHERE t2.x = v1.a;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 4 100.00 Using where
+1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.x 1 100.00
+Warnings:
+Note 1003 select `test`.`t2`.`x` AS `x`,`test`.`t1`.`a` AS `a`,(`test`.`t1`.`b` + 1) AS `c` from `test`.`t2` join `test`.`t1` where (`test`.`t1`.`a` = `test`.`t2`.`x`)
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_key 4
+Handler_read_rnd_next 5
+# Status of testing query execution:
+Variable_name Value
+Handler_delete 4
+Handler_read_key 4
+Handler_read_rnd 4
+Handler_read_rnd_next 5
+
+DROP TABLE t1,t2;
+DROP VIEW v1;
+#66
+CREATE TABLE t1 (a INT);
+CREATE VIEW v1 (x) AS SELECT a FROM t1;
+#
+# query: INSERT INTO v1 VALUES (10)
+# select: SELECT NULL
+#
+EXPLAIN INSERT INTO v1 VALUES (10);
+id select_type table type possible_keys key key_len ref rows Extra
+1 INSERT t1 ALL NULL NULL NULL NULL NULL NULL
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED INSERT INTO v1 VALUES (10);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 INSERT t1 ALL NULL NULL NULL NULL NULL 100.00 NULL
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT NULL;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select NULL AS `NULL`
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+# Status of testing query execution:
+Variable_name Value
+Handler_write 1
+
+DROP TABLE t1;
+DROP VIEW v1;
+#67
+CREATE TABLE t1 (a INT);
+CREATE TABLE t2 (b INT);
+INSERT INTO t2 VALUES (1), (2), (3);
+CREATE VIEW v1 (x) AS SELECT b FROM t2;
+#
+# query: INSERT INTO v1 SELECT * FROM t1
+# select: SELECT * FROM t1
+#
+EXPLAIN INSERT INTO v1 SELECT * FROM t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 system NULL NULL NULL NULL 0 const row not found
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED INSERT INTO v1 SELECT * FROM t1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 system NULL NULL NULL NULL 0 0.00 const row not found
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+Handler_read_rnd_next 1
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 system NULL NULL NULL NULL 0 0.00 const row not found
+Warnings:
+Note 1003 select NULL AS `a` from `test`.`t1`
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+Handler_read_rnd_next 1
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 1
+# Status of testing query execution:
+Variable_name Value
+Handler_read_rnd_next 1
+
+DROP TABLE t1, t2;
+DROP VIEW v1;
+#68
+CREATE TABLE t1 (i INT);
+EXPLAIN INSERT DELAYED INTO t1 VALUES (1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 INSERT t1 ALL NULL NULL NULL NULL NULL NULL
+DROP TABLE t1;
+#69
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE TABLE t2 (b INT);
+INSERT INTO t2 VALUES (1), (2), (3);
+#
+# query: UPDATE t1 SET a = 10 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x)
+# select: SELECT * FROM t1 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x)
+#
+EXPLAIN UPDATE t1 SET a = 10 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where
+2 DEPENDENT SUBQUERY <derived3> index_subquery key0 key0 5 func 2
+3 DERIVED t2 ALL NULL NULL NULL NULL 3 Using filesort
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t1 SET a = 10 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where
+2 DEPENDENT SUBQUERY <derived3> index_subquery key0 key0 5 func 2 100.00
+3 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 Using filesort
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00
+2 MATERIALIZED <derived3> ALL NULL NULL NULL NULL 3 100.00
+3 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 Using filesort
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join ((select `test`.`t2`.`b` AS `b` from `test`.`t2` order by `test`.`t2`.`b` limit 2,2) `x`) where 1
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_key 3
+Handler_read_rnd_next 10
+Sort_rows 3
+Sort_scan 1
+# Status of testing query execution:
+Variable_name Value
+Handler_read_key 3
+Handler_read_rnd_next 8
+Handler_update 1
+Sort_rows 3
+Sort_scan 1
+
+#
+# query: UPDATE t1, t2 SET a = 10 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x)
+# select: SELECT * FROM t1, t2 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x)
+#
+EXPLAIN UPDATE t1, t2 SET a = 10 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
+1 PRIMARY t2 ALL NULL NULL NULL NULL 3
+2 MATERIALIZED <derived3> ALL NULL NULL NULL NULL 3
+3 DERIVED t2 ALL NULL NULL NULL NULL 3 Using filesort
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t1, t2 SET a = 10 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 3 100.00
+2 MATERIALIZED <derived3> ALL NULL NULL NULL NULL 3 100.00
+3 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 Using filesort
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1, t2 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join)
+2 MATERIALIZED <derived3> ALL NULL NULL NULL NULL 3 100.00
+3 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 Using filesort
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t1` semi join ((select `test`.`t2`.`b` AS `b` from `test`.`t2` order by `test`.`t2`.`b` limit 2,2) `x`) join `test`.`t2` where 1
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_key 3
+Handler_read_rnd_next 10
+Sort_rows 3
+Sort_scan 1
+# Status of testing query execution:
+Variable_name Value
+Handler_read_key 3
+Handler_read_rnd_next 10
+Sort_rows 3
+Sort_scan 1
+
+#
+# query: UPDATE t1, (SELECT * FROM t2) y SET a = 10 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x)
+# select: SELECT * FROM t1, (SELECT * FROM t2) y WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x)
+#
+EXPLAIN UPDATE t1, (SELECT * FROM t2) y SET a = 10 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3
+1 PRIMARY <subquery3> eq_ref distinct_key distinct_key 4 func 1
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3
+3 MATERIALIZED <derived4> ALL NULL NULL NULL NULL 3
+4 DERIVED t2 ALL NULL NULL NULL NULL 3 Using filesort
+2 DERIVED t2 ALL NULL NULL NULL NULL 3
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t1, (SELECT * FROM t2) y SET a = 10 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00
+1 PRIMARY <subquery3> eq_ref distinct_key distinct_key 4 func 1 100.00
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3 100.00
+3 MATERIALIZED <derived4> ALL NULL NULL NULL NULL 3 100.00
+4 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 Using filesort
+2 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT * FROM t1, (SELECT * FROM t2) y WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00
+1 PRIMARY <subquery3> eq_ref distinct_key distinct_key 4 func 1 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join)
+3 MATERIALIZED <derived4> ALL NULL NULL NULL NULL 3 100.00
+4 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 Using filesort
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t1` semi join ((select `test`.`t2`.`b` AS `b` from `test`.`t2` order by `test`.`t2`.`b` limit 2,2) `x`) join `test`.`t2` where 1
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_key 3
+Handler_read_rnd_next 10
+Sort_rows 3
+Sort_scan 1
+# Status of testing query execution:
+Variable_name Value
+Handler_read_key 3
+Handler_read_rnd_next 10
+Sort_rows 3
+Sort_scan 1
+
+DROP TABLE t1,t2;
+#70
+CREATE TABLE t1 (c1 INT KEY);
+CREATE TABLE t2 (c2 INT);
+CREATE TABLE t3 (c3 INT);
+EXPLAIN EXTENDED UPDATE t3 SET c3 = (
+SELECT COUNT(d1.c1)
+FROM (
+SELECT a11.c1 FROM t1 AS a11
+STRAIGHT_JOIN t2 AS a21 ON a21.c2 = a11.c1
+JOIN t1 AS a12 ON a12.c1 = a11.c1
+) d1
+);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t3 ALL NULL NULL NULL NULL 0 100.00
+2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+DROP TABLE t1, t2, t3;
+#73
+CREATE TABLE t1 (id INT);
+CREATE TABLE t2 (id INT);
+INSERT INTO t1 VALUES (1), (2);
+EXPLAIN SELECT * FROM t1 LEFT JOIN t2 USING(id) GROUP BY t1.id;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 system NULL NULL NULL NULL 0 const row not found; Using temporary; Using filesort
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2
+DROP TABLE t1,t2;
+#74
+CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB;
+Warnings:
+Warning 1286 Unknown storage engine 'InnoDB'
+Warning 1266 Using storage engine MyISAM for table 't1'
+INSERT INTO t1 VALUES (1), (2), (3), (4), (5);
+# used key is modified & Using temporary
+#
+# query: UPDATE t1 SET a=a+1 WHERE a>10
+# select: SELECT a t1 FROM t1 WHERE a>10
+#
+EXPLAIN UPDATE t1 SET a=a+1 WHERE a>10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 1 Using where; Using buffer
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t1 SET a=a+1 WHERE a>10;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 1 100.00 Using where; Using buffer
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT a t1 FROM t1 WHERE a>10;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 5 20.00 Using where; Using index
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `t1` from `test`.`t1` where (`test`.`t1`.`a` > 10)
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_first 1
+Handler_read_next 5
+# Status of testing query execution:
+Variable_name Value
+Handler_read_key 1
+
+# used key is modified & Using filesort
+#
+# query: UPDATE t1 SET a=a+1 WHERE a>10 ORDER BY a+20
+# select: SELECT a t1 FROM t1 WHERE a>10 ORDER BY a+20
+#
+EXPLAIN UPDATE t1 SET a=a+1 WHERE a>10 ORDER BY a+20;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 1 Using where; Using filesort
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED UPDATE t1 SET a=a+1 WHERE a>10 ORDER BY a+20;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 1 100.00 Using where; Using filesort
+# Status of EXPLAIN EXTENDED query
+Variable_name Value
+FLUSH STATUS;
+FLUSH TABLES;
+EXPLAIN EXTENDED SELECT a t1 FROM t1 WHERE a>10 ORDER BY a+20;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 5 20.00 Using where; Using index; Using filesort
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `t1` from `test`.`t1` where (`test`.`t1`.`a` > 10) order by (`test`.`t1`.`a` + 20)
+# Status of EXPLAIN EXTENDED "equivalent" SELECT query execution
+Variable_name Value
+# Status of "equivalent" SELECT query execution:
+Variable_name Value
+Handler_read_rnd_next 6
+Sort_scan 1
+# Status of testing query execution:
+Variable_name Value
+Handler_read_key 1
+Sort_range 1
+
+DROP TABLE t1;
+#
+# Bug #12949629: CLIENT LOSES CONNECTION AFTER EXECUTING A PROCEDURE WITH
+# EXPLAIN UPDATE/DEL/INS
+#
+CREATE TABLE t1 (i INT);
+CREATE TABLE t2 (i INT);
+CREATE PROCEDURE p1() BEGIN EXPLAIN INSERT INTO t1 VALUES (1);END|
+CREATE PROCEDURE p2() BEGIN INSERT INTO t1 VALUES (1);END|
+CREATE PROCEDURE p3() BEGIN EXPLAIN INSERT INTO t1 SELECT 1;END|
+CREATE PROCEDURE p4() BEGIN INSERT INTO t1 SELECT 1;END|
+CREATE PROCEDURE p5() BEGIN EXPLAIN REPLACE INTO t1 VALUES (1);END|
+CREATE PROCEDURE p6() BEGIN REPLACE INTO t1 VALUES (1);END|
+CREATE PROCEDURE p7() BEGIN EXPLAIN REPLACE INTO t1 SELECT 1;END|
+CREATE PROCEDURE p8() BEGIN REPLACE INTO t1 SELECT 1;END|
+CREATE PROCEDURE p9() BEGIN EXPLAIN UPDATE t1 SET i = 10;END|
+CREATE PROCEDURE p10() BEGIN UPDATE t1 SET i = 10;END|
+CREATE PROCEDURE p11() BEGIN EXPLAIN UPDATE t1,t2 SET t1.i = 10 WHERE t1.i = t2.i ;END|
+CREATE PROCEDURE p12() BEGIN UPDATE t1,t2 SET t1.i = 10 WHERE t1.i = t2.i ;END|
+CREATE PROCEDURE p13() BEGIN EXPLAIN DELETE FROM t1;END|
+CREATE PROCEDURE p14() BEGIN DELETE FROM t1;END|
+CREATE PROCEDURE p15() BEGIN EXPLAIN DELETE FROM t1 USING t1;END|
+CREATE PROCEDURE p16() BEGIN DELETE FROM t1 USING t1;END|
+CALL p16();
+DROP PROCEDURE p16;
+CALL p15();
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 system NULL NULL NULL NULL 0 const row not found
+DROP PROCEDURE p15;
+CALL p14();
+DROP PROCEDURE p14;
+CALL p13();
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL 0 Deleting all rows
+DROP PROCEDURE p13;
+CALL p12();
+DROP PROCEDURE p12;
+CALL p11();
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+DROP PROCEDURE p11;
+CALL p10();
+DROP PROCEDURE p10;
+CALL p9();
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 0
+DROP PROCEDURE p9;
+CALL p8();
+DROP PROCEDURE p8;
+CALL p7();
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
+DROP PROCEDURE p7;
+CALL p6();
+DROP PROCEDURE p6;
+CALL p5();
+id select_type table type possible_keys key key_len ref rows Extra
+1 INSERT t1 ALL NULL NULL NULL NULL NULL NULL
+DROP PROCEDURE p5;
+CALL p4();
+DROP PROCEDURE p4;
+CALL p3();
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
+DROP PROCEDURE p3;
+CALL p2();
+DROP PROCEDURE p2;
+CALL p1();
+id select_type table type possible_keys key key_len ref rows Extra
+1 INSERT t1 ALL NULL NULL NULL NULL NULL NULL
+DROP PROCEDURE p1;
+DROP TABLE t1, t2;
+#
+set default_storage_engine= @save_storage_engine;
+set optimizer_switch=default;
diff --git a/mysql-test/r/mysqld--help.result b/mysql-test/r/mysqld--help.result
index aa8bb67d58c..08531847c66 100644
--- a/mysql-test/r/mysqld--help.result
+++ b/mysql-test/r/mysqld--help.result
@@ -329,7 +329,7 @@ The following options may be given as the first argument:
log if it is open.
--log-slow-verbosity=name
log-slow-verbosity=[value[,value ...]] where value is one
- of 'innodb', 'query_plan'
+ of 'innodb', 'query_plan', 'explain'
--log-tc=name Path to transaction coordinator log (used for
transactions that affect more than one storage engine,
when binary log is disabled).
diff --git a/mysql-test/r/selectivity.result b/mysql-test/r/selectivity.result
index 837e13bf238..ac8771bd90a 100644
--- a/mysql-test/r/selectivity.result
+++ b/mysql-test/r/selectivity.result
@@ -393,7 +393,7 @@ and not exists (select * from orders where o_custkey = c_custkey)
group by cntrycode
order by cntrycode;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE customer ALL NULL NULL NULL NULL 150 100.00 Using where; Using temporary; Using filesort
+1 PRIMARY customer ALL NULL NULL NULL NULL 150 100.00 Using where; Using temporary; Using filesort
4 DEPENDENT SUBQUERY orders ref i_o_custkey i_o_custkey 5 dbt3_s001.customer.c_custkey 15 100.00 Using index
3 SUBQUERY customer ALL NULL NULL NULL NULL 150 100.00 Using where
Warnings:
@@ -434,7 +434,7 @@ and not exists (select * from orders where o_custkey = c_custkey)
group by cntrycode
order by cntrycode;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE customer ALL NULL NULL NULL NULL 150 100.00 Using where; Using temporary; Using filesort
+1 PRIMARY customer ALL NULL NULL NULL NULL 150 100.00 Using where; Using temporary; Using filesort
4 DEPENDENT SUBQUERY orders ref i_o_custkey i_o_custkey 5 dbt3_s001.customer.c_custkey 15 100.00 Using index
3 SUBQUERY customer ALL NULL NULL NULL NULL 150 91.00 Using where
Warnings:
diff --git a/mysql-test/r/selectivity_innodb.result b/mysql-test/r/selectivity_innodb.result
index ec4f03ca56a..9bd92d7c7c8 100644
--- a/mysql-test/r/selectivity_innodb.result
+++ b/mysql-test/r/selectivity_innodb.result
@@ -396,7 +396,7 @@ and not exists (select * from orders where o_custkey = c_custkey)
group by cntrycode
order by cntrycode;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE customer ALL NULL NULL NULL NULL 150 100.00 Using where; Using temporary; Using filesort
+1 PRIMARY customer ALL NULL NULL NULL NULL 150 100.00 Using where; Using temporary; Using filesort
4 DEPENDENT SUBQUERY orders ref i_o_custkey i_o_custkey 5 dbt3_s001.customer.c_custkey 15 100.00 Using index
3 SUBQUERY customer ALL NULL NULL NULL NULL 150 100.00 Using where
Warnings:
@@ -437,7 +437,7 @@ and not exists (select * from orders where o_custkey = c_custkey)
group by cntrycode
order by cntrycode;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE customer ALL NULL NULL NULL NULL 150 100.00 Using where; Using temporary; Using filesort
+1 PRIMARY customer ALL NULL NULL NULL NULL 150 100.00 Using where; Using temporary; Using filesort
4 DEPENDENT SUBQUERY orders ref i_o_custkey i_o_custkey 5 dbt3_s001.customer.c_custkey 15 100.00 Using index
3 SUBQUERY customer ALL NULL NULL NULL NULL 150 91.00 Using where
Warnings:
diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result
index be0b1c28b06..7e0ac0b277c 100644
--- a/mysql-test/r/show_explain.result
+++ b/mysql-test/r/show_explain.result
@@ -165,7 +165,11 @@ set @show_explain_probe_select_id=1;
set debug_dbug='+d,show_explain_probe_join_exec_end';
select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1;
show explain for $thr2;
-ERROR HY000: Target is not running an EXPLAINable command
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY a ALL NULL NULL NULL NULL 10 Using where
+2 DEPENDENT SUBQUERY b ALL NULL NULL NULL NULL 10 Using where
+Warnings:
+Note 1003 select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1
a (select max(a) from t0 b where b.a+a.a<10)
0 9
set debug_dbug=@old_debug;
@@ -177,6 +181,8 @@ set debug_dbug='+d,show_explain_probe_join_exec_start';
set @foo= (select max(a) from t0 where sin(a) >0);
show explain for $thr2;
ERROR HY000: Target is not running an EXPLAINable command
+kill query $thr2;
+ERROR 70100: Query execution was interrupted
set debug_dbug=@old_debug;
#
# Attempt SHOW EXPLAIN for an UPDATE
@@ -186,22 +192,38 @@ set @show_explain_probe_select_id=2;
set debug_dbug='+d,show_explain_probe_join_exec_start';
update t2 set dummy=0 where (select max(a) from t0 where t2.a + t0.a <3) >3 ;
show explain for $thr2;
-ERROR HY000: Target is not running an EXPLAINable command
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where
+2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 10 Using where
+Warnings:
+Note 1003 update t2 set dummy=0 where (select max(a) from t0 where t2.a + t0.a <3) >3
show explain for $thr2;
-ERROR HY000: Target is not running an EXPLAINable command
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where
+2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 10 Using where
+Warnings:
+Note 1003 update t2 set dummy=0 where (select max(a) from t0 where t2.a + t0.a <3) >3
drop table t2;
set debug_dbug=@old_debug;
#
-# Attempt SHOW EXPLAIN for a DELETE
+# Attempt SHOW EXPLAIN for a DELETE (UPD: now works)
#
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';
delete from t2 where (select max(a) from t0 where t2.a + t0.a <3) >3 ;
show explain for $thr2;
-ERROR HY000: Target is not running an EXPLAINable command
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where
+2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 10 Using where
+Warnings:
+Note 1003 delete from t2 where (select max(a) from t0 where t2.a + t0.a <3) >3
show explain for $thr2;
-ERROR HY000: Target is not running an EXPLAINable command
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where
+2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 10 Using where
+Warnings:
+Note 1003 delete from t2 where (select max(a) from t0 where t2.a + t0.a <3) >3
drop table t2;
set debug_dbug=@old_debug;
#
@@ -220,13 +242,13 @@ Note 1003 select t2.a, ((select max(a) from t0 where t2.a + t0.a <3) >3) as SUBQ
show explain for $thr2;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 3
-2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Query plan already deleted
+2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 10 Using where
Warnings:
Note 1003 select t2.a, ((select max(a) from t0 where t2.a + t0.a <3) >3) as SUBQ from t2
show explain for $thr2;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 3
-2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Query plan already deleted
+2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 10 Using where
Warnings:
Note 1003 select t2.a, ((select max(a) from t0 where t2.a + t0.a <3) >3) as SUBQ from t2
a SUBQ
@@ -327,7 +349,11 @@ SELECT alias.a FROM t2, ( SELECT * FROM t2 ) AS alias GROUP BY alias.a;
# FIXED by "conservative assumptions about when QEP is available" fix:
# NOTE: current code will not show "Using join buffer":
show explain for $thr2;
-ERROR HY000: Target is not running an EXPLAINable command
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 5 Using temporary; Using filesort
+1 SIMPLE t2 ALL NULL NULL NULL NULL 5 Using join buffer (flat, BNL join)
+Warnings:
+Note 1003 SELECT alias.a FROM t2, ( SELECT * FROM t2 ) AS alias GROUP BY alias.a
a
1
2
@@ -381,13 +407,8 @@ set debug_dbug='+d,show_explain_probe_join_exec_end';
SELECT * FROM v1, t2;
show explain for $thr2;
ERROR HY000: Target is not running an EXPLAINable command
-a b
-8 4
-8 5
-8 6
-8 7
-8 8
-8 9
+kill query $thr2;
+ERROR 70100: Query execution was interrupted
set debug_dbug=@old_debug;
DROP VIEW v1;
DROP TABLE t2, t3;
@@ -412,7 +433,10 @@ set @show_explain_probe_select_id=1;
set debug_dbug='+d,show_explain_probe_join_exec_end';
select * from t0 where 1>10;
show explain for $thr2;
-ERROR HY000: Target is not running an EXPLAINable command
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
+Warnings:
+Note 1003 select * from t0 where 1>10
a
set debug_dbug=@old_debug;
#
@@ -424,7 +448,10 @@ set @show_explain_probe_select_id=1;
set debug_dbug='+d,show_explain_probe_join_exec_end';
select * from t0,t3 where t3.a=112233;
show explain for $thr2;
-ERROR HY000: Target is not running an EXPLAINable command
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL no matching row in const table
+Warnings:
+Note 1003 select * from t0,t3 where t3.a=112233
a a
set debug_dbug=@old_debug;
drop table t3;
@@ -529,7 +556,12 @@ set @show_explain_probe_select_id=1;
set debug_dbug='+d,show_explain_probe_join_exec_end';
SELECT * FROM t2 WHERE (5, 78) IN (SELECT `a1`, MAX(`a1`) FROM t2 GROUP BY `a1`);
show explain for $thr2;
-ERROR HY000: Target is not running an EXPLAINable command
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY <subquery2> const distinct_key distinct_key 8 const,const 1
+1 PRIMARY t2 ALL NULL NULL NULL NULL 20 Using join buffer (flat, BNL join)
+2 MATERIALIZED t2 index NULL a1 4 NULL 20 Using index
+Warnings:
+Note 1003 SELECT * FROM t2 WHERE (5, 78) IN (SELECT `a1`, MAX(`a1`) FROM t2 GROUP BY `a1`)
pk a1
set debug_dbug=@old_debug;
DROP TABLE t2;
@@ -635,7 +667,7 @@ SELECT a + 1 FROM v1;
show explain for $thr2;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2
-2 DERIVED NULL NULL NULL NULL NULL NULL NULL Query plan already deleted
+2 DERIVED t1 ALL NULL NULL NULL NULL 2
Warnings:
Note 1003 SELECT a + 1 FROM v1
a + 1
@@ -1045,7 +1077,7 @@ show explain for $thr2;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY alias1 ALL NULL NULL NULL NULL 14
1 PRIMARY t2 ALL NULL NULL NULL NULL 20
-3 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Query plan already deleted
+3 SUBQUERY t3 ALL NULL NULL NULL NULL 20 Using where
Warnings:
Note 1003 SELECT max(a+b+c) FROM t1 AS alias1, ( SELECT * FROM t2 ) AS alias
WHERE EXISTS ( SELECT * FROM t3 WHERE b = c ) OR a <= 10
@@ -1095,6 +1127,45 @@ set names default;
#
show explain for foo;
ERROR HY000: You may only use constant expressions in this statement
+#
+# MDEV-411: SHOW EXPLAIN: For dependent subquery EXPLAIN produces type=index, key, 'Using where; Using index',
+# while SHOW EXPLAIN says type=ALL, no key, 'Range checked for each record'
+#
+CREATE TABLE t1 (a INT NOT NULL, KEY(a)) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (7),(0);
+CREATE TABLE t2 (b INT NOT NULL) ENGINE=MyISAM;
+INSERT INTO t2 VALUES (0),(8);
+explain
+SELECT SUM(b) FROM ( SELECT * FROM t1 ) AS alias1, t2
+WHERE b <= ANY (
+SELECT a FROM t1
+WHERE a = b + SLEEP(0.2) OR a >= ( SELECT SUM(b) FROM t2 ));
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 index NULL a 4 NULL 2 Using index
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where
+3 DEPENDENT SUBQUERY t1 ALL a NULL NULL NULL 2 Range checked for each record (index map: 0x1)
+4 SUBQUERY t2 ALL NULL NULL NULL NULL 2
+set @show_explain_probe_select_id=1;
+set debug_dbug='+d,show_explain_probe_join_exec_start';
+SELECT SUM(b) FROM ( SELECT * FROM t1 ) AS alias1, t2
+WHERE b <= ANY (
+SELECT a FROM t1
+WHERE a = b + SLEEP(0.2) OR a >= ( SELECT SUM(b) FROM t2 ));
+show explain for $thr2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 index NULL a 4 NULL 2 Using index
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where
+3 DEPENDENT SUBQUERY t1 ALL a NULL NULL NULL 2 Range checked for each record (index map: 0x1)
+4 SUBQUERY t2 ALL NULL NULL NULL NULL 2
+Warnings:
+Note 1003 SELECT SUM(b) FROM ( SELECT * FROM t1 ) AS alias1, t2
+WHERE b <= ANY (
+SELECT a FROM t1
+WHERE a = b + SLEEP(0.2) OR a >= ( SELECT SUM(b) FROM t2 ))
+SUM(b)
+0
+set debug_dbug=@old_debug;
+DROP TABLE t1,t2;
# End
drop table t0;
set debug_sync='RESET';
diff --git a/mysql-test/r/show_explain_non_select.result b/mysql-test/r/show_explain_non_select.result
new file mode 100644
index 00000000000..0bd1e959405
--- /dev/null
+++ b/mysql-test/r/show_explain_non_select.result
@@ -0,0 +1,44 @@
+drop table if exists t0, t1;
+SET @old_debug= @@session.debug;
+set debug_sync='RESET';
+create table t0 (a int) engine=myisam;
+insert into t0 values (1),(2),(3),(4),(5),(6),(7),(8);
+create table t1 (a int, b int, filler char(100), key(a), key(b));
+insert into t1
+select A.a+10*B.a + 10*C.a, A.a+10*B.a + 10*C.a, 'filler'
+from t0 A, t0 B, t0 C;
+#
+# Test SHOW EXPLAIN for single-table DELETE
+#
+set debug_dbug='+d,show_explain_probe_delete_exec_start';
+delete from t1 where a<10 and b+1>1000;
+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 1 Using where
+Warnings:
+Note 1003 delete from t1 where a<10 and b+1>1000
+#
+# Test SHOW EXPLAIN for multi-table DELETE
+#
+set @show_explain_probe_select_id=1;
+set debug_dbug='+d,show_explain_probe_do_select';
+delete t1 from t1, t0 where t0.a=t1.a and t1.b +1 > 1000;
+show explain for $thr2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ALL NULL NULL NULL NULL 8 Using where
+1 SIMPLE t1 ref a a 5 test.t0.a 4 Using where
+Warnings:
+Note 1003 delete t1 from t1, t0 where t0.a=t1.a and t1.b +1 > 1000
+#
+# Test SHOW EXPLAIN for single-table UPDATE
+#
+set debug_dbug='+d,show_explain_probe_update_exec_start';
+update t1 set filler='filler-data-2' where a<10 and b+1>1000;
+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 1 Using where
+Warnings:
+Note 1003 update t1 set filler='filler-data-2' where a<10 and b+1>1000
+drop table t0,t1;
+set debug_dbug=@old_debug;
+set debug_sync='RESET';
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result
index 824079c3a59..81e0b2c84c0 100644
--- a/mysql-test/r/subselect.result
+++ b/mysql-test/r/subselect.result
@@ -10,7 +10,7 @@ select (select 2);
2
explain extended select (select 2);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1249 Select 2 was reduced during optimization
Note 1003 select 2 AS `(select 2)`
@@ -734,7 +734,7 @@ id
1
EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t2 ref id id 5 const 1 100.00 Using index
+1 SIMPLE t2 ref id id 5 const 1 100.00 Using index
Warnings:
Note 1249 Select 2 was reduced during optimization
Note 1003 select `test`.`t2`.`id` AS `id` from `test`.`t2` where (`test`.`t2`.`id` = 1)
@@ -746,7 +746,7 @@ id
2
EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1+(select 1));
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t2 ref id id 5 const 1 100.00 Using where; Using index
+1 SIMPLE t2 ref id id 5 const 1 100.00 Using where; Using index
Warnings:
Note 1249 Select 3 was reduced during optimization
Note 1249 Select 2 was reduced during optimization
@@ -880,7 +880,7 @@ select 10.5 > ANY (SELECT * from t1);
1
explain extended select (select a+1) from t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1249 Select 2 was reduced during optimization
@@ -4554,7 +4554,7 @@ int_nokey int_key
0 0
EXPLAIN EXTENDED SELECT * FROM C WHERE `int_key` IN (SELECT `int_nokey`);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY C ALL NULL NULL NULL NULL 20 100.00 Using where
+1 SIMPLE C ALL NULL NULL NULL NULL 20 100.00 Using where
DROP TABLE C;
# End of test for bug#45061.
#
@@ -6112,7 +6112,7 @@ FROM t1 AS sq4_alias1
WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR
sq4_alias1.col_varchar_key = @var3 ) AS alias3;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE <derived2> system NULL NULL NULL NULL 0 const row not found
+1 PRIMARY <derived2> system NULL NULL NULL NULL 0 const row not found
2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table
SELECT * FROM ( SELECT @var3:=12, sq4_alias1.*
FROM t1 AS sq4_alias1
@@ -6157,7 +6157,7 @@ FROM t2 AS c_sq1_alias1
WHERE (c_sq1_alias1.col_int_nokey != @var2
OR c_sq1_alias1.pk != @var3)) ) AS alias3;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
3 DEPENDENT SUBQUERY c_sq1_alias1 system PRIMARY NULL NULL NULL 1
SELECT * FROM ( SELECT sq4_alias1.*
FROM t1 AS sq4_alias1
diff --git a/mysql-test/r/subselect2.result b/mysql-test/r/subselect2.result
index 890ba2bb2d7..426e1ba39f9 100644
--- a/mysql-test/r/subselect2.result
+++ b/mysql-test/r/subselect2.result
@@ -286,7 +286,7 @@ WHERE date < '2012-12-12 12:12:12'
ORDER BY mirror_date ASC
) AS calculated_result;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE <derived2> ALL NULL NULL NULL NULL 2
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2
2 DERIVED t1 range date date 9 NULL 2 Using index condition; Using where; Rowid-ordered scan; Using filesort
SELECT * FROM (
SELECT node_uid, date, mirror_date, @result := 0 AS result
@@ -309,7 +309,7 @@ WHERE date < '2012-12-12 12:12:12'
ORDER BY mirror_date ASC
) AS calculated_result;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE <derived2> ALL NULL NULL NULL NULL 2
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2
2 DERIVED t1 range date date 9 NULL 2 Using index condition; Using where; Using filesort
SELECT * FROM (
SELECT node_uid, date, mirror_date, @result := 0 AS result
diff --git a/mysql-test/r/subselect3.result b/mysql-test/r/subselect3.result
index 1a33fb0c6a3..24d9f0de35a 100644
--- a/mysql-test/r/subselect3.result
+++ b/mysql-test/r/subselect3.result
@@ -1031,7 +1031,7 @@ update t22 set c = '2005-12-08 15:58:27' where a = 255;
explain select t21.* from t21,t22 where t21.a = t22.a and
t22.a in (select t12.a from t11, t12 where t11.a in(255,256) and t11.a = t12.a and t11.c is null) and t22.c is null order by t21.a;
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t11 ALL NULL NULL NULL NULL 8 Using where; Using temporary; Using filesort; Start temporary
+1 PRIMARY t11 ALL NULL NULL NULL NULL 8 Using where; Start temporary; Using temporary; Using filesort
1 PRIMARY t12 ALL NULL NULL NULL NULL 8 Using where; Using join buffer (flat, BNL join)
1 PRIMARY t22 ALL NULL NULL NULL NULL 26 Using where; End temporary; Using join buffer (flat, BNL join)
1 PRIMARY t21 ALL NULL NULL NULL NULL 26 Using where; Using join buffer (flat, BNL join)
diff --git a/mysql-test/r/subselect3_jcl6.result b/mysql-test/r/subselect3_jcl6.result
index 5bae1453a5e..19d3d25148f 100644
--- a/mysql-test/r/subselect3_jcl6.result
+++ b/mysql-test/r/subselect3_jcl6.result
@@ -1041,7 +1041,7 @@ update t22 set c = '2005-12-08 15:58:27' where a = 255;
explain select t21.* from t21,t22 where t21.a = t22.a and
t22.a in (select t12.a from t11, t12 where t11.a in(255,256) and t11.a = t12.a and t11.c is null) and t22.c is null order by t21.a;
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t11 ALL NULL NULL NULL NULL 8 Using where; Using temporary; Using filesort; Start temporary
+1 PRIMARY t11 ALL NULL NULL NULL NULL 8 Using where; Start temporary; Using temporary; Using filesort
1 PRIMARY t12 hash_ALL NULL #hash#$hj 4 test.t11.a 8 Using where; Using join buffer (flat, BNLH join)
1 PRIMARY t22 hash_ALL NULL #hash#$hj 4 test.t11.a 26 Using where; End temporary; Using join buffer (incremental, BNLH join)
1 PRIMARY t21 hash_ALL NULL #hash#$hj 4 test.t11.a 26 Using where; Using join buffer (incremental, BNLH join)
diff --git a/mysql-test/r/subselect4.result b/mysql-test/r/subselect4.result
index 85abcb0139d..b096d20c331 100644
--- a/mysql-test/r/subselect4.result
+++ b/mysql-test/r/subselect4.result
@@ -93,12 +93,12 @@ DROP TABLE t1,t2;
#
EXPLAIN SELECT 1 LIKE ( 1 IN ( SELECT 1 ) );
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1249 Select 2 was reduced during optimization
DESCRIBE SELECT 1 LIKE ( 1 IN ( SELECT 1 ) );
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1249 Select 2 was reduced during optimization
# None of the below should crash
@@ -513,8 +513,8 @@ id select_type table type possible_keys key key_len ref rows Extra
2 MATERIALIZED t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join)
EXECUTE stmt;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ALL t1_IDX NULL NULL NULL 5
-1 SIMPLE <subquery2> eq_ref distinct_key distinct_key 3 func 1
+1 PRIMARY t1 ALL t1_IDX NULL NULL NULL 5
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 3 func 1
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 Using where
2 MATERIALIZED t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join)
DEALLOCATE PREPARE stmt;
@@ -551,8 +551,8 @@ id select_type table type possible_keys key key_len ref rows Extra
2 MATERIALIZED t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join)
EXECUTE stmt;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ALL t1_IDX NULL NULL NULL 5
-1 SIMPLE <subquery2> eq_ref distinct_key distinct_key 3 func 1
+1 PRIMARY t1 ALL t1_IDX NULL NULL NULL 5
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 3 func 1
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 Using where
2 MATERIALIZED t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join)
DEALLOCATE PREPARE stmt;
@@ -588,8 +588,8 @@ id select_type table type possible_keys key key_len ref rows Extra
2 MATERIALIZED t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join)
EXECUTE stmt;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ALL NULL NULL NULL NULL 5
-1 SIMPLE <subquery2> eq_ref distinct_key distinct_key 3 func 1
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 3 func 1
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 Using where
2 MATERIALIZED t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join)
DEALLOCATE PREPARE stmt;
diff --git a/mysql-test/r/subselect_exists_to_in.result b/mysql-test/r/subselect_exists_to_in.result
index 19ae87f473f..348e0a40d95 100644
--- a/mysql-test/r/subselect_exists_to_in.result
+++ b/mysql-test/r/subselect_exists_to_in.result
@@ -14,7 +14,7 @@ select (select 2);
2
explain extended select (select 2);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1249 Select 2 was reduced during optimization
Note 1003 select 2 AS `(select 2)`
@@ -738,7 +738,7 @@ id
1
EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t2 ref id id 5 const 1 100.00 Using index
+1 SIMPLE t2 ref id id 5 const 1 100.00 Using index
Warnings:
Note 1249 Select 2 was reduced during optimization
Note 1003 select `test`.`t2`.`id` AS `id` from `test`.`t2` where (`test`.`t2`.`id` = 1)
@@ -750,7 +750,7 @@ id
2
EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1+(select 1));
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t2 ref id id 5 const 1 100.00 Using where; Using index
+1 SIMPLE t2 ref id id 5 const 1 100.00 Using where; Using index
Warnings:
Note 1249 Select 3 was reduced during optimization
Note 1249 Select 2 was reduced during optimization
@@ -884,7 +884,7 @@ select 10.5 > ANY (SELECT * from t1);
1
explain extended select (select a+1) from t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1249 Select 2 was reduced during optimization
@@ -4560,7 +4560,7 @@ int_nokey int_key
0 0
EXPLAIN EXTENDED SELECT * FROM C WHERE `int_key` IN (SELECT `int_nokey`);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY C ALL NULL NULL NULL NULL 20 100.00 Using where
+1 SIMPLE C ALL NULL NULL NULL NULL 20 100.00 Using where
DROP TABLE C;
# End of test for bug#45061.
#
@@ -6120,7 +6120,7 @@ FROM t1 AS sq4_alias1
WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR
sq4_alias1.col_varchar_key = @var3 ) AS alias3;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE <derived2> system NULL NULL NULL NULL 0 const row not found
+1 PRIMARY <derived2> system NULL NULL NULL NULL 0 const row not found
2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table
SELECT * FROM ( SELECT @var3:=12, sq4_alias1.*
FROM t1 AS sq4_alias1
@@ -6165,7 +6165,7 @@ FROM t2 AS c_sq1_alias1
WHERE (c_sq1_alias1.col_int_nokey != @var2
OR c_sq1_alias1.pk != @var3)) ) AS alias3;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
3 DEPENDENT SUBQUERY c_sq1_alias1 system PRIMARY NULL NULL NULL 1
SELECT * FROM ( SELECT sq4_alias1.*
FROM t1 AS sq4_alias1
diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result
index 627e5b03e32..3cda876a840 100644
--- a/mysql-test/r/subselect_no_mat.result
+++ b/mysql-test/r/subselect_no_mat.result
@@ -17,7 +17,7 @@ select (select 2);
2
explain extended select (select 2);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1249 Select 2 was reduced during optimization
Note 1003 select 2 AS `(select 2)`
@@ -741,7 +741,7 @@ id
1
EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t2 ref id id 5 const 1 100.00 Using index
+1 SIMPLE t2 ref id id 5 const 1 100.00 Using index
Warnings:
Note 1249 Select 2 was reduced during optimization
Note 1003 select `test`.`t2`.`id` AS `id` from `test`.`t2` where (`test`.`t2`.`id` = 1)
@@ -753,7 +753,7 @@ id
2
EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1+(select 1));
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t2 ref id id 5 const 1 100.00 Using where; Using index
+1 SIMPLE t2 ref id id 5 const 1 100.00 Using where; Using index
Warnings:
Note 1249 Select 3 was reduced during optimization
Note 1249 Select 2 was reduced during optimization
@@ -887,7 +887,7 @@ select 10.5 > ANY (SELECT * from t1);
1
explain extended select (select a+1) from t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1249 Select 2 was reduced during optimization
@@ -4556,7 +4556,7 @@ int_nokey int_key
0 0
EXPLAIN EXTENDED SELECT * FROM C WHERE `int_key` IN (SELECT `int_nokey`);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY C ALL NULL NULL NULL NULL 20 100.00 Using where
+1 SIMPLE C ALL NULL NULL NULL NULL 20 100.00 Using where
DROP TABLE C;
# End of test for bug#45061.
#
@@ -6111,7 +6111,7 @@ FROM t1 AS sq4_alias1
WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR
sq4_alias1.col_varchar_key = @var3 ) AS alias3;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE <derived2> system NULL NULL NULL NULL 0 const row not found
+1 PRIMARY <derived2> system NULL NULL NULL NULL 0 const row not found
2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table
SELECT * FROM ( SELECT @var3:=12, sq4_alias1.*
FROM t1 AS sq4_alias1
@@ -6156,7 +6156,7 @@ FROM t2 AS c_sq1_alias1
WHERE (c_sq1_alias1.col_int_nokey != @var2
OR c_sq1_alias1.pk != @var3)) ) AS alias3;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
3 DEPENDENT SUBQUERY c_sq1_alias1 system PRIMARY NULL NULL NULL 1
SELECT * FROM ( SELECT sq4_alias1.*
FROM t1 AS sq4_alias1
diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result
index 5368198f77a..283ba678ef3 100644
--- a/mysql-test/r/subselect_no_opts.result
+++ b/mysql-test/r/subselect_no_opts.result
@@ -13,7 +13,7 @@ select (select 2);
2
explain extended select (select 2);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1249 Select 2 was reduced during optimization
Note 1003 select 2 AS `(select 2)`
@@ -737,7 +737,7 @@ id
1
EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t2 ref id id 5 const 1 100.00 Using index
+1 SIMPLE t2 ref id id 5 const 1 100.00 Using index
Warnings:
Note 1249 Select 2 was reduced during optimization
Note 1003 select `test`.`t2`.`id` AS `id` from `test`.`t2` where (`test`.`t2`.`id` = 1)
@@ -749,7 +749,7 @@ id
2
EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1+(select 1));
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t2 ref id id 5 const 1 100.00 Using where; Using index
+1 SIMPLE t2 ref id id 5 const 1 100.00 Using where; Using index
Warnings:
Note 1249 Select 3 was reduced during optimization
Note 1249 Select 2 was reduced during optimization
@@ -883,7 +883,7 @@ select 10.5 > ANY (SELECT * from t1);
1
explain extended select (select a+1) from t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1249 Select 2 was reduced during optimization
@@ -4552,7 +4552,7 @@ int_nokey int_key
0 0
EXPLAIN EXTENDED SELECT * FROM C WHERE `int_key` IN (SELECT `int_nokey`);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY C ALL NULL NULL NULL NULL 20 100.00 Using where
+1 SIMPLE C ALL NULL NULL NULL NULL 20 100.00 Using where
DROP TABLE C;
# End of test for bug#45061.
#
@@ -6107,7 +6107,7 @@ FROM t1 AS sq4_alias1
WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR
sq4_alias1.col_varchar_key = @var3 ) AS alias3;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE <derived2> system NULL NULL NULL NULL 0 const row not found
+1 PRIMARY <derived2> system NULL NULL NULL NULL 0 const row not found
2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table
SELECT * FROM ( SELECT @var3:=12, sq4_alias1.*
FROM t1 AS sq4_alias1
@@ -6152,7 +6152,7 @@ FROM t2 AS c_sq1_alias1
WHERE (c_sq1_alias1.col_int_nokey != @var2
OR c_sq1_alias1.pk != @var3)) ) AS alias3;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
3 DEPENDENT SUBQUERY c_sq1_alias1 system PRIMARY NULL NULL NULL 1
SELECT * FROM ( SELECT sq4_alias1.*
FROM t1 AS sq4_alias1
diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result
index ad0d2ffe6a6..38af8086471 100644
--- a/mysql-test/r/subselect_no_scache.result
+++ b/mysql-test/r/subselect_no_scache.result
@@ -16,7 +16,7 @@ select (select 2);
2
explain extended select (select 2);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1249 Select 2 was reduced during optimization
Note 1003 select 2 AS `(select 2)`
@@ -740,7 +740,7 @@ id
1
EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t2 ref id id 5 const 1 100.00 Using index
+1 SIMPLE t2 ref id id 5 const 1 100.00 Using index
Warnings:
Note 1249 Select 2 was reduced during optimization
Note 1003 select `test`.`t2`.`id` AS `id` from `test`.`t2` where (`test`.`t2`.`id` = 1)
@@ -752,7 +752,7 @@ id
2
EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1+(select 1));
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t2 ref id id 5 const 1 100.00 Using where; Using index
+1 SIMPLE t2 ref id id 5 const 1 100.00 Using where; Using index
Warnings:
Note 1249 Select 3 was reduced during optimization
Note 1249 Select 2 was reduced during optimization
@@ -886,7 +886,7 @@ select 10.5 > ANY (SELECT * from t1);
1
explain extended select (select a+1) from t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1249 Select 2 was reduced during optimization
@@ -4560,7 +4560,7 @@ int_nokey int_key
0 0
EXPLAIN EXTENDED SELECT * FROM C WHERE `int_key` IN (SELECT `int_nokey`);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY C ALL NULL NULL NULL NULL 20 100.00 Using where
+1 SIMPLE C ALL NULL NULL NULL NULL 20 100.00 Using where
DROP TABLE C;
# End of test for bug#45061.
#
@@ -6118,7 +6118,7 @@ FROM t1 AS sq4_alias1
WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR
sq4_alias1.col_varchar_key = @var3 ) AS alias3;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE <derived2> system NULL NULL NULL NULL 0 const row not found
+1 PRIMARY <derived2> system NULL NULL NULL NULL 0 const row not found
2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table
SELECT * FROM ( SELECT @var3:=12, sq4_alias1.*
FROM t1 AS sq4_alias1
@@ -6163,7 +6163,7 @@ FROM t2 AS c_sq1_alias1
WHERE (c_sq1_alias1.col_int_nokey != @var2
OR c_sq1_alias1.pk != @var3)) ) AS alias3;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
3 DEPENDENT SUBQUERY c_sq1_alias1 system PRIMARY NULL NULL NULL 1
SELECT * FROM ( SELECT sq4_alias1.*
FROM t1 AS sq4_alias1
diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result
index 39cc060e955..281fab3d1ee 100644
--- a/mysql-test/r/subselect_no_semijoin.result
+++ b/mysql-test/r/subselect_no_semijoin.result
@@ -13,7 +13,7 @@ select (select 2);
2
explain extended select (select 2);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1249 Select 2 was reduced during optimization
Note 1003 select 2 AS `(select 2)`
@@ -737,7 +737,7 @@ id
1
EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t2 ref id id 5 const 1 100.00 Using index
+1 SIMPLE t2 ref id id 5 const 1 100.00 Using index
Warnings:
Note 1249 Select 2 was reduced during optimization
Note 1003 select `test`.`t2`.`id` AS `id` from `test`.`t2` where (`test`.`t2`.`id` = 1)
@@ -749,7 +749,7 @@ id
2
EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1+(select 1));
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t2 ref id id 5 const 1 100.00 Using where; Using index
+1 SIMPLE t2 ref id id 5 const 1 100.00 Using where; Using index
Warnings:
Note 1249 Select 3 was reduced during optimization
Note 1249 Select 2 was reduced during optimization
@@ -883,7 +883,7 @@ select 10.5 > ANY (SELECT * from t1);
1
explain extended select (select a+1) from t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1249 Select 2 was reduced during optimization
@@ -4552,7 +4552,7 @@ int_nokey int_key
0 0
EXPLAIN EXTENDED SELECT * FROM C WHERE `int_key` IN (SELECT `int_nokey`);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY C ALL NULL NULL NULL NULL 20 100.00 Using where
+1 SIMPLE C ALL NULL NULL NULL NULL 20 100.00 Using where
DROP TABLE C;
# End of test for bug#45061.
#
@@ -6107,7 +6107,7 @@ FROM t1 AS sq4_alias1
WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR
sq4_alias1.col_varchar_key = @var3 ) AS alias3;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE <derived2> system NULL NULL NULL NULL 0 const row not found
+1 PRIMARY <derived2> system NULL NULL NULL NULL 0 const row not found
2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table
SELECT * FROM ( SELECT @var3:=12, sq4_alias1.*
FROM t1 AS sq4_alias1
@@ -6152,7 +6152,7 @@ FROM t2 AS c_sq1_alias1
WHERE (c_sq1_alias1.col_int_nokey != @var2
OR c_sq1_alias1.pk != @var3)) ) AS alias3;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
3 DEPENDENT SUBQUERY c_sq1_alias1 system PRIMARY NULL NULL NULL 1
SELECT * FROM ( SELECT sq4_alias1.*
FROM t1 AS sq4_alias1
diff --git a/mysql-test/r/subselect_sj.result b/mysql-test/r/subselect_sj.result
index 2d229db9ec5..51e5c5e54d0 100644
--- a/mysql-test/r/subselect_sj.result
+++ b/mysql-test/r/subselect_sj.result
@@ -941,9 +941,9 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 eq_ref PRIMARY PRIMARY 4 test.t1.t1field 1 Using index
EXECUTE stmt;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 2 Using index
-1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.t1field 1 Using index
-1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.t1field 1 Using index
+1 PRIMARY t1 index PRIMARY PRIMARY 4 NULL 2 Using index
+1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t1.t1field 1 Using index
+1 PRIMARY t3 eq_ref PRIMARY PRIMARY 4 test.t1.t1field 1 Using index
DROP TABLE t1, t2, t3;
DROP VIEW v2, v3;
# End of Bug#49198
diff --git a/mysql-test/r/subselect_sj_jcl6.result b/mysql-test/r/subselect_sj_jcl6.result
index a0ebbb3305d..73777dd71c3 100644
--- a/mysql-test/r/subselect_sj_jcl6.result
+++ b/mysql-test/r/subselect_sj_jcl6.result
@@ -954,9 +954,9 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 eq_ref PRIMARY PRIMARY 4 test.t1.t1field 1 Using index
EXECUTE stmt;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 2 Using index
-1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.t1field 1 Using index
-1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.t1field 1 Using index
+1 PRIMARY t1 index PRIMARY PRIMARY 4 NULL 2 Using index
+1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t1.t1field 1 Using index
+1 PRIMARY t3 eq_ref PRIMARY PRIMARY 4 test.t1.t1field 1 Using index
DROP TABLE t1, t2, t3;
DROP VIEW v2, v3;
# End of Bug#49198
diff --git a/mysql-test/r/table_elim.result b/mysql-test/r/table_elim.result
index 0b19b6b4eaf..59054607acb 100644
--- a/mysql-test/r/table_elim.result
+++ b/mysql-test/r/table_elim.result
@@ -119,27 +119,27 @@ t2 where id=f.id);
This should use one table:
explain select id from v1 where id=2;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE f const PRIMARY PRIMARY 4 const 1 Using index
+1 PRIMARY f const PRIMARY PRIMARY 4 const 1 Using index
This should use one table:
explain extended select id from v1 where id in (1,2,3,4);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE f range PRIMARY PRIMARY 4 NULL 4 100.00 Using where; Using index
+1 PRIMARY f range PRIMARY PRIMARY 4 NULL 4 100.00 Using where; Using index
Warnings:
Note 1276 Field or reference 'test.a2.id' of SELECT #3 was resolved in SELECT #2
Note 1003 select `f`.`id` AS `id` from `test`.`t0` `f` where (`f`.`id` in (1,2,3,4))
This should use facts and a1 tables:
explain extended select id from v1 where attr1 between 12 and 14;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE a1 range PRIMARY,attr1 attr1 5 NULL 2 100.00 Using index condition
-1 SIMPLE f eq_ref PRIMARY PRIMARY 4 test.a1.id 1 100.00 Using index
+1 PRIMARY a1 range PRIMARY,attr1 attr1 5 NULL 2 100.00 Using index condition
+1 PRIMARY f eq_ref PRIMARY PRIMARY 4 test.a1.id 1 100.00 Using index
Warnings:
Note 1276 Field or reference 'test.a2.id' of SELECT #3 was resolved in SELECT #2
Note 1003 select `f`.`id` AS `id` from `test`.`t0` `f` join `test`.`t1` `a1` where ((`f`.`id` = `a1`.`id`) and (`a1`.`attr1` between 12 and 14))
This should use facts, a2 and its subquery:
explain extended select id from v1 where attr2 between 12 and 14;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE a2 range PRIMARY,attr2 attr2 5 NULL 5 100.00 Using index condition; Using where
-1 SIMPLE f eq_ref PRIMARY PRIMARY 4 test.a2.id 1 100.00 Using index
+1 PRIMARY a2 range PRIMARY,attr2 attr2 5 NULL 5 100.00 Using index condition; Using where
+1 PRIMARY f eq_ref PRIMARY PRIMARY 4 test.a2.id 1 100.00 Using index
3 DEPENDENT SUBQUERY t2 ref PRIMARY PRIMARY 4 test.a2.id 2 100.00 Using index
Warnings:
Note 1276 Field or reference 'test.a2.id' of SELECT #3 was resolved in SELECT #2
@@ -147,27 +147,27 @@ Note 1003 select `f`.`id` AS `id` from `test`.`t0` `f` join `test`.`t2` `a2` whe
This should use one table:
explain select id from v2 where id=2;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE f const PRIMARY PRIMARY 4 const 1 Using index
+1 PRIMARY f const PRIMARY PRIMARY 4 const 1 Using index
This should use one table:
explain extended select id from v2 where id in (1,2,3,4);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE f range PRIMARY PRIMARY 4 NULL 4 100.00 Using where; Using index
+1 PRIMARY f range PRIMARY PRIMARY 4 NULL 4 100.00 Using where; Using index
Warnings:
Note 1276 Field or reference 'test.f.id' of SELECT #3 was resolved in SELECT #2
Note 1003 select `f`.`id` AS `id` from `test`.`t0` `f` where (`f`.`id` in (1,2,3,4))
This should use facts and a1 tables:
explain extended select id from v2 where attr1 between 12 and 14;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE a1 range PRIMARY,attr1 attr1 5 NULL 2 100.00 Using index condition
-1 SIMPLE f eq_ref PRIMARY PRIMARY 4 test.a1.id 1 100.00 Using index
+1 PRIMARY a1 range PRIMARY,attr1 attr1 5 NULL 2 100.00 Using index condition
+1 PRIMARY f eq_ref PRIMARY PRIMARY 4 test.a1.id 1 100.00 Using index
Warnings:
Note 1276 Field or reference 'test.f.id' of SELECT #3 was resolved in SELECT #2
Note 1003 select `f`.`id` AS `id` from `test`.`t0` `f` join `test`.`t1` `a1` where ((`f`.`id` = `a1`.`id`) and (`a1`.`attr1` between 12 and 14))
This should use facts, a2 and its subquery:
explain extended select id from v2 where attr2 between 12 and 14;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE a2 range PRIMARY,attr2 attr2 5 NULL 5 100.00 Using index condition
-1 SIMPLE f eq_ref PRIMARY PRIMARY 4 test.a2.id 1 100.00 Using where; Using index
+1 PRIMARY a2 range PRIMARY,attr2 attr2 5 NULL 5 100.00 Using index condition
+1 PRIMARY f eq_ref PRIMARY PRIMARY 4 test.a2.id 1 100.00 Using where; Using index
3 DEPENDENT SUBQUERY t2 ref PRIMARY PRIMARY 4 test.f.id 2 100.00 Using index
Warnings:
Note 1276 Field or reference 'test.f.id' of SELECT #3 was resolved in SELECT #2
diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result
index 53c9267f019..3969d9d4a09 100644
--- a/mysql-test/r/view.result
+++ b/mysql-test/r/view.result
@@ -119,7 +119,7 @@ c
12
explain extended select c from v5;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE <derived3> ALL NULL NULL NULL NULL 5 100.00
+1 PRIMARY <derived3> ALL NULL NULL NULL NULL 5 100.00
3 DERIVED t1 ALL NULL NULL NULL NULL 5 100.00
Warnings:
Note 1003 select (`v2`.`c` + 1) AS `c` from `test`.`v2`
@@ -4473,8 +4473,8 @@ f1 f1
1 1
EXPLAIN EXTENDED SELECT * FROM v2 AS a1, v2 AS a2;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE <derived3> ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort
-1 SIMPLE <derived5> ALL NULL NULL NULL NULL 2 100.00 Using join buffer (flat, BNL join)
+1 PRIMARY <derived3> ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort
+1 PRIMARY <derived5> ALL NULL NULL NULL NULL 2 100.00 Using join buffer (flat, BNL join)
5 DERIVED t1 ALL NULL NULL NULL NULL 2 100.00
3 DERIVED t1 ALL NULL NULL NULL NULL 2 100.00
Warnings:
diff --git a/mysql-test/suite/sys_vars/r/log_slow_verbosity_basic.result b/mysql-test/suite/sys_vars/r/log_slow_verbosity_basic.result
index 24b805d4d9c..a291e276e4b 100644
--- a/mysql-test/suite/sys_vars/r/log_slow_verbosity_basic.result
+++ b/mysql-test/suite/sys_vars/r/log_slow_verbosity_basic.result
@@ -37,6 +37,22 @@ set session log_slow_verbosity=3;
select @@session.log_slow_verbosity;
@@session.log_slow_verbosity
innodb,query_plan
+set session log_slow_verbosity=4;
+select @@session.log_slow_verbosity;
+@@session.log_slow_verbosity
+explain
+set session log_slow_verbosity=5;
+select @@session.log_slow_verbosity;
+@@session.log_slow_verbosity
+innodb,explain
+set session log_slow_verbosity=6;
+select @@session.log_slow_verbosity;
+@@session.log_slow_verbosity
+query_plan,explain
+set session log_slow_verbosity=7;
+select @@session.log_slow_verbosity;
+@@session.log_slow_verbosity
+innodb,query_plan,explain
set session log_slow_verbosity='innodb';
select @@session.log_slow_verbosity;
@@session.log_slow_verbosity
@@ -49,6 +65,14 @@ set session log_slow_verbosity='innodb,query_plan';
select @@session.log_slow_verbosity;
@@session.log_slow_verbosity
innodb,query_plan
+set session log_slow_verbosity='explain';
+select @@session.log_slow_verbosity;
+@@session.log_slow_verbosity
+explain
+set session log_slow_verbosity='innodb,query_plan,explain';
+select @@session.log_slow_verbosity;
+@@session.log_slow_verbosity
+innodb,query_plan,explain
set session log_slow_verbosity='';
select @@session.log_slow_verbosity;
@@session.log_slow_verbosity
@@ -59,6 +83,6 @@ set session log_slow_verbosity=1e1;
ERROR 42000: Incorrect argument type to variable 'log_slow_verbosity'
set session log_slow_verbosity="foo";
ERROR 42000: Variable 'log_slow_verbosity' can't be set to the value of 'foo'
-set session log_slow_verbosity=4;
-ERROR 42000: Variable 'log_slow_verbosity' can't be set to the value of '4'
+set session log_slow_verbosity=8;
+ERROR 42000: Variable 'log_slow_verbosity' can't be set to the value of '8'
SET @@global.log_slow_verbosity = @start_global_value;
diff --git a/mysql-test/suite/sys_vars/t/log_slow_verbosity_basic.test b/mysql-test/suite/sys_vars/t/log_slow_verbosity_basic.test
index 9302d5f1210..f45fa5da9c5 100644
--- a/mysql-test/suite/sys_vars/t/log_slow_verbosity_basic.test
+++ b/mysql-test/suite/sys_vars/t/log_slow_verbosity_basic.test
@@ -29,12 +29,26 @@ set session log_slow_verbosity=2;
select @@session.log_slow_verbosity;
set session log_slow_verbosity=3;
select @@session.log_slow_verbosity;
+set session log_slow_verbosity=4;
+select @@session.log_slow_verbosity;
+set session log_slow_verbosity=5;
+select @@session.log_slow_verbosity;
+set session log_slow_verbosity=6;
+select @@session.log_slow_verbosity;
+set session log_slow_verbosity=7;
+select @@session.log_slow_verbosity;
+
+
set session log_slow_verbosity='innodb';
select @@session.log_slow_verbosity;
set session log_slow_verbosity='query_plan';
select @@session.log_slow_verbosity;
set session log_slow_verbosity='innodb,query_plan';
select @@session.log_slow_verbosity;
+set session log_slow_verbosity='explain';
+select @@session.log_slow_verbosity;
+set session log_slow_verbosity='innodb,query_plan,explain';
+select @@session.log_slow_verbosity;
set session log_slow_verbosity='';
select @@session.log_slow_verbosity;
@@ -48,6 +62,6 @@ set session log_slow_verbosity=1e1;
--error ER_WRONG_VALUE_FOR_VAR
set session log_slow_verbosity="foo";
--error ER_WRONG_VALUE_FOR_VAR
-set session log_slow_verbosity=4;
+set session log_slow_verbosity=8;
SET @@global.log_slow_verbosity = @start_global_value;
diff --git a/mysql-test/t/explain_non_select.test b/mysql-test/t/explain_non_select.test
new file mode 100644
index 00000000000..f05373c312e
--- /dev/null
+++ b/mysql-test/t/explain_non_select.test
@@ -0,0 +1,200 @@
+#
+# MariaDB tests for EXPLAIN UPDATE/DELETE.
+#
+--source include/have_partition.inc
+
+--disable_warnings
+drop table if exists t0, t1;
+--enable_warnings
+
+create table t0 (a int) engine=myisam;
+insert into t0 values (1),(2),(3),(4),(5),(6),(7),(8);
+
+--echo #
+--echo # Tests for single-table DELETE
+--echo #
+
+explain select * from t0 where a=3;
+explain delete from t0 where a=3;
+
+--echo # DELETE without WHERE is a special case:
+explain delete from t0;
+
+create table t1 (a int, b int, filler char(100), key(a), key(b));
+insert into t1
+select A.a+10*B.a + 10*C.a, A.a+10*B.a + 10*C.a, 'filler'
+from t0 A, t0 B, t0 C;
+
+--echo # This should use an index, possible_keys=NULL because there is no WHERE
+explain delete from t1 order by a limit 2;
+
+--echo # This should use range, possible_keys={a,b}
+explain delete from t1 where a<20 and b < 10;
+
+--echo # This should use ALL + filesort
+explain delete from t1 order by a+1 limit 2;
+
+--echo # This should use range + using filesort
+explain delete from t1 where a<20 order by b limit 2;
+
+--echo # Try some subqueries:
+explain delete from t1 where a < (select max(a) from t0);
+explain delete from t1 where a < (select max(a) from t0 where a < t1.b);
+
+--echo #
+--echo # Tests for multi-table DELETE
+--echo #
+explain delete t1 from t0, t1 where t0.a = t1.a;
+drop table t0, t1;
+
+--echo # ###################################################################
+--echo # ## EXPLAIN UPDATE tests
+--echo # ###################################################################
+create table t0 (a int) engine=myisam;
+insert into t0 values (1),(2),(3),(4),(5),(6),(7),(8);
+
+explain update t0 set a=3 where a=4;
+
+create table t1 (a int, b int, filler char(100), key(a), key(b));
+insert into t1
+select A.a+10*B.a + 10*C.a, A.a+10*B.a + 10*C.a, 'filler'
+from t0 A, t0 B, t0 C;
+
+explain update t1 set a=a+1 where 3>4;
+explain update t1 set a=a+1 where a=3 and a=4;
+
+--echo # This should use an index, possible_keys=NULL because there is no WHERE
+explain update t1 set a=a+1 order by a limit 2;
+
+--echo # This should use range, possible_keys={a,b}
+explain update t1 set filler='fooo' where a<20 and b < 10;
+
+--echo # This should use ALL + filesort
+explain update t1 set filler='fooo' order by a+1 limit 2;
+
+--echo # This should use range + using filesort
+explain update t1 set filler='fooo' where a<20 order by b limit 2;
+
+--echo # Try some subqueries:
+explain update t1 set filler='fooo' where a < (select max(a) from t0);
+explain update t1 set filler='fooo' where a < (select max(a) from t0 where a < t1.b);
+
+--echo #
+--echo # Tests for multi-table UPDATE
+--echo #
+explain update t0, t1 set t1.a=t1.a+1 where t0.a = t1.a;
+
+
+drop table t0, t1;
+
+--echo #
+--echo # Try DELETE ... RETURNING ...
+--echo #
+create table t0 (a int);
+insert into t0 values (1),(2),(3),(4);
+explain delete from t0 where a=1 returning a;
+explain delete from t0 returning a;
+drop table t0;
+
+--echo #
+--echo # MDEV-5070 - EXPLAIN INSERT ... SELECT crashes on 10.0-base-explain-slowquerylog
+--echo #
+create table t0 (a int);
+insert into t0 values (1),(2),(3),(4),(5),(6),(7),(8);
+create table t1 (a int);
+
+explain insert into t1 select * from t0;
+explain replace into t1 select * from t0;
+
+drop table t0, t1;
+
+--echo #
+--echo # MDEV-5067: Valgrind warnings (Invalid read) in QPF_table_access::print_explain
+--echo #
+CREATE TABLE t1 (i INT) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (7),(0),(9);
+
+SELECT * FROM t1 INNER JOIN ( SELECT DISTINCT * FROM t1 ) AS sq ON (sq.i = t1.i);
+
+DROP TABLE t1;
+
+--echo #
+--echo # MDEV-5093, MDEV-5094: EXPLAIN PARTITIONS and EXPLAIN EXTENDED do not
+--echo # work for EXPLAIN UPDATE.
+--echo #
+create table t1 (i int);
+explain partitions update t1 set i = 3;
+
+create table t2 (a int, b int) partition by hash(a) partitions 5;
+insert into t2 values (0,0),(1,1),(2,2),(3,3),(4,4);
+
+explain partitions update t2 set b=3 where a in (3,4);
+explain partitions delete from t2 where a in (3,4);
+
+explain extended update t2 set b=3 where a in (3,4);
+explain extended delete from t2 where a in (3,4);
+
+drop table t1,t2;
+
+--echo #
+--echo # Check the special case where partition pruning removed all partitions
+--echo #
+
+create table t1 (a int, b int)
+partition by range (a) (
+ partition p0 values less than (10),
+ partition p1 values less than (20),
+ partition p2 values less than (30)
+);
+insert into t1 values (9,9), (19,19), (29,29);
+
+explain partitions select * from t1 where a in (32,33);
+
+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;
+
+--echo #
+--echo # MDEV-5122: "Commands out of sync", "Malformed packet" or client hang up on unique key violation
+--echo #
+drop table if exists t1;
+
+--disable_warnings
+drop function if exists f1;
+--enable_warnings
+
+create table t1 (a int, unique(a));
+
+delimiter |;
+create function f1(x int)
+ returns int
+begin
+ insert into t1 values(x),(x);
+ return 10;
+end|
+delimiter ;|
+
+--error ER_DUP_ENTRY
+select f1(100);
+select 'OK';
+
+drop function f1;
+drop table t1;
+
+
diff --git a/mysql-test/t/explain_slowquerylog-master.opt b/mysql-test/t/explain_slowquerylog-master.opt
new file mode 100644
index 00000000000..0a3ad969e79
--- /dev/null
+++ b/mysql-test/t/explain_slowquerylog-master.opt
@@ -0,0 +1 @@
+--slow-query-log --long-query-time=0.00000 --log-slow-verbosity=query_plan,explain
diff --git a/mysql-test/t/explain_slowquerylog.test b/mysql-test/t/explain_slowquerylog.test
new file mode 100644
index 00000000000..8c8be555640
--- /dev/null
+++ b/mysql-test/t/explain_slowquerylog.test
@@ -0,0 +1,49 @@
+#
+# This is a test for EXPLAINs being written into slow query log.
+# For now, we just run the queries and hope not to crash.
+#
+#
+--disable_warnings
+drop table if exists t0,t1;
+--enable_warnings
+
+create table t0 (a int);
+insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+
+explain select * from t0 where a < 3;
+
+--echo #
+--echo # MDEV-5045: Server crashes in QPF_query::print_explain with log_slow_verbosity='query_plan,explain'
+--echo #
+set autocommit=1;
+drop table t0;
+
+--echo #
+--echo # MDEV-5047 virtual THD::~THD(): Assertion `status_var.memory_used == 0' fails on disconnect
+--echo #
+--connect (con1,localhost,root,,)
+--error ER_NO_SUCH_TABLE
+ALTER TABLE nonexisting ENABLE KEYS;
+SHOW WARNINGS;
+--disconnect con1
+--connection default
+SELECT 1;
+
+--echo #
+--echo # MDEV-5060 Server crashes on EXPLAIN EXTENDED or EXPLAIN PARTITIONS with explain in slow_log
+--echo #
+EXPLAIN PARTITIONS SELECT 1 ;
+
+
+--echo #
+--echo # MDEV-5106: Server crashes in Explain_union::print_explain on ER_TOO_BIG_SELECT with explain in slow log
+--echo #
+CREATE TABLE t1 (i INT) ENGINE=MyISAM;
+INSERT INTO t1 VALUES
+(1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
+SET max_join_size = 10;
+--error ER_TOO_BIG_SELECT
+( SELECT ta.* FROM t1 ta, t1 tb ) UNION ( SELECT * FROM t1 );
+SELECT 'Server still alive?' as 'Yes';
+
+DROP TABLE t1;
diff --git a/mysql-test/t/grant_explain_non_select.test b/mysql-test/t/grant_explain_non_select.test
new file mode 100644
index 00000000000..d59a8f3d8ce
--- /dev/null
+++ b/mysql-test/t/grant_explain_non_select.test
@@ -0,0 +1,258 @@
+#
+# Privilege-specific tests for WL#4897: Add EXPLAIN INSERT/UPDATE/DELETE
+#
+
+# Grant tests not performed with embedded server
+-- source include/not_embedded.inc
+
+# Save the initial number of concurrent sessions
+--source include/count_sessions.inc
+
+CREATE DATABASE privtest_db;
+
+CREATE TABLE privtest_db.t1 (a INT);
+CREATE TABLE privtest_db.t2 (a INT);
+INSERT INTO privtest_db.t2 VALUES (1), (2), (3);
+
+GRANT USAGE ON *.* TO 'privtest'@'localhost';
+GRANT SELECT ON privtest_db.t2 TO 'privtest'@'localhost';
+
+connect(con1,localhost,privtest,,);
+connection con1;
+
+USE privtest_db;
+
+--error ER_TABLEACCESS_DENIED_ERROR
+EXPLAIN INSERT INTO t1 VALUES (10);
+--error ER_TABLEACCESS_DENIED_ERROR
+ INSERT INTO t1 VALUES (10);
+
+--error ER_TABLEACCESS_DENIED_ERROR
+EXPLAIN INSERT INTO t1 SELECT * FROM t2;
+--error ER_TABLEACCESS_DENIED_ERROR
+ INSERT INTO t1 SELECT * FROM t2;
+
+connection default;
+GRANT INSERT ON privtest_db.t1 TO 'privtest'@'localhost';
+connection con1;
+
+EXPLAIN INSERT INTO t1 VALUES (10);
+ INSERT INTO t1 VALUES (10);
+
+EXPLAIN INSERT INTO t1 SELECT * FROM t2;
+ INSERT INTO t1 SELECT * FROM t2;
+
+
+connection default;
+REVOKE ALL PRIVILEGES ON privtest_db.t1 FROM 'privtest'@'localhost';
+connection con1;
+
+--error ER_TABLEACCESS_DENIED_ERROR
+EXPLAIN REPLACE INTO t1 VALUES (10);
+--error ER_TABLEACCESS_DENIED_ERROR
+ REPLACE INTO t1 VALUES (10);
+
+--error ER_TABLEACCESS_DENIED_ERROR
+EXPLAIN REPLACE INTO t1 SELECT * FROM t2;
+--error ER_TABLEACCESS_DENIED_ERROR
+ REPLACE INTO t1 SELECT * FROM t2;
+
+connection default;
+GRANT INSERT ON privtest_db.t1 TO 'privtest'@'localhost';
+connection con1;
+
+--error ER_TABLEACCESS_DENIED_ERROR
+EXPLAIN REPLACE INTO t1 VALUES (10);
+--error ER_TABLEACCESS_DENIED_ERROR
+ REPLACE INTO t1 VALUES (10);
+
+--error ER_TABLEACCESS_DENIED_ERROR
+EXPLAIN REPLACE INTO t1 SELECT * FROM t2;
+--error ER_TABLEACCESS_DENIED_ERROR
+ REPLACE INTO t1 SELECT * FROM t2;
+
+connection default;
+REVOKE INSERT ON privtest_db.t1 FROM 'privtest'@'localhost';
+GRANT DELETE ON privtest_db.t1 TO 'privtest'@'localhost';
+connection con1;
+
+--error ER_TABLEACCESS_DENIED_ERROR
+EXPLAIN REPLACE INTO t1 VALUES (10);
+--error ER_TABLEACCESS_DENIED_ERROR
+ REPLACE INTO t1 VALUES (10);
+
+--error ER_TABLEACCESS_DENIED_ERROR
+EXPLAIN REPLACE INTO t1 SELECT * FROM t2;
+--error ER_TABLEACCESS_DENIED_ERROR
+ REPLACE INTO t1 SELECT * FROM t2;
+
+connection default;
+GRANT INSERT, DELETE ON privtest_db.t1 TO 'privtest'@'localhost';
+connection con1;
+
+EXPLAIN REPLACE INTO t1 VALUES (10);
+ REPLACE INTO t1 VALUES (10);
+
+EXPLAIN REPLACE INTO t1 SELECT * FROM t2;
+ REPLACE INTO t1 SELECT * FROM t2;
+
+connection default;
+REVOKE ALL PRIVILEGES ON privtest_db.t1 FROM 'privtest'@'localhost';
+connection con1;
+
+--error ER_TABLEACCESS_DENIED_ERROR
+EXPLAIN UPDATE t1 SET a = a + 1;
+--error ER_TABLEACCESS_DENIED_ERROR
+ UPDATE t1 SET a = a + 1;
+
+--error ER_TABLEACCESS_DENIED_ERROR
+EXPLAIN UPDATE t1, t2 SET t1.a = t1.a + 1 WHERE t1.a = t2.a;
+--error ER_TABLEACCESS_DENIED_ERROR
+ UPDATE t1, t2 SET t1.a = t1.a + 1 WHERE t1.a = t2.a;
+
+connection default;
+GRANT UPDATE ON privtest_db.t1 TO 'privtest'@'localhost';
+connection con1;
+
+--error ER_COLUMNACCESS_DENIED_ERROR
+EXPLAIN UPDATE t1 SET a = a + 1;
+--error ER_COLUMNACCESS_DENIED_ERROR
+ UPDATE t1 SET a = a + 1;
+
+--error ER_COLUMNACCESS_DENIED_ERROR
+EXPLAIN UPDATE t1, t2 SET t1.a = t1.a + 1 WHERE t1.a = t2.a;
+--error ER_COLUMNACCESS_DENIED_ERROR
+ UPDATE t1, t2 SET t1.a = t1.a + 1 WHERE t1.a = t2.a;
+
+connection default;
+REVOKE UPDATE ON privtest_db.t1 FROM 'privtest'@'localhost';
+GRANT SELECT ON privtest_db.t1 TO 'privtest'@'localhost';
+connection con1;
+
+--error ER_TABLEACCESS_DENIED_ERROR
+EXPLAIN UPDATE t1 SET a = a + 1;
+--error ER_TABLEACCESS_DENIED_ERROR
+ UPDATE t1 SET a = a + 1;
+
+--error ER_TABLEACCESS_DENIED_ERROR
+EXPLAIN UPDATE t1, t2 SET t1.a = t1.a + 1 WHERE t1.a = t2.a;
+--error ER_TABLEACCESS_DENIED_ERROR
+ UPDATE t1, t2 SET t1.a = t1.a + 1 WHERE t1.a = t2.a;
+
+connection default;
+GRANT UPDATE, SELECT ON privtest_db.t1 TO 'privtest'@'localhost';
+connection con1;
+
+EXPLAIN UPDATE t1 SET a = a + 1;
+ UPDATE t1 SET a = a + 1;
+
+EXPLAIN UPDATE t1, t2 SET t1.a = t1.a + 1 WHERE t1.a = t2.a;
+ UPDATE t1, t2 SET t1.a = t1.a + 1 WHERE t1.a = t2.a;
+
+connection default;
+REVOKE ALL PRIVILEGES ON privtest_db.t1 FROM 'privtest'@'localhost';
+connection con1;
+
+--error ER_TABLEACCESS_DENIED_ERROR
+EXPLAIN DELETE FROM t1 WHERE a = 10;
+--error ER_TABLEACCESS_DENIED_ERROR
+ DELETE FROM t1 WHERE a = 10;
+
+--error ER_TABLEACCESS_DENIED_ERROR
+EXPLAIN DELETE FROM t1 USING t1, t2 WHERE t1.a = t2.a;
+--error ER_TABLEACCESS_DENIED_ERROR
+ DELETE FROM t1 USING t1, t2 WHERE t1.a = t2.a;
+
+connection default;
+GRANT DELETE ON privtest_db.t1 TO 'privtest'@'localhost';
+connection con1;
+
+--error ER_COLUMNACCESS_DENIED_ERROR
+EXPLAIN DELETE FROM t1 WHERE a = 10;
+--error ER_COLUMNACCESS_DENIED_ERROR
+ DELETE FROM t1 WHERE a = 10;
+
+--error ER_TABLEACCESS_DENIED_ERROR
+EXPLAIN DELETE FROM t1 USING t1, t2 WHERE t1.a = t2.a;
+--error ER_TABLEACCESS_DENIED_ERROR
+ DELETE FROM t1 USING t1, t2 WHERE t1.a = t2.a;
+
+connection default;
+REVOKE ALL PRIVILEGES ON privtest_db.t1 FROM 'privtest'@'localhost';
+GRANT SELECT ON privtest_db.t1 TO 'privtest'@'localhost';
+connection con1;
+
+--error ER_TABLEACCESS_DENIED_ERROR
+EXPLAIN DELETE FROM t1 WHERE a = 10;
+--error ER_TABLEACCESS_DENIED_ERROR
+ DELETE FROM t1 WHERE a = 10;
+
+--error ER_TABLEACCESS_DENIED_ERROR
+EXPLAIN DELETE FROM t1 USING t1, t2 WHERE t1.a = t2.a;
+--error ER_TABLEACCESS_DENIED_ERROR
+ DELETE FROM t1 USING t1, t2 WHERE t1.a = t2.a;
+
+connection default;
+REVOKE ALL PRIVILEGES ON privtest_db.t1 FROM 'privtest'@'localhost';
+GRANT DELETE, SELECT ON privtest_db.t1 TO 'privtest'@'localhost';
+connection con1;
+
+EXPLAIN DELETE FROM t1 WHERE a = 10;
+ DELETE FROM t1 WHERE a = 10;
+
+EXPLAIN DELETE FROM t1 USING t1, t2 WHERE t1.a = t2.a;
+ DELETE FROM t1 USING t1, t2 WHERE t1.a = t2.a;
+
+# Views
+
+connection default;
+REVOKE ALL PRIVILEGES ON privtest_db.t1 FROM 'privtest'@'localhost';
+CREATE VIEW privtest_db.v1 (a) AS SELECT a FROM privtest_db.t1;
+GRANT SELECT, INSERT, UPDATE, DELETE ON privtest_db.v1 TO 'privtest'@'localhost';
+connection con1;
+
+--error ER_VIEW_NO_EXPLAIN
+EXPLAIN SELECT * FROM v1;
+ SELECT * FROM v1;
+
+--error ER_VIEW_NO_EXPLAIN
+EXPLAIN INSERT INTO v1 VALUES (10);
+ INSERT INTO v1 VALUES (10);
+
+--error ER_VIEW_NO_EXPLAIN
+EXPLAIN INSERT INTO v1 SELECT * FROM t2;
+ INSERT INTO v1 SELECT * FROM t2;
+
+--error ER_VIEW_NO_EXPLAIN
+EXPLAIN REPLACE INTO v1 VALUES (10);
+ REPLACE INTO v1 VALUES (10);
+
+--error ER_VIEW_NO_EXPLAIN
+EXPLAIN REPLACE INTO v1 SELECT * FROM t2;
+ REPLACE INTO v1 SELECT * FROM t2;
+
+--error ER_VIEW_NO_EXPLAIN
+EXPLAIN UPDATE v1 SET a = a + 1;
+ UPDATE v1 SET a = a + 1;
+
+--error ER_VIEW_NO_EXPLAIN
+EXPLAIN UPDATE v1, t2 SET v1.a = v1.a + 1 WHERE v1.a = t2.a;
+ UPDATE v1, t2 SET v1.a = v1.a + 1 WHERE v1.a = t2.a;
+
+--error ER_VIEW_NO_EXPLAIN
+EXPLAIN DELETE FROM v1 WHERE a = 10;
+ DELETE FROM v1 WHERE a = 10;
+
+--error ER_VIEW_NO_EXPLAIN
+EXPLAIN DELETE FROM v1 USING v1, t2 WHERE v1.a = t2.a;
+ DELETE FROM v1 USING v1, t2 WHERE v1.a = t2.a;
+
+connection default;
+disconnect con1;
+
+DROP USER 'privtest'@localhost;
+USE test;
+DROP DATABASE privtest_db;
+
+# Wait till we reached the initial number of concurrent sessions
+--source include/wait_until_count_sessions.inc
diff --git a/mysql-test/t/myisam_explain_non_select_all.test b/mysql-test/t/myisam_explain_non_select_all.test
new file mode 100644
index 00000000000..ccd4ebd6297
--- /dev/null
+++ b/mysql-test/t/myisam_explain_non_select_all.test
@@ -0,0 +1,21 @@
+#
+# Run explain_non_select.inc on MyISAM with all of the so-called 6.0 features.
+#
+
+#--source include/have_semijoin.inc
+#--source include/have_materialization.inc
+#--source include/have_firstmatch.inc
+#--source include/have_loosescan.inc
+#--source include/have_index_condition_pushdown.inc
+#--source include/have_mrr.inc
+
+#set optimizer_switch='semijoin=on,materialization=on,firstmatch=on,loosescan=on,index_condition_pushdown=on,mrr=on,mrr_cost_based=off';
+
+set @save_storage_engine= @@session.default_storage_engine;
+set session default_storage_engine = MyISAM;
+--let $json = 0
+--let $validation = 0
+--source include/explain_non_select.inc
+set default_storage_engine= @save_storage_engine;
+
+set optimizer_switch=default;
diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test
index 41091d7f5b9..2ac4e214dbc 100644
--- a/mysql-test/t/show_explain.test
+++ b/mysql-test/t/show_explain.test
@@ -202,7 +202,6 @@ set debug_dbug='+d,show_explain_probe_join_exec_end';
send select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1;
connection default;
--source include/wait_condition.inc
---error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2;
connection con1;
reap;
@@ -225,7 +224,9 @@ connection default;
--source include/wait_condition.inc
--error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2;
+evalp kill query $thr2;
connection con1;
+--error ER_QUERY_INTERRUPTED
reap;
set debug_dbug=@old_debug;
@@ -238,10 +239,10 @@ 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_TARGET_NOT_EXPLAINABLE
+#--error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2;
--source include/wait_condition.inc
---error ER_TARGET_NOT_EXPLAINABLE
+#--error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2;
connection con1;
reap;
@@ -249,7 +250,7 @@ drop table t2;
set debug_dbug=@old_debug;
--echo #
---echo # Attempt SHOW EXPLAIN for a DELETE
+--echo # Attempt SHOW EXPLAIN for a DELETE (UPD: now works)
--echo #
create table t2 as select a as a, a as dummy from t0 limit 2;
set @show_explain_probe_select_id=2;
@@ -257,10 +258,10 @@ 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_TARGET_NOT_EXPLAINABLE
+#--error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2;
--source include/wait_condition.inc
---error ER_TARGET_NOT_EXPLAINABLE
+#--error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2;
connection con1;
reap;
@@ -349,7 +350,7 @@ connection default;
--source include/wait_condition.inc
--echo # FIXED by "conservative assumptions about when QEP is available" fix:
--echo # NOTE: current code will not show "Using join buffer":
---error ER_TARGET_NOT_EXPLAINABLE
+#--error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2;
connection con1;
reap;
@@ -400,7 +401,9 @@ connection default;
--source include/wait_condition.inc
--error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2;
+evalp kill query $thr2;
connection con1;
+--error ER_QUERY_INTERRUPTED
reap;
set debug_dbug=@old_debug;
DROP VIEW v1;
@@ -428,7 +431,7 @@ set debug_dbug='+d,show_explain_probe_join_exec_end';
send select * from t0 where 1>10;
connection default;
--source include/wait_condition.inc
---error ER_TARGET_NOT_EXPLAINABLE
+#--error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2;
connection con1;
reap;
@@ -444,7 +447,7 @@ 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
---error ER_TARGET_NOT_EXPLAINABLE
+# --error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2;
connection con1;
reap;
@@ -540,7 +543,7 @@ send
SELECT * FROM t2 WHERE (5, 78) IN (SELECT `a1`, MAX(`a1`) FROM t2 GROUP BY `a1`);
connection default;
--source include/wait_condition.inc
---error ER_TARGET_NOT_EXPLAINABLE
+# --error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2;
connection con1;
reap;
@@ -1129,9 +1132,44 @@ set names default;
--error ER_SET_CONSTANTS_ONLY
show explain for foo;
+--echo #
+--echo # MDEV-411: SHOW EXPLAIN: For dependent subquery EXPLAIN produces type=index, key, 'Using where; Using index',
+--echo # while SHOW EXPLAIN says type=ALL, no key, 'Range checked for each record'
+--echo #
+CREATE TABLE t1 (a INT NOT NULL, KEY(a)) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (7),(0);
+
+CREATE TABLE t2 (b INT NOT NULL) ENGINE=MyISAM;
+INSERT INTO t2 VALUES (0),(8);
+
+explain
+SELECT SUM(b) FROM ( SELECT * FROM t1 ) AS alias1, t2
+WHERE b <= ANY (
+ SELECT a FROM t1
+ WHERE a = b + SLEEP(0.2) OR a >= ( SELECT SUM(b) FROM t2 ));
+
+
+set @show_explain_probe_select_id=1;
+set debug_dbug='+d,show_explain_probe_join_exec_start';
+
+send
+SELECT SUM(b) FROM ( SELECT * FROM t1 ) AS alias1, t2
+WHERE b <= ANY (
+ SELECT a FROM t1
+ WHERE a = b + SLEEP(0.2) OR a >= ( SELECT SUM(b) FROM t2 ));
+
+connection default;
+--source include/wait_condition.inc
+evalp show explain for $thr2;
+
+connection con1;
+reap;
+
+set debug_dbug=@old_debug;
+DROP TABLE t1,t2;
+
--echo # End
drop table t0;
-
connection default;
disconnect con1;
set debug_sync='RESET';
diff --git a/mysql-test/t/show_explain_non_select.test b/mysql-test/t/show_explain_non_select.test
new file mode 100644
index 00000000000..21b16739141
--- /dev/null
+++ b/mysql-test/t/show_explain_non_select.test
@@ -0,0 +1,78 @@
+#
+# SHOW EXPLAIN tests for non-select subqueries
+#
+--source include/have_debug.inc
+--source include/have_innodb.inc
+--source include/not_embedded.inc
+
+--disable_warnings
+drop table if exists t0, t1;
+--enable_warnings
+
+SET @old_debug= @@session.debug;
+set debug_sync='RESET';
+
+#
+# Setup two threads and their ids
+#
+let $thr1=`select connection_id()`;
+connect (con2, localhost, root,,);
+connection con2;
+let $thr2=`select connection_id()`;
+connection default;
+
+#
+# Create tables
+#
+create table t0 (a int) engine=myisam;
+insert into t0 values (1),(2),(3),(4),(5),(6),(7),(8);
+
+create table t1 (a int, b int, filler char(100), key(a), key(b));
+insert into t1
+select A.a+10*B.a + 10*C.a, A.a+10*B.a + 10*C.a, 'filler'
+from t0 A, t0 B, t0 C;
+
+let $wait_condition= select State='show_explain_trap' from information_schema.processlist where id=$thr2;
+
+--echo #
+--echo # Test SHOW EXPLAIN for single-table DELETE
+--echo #
+connection con2;
+set debug_dbug='+d,show_explain_probe_delete_exec_start';
+send delete from t1 where a<10 and b+1>1000;
+
+connection default;
+--source include/wait_condition.inc
+evalp show explain for $thr2;
+connection con2;
+reap;
+
+--echo #
+--echo # Test SHOW EXPLAIN for multi-table DELETE
+--echo #
+set @show_explain_probe_select_id=1;
+set debug_dbug='+d,show_explain_probe_do_select';
+send delete t1 from t1, t0 where t0.a=t1.a and t1.b +1 > 1000;
+connection default;
+--source include/wait_condition.inc
+evalp show explain for $thr2;
+connection con2;
+reap;
+
+--echo #
+--echo # Test SHOW EXPLAIN for single-table UPDATE
+--echo #
+connection con2;
+set debug_dbug='+d,show_explain_probe_update_exec_start';
+send update t1 set filler='filler-data-2' where a<10 and b+1>1000;
+
+connection default;
+--source include/wait_condition.inc
+evalp show explain for $thr2;
+connection con2;
+reap;
+
+drop table t0,t1;
+
+set debug_dbug=@old_debug;
+set debug_sync='RESET';
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index c4e0729b678..fe100b0e060 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -82,6 +82,7 @@ SET (SQL_SOURCE
sql_reload.cc sql_cmd.h
# added in MariaDB:
+ sql_explain.h sql_explain.cc
sql_lifo_buffer.h sql_join_cache.h sql_join_cache.cc
create_options.cc multi_range_read.cc
opt_index_cond_pushdown.cc opt_subselect.cc
diff --git a/sql/log.cc b/sql/log.cc
index 94e5c45f135..b2cd03de481 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -2841,6 +2841,15 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
"Yes" : "No"),
thd->query_plan_fsort_passes) == (size_t) -1)
tmp_errno= errno;
+ if (thd->variables.log_slow_verbosity & LOG_SLOW_VERBOSITY_EXPLAIN &&
+ thd->lex->explain)
+ {
+ StringBuffer<128> buf;
+ DBUG_ASSERT(!thd->free_list);
+ if (!print_explain_query(thd->lex, thd, &buf))
+ my_b_printf(&log_file, "%s", buf.c_ptr_safe());
+ thd->free_items();
+ }
if (thd->db && strcmp(thd->db, db))
{ // Database changed
if (my_b_printf(&log_file,"use %s;\n",thd->db) == (size_t) -1)
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 5094e47219f..6f75e3b9dba 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -9303,6 +9303,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
call might reset the value of current_stmt_binlog_format, so
we need to do any changes to that value after this function.
*/
+ delete_explain_query(thd->lex);
lex_start(thd);
mysql_reset_thd_for_next_command(thd, 0);
/*
diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc
index 6623d7655d7..a050463cbf0 100644
--- a/sql/log_event_old.cc
+++ b/sql/log_event_old.cc
@@ -86,6 +86,7 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info
call might reset the value of current_stmt_binlog_format, so
we need to do any changes to that value after this function.
*/
+ delete_explain_query(thd->lex);
lex_start(ev_thd);
mysql_reset_thd_for_next_command(ev_thd, 0);
diff --git a/sql/log_slow.h b/sql/log_slow.h
index 92a2d1bf4f6..e8faf79a047 100644
--- a/sql/log_slow.h
+++ b/sql/log_slow.h
@@ -18,6 +18,7 @@
#define LOG_SLOW_VERBOSITY_INIT 0
#define LOG_SLOW_VERBOSITY_INNODB 1 << 0
#define LOG_SLOW_VERBOSITY_QUERY_PLAN 1 << 1
+#define LOG_SLOW_VERBOSITY_EXPLAIN 1 << 2
#define QPLAN_INIT QPLAN_QC_NO
diff --git a/sql/my_apc.cc b/sql/my_apc.cc
index 755b3890433..17660688be0 100644
--- a/sql/my_apc.cc
+++ b/sql/my_apc.cc
@@ -70,6 +70,7 @@ void Apc_target::enable()
void Apc_target::disable()
{
bool process= FALSE;
+ DBUG_ASSERT(enabled);
mysql_mutex_lock(LOCK_thd_data_ptr);
if (!(--enabled))
process= TRUE;
diff --git a/sql/my_apc.h b/sql/my_apc.h
index c84074b2da5..a12db5093a4 100644
--- a/sql/my_apc.h
+++ b/sql/my_apc.h
@@ -64,6 +64,8 @@ public:
{
return test(apc_calls);
}
+
+ inline bool is_enabled() { return enabled; }
/* Functor class for calls you can schedule */
class Apc_call
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index dfbcac9aa55..384c99cff54 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -861,6 +861,14 @@ class PARAM : public RANGE_OPT_PARAM
{
public:
ha_rows quick_rows[MAX_KEY];
+
+ /*
+ This will collect 'possible keys' based on the range optimization.
+
+ Queries with a JOIN object actually use ref optimizer (see add_key_field)
+ to collect possible_keys. This is used by single table UPDATE/DELETE.
+ */
+ key_map possible_keys;
longlong baseflag;
uint max_key_part, range_count;
@@ -2955,6 +2963,8 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
read_time= (double) records + scan_time + 1; // Force to use index
else if (read_time <= 2.0 && !force_quick_range)
DBUG_RETURN(0); /* No need for quick select */
+
+ possible_keys.clear_all();
DBUG_PRINT("info",("Time to scan table: %g", read_time));
@@ -2986,6 +2996,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
param.using_real_indexes= TRUE;
param.remove_jump_scans= TRUE;
param.force_default_mrr= ordered_output;
+ param.possible_keys.clear_all();
thd->no_errors=1; // Don't warn about NULL
init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0,
@@ -3197,6 +3208,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
quick= NULL;
}
}
+ possible_keys= param.possible_keys;
free_mem:
free_root(&alloc,MYF(0)); // Return memory & allocator
@@ -3204,6 +3216,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
thd->no_errors=0;
}
+
DBUG_EXECUTE("info", print_quick(quick, &needed_reg););
/*
@@ -10493,6 +10506,7 @@ ha_rows check_quick_select(PARAM *param, uint idx, bool index_only,
if (rows != HA_POS_ERROR)
{
param->quick_rows[keynr]= rows;
+ param->possible_keys.set_bit(keynr);
if (update_tbl_stats)
{
param->table->quick_keys.set_bit(keynr);
@@ -11986,78 +12000,134 @@ void QUICK_SELECT_I::add_key_name(String *str, bool *first)
}
-void QUICK_RANGE_SELECT::add_info_string(String *str)
+Explain_quick_select* QUICK_RANGE_SELECT::get_explain(MEM_ROOT *alloc)
{
- bool first= TRUE;
-
- add_key_name(str, &first);
+ Explain_quick_select *res;
+ if ((res= new (alloc) Explain_quick_select(QS_TYPE_RANGE)))
+ res->range.set(alloc, head->key_info[index].name, max_used_key_length);
+ return res;
}
-void QUICK_INDEX_MERGE_SELECT::add_info_string(String *str)
+
+Explain_quick_select* QUICK_GROUP_MIN_MAX_SELECT::get_explain(MEM_ROOT *alloc)
{
+ Explain_quick_select *res;
+ if ((res= new (alloc) Explain_quick_select(QS_TYPE_GROUP_MIN_MAX)))
+ res->range.set(alloc, head->key_info[index].name, max_used_key_length);
+ return res;
+}
+
+
+Explain_quick_select* QUICK_INDEX_SORT_SELECT::get_explain(MEM_ROOT *alloc)
+{
+ Explain_quick_select *res;
+ if (!(res= new (alloc) Explain_quick_select(get_type())))
+ return NULL;
+
QUICK_RANGE_SELECT *quick;
- bool first= TRUE;
+ Explain_quick_select *child_explain;
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
-
- str->append(STRING_WITH_LEN("sort_union("));
while ((quick= it++))
{
- quick->add_key_name(str, &first);
+ if ((child_explain= quick->get_explain(alloc)))
+ res->children.push_back(child_explain);
+ else
+ return NULL;
}
+
if (pk_quick_select)
- pk_quick_select->add_key_name(str, &first);
- str->append(')');
+ {
+ if ((child_explain= pk_quick_select->get_explain(alloc)))
+ res->children.push_back(child_explain);
+ else
+ return NULL;
+ }
+ return res;
}
-void QUICK_INDEX_INTERSECT_SELECT::add_info_string(String *str)
+
+/*
+ Same as QUICK_INDEX_SORT_SELECT::get_explain(), but primary key is printed
+ first
+*/
+
+Explain_quick_select* QUICK_INDEX_INTERSECT_SELECT::get_explain(MEM_ROOT *alloc)
{
- QUICK_RANGE_SELECT *quick;
- bool first= TRUE;
- List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
+ Explain_quick_select *res;
+ Explain_quick_select *child_explain;
+
+ if (!(res= new (alloc) Explain_quick_select(get_type())))
+ return NULL;
- str->append(STRING_WITH_LEN("sort_intersect("));
if (pk_quick_select)
- pk_quick_select->add_key_name(str, &first);
+ {
+ if ((child_explain= pk_quick_select->get_explain(alloc)))
+ res->children.push_back(child_explain);
+ else
+ return NULL;
+ }
+
+ QUICK_RANGE_SELECT *quick;
+ List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
while ((quick= it++))
{
- quick->add_key_name(str, &first);
+ if ((child_explain= quick->get_explain(alloc)))
+ res->children.push_back(child_explain);
+ else
+ return NULL;
}
- str->append(')');
+ return res;
}
-void QUICK_ROR_INTERSECT_SELECT::add_info_string(String *str)
+
+Explain_quick_select* QUICK_ROR_INTERSECT_SELECT::get_explain(MEM_ROOT *alloc)
{
- bool first= TRUE;
+ Explain_quick_select *res;
+ Explain_quick_select *child_explain;
+
+ if (!(res= new (alloc) Explain_quick_select(get_type())))
+ return NULL;
+
QUICK_SELECT_WITH_RECORD *qr;
List_iterator_fast<QUICK_SELECT_WITH_RECORD> it(quick_selects);
-
- str->append(STRING_WITH_LEN("intersect("));
while ((qr= it++))
{
- qr->quick->add_key_name(str, &first);
+ if ((child_explain= qr->quick->get_explain(alloc)))
+ res->children.push_back(child_explain);
+ else
+ return NULL;
}
+
if (cpk_quick)
- cpk_quick->add_key_name(str, &first);
- str->append(')');
+ {
+ if ((child_explain= cpk_quick->get_explain(alloc)))
+ res->children.push_back(child_explain);
+ else
+ return NULL;
+ }
+ return res;
}
-void QUICK_ROR_UNION_SELECT::add_info_string(String *str)
+Explain_quick_select* QUICK_ROR_UNION_SELECT::get_explain(MEM_ROOT *alloc)
{
+ Explain_quick_select *res;
+ Explain_quick_select *child_explain;
+
+ if (!(res= new (alloc) Explain_quick_select(get_type())))
+ return NULL;
+
QUICK_SELECT_I *quick;
- bool first= TRUE;
List_iterator_fast<QUICK_SELECT_I> it(quick_selects);
-
- str->append(STRING_WITH_LEN("union("));
while ((quick= it++))
{
- if (first)
- first= FALSE;
+ if ((child_explain= quick->get_explain(alloc)))
+ res->children.push_back(child_explain);
else
- str->append(',');
- quick->add_info_string(str);
+ return NULL;
}
- str->append(')');
+
+ return res;
}
diff --git a/sql/opt_range.h b/sql/opt_range.h
index 3dbdce00e9d..4f2ab6df60d 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -52,7 +52,7 @@ typedef struct st_key_part {
Field::imagetype image_type;
} KEY_PART;
-
+class Explain_quick_select;
/*
A "MIN_TUPLE < tbl.key_tuple < MAX_TUPLE" interval.
@@ -345,13 +345,8 @@ public:
void add_key_name(String *str, bool *first);
- /*
- Append text representation of quick select structure (what and how is
- merged) to str. The result is added to "Extra" field in EXPLAIN output.
- This function is implemented only by quick selects that merge other quick
- selects output and/or can produce output suitable for merging.
- */
- virtual void add_info_string(String *str) {}
+ /* Save information about quick select's query plan */
+ virtual Explain_quick_select* get_explain(MEM_ROOT *alloc)= 0;
/*
Return 1 if any index used by this quick select
@@ -478,7 +473,7 @@ public:
{ file->position(record); }
int get_type() { return QS_TYPE_RANGE; }
void add_keys_and_lengths(String *key_names, String *used_lengths);
- void add_info_string(String *str);
+ Explain_quick_select *get_explain(MEM_ROOT *alloc);
#ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose);
#endif
@@ -615,6 +610,7 @@ public:
#ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose);
#endif
+ Explain_quick_select *get_explain(MEM_ROOT *alloc);
bool push_quick_back(QUICK_RANGE_SELECT *quick_sel_range);
@@ -663,7 +659,6 @@ public:
int get_next();
int get_type() { return QS_TYPE_INDEX_MERGE; }
void add_keys_and_lengths(String *key_names, String *used_lengths);
- void add_info_string(String *str);
};
class QUICK_INDEX_INTERSECT_SELECT : public QUICK_INDEX_SORT_SELECT
@@ -679,7 +674,7 @@ public:
int get_next();
int get_type() { return QS_TYPE_INDEX_INTERSECT; }
void add_keys_and_lengths(String *key_names, String *used_lengths);
- void add_info_string(String *str);
+ Explain_quick_select *get_explain(MEM_ROOT *alloc);
};
@@ -717,7 +712,7 @@ public:
bool unique_key_range() { return false; }
int get_type() { return QS_TYPE_ROR_INTERSECT; }
void add_keys_and_lengths(String *key_names, String *used_lengths);
- void add_info_string(String *str);
+ Explain_quick_select *get_explain(MEM_ROOT *alloc);
bool is_keys_used(const MY_BITMAP *fields);
#ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose);
@@ -796,7 +791,7 @@ public:
bool unique_key_range() { return false; }
int get_type() { return QS_TYPE_ROR_UNION; }
void add_keys_and_lengths(String *key_names, String *used_lengths);
- void add_info_string(String *str);
+ Explain_quick_select *get_explain(MEM_ROOT *alloc);
bool is_keys_used(const MY_BITMAP *fields);
#ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose);
@@ -944,11 +939,8 @@ public:
void dbug_dump(int indent, bool verbose);
#endif
bool is_agg_distinct() { return have_agg_distinct; }
- virtual void append_loose_scan_type(String *str)
- {
- if (is_index_scan)
- str->append(STRING_WITH_LEN(" (scanning)"));
- }
+ bool loose_scan_is_scanning() { return is_index_scan; }
+ Explain_quick_select *get_explain(MEM_ROOT *alloc);
};
@@ -990,6 +982,8 @@ class SQL_SELECT :public Sql_alloc {
key_map quick_keys; // Possible quick keys
key_map needed_reg; // Possible quick keys after prev tables.
table_map const_tables,read_tables;
+ /* See PARAM::possible_keys */
+ key_map possible_keys;
bool free_cond; /* Currently not used and always FALSE */
SQL_SELECT();
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index c0be41e0f3c..a43dfe40698 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -313,14 +313,30 @@ sp_get_flags_for_command(LEX *lex)
flags= sp_head::HAS_COMMIT_OR_ROLLBACK;
break;
case SQLCOM_DELETE:
+ case SQLCOM_DELETE_MULTI:
{
- if (lex->select_lex.item_list.is_empty())
+ /*
+ DELETE normally doesn't return resultset, but there are two exceptions:
+ - DELETE ... RETURNING
+ - EXPLAIN DELETE ...
+ */
+ if (lex->select_lex.item_list.is_empty() && !lex->describe)
+ flags= 0;
+ else
+ flags= sp_head::MULTI_RESULTS;
+ break;
+ }
+ 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;
else
- {
- /* This is DELETE ... RETURNING ... */
flags= sp_head::MULTI_RESULTS;
- }
break;
}
default:
@@ -2944,6 +2960,8 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
else if (! thd->in_sub_stmt)
thd->mdl_context.release_statement_locks();
}
+ //TODO: why is this here if log_slow_query is in sp_instr_stmt_execute?
+ delete_explain_query(m_lex);
if (m_lex->query_tables_own_last)
{
@@ -3165,6 +3183,7 @@ sp_instr_set::exec_core(THD *thd, uint *nextp)
my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
}
}
+ delete_explain_query(thd->lex);
*nextp = m_ip+1;
return res;
diff --git a/sql/sql_array.h b/sql/sql_array.h
index 697819787f2..b527f26b186 100644
--- a/sql/sql_array.h
+++ b/sql/sql_array.h
@@ -117,6 +117,7 @@ public:
*/
Elem& at(size_t idx)
{
+ DBUG_ASSERT(idx < array.elements);
return *(((Elem*)array.buffer) + idx);
}
/// Const variant of at(), which cannot change data
@@ -199,6 +200,23 @@ public:
set_dynamic(&array, &el, idx);
}
+ bool resize(size_t new_size, Elem default_val)
+ {
+ size_t old_size= elements();
+ if (allocate_dynamic(&array, new_size))
+ return true;
+
+ if (new_size > old_size)
+ {
+ set_dynamic(&array, (uchar*)&default_val, new_size - 1);
+ /*for (size_t i= old_size; i != new_size; i++)
+ {
+ at(i)= default_val;
+ }*/
+ }
+ return false;
+ }
+
~Dynamic_array()
{
delete_dynamic(&array);
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index bc0e9b792b5..31ce21509a9 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -2224,6 +2224,7 @@ int THD::send_explain_fields(select_result *result)
{
List<Item> field_list;
make_explain_field_list(field_list);
+ result->prepare(field_list, NULL);
return (result->send_result_set_metadata(field_list,
Protocol::SEND_NUM_ROWS |
Protocol::SEND_EOF));
diff --git a/sql/sql_class.h b/sql/sql_class.h
index f68243ff544..06edfd8c334 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -3634,6 +3634,11 @@ public:
void begin_dataset() {}
#endif
virtual void update_used_tables() {}
+
+ void reset_offset_limit()
+ {
+ unit->offset_limit_cnt= 0;
+ }
};
@@ -3662,6 +3667,26 @@ public:
};
+/*
+ This is a select_result_sink which stores the data in text form.
+*/
+
+class select_result_text_buffer : public select_result_sink
+{
+public:
+ select_result_text_buffer(THD *thd_arg) : thd(thd_arg) {}
+ int send_data(List<Item> &items);
+ bool send_result_set_metadata(List<Item> &fields, uint flag);
+
+ void save_to(String *res);
+private:
+ int append_row(List<Item> &items, bool send_names);
+
+ THD *thd;
+ List<char*> rows;
+ int n_columns;
+};
+
/*
Base class for select_result descendands which intercept and
@@ -4389,7 +4414,9 @@ class multi_update :public select_result_interceptor
so that afterward send_error() needs to find out that.
*/
bool error_handled;
-
+
+ /* Need this to protect against multiple prepare() calls */
+ bool prepared;
public:
multi_update(TABLE_LIST *ut, List<TABLE_LIST> *leaves_list,
List<Item> *fields, List<Item> *values,
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 1e0789aab12..1500f1615fb 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -40,6 +40,161 @@
#include "records.h" // init_read_record,
#include "sql_derived.h" // mysql_handle_list_of_derived
// end_read_record
+#include "sql_partition.h" // make_used_partitions_str
+
+/*
+ @brief
+ Print query plan of a single-table DELETE command
+
+ @detail
+ This function is used by EXPLAIN DELETE and by SHOW EXPLAIN when it is
+ invoked on a running DELETE statement.
+*/
+
+void Delete_plan::save_explain_data(Explain_query *query)
+{
+ Explain_delete* explain= new Explain_delete;
+
+ if (deleting_all_rows)
+ {
+ explain->deleting_all_rows= true;
+ explain->select_type= "SIMPLE";
+ explain->rows= scanned_rows;
+ }
+ else
+ {
+ explain->deleting_all_rows= false;
+ Update_plan::save_explain_data_intern(query, explain);
+ }
+
+ query->add_upd_del_plan(explain);
+}
+
+
+void Update_plan::save_explain_data(Explain_query *query)
+{
+ Explain_update* explain= new Explain_update;
+ save_explain_data_intern(query, explain);
+ query->add_upd_del_plan(explain);
+}
+
+
+void Update_plan::save_explain_data_intern(Explain_query *query,
+ Explain_update *explain)
+{
+ explain->select_type= "SIMPLE";
+ explain->table_name.append(table->pos_in_table_list->alias);
+
+ explain->impossible_where= false;
+ explain->no_partitions= false;
+
+ if (impossible_where)
+ {
+ explain->impossible_where= true;
+ return;
+ }
+
+ if (no_partitions)
+ {
+ explain->no_partitions= true;
+ return;
+ }
+
+ select_lex->set_explain_type(TRUE);
+ explain->select_type= select_lex->type;
+ /* Partitions */
+ {
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ partition_info *part_info;
+ if ((part_info= table->part_info))
+ {
+ make_used_partitions_str(part_info, &explain->used_partitions);
+ explain->used_partitions_set= true;
+ }
+ else
+ explain->used_partitions_set= false;
+#else
+ /* just produce empty column if partitioning is not compiled in */
+ explain->used_partitions_set= false;
+#endif
+ }
+
+
+ /* Set jtype */
+ if (select && select->quick)
+ {
+ int quick_type= select->quick->get_type();
+ if ((quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE) ||
+ (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))
+ explain->jtype= JT_INDEX_MERGE;
+ else
+ explain->jtype= JT_RANGE;
+ }
+ else
+ {
+ if (index == MAX_KEY)
+ explain->jtype= JT_ALL;
+ else
+ explain->jtype= JT_NEXT;
+ }
+
+ explain->using_where= test(select && select->cond);
+ explain->using_filesort= using_filesort;
+ explain->using_io_buffer= using_io_buffer;
+
+ make_possible_keys_line(table, possible_keys, &explain->possible_keys_line);
+
+ explain->quick_info= NULL;
+
+ /* Calculate key_len */
+ if (select && select->quick)
+ {
+ explain->quick_info= select->quick->get_explain(mem_root);
+ }
+ else
+ {
+ if (index != MAX_KEY)
+ {
+ explain->key_str.append(table->key_info[index].name);
+ char buf[64];
+ size_t length;
+ length= longlong10_to_str(table->key_info[index].key_length, buf, 10) - buf;
+ explain->key_len_str.append(buf, length);
+ }
+ }
+ explain->rows= scanned_rows;
+
+ if (select && select->quick &&
+ select->quick->get_type() == QUICK_SELECT_I::QS_TYPE_RANGE)
+ {
+ explain_append_mrr_info((QUICK_RANGE_SELECT*)select->quick,
+ &explain->mrr_type);
+ }
+
+ bool skip= updating_a_view;
+
+ /* Save subquery children */
+ for (SELECT_LEX_UNIT *unit= select_lex->first_inner_unit();
+ unit;
+ unit= unit->next_unit())
+ {
+ if (skip)
+ {
+ skip= false;
+ continue;
+ }
+ /*
+ Display subqueries only if they are not parts of eliminated WHERE/ON
+ clauses.
+ */
+ if (!(unit->item && unit->item->eliminated))
+ explain->add_child(unit->first_select()->select_number);
+ }
+}
+
+
/**
Implement DELETE SQL word.
@@ -64,13 +219,16 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
bool reverse= FALSE;
ORDER *order= (ORDER *) ((order_list && order_list->elements) ?
order_list->first : NULL);
- uint usable_index= MAX_KEY;
SELECT_LEX *select_lex= &thd->lex->select_lex;
killed_state killed_status= NOT_KILLED;
THD::enum_binlog_query_type query_type= THD::ROW_QUERY_TYPE;
bool with_select= !select_lex->item_list.is_empty();
+ Delete_plan query_plan(thd->mem_root);
+ query_plan.index= MAX_KEY;
+ query_plan.using_filesort= FALSE;
DBUG_ENTER("mysql_delete");
+ create_explain_query(thd->lex, thd->mem_root);
if (open_and_lock_tables(thd, table_list, TRUE, 0))
DBUG_RETURN(TRUE);
@@ -92,6 +250,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
}
THD_STAGE_INFO(thd, stage_init);
table->map=1;
+ query_plan.select_lex= &thd->lex->select_lex;
+ query_plan.table= table;
+ query_plan.updating_a_view= test(table_list->view);
if (mysql_prepare_delete(thd, table_list, select_lex->with_wild,
select_lex->item_list, &conds))
@@ -168,6 +329,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
ha_rows const maybe_deleted= table->file->stats.records;
DBUG_PRINT("debug", ("Trying to use delete_all_rows()"));
+
+ query_plan.set_delete_all_rows(maybe_deleted);
+ if (thd->lex->describe)
+ goto exit_without_my_ok;
+
if (!(error=table->file->ha_delete_all_rows()))
{
/*
@@ -192,14 +358,23 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
Item::cond_result result;
conds= remove_eq_conds(thd, conds, &result);
if (result == Item::COND_FALSE) // Impossible where
+ {
limit= 0;
+ query_plan.set_impossible_where();
+ if (thd->lex->describe)
+ goto exit_without_my_ok;
+ }
}
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (prune_partitions(thd, table, conds))
{
free_underlaid_joins(thd, select_lex);
- // No matching record
+
+ query_plan.set_no_partitions();
+ if (thd->lex->describe)
+ goto exit_without_my_ok;
+
my_ok(thd, 0);
DBUG_RETURN(0);
}
@@ -216,6 +391,10 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
DBUG_RETURN(TRUE);
if ((select && select->check_quick(thd, safe_update, limit)) || !limit)
{
+ query_plan.set_impossible_where();
+ if (thd->lex->describe)
+ goto exit_without_my_ok;
+
delete select;
free_underlaid_joins(thd, select_lex);
/*
@@ -246,28 +425,54 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (options & OPTION_QUICK)
(void) table->file->extra(HA_EXTRA_QUICK);
+ query_plan.scanned_rows= select? select->records: table->file->stats.records;
if (order)
{
- uint length= 0;
- SORT_FIELD *sortorder;
- ha_rows examined_rows;
- ha_rows found_rows;
-
table->update_const_key_parts(conds);
order= simple_remove_const(order, conds);
- bool need_sort;
if (select && select->quick && select->quick->unique_key_range())
{ // Single row select (always "ordered")
- need_sort= FALSE;
- usable_index= MAX_KEY;
+ query_plan.using_filesort= FALSE;
+ query_plan.index= MAX_KEY;
}
else
- usable_index= get_index_for_order(order, table, select, limit,
- &need_sort, &reverse);
- if (need_sort)
{
- DBUG_ASSERT(usable_index == MAX_KEY);
+ ha_rows scanned_limit= query_plan.scanned_rows;
+ query_plan.index= get_index_for_order(order, table, select, limit,
+ &scanned_limit,
+ &query_plan.using_filesort,
+ &reverse);
+ if (!query_plan.using_filesort)
+ query_plan.scanned_rows= scanned_limit;
+ }
+ }
+
+ query_plan.select= select;
+ query_plan.possible_keys= select? select->possible_keys: key_map(0);
+
+ /*
+ Ok, we have generated a query plan for the DELETE.
+ - if we're running EXPLAIN DELETE, goto produce explain output
+ - otherwise, execute the query plan
+ */
+ if (thd->lex->describe)
+ goto exit_without_my_ok;
+
+ query_plan.save_explain_data(thd->lex->explain);
+
+ DBUG_EXECUTE_IF("show_explain_probe_delete_exec_start",
+ dbug_serve_apcs(thd, 1););
+
+ if (query_plan.using_filesort)
+ {
+ ha_rows examined_rows;
+ ha_rows found_rows;
+ uint length= 0;
+ SORT_FIELD *sortorder;
+
+ {
+ DBUG_ASSERT(query_plan.index == MAX_KEY);
table->sort.io_cache= (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
MYF(MY_FAE | MY_ZEROFILL |
MY_THREAD_SPECIFIC));
@@ -301,7 +506,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
free_underlaid_joins(thd, select_lex);
DBUG_RETURN(TRUE);
}
- if (usable_index == MAX_KEY || (select && select->quick))
+ if (query_plan.index == MAX_KEY || (select && select->quick))
{
if (init_read_record(&info, thd, table, select, 1, 1, FALSE))
{
@@ -311,7 +516,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
}
}
else
- init_read_record_idx(&info, thd, table, 1, usable_index, reverse);
+ init_read_record_idx(&info, thd, table, 1, query_plan.index, reverse);
init_ftfuncs(thd, select_lex, 1);
THD_STAGE_INFO(thd, stage_updating);
@@ -479,6 +684,16 @@ cleanup:
DBUG_PRINT("info",("%ld records deleted",(long) deleted));
}
DBUG_RETURN(error >= 0 || thd->is_error());
+
+ /* Special exits */
+exit_without_my_ok:
+ query_plan.save_explain_data(thd->lex->explain);
+ int err2= thd->lex->explain->send_explain(thd);
+
+ delete select;
+ free_underlaid_joins(thd, select_lex);
+ //table->set_keyread(false);
+ DBUG_RETURN((err2 || thd->is_error() || thd->killed) ? 1 : 0);
}
diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc
new file mode 100644
index 00000000000..b3078c10b72
--- /dev/null
+++ b/sql/sql_explain.cc
@@ -0,0 +1,954 @@
+/*
+ Copyright (c) 2013 Monty Program Ab
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifdef USE_PRAGMA_IMPLEMENTATION
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "sql_priv.h"
+#include "sql_select.h"
+
+
+Explain_query::Explain_query(THD *thd_arg) :
+ upd_del_plan(NULL), insert_plan(NULL), thd(thd_arg), apc_enabled(false)
+{
+ operations= 0;
+}
+
+
+Explain_query::~Explain_query()
+{
+ if (apc_enabled)
+ thd->apc_target.disable();
+
+ delete upd_del_plan;
+ delete insert_plan;
+ uint i;
+ for (i= 0 ; i < unions.elements(); i++)
+ delete unions.at(i);
+ for (i= 0 ; i < selects.elements(); i++)
+ delete selects.at(i);
+}
+
+
+Explain_node *Explain_query::get_node(uint select_id)
+{
+ Explain_union *u;
+ if ((u= get_union(select_id)))
+ return u;
+ else
+ return get_select(select_id);
+}
+
+Explain_union *Explain_query::get_union(uint select_id)
+{
+ return (unions.elements() > select_id) ? unions.at(select_id) : NULL;
+}
+
+Explain_select *Explain_query::get_select(uint select_id)
+{
+ return (selects.elements() > select_id) ? selects.at(select_id) : NULL;
+}
+
+
+void Explain_query::add_node(Explain_node *node)
+{
+ uint select_id;
+ operations++;
+ if (node->get_type() == Explain_node::EXPLAIN_UNION)
+ {
+ Explain_union *u= (Explain_union*)node;
+ select_id= u->get_select_id();
+ if (unions.elements() <= select_id)
+ unions.resize(MY_MAX(select_id+1, unions.elements()*2), NULL);
+
+ Explain_union *old_node;
+ if ((old_node= get_union(select_id)))
+ delete old_node;
+
+ unions.at(select_id)= u;
+ }
+ else
+ {
+ Explain_select *sel= (Explain_select*)node;
+ if (sel->select_id == FAKE_SELECT_LEX_ID)
+ {
+ DBUG_ASSERT(0); // this is a "fake select" from a UNION.
+ }
+ else
+ {
+ select_id= sel->select_id;
+ Explain_select *old_node;
+
+ if (selects.elements() <= select_id)
+ selects.resize(MY_MAX(select_id+1, selects.elements()*2), NULL);
+
+ if ((old_node= get_select(select_id)))
+ delete old_node;
+
+ selects.at(select_id)= sel;
+ }
+ }
+}
+
+
+void Explain_query::add_insert_plan(Explain_insert *insert_plan_arg)
+{
+ insert_plan= insert_plan_arg;
+ query_plan_ready();
+}
+
+
+void Explain_query::add_upd_del_plan(Explain_update *upd_del_plan_arg)
+{
+ upd_del_plan= upd_del_plan_arg;
+ query_plan_ready();
+}
+
+
+void Explain_query::query_plan_ready()
+{
+ if (!apc_enabled)
+ thd->apc_target.enable();
+ apc_enabled= true;
+}
+
+/*
+ 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
+*/
+
+int Explain_query::print_explain(select_result_sink *output,
+ uint8 explain_flags)
+{
+ if (upd_del_plan)
+ {
+ 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 */
+ Explain_node *node= get_node(1);
+ if (!node)
+ return 1; /* No query plan */
+ return node->print_explain(this, output, explain_flags);
+ }
+}
+
+
+bool print_explain_query(LEX *lex, THD *thd, String *str)
+{
+ return lex->explain->print_explain_str(thd, str);
+}
+
+
+/*
+ Return tabular EXPLAIN output as a text string
+*/
+
+bool Explain_query::print_explain_str(THD *thd, String *out_str)
+{
+ List<Item> fields;
+ thd->make_explain_field_list(fields);
+
+ select_result_text_buffer output_buf(thd);
+ output_buf.send_result_set_metadata(fields, thd->lex->describe);
+ if (print_explain(&output_buf, thd->lex->describe))
+ return true;
+ output_buf.save_to(out_str);
+ return false;
+}
+
+
+static void push_str(List<Item> *item_list, const char *str)
+{
+ item_list->push_back(new Item_string(str,
+ strlen(str), system_charset_info));
+}
+
+
+static void push_string(List<Item> *item_list, String *str)
+{
+ item_list->push_back(new Item_string(str->ptr(), str->length(),
+ system_charset_info));
+}
+
+
+int Explain_union::print_explain(Explain_query *query,
+ select_result_sink *output,
+ uint8 explain_flags)
+{
+ /* print all UNION children, in order */
+ for (int i= 0; i < (int) union_members.elements(); i++)
+ {
+ Explain_select *sel= query->get_select(union_members.at(i));
+ sel->print_explain(query, output, explain_flags);
+ }
+
+ /* Print a line with "UNION RESULT" */
+ List<Item> item_list;
+ Item *item_null= new Item_null();
+
+ /* `id` column */
+ item_list.push_back(item_null);
+
+ /* `select_type` column */
+ push_str(&item_list, fake_select_type);
+
+ /* `table` column: something like "<union1,2>" */
+ {
+ char table_name_buffer[SAFE_NAME_LEN];
+ uint childno= 0;
+ uint len= 6, lastop= 0;
+ memcpy(table_name_buffer, STRING_WITH_LEN("<union"));
+
+ for (; childno < union_members.elements() && len + lastop + 5 < NAME_LEN;
+ childno++)
+ {
+ len+= lastop;
+ lastop= my_snprintf(table_name_buffer + len, NAME_LEN - len,
+ "%u,", union_members.at(childno));
+ }
+
+ if (childno < union_members.elements() || len + lastop >= NAME_LEN)
+ {
+ memcpy(table_name_buffer + len, STRING_WITH_LEN("...>") + 1);
+ len+= 4;
+ }
+ else
+ {
+ len+= lastop;
+ table_name_buffer[len - 1]= '>'; // change ',' to '>'
+ }
+ const CHARSET_INFO *cs= system_charset_info;
+ item_list.push_back(new Item_string(table_name_buffer, len, cs));
+ }
+
+ /* `partitions` column */
+ if (explain_flags & DESCRIBE_PARTITIONS)
+ item_list.push_back(item_null);
+
+ /* `type` column */
+ push_str(&item_list, join_type_str[JT_ALL]);
+
+ /* `possible_keys` column */
+ item_list.push_back(item_null);
+
+ /* `key` */
+ item_list.push_back(item_null);
+
+ /* `key_len` */
+ item_list.push_back(item_null);
+
+ /* `ref` */
+ item_list.push_back(item_null);
+
+ /* `rows` */
+ item_list.push_back(item_null);
+
+ /* `filtered` */
+ if (explain_flags & DESCRIBE_EXTENDED)
+ item_list.push_back(item_null);
+
+ /* `Extra` */
+ StringBuffer<256> extra_buf;
+ if (using_filesort)
+ {
+ extra_buf.append(STRING_WITH_LEN("Using filesort"));
+ }
+ const CHARSET_INFO *cs= system_charset_info;
+ item_list.push_back(new Item_string(extra_buf.ptr(), extra_buf.length(), cs));
+
+ //output->unit.offset_limit_cnt= 0;
+ if (output->send_data(item_list))
+ return 1;
+
+ /*
+ Print all subquery children (UNION children have already been printed at
+ the start of this function)
+ */
+ return print_explain_for_children(query, output, explain_flags);
+}
+
+
+/*
+ Print EXPLAINs for all children nodes (i.e. for subqueries)
+*/
+
+int Explain_node::print_explain_for_children(Explain_query *query,
+ select_result_sink *output,
+ uint8 explain_flags)
+{
+ for (int i= 0; i < (int) children.elements(); i++)
+ {
+ Explain_node *node= query->get_node(children.at(i));
+ if (node->print_explain(query, output, explain_flags))
+ return 1;
+ }
+ return 0;
+}
+
+
+Explain_select::~Explain_select()
+{
+ if (join_tabs)
+ {
+ for (uint i= 0; i< n_join_tabs; i++)
+ delete join_tabs[i];
+ my_free(join_tabs);
+ }
+}
+
+
+int Explain_select::print_explain(Explain_query *query,
+ select_result_sink *output,
+ uint8 explain_flags)
+{
+ if (message)
+ {
+ List<Item> item_list;
+ const CHARSET_INFO *cs= system_charset_info;
+ Item *item_null= new Item_null();
+
+ item_list.push_back(new Item_int((int32) select_id));
+ item_list.push_back(new Item_string(select_type,
+ strlen(select_type), cs));
+ for (uint i=0 ; i < 7; i++)
+ item_list.push_back(item_null);
+ if (explain_flags & DESCRIBE_PARTITIONS)
+ item_list.push_back(item_null);
+ if (explain_flags & DESCRIBE_EXTENDED)
+ item_list.push_back(item_null);
+
+ item_list.push_back(new Item_string(message,strlen(message),cs));
+
+ if (output->send_data(item_list))
+ return 1;
+ }
+ else
+ {
+ bool using_tmp= using_temporary;
+ bool using_fs= using_filesort;
+ for (uint i=0; i< n_join_tabs; i++)
+ {
+ join_tabs[i]->print_explain(output, explain_flags, select_id,
+ select_type, using_tmp, using_fs);
+ if (i == 0)
+ {
+ /*
+ "Using temporary; Using filesort" should only be shown near the 1st
+ table
+ */
+ using_tmp= false;
+ using_fs= false;
+ }
+ }
+ }
+
+ return print_explain_for_children(query, output, explain_flags);
+}
+
+
+void Explain_table_access::push_extra(enum explain_extra_tag extra_tag)
+{
+ extra_tags.append(extra_tag);
+}
+
+
+int Explain_table_access::print_explain(select_result_sink *output, uint8 explain_flags,
+ uint select_id, const char *select_type,
+ bool using_temporary, bool using_filesort)
+{
+ const CHARSET_INFO *cs= system_charset_info;
+ const char *hash_key_prefix= "#hash#";
+ bool is_hj= (type == JT_HASH || type == JT_HASH_NEXT ||
+ type == JT_HASH_RANGE || type == JT_HASH_INDEX_MERGE);
+
+ List<Item> item_list;
+ Item *item_null= new Item_null();
+
+ if (sjm_nest_select_id)
+ select_id= sjm_nest_select_id;
+
+ /* `id` column */
+ item_list.push_back(new Item_int((int32) select_id));
+
+ /* `select_type` column */
+ if (sjm_nest_select_id)
+ push_str(&item_list, "MATERIALIZED");
+ else
+ push_str(&item_list, select_type);
+
+ /* `table` column */
+ push_string(&item_list, &table_name);
+
+ /* `partitions` column */
+ if (explain_flags & DESCRIBE_PARTITIONS)
+ {
+ if (used_partitions_set)
+ {
+ push_string(&item_list, &used_partitions);
+ }
+ else
+ item_list.push_back(item_null);
+ }
+
+ /* `type` column */
+ push_str(&item_list, join_type_str[type]);
+
+ /* `possible_keys` column */
+ if (possible_keys_str.length() > 0)
+ push_string(&item_list, &possible_keys_str);
+ else
+ item_list.push_back(item_null);
+
+ /* `key` */
+ StringBuffer<64> key_str;
+ if (key.get_key_name())
+ {
+ if (is_hj)
+ key_str.append(hash_key_prefix, strlen(hash_key_prefix), cs);
+
+ key_str.append(key.get_key_name());
+
+ if (is_hj && type != JT_HASH)
+ key_str.append(':');
+ }
+
+ if (quick_info)
+ {
+ StringBuffer<64> buf2;
+ quick_info->print_key(&buf2);
+ key_str.append(buf2);
+ }
+ if (type == JT_HASH_NEXT)
+ key_str.append(hash_next_key.get_key_name());
+
+ if (key_str.length() > 0)
+ push_string(&item_list, &key_str);
+ else
+ item_list.push_back(item_null);
+
+ /* `key_len` */
+ StringBuffer<64> key_len_str;
+
+ if (key.get_key_len() != (uint)-1)
+ {
+ char buf[64];
+ size_t length;
+ length= longlong10_to_str(key.get_key_len(), buf, 10) - buf;
+ key_len_str.append(buf, length);
+ if (is_hj && type != JT_HASH)
+ key_len_str.append(':');
+ }
+
+ if (quick_info)
+ {
+ StringBuffer<64> buf2;
+ quick_info->print_key_len(&buf2);
+ key_len_str.append(buf2);
+ }
+
+ if (type == JT_HASH_NEXT)
+ {
+ char buf[64];
+ size_t length;
+ length= longlong10_to_str(hash_next_key.get_key_len(), buf, 10) - buf;
+ key_len_str.append(buf, length);
+ }
+
+ if (key_len_str.length() > 0)
+ push_string(&item_list, &key_len_str);
+ else
+ item_list.push_back(item_null);
+
+ /* `ref` */
+ if (ref_set)
+ push_string(&item_list, &ref);
+ else
+ item_list.push_back(item_null);
+
+ /* `rows` */
+ if (rows_set)
+ {
+ item_list.push_back(new Item_int((longlong) (ulonglong) rows,
+ MY_INT64_NUM_DECIMAL_DIGITS));
+ }
+ else
+ item_list.push_back(item_null);
+
+ /* `filtered` */
+ if (explain_flags & DESCRIBE_EXTENDED)
+ {
+ if (filtered_set)
+ {
+ item_list.push_back(new Item_float(filtered, 2));
+ }
+ else
+ item_list.push_back(item_null);
+ }
+
+ /* `Extra` */
+ StringBuffer<256> extra_buf;
+ bool first= true;
+ for (int i=0; i < (int)extra_tags.elements(); i++)
+ {
+ if (first)
+ first= false;
+ else
+ extra_buf.append(STRING_WITH_LEN("; "));
+ append_tag_name(&extra_buf, extra_tags.at(i));
+ }
+
+ if (using_temporary)
+ {
+ if (first)
+ first= false;
+ else
+ extra_buf.append(STRING_WITH_LEN("; "));
+ extra_buf.append(STRING_WITH_LEN("Using temporary"));
+ }
+
+ if (using_filesort)
+ {
+ if (first)
+ first= false;
+ else
+ extra_buf.append(STRING_WITH_LEN("; "));
+ extra_buf.append(STRING_WITH_LEN("Using filesort"));
+ }
+
+ item_list.push_back(new Item_string(extra_buf.ptr(), extra_buf.length(), cs));
+
+ if (output->send_data(item_list))
+ return 1;
+
+ return 0;
+}
+
+
+/*
+ Elements in this array match members of enum Extra_tag, defined in
+ sql_explain.h
+*/
+
+const char * extra_tag_text[]=
+{
+ "ET_none",
+ "Using index condition",
+ "Using index condition(BKA)",
+ "Using ", // special handling
+ "Range checked for each record (index map: 0x", // special handling
+ "Using where with pushed condition",
+ "Using where",
+ "Not exists",
+
+ "Using index",
+ "Full scan on NULL key",
+ "Skip_open_table",
+ "Open_frm_only",
+ "Open_full_table",
+
+ "Scanned 0 databases",
+ "Scanned 1 database",
+ "Scanned all databases",
+
+ "Using index for group-by", // special handling
+
+ "USING MRR: DONT PRINT ME", // special handling
+
+ "Distinct",
+ "LooseScan",
+ "Start temporary",
+ "End temporary",
+ "FirstMatch", // special handling
+
+ "Using join buffer", // special handling
+
+ "const row not found",
+ "unique row not found",
+ "Impossible ON condition"
+};
+
+
+void Explain_table_access::append_tag_name(String *str, enum explain_extra_tag tag)
+{
+ switch (tag) {
+ case ET_USING:
+ {
+ // quick select
+ str->append(STRING_WITH_LEN("Using "));
+ quick_info->print_extra(str);
+ break;
+ }
+ case ET_RANGE_CHECKED_FOR_EACH_RECORD:
+ {
+ /* 4 bits per 1 hex digit + terminating '\0' */
+ char buf[MAX_KEY / 4 + 1];
+ str->append(STRING_WITH_LEN("Range checked for each "
+ "record (index map: 0x"));
+ str->append(range_checked_map.print(buf));
+ str->append(')');
+ break;
+ }
+ case ET_USING_MRR:
+ {
+ str->append(mrr_type);
+ break;
+ }
+ case ET_USING_JOIN_BUFFER:
+ {
+ str->append(extra_tag_text[tag]);
+
+ str->append(STRING_WITH_LEN(" ("));
+ const char *buffer_type= bka_type.incremental ? "incremental" : "flat";
+ str->append(buffer_type);
+ str->append(STRING_WITH_LEN(", "));
+ str->append(bka_type.join_alg);
+ str->append(STRING_WITH_LEN(" join"));
+ str->append(STRING_WITH_LEN(")"));
+ if (bka_type.mrr_type.length())
+ str->append(bka_type.mrr_type);
+
+ break;
+ }
+ case ET_FIRST_MATCH:
+ {
+ if (firstmatch_table_name.length())
+ {
+ str->append("FirstMatch(");
+ str->append(firstmatch_table_name);
+ str->append(")");
+ }
+ else
+ str->append(extra_tag_text[tag]);
+ break;
+ }
+ case ET_USING_INDEX_FOR_GROUP_BY:
+ {
+ str->append(extra_tag_text[tag]);
+ if (loose_scan_is_scanning)
+ str->append(" (scanning)");
+ break;
+ }
+ default:
+ str->append(extra_tag_text[tag]);
+ }
+}
+
+
+/*
+ This is called for top-level Explain_quick_select only. The point of this
+ function is:
+ - index_merge should print $index_merge_type (child, ...)
+ - 'range' should not print anything.
+*/
+
+void Explain_quick_select::print_extra(String *str)
+{
+ if (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE ||
+ quick_type == QUICK_SELECT_I::QS_TYPE_RANGE_DESC ||
+ quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)
+ {
+ /* print nothing */
+ }
+ else
+ print_extra_recursive(str);
+}
+
+
+void Explain_quick_select::print_extra_recursive(String *str)
+{
+ if (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE ||
+ quick_type == QUICK_SELECT_I::QS_TYPE_RANGE_DESC)
+ {
+ str->append(range.get_key_name());
+ }
+ else
+ {
+ str->append(get_name_by_type());
+ str->append('(');
+ List_iterator_fast<Explain_quick_select> it (children);
+ Explain_quick_select* child;
+ bool first= true;
+ while ((child = it++))
+ {
+ if (first)
+ first= false;
+ else
+ str->append(',');
+
+ child->print_extra_recursive(str);
+ }
+ str->append(')');
+ }
+}
+
+
+const char * Explain_quick_select::get_name_by_type()
+{
+ switch (quick_type) {
+ case QUICK_SELECT_I::QS_TYPE_INDEX_MERGE:
+ return "sort_union";
+ case QUICK_SELECT_I::QS_TYPE_ROR_UNION:
+ return "union";
+ case QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT:
+ return "intersect";
+ case QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT:
+ return "sort_intersect";
+ default:
+ DBUG_ASSERT(0);
+ return "unknown quick select type";
+ }
+}
+
+
+/*
+ This prints a comma-separated list of used indexes, ignoring nesting
+*/
+
+void Explain_quick_select::print_key(String *str)
+{
+ if (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE ||
+ quick_type == QUICK_SELECT_I::QS_TYPE_RANGE_DESC ||
+ quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)
+ {
+ if (str->length() > 0)
+ str->append(',');
+ str->append(range.get_key_name());
+ }
+ else
+ {
+ List_iterator_fast<Explain_quick_select> it (children);
+ Explain_quick_select* child;
+ while ((child = it++))
+ {
+ child->print_key(str);
+ }
+ }
+}
+
+
+/*
+ This prints a comma-separated list of used key_lengths, ignoring nesting
+*/
+
+void Explain_quick_select::print_key_len(String *str)
+{
+ if (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE ||
+ quick_type == QUICK_SELECT_I::QS_TYPE_RANGE_DESC ||
+ quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)
+ {
+ char buf[64];
+ size_t length;
+ length= longlong10_to_str(range.get_key_len(), buf, 10) - buf;
+ if (str->length() > 0)
+ str->append(',');
+ str->append(buf, length);
+ }
+ else
+ {
+ List_iterator_fast<Explain_quick_select> it (children);
+ Explain_quick_select* child;
+ while ((child = it++))
+ {
+ child->print_key_len(str);
+ }
+ }
+}
+
+
+int Explain_delete::print_explain(Explain_query *query,
+ select_result_sink *output,
+ uint8 explain_flags)
+{
+ if (deleting_all_rows)
+ {
+ const char *msg= "Deleting all rows";
+ int res= print_explain_message_line(output, explain_flags,
+ 1 /*select number*/,
+ select_type, &rows, msg);
+ return res;
+
+ }
+ else
+ {
+ return Explain_update::print_explain(query, output, explain_flags);
+ }
+}
+
+
+int Explain_update::print_explain(Explain_query *query,
+ select_result_sink *output,
+ uint8 explain_flags)
+{
+ StringBuffer<64> key_buf;
+ StringBuffer<64> key_len_buf;
+ StringBuffer<64> extra_str;
+ if (impossible_where || no_partitions)
+ {
+ const char *msg= impossible_where ?
+ "Impossible WHERE" :
+ "No matching rows after partition pruning";
+ int res= print_explain_message_line(output, explain_flags,
+ 1 /*select number*/,
+ select_type,
+ NULL, /* rows */
+ msg);
+ return res;
+ }
+
+
+ if (quick_info)
+ {
+ quick_info->print_key(&key_buf);
+ quick_info->print_key_len(&key_len_buf);
+
+ StringBuffer<64> quick_buf;
+ quick_info->print_extra(&quick_buf);
+ if (quick_buf.length())
+ {
+ extra_str.append(STRING_WITH_LEN("Using "));
+ extra_str.append(quick_buf);
+ }
+ }
+ else
+ {
+ key_buf.copy(key_str);
+ key_len_buf.copy(key_len_str);
+ }
+
+ if (using_where)
+ {
+ if (extra_str.length() !=0)
+ extra_str.append(STRING_WITH_LEN("; "));
+ extra_str.append(STRING_WITH_LEN("Using where"));
+ }
+
+ if (mrr_type.length() != 0)
+ {
+ if (extra_str.length() !=0)
+ extra_str.append(STRING_WITH_LEN("; "));
+ extra_str.append(mrr_type);
+ }
+
+ if (using_filesort)
+ {
+ if (extra_str.length() !=0)
+ extra_str.append(STRING_WITH_LEN("; "));
+ extra_str.append(STRING_WITH_LEN("Using filesort"));
+ }
+
+ if (using_io_buffer)
+ {
+ if (extra_str.length() !=0)
+ extra_str.append(STRING_WITH_LEN("; "));
+ extra_str.append(STRING_WITH_LEN("Using buffer"));
+ }
+
+ /*
+ Single-table DELETE commands do not do "Using temporary".
+ "Using index condition" is also not possible (which is an unjustified limitation)
+ */
+
+ print_explain_row(output, explain_flags,
+ 1, /* id */
+ select_type,
+ table_name.c_ptr(),
+ used_partitions_set? used_partitions.c_ptr() : NULL,
+ jtype,
+ possible_keys_line.length()? possible_keys_line.c_ptr(): NULL,
+ key_buf.length()? key_buf.c_ptr() : NULL,
+ key_len_buf.length() ? key_len_buf.c_ptr() : NULL,
+ NULL, /* 'ref' is always NULL in single-table EXPLAIN DELETE */
+ &rows,
+ extra_str.c_ptr_safe());
+
+ 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;
+ lex->explain= NULL;
+}
+
+
+void create_explain_query(LEX *lex, MEM_ROOT *mem_root)
+{
+ DBUG_ASSERT(!lex->explain);
+ lex->explain= new Explain_query(lex->thd);
+ DBUG_ASSERT(mem_root == current_thd->mem_root);
+ lex->explain->mem_root= mem_root;
+}
+
+void create_explain_query_if_not_exists(LEX *lex, MEM_ROOT *mem_root)
+{
+ if (!lex->explain)
+ create_explain_query(lex, mem_root);
+}
+
diff --git a/sql/sql_explain.h b/sql/sql_explain.h
new file mode 100644
index 00000000000..1309a02481b
--- /dev/null
+++ b/sql/sql_explain.h
@@ -0,0 +1,550 @@
+/*
+ Copyright (c) 2013 Monty Program Ab
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/**************************************************************************************
+
+ Data structures for producing EXPLAIN outputs.
+
+ These structures
+ - Can be produced inexpensively from query plan.
+ - Store sufficient information to produce tabular EXPLAIN output (the goal is
+ to be able to produce JSON also)
+
+*************************************************************************************/
+
+
+const int FAKE_SELECT_LEX_ID= (int)UINT_MAX;
+
+class Explain_query;
+
+/*
+ A node can be either a SELECT, or a UNION.
+*/
+class Explain_node : public Sql_alloc
+{
+public:
+ 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;
+
+ /*
+ A node may have children nodes. When a node's explain structure is
+ created, children nodes may not yet have QPFs. This is why we store ids.
+ */
+ Dynamic_array<int> children;
+ void add_child(int select_no)
+ {
+ children.append(select_no);
+ }
+
+ virtual int print_explain(Explain_query *query, select_result_sink *output,
+ uint8 explain_flags)=0;
+
+ int print_explain_for_children(Explain_query *query, select_result_sink *output,
+ uint8 explain_flags);
+ virtual ~Explain_node(){}
+};
+
+
+class Explain_table_access;
+
+
+/*
+ EXPLAIN structure for a SELECT.
+
+ A select can be:
+ 1. A degenerate case. In this case, message!=NULL, and it contains a
+ description of what kind of degenerate case it is (e.g. "Impossible
+ WHERE").
+ 2. a non-degenrate join. In this case, join_tabs describes the join.
+
+ In the non-degenerate case, a SELECT may have a GROUP BY/ORDER BY operation.
+
+ In both cases, the select may have children nodes. class Explain_node provides
+ a way get node's children.
+*/
+
+class Explain_select : public Explain_node
+{
+public:
+ enum explain_node_type get_type() { return EXPLAIN_SELECT; }
+
+ Explain_select() :
+ message(NULL), join_tabs(NULL),
+ using_temporary(false), using_filesort(false)
+ {}
+
+ ~Explain_select();
+
+ bool add_table(Explain_table_access *tab)
+ {
+ if (!join_tabs)
+ {
+ join_tabs= (Explain_table_access**) my_malloc(sizeof(Explain_table_access*) *
+ MAX_TABLES, MYF(0));
+ n_join_tabs= 0;
+ }
+ join_tabs[n_join_tabs++]= tab;
+ return false;
+ }
+
+public:
+ int select_id;
+ const char *select_type;
+
+ int get_select_id() { return select_id; }
+
+ /*
+ If message != NULL, this is a degenerate join plan, and all subsequent
+ members have no info
+ */
+ const char *message;
+
+ /*
+ A flat array of Explain structs for tables. The order is "just like EXPLAIN
+ would print them".
+ */
+ Explain_table_access** join_tabs;
+ uint n_join_tabs;
+
+ /* Global join attributes. In tabular form, they are printed on the first row */
+ bool using_temporary;
+ bool using_filesort;
+
+ int print_explain(Explain_query *query, select_result_sink *output,
+ uint8 explain_flags);
+};
+
+
+/*
+ Explain structure for a UNION.
+
+ A UNION may or may not have "Using filesort".
+*/
+
+class Explain_union : public Explain_node
+{
+public:
+ enum explain_node_type get_type() { return EXPLAIN_UNION; }
+
+ int get_select_id()
+ {
+ DBUG_ASSERT(union_members.elements() > 0);
+ return union_members.at(0);
+ }
+ /*
+ Members of the UNION. Note: these are different from UNION's "children".
+ Example:
+
+ (select * from t1) union
+ (select * from t2) order by (select col1 from t3 ...)
+
+ here
+ - select-from-t1 and select-from-t2 are "union members",
+ - select-from-t3 is the only "child".
+ */
+ Dynamic_array<int> union_members;
+
+ void add_select(int select_no)
+ {
+ union_members.append(select_no);
+ }
+ int print_explain(Explain_query *query, select_result_sink *output,
+ uint8 explain_flags);
+
+ const char *fake_select_type;
+ bool using_filesort;
+};
+
+
+class Explain_update;
+class Explain_delete;
+class Explain_insert;
+
+/*
+ Explain structure for a query (i.e. a statement).
+
+ This should be able to survive when the query plan was deleted. Currently,
+ we do not intend for it survive until after query's MEM_ROOT is freed. It
+ does surivive freeing of query's items.
+
+ For reference, the process of post-query cleanup is as follows:
+
+ >dispatch_command
+ | >mysql_parse
+ | | ...
+ | | lex_end()
+ | | ...
+ | | >THD::cleanup_after_query
+ | | | ...
+ | | | free_items()
+ | | | ...
+ | | <THD::cleanup_after_query
+ | |
+ | <mysql_parse
+ |
+ | log_slow_statement()
+ |
+ | free_root()
+ |
+ >dispatch_command
+
+ That is, the order of actions is:
+ - free query's Items
+ - write to slow query log
+ - free query's MEM_ROOT
+
+*/
+
+class Explain_query : public Sql_alloc
+{
+public:
+ Explain_query(THD *thd);
+ ~Explain_query();
+
+ /* Add a new node */
+ void add_node(Explain_node *node);
+ void add_insert_plan(Explain_insert *insert_plan_arg);
+ void add_upd_del_plan(Explain_update *upd_del_plan_arg);
+
+ /* This will return a select, or a union */
+ Explain_node *get_node(uint select_id);
+
+ /* This will return a select (even if there is a union with this id) */
+ Explain_select *get_select(uint select_id);
+
+ Explain_union *get_union(uint select_id);
+
+ /* 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 insert_plan || upd_del_plan|| get_node(1) != NULL; }
+
+ void query_plan_ready();
+
+ MEM_ROOT *mem_root;
+private:
+ /* Explain_delete inherits from Explain_update */
+ Explain_update *upd_del_plan;
+
+ /* Query "plan" for INSERTs */
+ Explain_insert *insert_plan;
+
+ Dynamic_array<Explain_union*> unions;
+ Dynamic_array<Explain_select*> selects;
+
+ THD *thd; // for APC start/stop
+ bool apc_enabled;
+ /*
+ Debugging aid: count how many times add_node() was called. Ideally, it
+ should be one, we currently allow O(1) query plan saves for each
+ select or union. The goal is not to have O(#rows_in_some_table), which
+ is unacceptable.
+ */
+ longlong operations;
+};
+
+
+/*
+ Some of the tags have matching text. See extra_tag_text for text names, and
+ Explain_table_access::append_tag_name() for code to convert from tag form to text
+ form.
+*/
+enum explain_extra_tag
+{
+ ET_none= 0, /* not-a-tag */
+ ET_USING_INDEX_CONDITION,
+ ET_USING_INDEX_CONDITION_BKA,
+ ET_USING, /* For quick selects of various kinds */
+ ET_RANGE_CHECKED_FOR_EACH_RECORD,
+ ET_USING_WHERE_WITH_PUSHED_CONDITION,
+ ET_USING_WHERE,
+ ET_NOT_EXISTS,
+
+ ET_USING_INDEX,
+ ET_FULL_SCAN_ON_NULL_KEY,
+ ET_SKIP_OPEN_TABLE,
+ ET_OPEN_FRM_ONLY,
+ ET_OPEN_FULL_TABLE,
+
+ ET_SCANNED_0_DATABASES,
+ ET_SCANNED_1_DATABASE,
+ ET_SCANNED_ALL_DATABASES,
+
+ ET_USING_INDEX_FOR_GROUP_BY,
+
+ ET_USING_MRR, // does not print "Using mrr".
+
+ ET_DISTINCT,
+ ET_LOOSESCAN,
+ ET_START_TEMPORARY,
+ ET_END_TEMPORARY,
+ ET_FIRST_MATCH,
+
+ ET_USING_JOIN_BUFFER,
+
+ ET_CONST_ROW_NOT_FOUND,
+ ET_UNIQUE_ROW_NOT_FOUND,
+ ET_IMPOSSIBLE_ON_CONDITION,
+
+ ET_total
+};
+
+
+typedef struct st_explain_bka_type
+{
+ bool incremental;
+ const char *join_alg;
+ StringBuffer<64> mrr_type;
+
+} EXPLAIN_BKA_TYPE;
+
+
+/*
+ Data about how an index is used by some access method
+*/
+class Explain_index_use : public Sql_alloc
+{
+ char *key_name;
+ uint key_len;
+ /* will add #keyparts here if we implement EXPLAIN FORMAT=JSON */
+public:
+
+ void set(MEM_ROOT *root, const char *key_name_arg, uint key_len_arg)
+ {
+ if (key_name_arg)
+ {
+ size_t name_len= strlen(key_name_arg);
+ if ((key_name= (char*)alloc_root(root, name_len+1)))
+ memcpy(key_name, key_name_arg, name_len+1);
+ }
+ else
+ key_name= NULL;
+ key_len= key_len_arg;
+ }
+
+ inline const char *get_key_name() { return key_name; }
+ inline uint get_key_len() { return key_len; }
+};
+
+
+/*
+ QPF for quick range selects, as well as index_merge select
+*/
+class Explain_quick_select : public Sql_alloc
+{
+public:
+ Explain_quick_select(int quick_type_arg) : quick_type(quick_type_arg)
+ {}
+
+ const int quick_type;
+
+ /* This is used when quick_type == QUICK_SELECT_I::QS_TYPE_RANGE */
+ Explain_index_use range;
+
+ /* Used in all other cases */
+ List<Explain_quick_select> children;
+
+ void print_extra(String *str);
+ void print_key(String *str);
+ void print_key_len(String *str);
+private:
+ void print_extra_recursive(String *str);
+ const char *get_name_by_type();
+};
+
+
+/*
+ Query Plan Footprint for a JOIN_TAB.
+*/
+class Explain_table_access : public Sql_alloc
+{
+public:
+ void push_extra(enum explain_extra_tag extra_tag);
+
+ /* Internals */
+public:
+ /*
+ 0 means this tab is not inside SJM nest and should use Explain_select's id
+ other value means the tab is inside an SJM nest.
+ */
+ int sjm_nest_select_id;
+
+ /* id and 'select_type' are cared-of by the parent Explain_select */
+ StringBuffer<32> table_name;
+
+ enum join_type type;
+
+ StringBuffer<32> used_partitions;
+ bool used_partitions_set;
+
+ /* Empty string means "NULL" will be printed */
+ StringBuffer<32> possible_keys_str;
+
+ /*
+ Index use: key name and length.
+ Note: that when one is accessing I_S tables, those may show use of
+ non-existant indexes.
+
+ key.key_name == NULL means 'NULL' will be shown in tabular output.
+ key.key_len == (uint)-1 means 'NULL' will be shown in tabular output.
+ */
+ Explain_index_use key;
+
+ /*
+ when type==JT_HASH_NEXT, 'key' stores the hash join pseudo-key.
+ hash_next_key stores the table's key.
+ */
+ Explain_index_use hash_next_key;
+
+ bool ref_set; /* not set means 'NULL' should be printed */
+ StringBuffer<32> ref;
+
+ bool rows_set; /* not set means 'NULL' should be printed */
+ ha_rows rows;
+
+ bool filtered_set; /* not set means 'NULL' should be printed */
+ double filtered;
+
+ /*
+ Contents of the 'Extra' column. Some are converted into strings, some have
+ parameters, values for which are stored below.
+ */
+ Dynamic_array<enum explain_extra_tag> extra_tags;
+
+ // Valid if ET_USING tag is present
+ Explain_quick_select *quick_info;
+
+ // Valid if ET_USING_INDEX_FOR_GROUP_BY is present
+ bool loose_scan_is_scanning;
+
+ // valid with ET_RANGE_CHECKED_FOR_EACH_RECORD
+ key_map range_checked_map;
+
+ // valid with ET_USING_MRR
+ StringBuffer<32> mrr_type;
+
+ // valid with ET_USING_JOIN_BUFFER
+ EXPLAIN_BKA_TYPE bka_type;
+
+ StringBuffer<32> firstmatch_table_name;
+
+ int print_explain(select_result_sink *output, uint8 explain_flags,
+ uint select_id, const char *select_type,
+ bool using_temporary, bool using_filesort);
+private:
+ void append_tag_name(String *str, enum explain_extra_tag tag);
+};
+
+
+/*
+ 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.
+*/
+
+class Explain_update : public Explain_node
+{
+public:
+ virtual enum explain_node_type get_type() { return EXPLAIN_UPDATE; }
+ virtual int get_select_id() { return 1; /* always root */ }
+
+ const char *select_type;
+
+ StringBuffer<32> used_partitions;
+ bool used_partitions_set;
+
+ bool impossible_where;
+ bool no_partitions;
+ StringBuffer<64> table_name;
+
+ enum join_type jtype;
+ StringBuffer<128> possible_keys_line;
+ StringBuffer<128> key_str;
+ StringBuffer<128> key_len_str;
+ StringBuffer<64> mrr_type;
+
+ Explain_quick_select *quick_info;
+
+ bool using_where;
+ ha_rows rows;
+
+ bool using_filesort;
+ bool using_io_buffer;
+
+ virtual int print_explain(Explain_query *query, select_result_sink *output,
+ uint8 explain_flags);
+};
+
+
+/*
+ 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
+{
+public:
+ /*
+ TRUE means we're going to call handler->delete_all_rows() and not read any
+ rows.
+ */
+ bool deleting_all_rows;
+
+ virtual enum explain_node_type get_type() { return EXPLAIN_DELETE; }
+ virtual int get_select_id() { return 1; /* always root */ }
+
+ virtual int print_explain(Explain_query *query, select_result_sink *output,
+ uint8 explain_flags);
+};
+
+
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 0be22d17557..4e352b33e38 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -461,7 +461,8 @@ void upgrade_lock_type(THD *thd, thr_lock_type *lock_type,
if (specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE) ||
thd->variables.max_insert_delayed_threads == 0 ||
thd->locked_tables_mode > LTM_LOCK_TABLES ||
- thd->lex->uses_stored_routines())
+ thd->lex->uses_stored_routines() /*||
+ thd->lex->describe*/)
{
*lock_type= TL_WRITE;
return;
@@ -651,6 +652,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->add_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
@@ -667,6 +698,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;
@@ -694,6 +726,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
Item *unused_conds= 0;
DBUG_ENTER("mysql_insert");
+ create_explain_query(thd->lex, thd->mem_root);
/*
Upgrade lock type if the requested lock is incompatible with
the current connection mode or table operation.
@@ -785,6 +818,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= thd->lex->explain->send_explain(thd);
+ goto abort;
+ }
/*
Fill in the given fields and dump it to the table file
@@ -1137,10 +1181,11 @@ abort:
#endif
if (table != NULL)
table->file->ha_release_auto_increment();
+
if (!joins_freed)
free_underlaid_joins(thd, &thd->lex->select_lex);
thd->abort_on_warning= 0;
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(retval);
}
diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc
index 0acccfcee48..3b39ebf145f 100644
--- a/sql/sql_join_cache.cc
+++ b/sql/sql_join_cache.cc
@@ -2553,49 +2553,41 @@ finish:
/*
- Add a comment on the join algorithm employed by the join cache
+ Save data on the join algorithm employed by the join cache
SYNOPSIS
- print_explain_comment()
+ save_explain_data()
str string to add the comment on the employed join algorithm to
DESCRIPTION
- This function adds info on the type of the used join buffer (flat or
+ This function puts info about the type of the used join buffer (flat or
incremental) and on the type of the the employed join algorithm (BNL,
- BNLH, BKA or BKAH) to the the end of the sring str.
+ BNLH, BKA or BKAH) to the data structure
RETURN VALUE
none
*/
-void JOIN_CACHE::print_explain_comment(String *str)
+void JOIN_CACHE::save_explain_data(struct st_explain_bka_type *explain)
{
- str->append(STRING_WITH_LEN(" ("));
- const char *buffer_type= prev_cache ? "incremental" : "flat";
- str->append(buffer_type);
- str->append(STRING_WITH_LEN(", "));
-
- const char *join_alg="";
+ explain->incremental= test(prev_cache);
+
switch (get_join_alg()) {
case BNL_JOIN_ALG:
- join_alg= "BNL";
+ explain->join_alg= "BNL";
break;
case BNLH_JOIN_ALG:
- join_alg= "BNLH";
+ explain->join_alg= "BNLH";
break;
case BKA_JOIN_ALG:
- join_alg= "BKA";
+ explain->join_alg= "BKA";
break;
case BKAH_JOIN_ALG:
- join_alg= "BKAH";
+ explain->join_alg= "BKAH";
break;
default:
DBUG_ASSERT(0);
}
-
- str->append(join_alg);
- str->append(STRING_WITH_LEN(" join"));
- str->append(STRING_WITH_LEN(")"));
}
/**
@@ -2621,18 +2613,17 @@ static void add_mrr_explain_info(String *str, uint mrr_mode, handler *file)
}
}
-
-void JOIN_CACHE_BKA::print_explain_comment(String *str)
+void JOIN_CACHE_BKA::save_explain_data(struct st_explain_bka_type *explain)
{
- JOIN_CACHE::print_explain_comment(str);
- add_mrr_explain_info(str, mrr_mode, join_tab->table->file);
+ JOIN_CACHE::save_explain_data(explain);
+ add_mrr_explain_info(&explain->mrr_type, mrr_mode, join_tab->table->file);
}
-void JOIN_CACHE_BKAH::print_explain_comment(String *str)
+void JOIN_CACHE_BKAH::save_explain_data(struct st_explain_bka_type *explain)
{
- JOIN_CACHE::print_explain_comment(str);
- add_mrr_explain_info(str, mrr_mode, join_tab->table->file);
+ JOIN_CACHE::save_explain_data(explain);
+ add_mrr_explain_info(&explain->mrr_type, mrr_mode, join_tab->table->file);
}
diff --git a/sql/sql_join_cache.h b/sql/sql_join_cache.h
index 25b5918ef60..568cc91ecf7 100644
--- a/sql/sql_join_cache.h
+++ b/sql/sql_join_cache.h
@@ -63,6 +63,7 @@ typedef struct st_cache_field {
class JOIN_TAB_SCAN;
+struct st_explain_bka_type;
/*
JOIN_CACHE is the base class to support the implementations of
@@ -658,7 +659,7 @@ public:
enum_nested_loop_state join_records(bool skip_last);
/* Add a comment on the join algorithm employed by the join cache */
- virtual void print_explain_comment(String *str);
+ virtual void save_explain_data(struct st_explain_bka_type *explain);
THD *thd();
@@ -1336,7 +1337,7 @@ public:
/* Check index condition of the joined table for a record from BKA cache */
bool skip_index_tuple(range_id_t range_info);
- void print_explain_comment(String *str);
+ void save_explain_data(struct st_explain_bka_type *explain);
};
@@ -1427,5 +1428,5 @@ public:
/* Check index condition of the joined table for a record from BKAH cache */
bool skip_index_tuple(range_id_t range_info);
- void print_explain_comment(String *str);
+ void save_explain_data(struct st_explain_bka_type *explain);
};
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 1403221a8a9..f50953e4103 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -447,6 +447,8 @@ void lex_start(THD *thd)
DBUG_ENTER("lex_start");
lex->thd= lex->unit.thd= thd;
+
+ DBUG_ASSERT(!lex->explain);
lex->context_stack.empty();
lex->unit.init_query();
@@ -2533,7 +2535,8 @@ void Query_tables_list::destroy_query_tables_list()
*/
LEX::LEX()
- :result(0), option_type(OPT_DEFAULT), is_lex_started(0),
+ : explain(NULL),
+ result(0), option_type(OPT_DEFAULT), is_lex_started(0),
limit_rows_examined_cnt(ULONGLONG_MAX)
{
@@ -3476,6 +3479,18 @@ bool st_select_lex::optimize_unflattened_subqueries(bool const_only)
is_correlated_unit|= sl->is_correlated;
inner_join->select_options= save_options;
un->thd->lex->current_select= save_select;
+
+ Explain_query *eq;
+ if ((eq= inner_join->thd->lex->explain))
+ {
+ Explain_select *expl_sel;
+ if ((expl_sel= eq->get_select(inner_join->select_lex->select_number)))
+ {
+ sl->set_explain_type(TRUE);
+ expl_sel->select_type= sl->type;
+ }
+ }
+
if (empty_union_result)
{
/*
@@ -4152,114 +4167,85 @@ bool st_select_lex::is_merged_child_of(st_select_lex *ancestor)
return all_merged;
}
+/*
+ This is used by SHOW EXPLAIN. It assuses query plan has been already
+ collected into QPF structures and we only need to print it out.
+*/
-int print_explain_message_line(select_result_sink *result,
- SELECT_LEX *select_lex,
- bool on_the_fly,
- uint8 options,
- const char *message);
-
-
-int st_select_lex::print_explain(select_result_sink *output,
- uint8 explain_flags,
- bool *printed_anything)
+int LEX::print_explain(select_result_sink *output, uint8 explain_flags,
+ bool *printed_anything)
{
int res;
- if (join && join->have_query_plan == JOIN::QEP_AVAILABLE)
+ if (explain && explain->have_query_plan())
{
- /*
- There is a number of reasons join can be marked as degenerate, so all
- three conditions below can happen simultaneously, or individually:
- */
- *printed_anything= TRUE;
- 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->skip_sort_order && !join->no_order &&
- (join->order || join->group_list), // bool need_order
- join->select_distinct, // bool distinct
- NULL); //const char *message
- }
- if (res)
- goto err;
-
- for (SELECT_LEX_UNIT *unit= join->select_lex->first_inner_unit();
- unit;
- unit= unit->next_unit())
- {
- /*
- Display subqueries only if they are not parts of eliminated WHERE/ON
- clauses.
- */
- if (!(unit->item && unit->item->eliminated))
- {
- if ((res= unit->print_explain(output, explain_flags, printed_anything)))
- goto err;
- }
- }
+ res= explain->print_explain(output, explain_flags);
+ *printed_anything= true;
}
else
{
- const char *msg;
- if (!join)
- DBUG_ASSERT(0); /* Seems not to be possible */
-
- /* Not printing anything useful, don't touch *printed_anything here */
- if (join->have_query_plan == JOIN::QEP_NOT_PRESENT_YET)
- msg= "Not yet optimized";
- else
- {
- DBUG_ASSERT(join->have_query_plan == JOIN::QEP_DELETED);
- msg= "Query plan already deleted";
- }
- res= print_explain_message_line(output, this, TRUE /* on_the_fly */,
- 0, msg);
+ res= 0;
+ *printed_anything= false;
}
-err:
return res;
}
-int st_select_lex_unit::print_explain(select_result_sink *output,
- uint8 explain_flags, bool *printed_anything)
+/*
+ Save explain structures of a UNION. The only variable member is whether the
+ union has "Using filesort".
+
+ There is also save_union_explain_part2() function, which is called before we read
+ UNION's output.
+
+ The reason for it is examples like this:
+
+ SELECT col1 FROM t1 UNION SELECT col2 FROM t2 ORDER BY (select ... from t3 ...)
+
+ Here, the (select ... from t3 ...) subquery must be a child of UNION's
+ st_select_lex. However, it is not connected as child until a very late
+ stage in execution.
+*/
+
+int st_select_lex_unit::save_union_explain(Explain_query *output)
{
- 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.
- */
- const char *msg="Query plan already deleted";
- res= print_explain_message_line(output, first, TRUE /* on_the_fly */,
- 0, msg);
- return 0;
- }
+ Explain_union *eu= new (output->mem_root) Explain_union;
for (SELECT_LEX *sl= first; sl; sl= sl->next_select())
- {
- if ((res= sl->print_explain(output, explain_flags, printed_anything)))
- break;
- }
+ eu->add_select(sl->select_number);
+
+ eu->fake_select_type= "UNION RESULT";
+ eu->using_filesort= test(global_parameters->order_list.first);
+
+ // Save the UNION node
+ output->add_node(eu);
+
+ if (eu->get_select_id() == 1)
+ output->query_plan_ready();
- /* Note: fake_select_lex->join may be NULL or non-NULL at this point */
+ return 0;
+}
+
+
+/*
+ @see st_select_lex_unit::save_union_explain
+*/
+
+int st_select_lex_unit::save_union_explain_part2(Explain_query *output)
+{
+ Explain_union *eu= output->get_union(first_select()->select_number);
if (fake_select_lex)
{
- res= print_fake_select_lex_join(output, TRUE /* on the fly */,
- fake_select_lex, explain_flags);
+ for (SELECT_LEX_UNIT *unit= fake_select_lex->first_inner_unit();
+ unit; unit= unit->next_unit())
+ {
+ if (!(unit->item && unit->item->eliminated))
+ {
+ eu->add_child(unit->first_select()->select_number);
+ }
+ }
}
- return res;
+ return 0;
}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 9f5b6e258b0..e27f3cbd4a6 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -534,7 +534,12 @@ class select_result;
class JOIN;
class select_union;
class Procedure;
+class Explain_query;
+void delete_explain_query(LEX *lex);
+void create_explain_query(LEX *lex, MEM_ROOT *mem_root);
+void create_explain_query_if_not_exists(LEX *lex, MEM_ROOT *mem_root);
+bool print_explain_query(LEX *lex, THD *thd, String *str);
class st_select_lex_unit: public st_select_lex_node {
protected:
@@ -645,8 +650,9 @@ public:
friend int subselect_union_engine::exec();
List<Item> *get_unit_column_types();
- int print_explain(select_result_sink *output, uint8 explain_flags,
- bool *printed_anything);
+
+ int save_union_explain(Explain_query *output);
+ int save_union_explain_part2(Explain_query *output);
};
typedef class st_select_lex_unit SELECT_LEX_UNIT;
@@ -943,6 +949,10 @@ public:
void clear_index_hints(void) { index_hints= NULL; }
bool is_part_of_union() { return master_unit()->is_union(); }
+ bool is_top_level_node()
+ {
+ return (select_number == 1) && !is_part_of_union();
+ }
bool optimize_unflattened_subqueries(bool const_only);
/* Set the EXPLAIN type for this subquery. */
void set_explain_type(bool on_the_fly);
@@ -971,8 +981,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, uint8 explain_flags,
- bool *printed_anything);
+
/*
For MODE_ONLY_FULL_GROUP_BY we need to maintain two flags:
- Non-aggregated fields are used in this select.
@@ -2209,6 +2218,89 @@ protected:
LEX *m_lex;
};
+
+class Delete_plan;
+class SQL_SELECT;
+
+class Explain_query;
+class Explain_update;
+
+/*
+ Query plan of a single-table UPDATE.
+ (This is actually a plan for single-table DELETE also)
+*/
+
+class Update_plan
+{
+protected:
+ bool impossible_where;
+ bool no_partitions;
+public:
+ /*
+ When single-table UPDATE updates a VIEW, that VIEW's select is still
+ listed as the first child. When we print EXPLAIN, it looks like a
+ subquery.
+ In order to get rid of it, updating_a_view=TRUE means that first child
+ select should not be shown when printing EXPLAIN.
+ */
+ bool updating_a_view;
+
+ /* Allocate things there */
+ MEM_ROOT *mem_root;
+
+ TABLE *table;
+ SQL_SELECT *select;
+ uint index;
+ ha_rows scanned_rows;
+ /*
+ Top-level select_lex. Most of its fields are not used, we need it only to
+ get to the subqueries.
+ */
+ SELECT_LEX *select_lex;
+
+ key_map possible_keys;
+ bool using_filesort;
+ bool using_io_buffer;
+
+ /* Set this plan to be a plan to do nothing because of impossible WHERE */
+ void set_impossible_where() { impossible_where= true; }
+ void set_no_partitions() { no_partitions= true; }
+
+ void save_explain_data(Explain_query *query);
+ void save_explain_data_intern(Explain_query *query, Explain_update *eu);
+ virtual ~Update_plan() {}
+
+ Update_plan(MEM_ROOT *mem_root_arg) :
+ impossible_where(false), no_partitions(false),
+ mem_root(mem_root_arg),
+ using_filesort(false), using_io_buffer(false)
+ {}
+};
+
+
+/* Query plan of a single-table DELETE */
+class Delete_plan : public Update_plan
+{
+ bool deleting_all_rows;
+public:
+
+ /* Construction functions */
+ Delete_plan(MEM_ROOT *mem_root_arg) :
+ Update_plan(mem_root_arg),
+ deleting_all_rows(false)
+ {}
+
+ /* Set this query plan to be a plan to make a call to h->delete_all_rows() */
+ void set_delete_all_rows(ha_rows rows_arg)
+ {
+ deleting_all_rows= true;
+ scanned_rows= rows_arg;
+ }
+
+ void save_explain_data(Explain_query *query);
+};
+
+
/* The state of the lex parsing. This is saved in the THD struct */
struct LEX: public Query_tables_list
@@ -2219,6 +2311,9 @@ struct LEX: public Query_tables_list
SELECT_LEX *current_select;
/* list of all SELECT_LEX */
SELECT_LEX *all_selects_list;
+
+ /* Query Plan Footprint of a currently running select */
+ Explain_query *explain;
char *length,*dec,*change;
LEX_STRING name;
@@ -2636,6 +2731,9 @@ struct LEX: public Query_tables_list
}
return FALSE;
}
+
+ int print_explain(select_result_sink *output, uint8 explain_flags,
+ bool *printed_anything);
};
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 6a3d5a420e9..8f4b7f98a81 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -758,6 +758,7 @@ static void handle_bootstrap_impl(THD *thd)
#if defined(ENABLED_PROFILING)
thd->profiling.finish_current_query();
#endif
+ delete_explain_query(thd->lex);
if (bootstrap_error)
break;
@@ -981,7 +982,9 @@ bool do_command(THD *thd)
my_net_set_read_timeout(net, thd->variables.net_read_timeout);
DBUG_ASSERT(packet_length);
+ DBUG_ASSERT(!thd->apc_target.is_enabled());
return_value= dispatch_command(command, thd, packet+1, (uint) (packet_length-1));
+ DBUG_ASSERT(!thd->apc_target.is_enabled());
out:
/* The statement instrumentation must be closed in all cases. */
@@ -1303,6 +1306,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
ulong length= (ulong)(packet_end - beginning_of_next_stmt);
log_slow_statement(thd);
+ DBUG_ASSERT(!thd->apc_target.is_enabled());
/* Remove garbage at start of query */
while (length > 0 && my_isspace(thd->charset(), *beginning_of_next_stmt))
@@ -1729,10 +1733,15 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
+/*
+ @note
+ This function must call delete_explain_query().
+*/
void log_slow_statement(THD *thd)
{
DBUG_ENTER("log_slow_statement");
+
/*
The following should never be true with our current code base,
but better to keep this here so we don't accidently try to log a
@@ -1741,11 +1750,15 @@ void log_slow_statement(THD *thd)
if (unlikely(thd->in_sub_stmt))
DBUG_VOID_RETURN; // Don't set time for sub stmt
+
/* Follow the slow log filter configuration. */
if (!thd->enable_slow_log ||
(thd->variables.log_slow_filter
&& !(thd->variables.log_slow_filter & thd->query_plan_flags)))
+ {
+ delete_explain_query(thd->lex);
DBUG_VOID_RETURN;
+ }
if (((thd->server_status & SERVER_QUERY_WAS_SLOW) ||
((thd->server_status &
@@ -1767,6 +1780,8 @@ void log_slow_statement(THD *thd)
slow_log_print(thd, thd->query(), thd->query_length(),
thd->utime_after_query);
}
+
+ delete_explain_query(thd->lex);
DBUG_VOID_RETURN;
}
@@ -2393,7 +2408,7 @@ mysql_execute_command(THD *thd)
/* Release metadata locks acquired in this transaction. */
thd->mdl_context.release_transactional_locks();
}
-
+
#ifndef DBUG_OFF
if (lex->sql_command != SQLCOM_SET_OPTION)
DEBUG_SYNC(thd,"before_execute_sql_command");
@@ -3413,6 +3428,7 @@ end_with_restore_list:
case SQLCOM_INSERT_SELECT:
{
select_result *sel_result;
+ bool explain= test(lex->describe);
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if ((res= insert_precheck(thd, all_tables)))
break;
@@ -3482,6 +3498,10 @@ end_with_restore_list:
}
delete sel_result;
}
+
+ if (!res && explain)
+ res= thd->lex->explain->send_explain(thd);
+
/* revert changes for SP */
MYSQL_INSERT_SELECT_DONE(res, (ulong) thd->get_row_count_func());
select_lex->table_list.first= first_table;
@@ -3522,7 +3542,8 @@ end_with_restore_list:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first;
- multi_delete *del_result;
+ bool explain= test(lex->describe);
+ multi_delete *result;
if ((res= multi_delete_precheck(thd, all_tables)))
break;
@@ -3544,25 +3565,34 @@ end_with_restore_list:
goto error;
}
- if (!thd->is_fatal_error &&
- (del_result= new multi_delete(aux_tables, lex->table_count)))
- {
- res= mysql_select(thd, &select_lex->ref_pointer_array,
- select_lex->get_table_list(),
- select_lex->with_wild,
- select_lex->item_list,
- select_lex->where,
- 0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
- (ORDER *)NULL,
- (select_lex->options | thd->variables.option_bits |
- SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
- OPTION_SETUP_TABLES_DONE) & ~OPTION_BUFFER_RESULT,
- del_result, unit, select_lex);
- res|= thd->is_error();
- MYSQL_MULTI_DELETE_DONE(res, del_result->num_deleted());
- if (res)
- del_result->abort_result_set();
- delete del_result;
+ if (!thd->is_fatal_error)
+ {
+ result= new multi_delete(aux_tables, lex->table_count);
+ if (result)
+ {
+ res= mysql_select(thd, &select_lex->ref_pointer_array,
+ select_lex->get_table_list(),
+ select_lex->with_wild,
+ select_lex->item_list,
+ select_lex->where,
+ 0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
+ (ORDER *)NULL,
+ (select_lex->options | thd->variables.option_bits |
+ SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
+ OPTION_SETUP_TABLES_DONE) & ~OPTION_BUFFER_RESULT,
+ result, unit, select_lex);
+ res|= thd->is_error();
+
+ MYSQL_MULTI_DELETE_DONE(res, result->num_deleted());
+ if (res)
+ result->abort_result_set(); /* for both DELETE and EXPLAIN DELETE */
+ else
+ {
+ if (explain)
+ res= thd->lex->explain->send_explain(thd);
+ }
+ delete result;
+ }
}
else
{
@@ -5021,8 +5051,8 @@ finish:
ha_maria::implicit_commit(thd, FALSE);
#endif
}
-
lex->unit.cleanup();
+
/* Free tables */
THD_STAGE_INFO(thd, stage_closing_tables);
close_thread_tables(thd);
@@ -5096,24 +5126,37 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
if (!(result= new select_send()))
return 1; /* purecov: inspected */
thd->send_explain_fields(result);
- res= mysql_explain_union(thd, &thd->lex->unit, result);
+
/*
- The code which prints the extended description is not robust
- against malformed queries, so skip it if we have an error.
+ This will call optimize() for all parts of query. The query plan is
+ printed out below.
*/
- if (!res && (lex->describe & DESCRIBE_EXTENDED))
+ res= mysql_explain_union(thd, &thd->lex->unit, result);
+
+ /* Print EXPLAIN only if we don't have an error */
+ if (!res)
{
- char buff[1024];
- String str(buff,(uint32) sizeof(buff), system_charset_info);
- str.length(0);
- /*
- The warnings system requires input in utf8, @see
- mysqld_show_warnings().
- */
- thd->lex->unit.print(&str, QT_TO_SYSTEM_CHARSET);
- push_warning(thd, Sql_condition::WARN_LEVEL_NOTE,
- ER_YES, str.c_ptr_safe());
+ /*
+ Do like the original select_describe did: remove OFFSET from the
+ top-level LIMIT
+ */
+ result->reset_offset_limit();
+ thd->lex->explain->print_explain(result, thd->lex->describe);
+ if (lex->describe & DESCRIBE_EXTENDED)
+ {
+ char buff[1024];
+ String str(buff,(uint32) sizeof(buff), system_charset_info);
+ str.length(0);
+ /*
+ The warnings system requires input in utf8, @see
+ mysqld_show_warnings().
+ */
+ thd->lex->unit.print(&str, QT_TO_SYSTEM_CHARSET);
+ push_warning(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_YES, str.c_ptr_safe());
+ }
}
+
if (res)
result->abort_result_set();
else
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 494f603cd8e..2824f6bfd27 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -2523,6 +2523,7 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
object and because of this can be used in different threads.
*/
lex->thd= thd;
+ DBUG_ASSERT(!lex->explain);
if (lex->empty_field_list_on_rset)
{
@@ -3966,6 +3967,21 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
if (! cursor)
cleanup_stmt();
+
+ /*
+ EXECUTE command has its own dummy "explain data". We don't need it,
+ instead, we want to keep the query plan of the statement that was
+ executed.
+ */
+ if (!stmt_backup.lex->explain ||
+ !stmt_backup.lex->explain->have_query_plan())
+ {
+ delete_explain_query(stmt_backup.lex);
+ stmt_backup.lex->explain = thd->lex->explain;
+ thd->lex->explain= NULL;
+ }
+ else
+ delete_explain_query(thd->lex);
thd->set_statement(&stmt_backup);
thd->stmt_arena= old_stmt_arena;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 9d17a0b9021..634902fc412 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -997,20 +997,35 @@ err:
DBUG_RETURN(res); /* purecov: inspected */
}
-
int JOIN::optimize()
{
+ bool was_optimized= optimized;
int res= optimize_inner();
/*
If we're inside a non-correlated subquery, this function may be
called for the second time after the subquery has been executed
and deleted. The second call will not produce a valid query plan, it will
short-circuit because optimized==TRUE.
+
+ "was_optimized != optimized" is here to handle this case:
+ - first optimization starts, gets an error (from a const. cheap
+ subquery), returns 1
+ - another JOIN::optimize() call made, and now join->optimize() will
+ return 0, even though we never had a query plan.
*/
- if (!res && have_query_plan != QEP_DELETED)
+ if (was_optimized != optimized && !res && have_query_plan != QEP_DELETED)
+ {
+ create_explain_query_if_not_exists(thd->lex, thd->mem_root);
have_query_plan= QEP_AVAILABLE;
+ save_explain_data(thd->lex->explain, false /* can overwrite */,
+ need_tmp,
+ !skip_sort_order && !no_order && (order || group_list),
+ select_distinct);
+ }
return res;
}
+
+
/**
global select optimisation.
@@ -1613,8 +1628,10 @@ TODO: make view to decide if it is possible to write to WHERE directly or make S
JOIN_TAB *tab= &join_tab[const_tables];
bool all_order_fields_used;
if (order)
+ {
skip_sort_order= test_if_skip_sort_order(tab, order, select_limit, 1,
&tab->table->keys_in_use_for_order_by);
+ }
if ((group_list=create_distinct_group(thd, select_lex->ref_pointer_array,
order, fields_list, all_fields,
&all_order_fields_used)))
@@ -2292,29 +2309,56 @@ JOIN::save_join_tab()
}
+void JOIN::save_explain_data(Explain_query *output, bool can_overwrite,
+ bool need_tmp_table, bool need_order,
+ bool distinct)
+{
+ if (select_lex->select_number != UINT_MAX &&
+ select_lex->select_number != INT_MAX /* this is not a UNION's "fake select */ &&
+ have_query_plan != JOIN::QEP_NOT_PRESENT_YET &&
+ have_query_plan != JOIN::QEP_DELETED && // this happens when there was
+ // no QEP ever, but then
+ //cleanup() is called multiple times
+ output && // for "SET" command in SPs.
+ (can_overwrite? true: !output->get_select(select_lex->select_number)))
+ {
+ const char *message= NULL;
+ if (!table_count || !tables_list || zero_result_cause)
+ {
+ /* It's a degenerate join */
+ message= zero_result_cause ? zero_result_cause : "No tables used";
+ }
+ save_explain_data_intern(thd->lex->explain, need_tmp_table, need_order,
+ distinct, message);
+ }
+}
+
+
void JOIN::exec()
{
- /*
- Enable SHOW EXPLAIN only if we're in the top-level query.
- */
- thd->apc_target.enable();
DBUG_EXECUTE_IF("show_explain_probe_join_exec_start",
if (dbug_user_var_equals_int(thd,
"show_explain_probe_select_id",
select_lex->select_number))
dbug_serve_apcs(thd, 1);
);
-
exec_inner();
+ if (!exec_saved_explain)
+ {
+ save_explain_data(thd->lex->explain, true /* can overwrite */,
+ need_tmp,
+ order != 0 && !skip_sort_order,
+ select_distinct);
+ exec_saved_explain= true;
+ }
+
DBUG_EXECUTE_IF("show_explain_probe_join_exec_end",
if (dbug_user_var_equals_int(thd,
"show_explain_probe_select_id",
select_lex->select_number))
dbug_serve_apcs(thd, 1);
);
-
- thd->apc_target.disable();
}
@@ -3880,7 +3924,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
if (*s->on_expr_ref)
{
/* Generate empty row */
- s->info= "Impossible ON condition";
+ s->info= ET_IMPOSSIBLE_ON_CONDITION;
found_const_table_map|= s->table->map;
s->type= JT_CONST;
mark_as_null_row(s->table); // All fields are NULL
@@ -11188,7 +11232,8 @@ void JOIN::cleanup(bool full)
DBUG_ENTER("JOIN::cleanup");
DBUG_PRINT("enter", ("full %u", (uint) full));
- have_query_plan= QEP_DELETED;
+ if (full)
+ have_query_plan= QEP_DELETED;
if (table)
{
@@ -17583,7 +17628,7 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos)
{
if ((error=join_read_system(tab)))
{ // Info for DESCRIBE
- tab->info="const row not found";
+ tab->info= ET_CONST_ROW_NOT_FOUND;
/* Mark for EXPLAIN that the row was not found */
pos->records_read=0.0;
pos->ref_depend_map= 0;
@@ -17609,7 +17654,7 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos)
table->disable_keyread();
if (error)
{
- tab->info="unique row not found";
+ tab->info= ET_UNIQUE_ROW_NOT_FOUND;
/* Mark for EXPLAIN that the row was not found */
pos->records_read=0.0;
pos->ref_depend_map= 0;
@@ -22476,32 +22521,167 @@ void JOIN::clear()
/*
Print an EXPLAIN line with all NULLs and given message in the 'Extra' column
*/
+
int print_explain_message_line(select_result_sink *result,
- SELECT_LEX *select_lex,
- bool on_the_fly,
uint8 options,
+ uint select_number,
+ const char *select_type,
+ ha_rows *rows,
const char *message)
{
const CHARSET_INFO *cs= system_charset_info;
Item *item_null= new Item_null();
List<Item> item_list;
- if (on_the_fly)
- select_lex->set_explain_type(on_the_fly);
+ item_list.push_back(new Item_int((int32) select_number));
+ item_list.push_back(new Item_string(select_type,
+ strlen(select_type), cs));
+ /* `table` */
+ item_list.push_back(item_null);
+
+ /* `partitions` */
+ if (options & DESCRIBE_PARTITIONS)
+ item_list.push_back(item_null);
+
+ /* type, possible_keys, key, key_len, ref */
+ for (uint i=0 ; i < 5; i++)
+ item_list.push_back(item_null);
- item_list.push_back(new Item_int((int32)
- select_lex->select_number));
- item_list.push_back(new Item_string(select_lex->type,
- strlen(select_lex->type), cs));
- for (uint i=0 ; i < 7; i++)
+ /* `rows` */
+ if (rows)
+ {
+ item_list.push_back(new Item_int(*rows,
+ MY_INT64_NUM_DECIMAL_DIGITS));
+ }
+ else
+ item_list.push_back(item_null);
+
+ /* `filtered` */
+ if (options & DESCRIBE_EXTENDED)
+ item_list.push_back(item_null);
+
+ /* `Extra` */
+ 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;
+ return 0;
+}
+
+
+/*
+ Make a comma-separated list of possible_keys names and add it into the string
+*/
+
+void make_possible_keys_line(TABLE *table, key_map possible_keys, String *line)
+{
+ if (!possible_keys.is_clear_all())
+ {
+ uint j;
+ for (j=0 ; j < table->s->keys ; j++)
+ {
+ if (possible_keys.is_set(j))
+ {
+ if (line->length())
+ line->append(',');
+ line->append(table->key_info[j].name,
+ strlen(table->key_info[j].name),
+ system_charset_info);
+ }
+ }
+ }
+}
+
+/*
+ Print an EXPLAIN output row, based on information provided in the parameters
+
+ @note
+ Parameters that may have NULL value in EXPLAIN output, should be passed
+ (char*)NULL.
+
+ @return
+ 0 - OK
+ 1 - OOM Error
+*/
+
+int print_explain_row(select_result_sink *result,
+ uint8 options,
+ uint select_number,
+ const char *select_type,
+ const char *table_name,
+ const char *partitions,
+ enum join_type jtype,
+ const char *possible_keys,
+ const char *index,
+ const char *key_len,
+ const char *ref,
+ ha_rows *rows,
+ const char *extra)
+{
+ const CHARSET_INFO *cs= system_charset_info;
+ Item *item_null= new Item_null();
+ List<Item> item_list;
+ Item *item;
+
+ item_list.push_back(new Item_int((int32) select_number));
+ item_list.push_back(new Item_string(select_type,
+ strlen(select_type), cs));
+ item_list.push_back(new Item_string(table_name,
+ strlen(table_name), cs));
if (options & DESCRIBE_PARTITIONS)
+ {
+ if (partitions)
+ {
+ item_list.push_back(new Item_string(partitions,
+ strlen(partitions), cs));
+ }
+ else
+ item_list.push_back(item_null);
+ }
+
+ const char *jtype_str= join_type_str[jtype];
+ item_list.push_back(new Item_string(jtype_str,
+ strlen(jtype_str), cs));
+
+ item= possible_keys? new Item_string(possible_keys, strlen(possible_keys),
+ cs) : item_null;
+ item_list.push_back(item);
+
+ /* 'index */
+ item= index ? new Item_string(index, strlen(index), cs) : item_null;
+ item_list.push_back(item);
+
+ /* 'key_len */
+ item= key_len ? new Item_string(key_len, strlen(key_len), cs) : item_null;
+ item_list.push_back(item);
+
+ /* 'ref' */
+ item= ref ? new Item_string(ref, strlen(ref), cs) : item_null;
+ item_list.push_back(item);
+
+ /* '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);
- item_list.push_back(new Item_string(message,strlen(message),cs));
-
if (result->send_data(item_list))
return 1;
return 0;
@@ -22587,102 +22767,118 @@ int print_fake_select_lex_join(select_result_sink *result, bool on_the_fly,
}
-/**
- EXPLAIN handling.
+/*
+ Append MRR information from quick select to the given string
+*/
+
+void explain_append_mrr_info(QUICK_RANGE_SELECT *quick, String *res)
+{
+ char mrr_str_buf[128];
+ mrr_str_buf[0]=0;
+ int len;
+ handler *h= quick->head->file;
+ len= h->multi_range_read_explain_info(quick->mrr_flags, mrr_str_buf,
+ sizeof(mrr_str_buf));
+ if (len > 0)
+ {
+ //res->append(STRING_WITH_LEN("; "));
+ res->append(mrr_str_buf, len);
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// TODO: join with make_possible_keys_line ?
+void append_possible_keys(String *str, TABLE *table, key_map possible_keys)
+{
+ uint j;
+ for (j=0 ; j < table->s->keys ; j++)
+ {
+ if (possible_keys.is_set(j))
+ {
+ if (str->length())
+ str->append(',');
+ str->append(table->key_info[j].name,
+ strlen(table->key_info[j].name),
+ system_charset_info);
+ }
+ }
+}
+
- Produce lines explaining execution of *this* select (not including children
- selects)
- @param on_the_fly TRUE <=> we're being executed on-the-fly, so don't make
- modifications to any select's data structures
+/*
+ Save Query Plan Footprint
+
+ @note
+ Currently, this function may be called multiple times
*/
-int JOIN::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)
+int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table,
+ bool need_order, bool distinct,
+ const char *message)
{
- List<Item> field_list;
- List<Item> item_list;
+ Explain_node *explain_node;
JOIN *join= this; /* Legacy: this code used to be a non-member function */
THD *thd=join->thd;
- Item *item_null= new Item_null();
- CHARSET_INFO *cs= system_charset_info;
+ const CHARSET_INFO *cs= system_charset_info;
int quick_type;
int error= 0;
- DBUG_ENTER("JOIN::print_explain");
+ DBUG_ENTER("JOIN::save_explain_data_intern");
DBUG_PRINT("info", ("Select 0x%lx, type %s, message %s",
(ulong)join->select_lex, join->select_lex->type,
message ? message : "NULL"));
- DBUG_ASSERT(on_the_fly? have_query_plan == QEP_AVAILABLE: TRUE);
+ DBUG_ASSERT(have_query_plan == QEP_AVAILABLE);
/* Don't log this into the slow query log */
- if (!on_the_fly)
- {
- thd->server_status&= ~(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED);
- join->unit->offset_limit_cnt= 0;
- }
-
- /*
- NOTE: the number/types of items pushed into item_list must be in sync with
- EXPLAIN column types as they're "defined" in THD::send_explain_fields()
- */
if (message)
{
- if (print_explain_message_line(result, join->select_lex, on_the_fly,
- explain_flags, message))
- error= 1;
+ Explain_select *xpl_sel;
+ explain_node= xpl_sel= new (output->mem_root) Explain_select;
+ join->select_lex->set_explain_type(true);
+ xpl_sel->select_id= join->select_lex->select_number;
+ xpl_sel->select_type= join->select_lex->type;
+ xpl_sel->message= message;
+ /* Setting xpl_sel->message means that all other members are invalid */
+ output->add_node(xpl_sel);
}
else if (join->select_lex == join->unit->fake_select_lex)
{
- if (print_fake_select_lex_join(result, on_the_fly,
- join->select_lex,
- explain_flags))
- error= 1;
+ /* Do nothing, Explain_union will create and print fake_select_lex */
}
else if (!join->select_lex->master_unit()->derived ||
join->select_lex->master_unit()->derived->is_materialized_derived())
{
+ Explain_select *xpl_sel;
+ explain_node= xpl_sel= new (output->mem_root) Explain_select;
table_map used_tables=0;
- //if (!join->select_lex->type)
- if (on_the_fly)
- join->select_lex->set_explain_type(on_the_fly);
- bool printing_materialize_nest= FALSE;
- uint select_id= join->select_lex->select_number;
+ join->select_lex->set_explain_type(true);
+ xpl_sel->select_id= join->select_lex->select_number;
+ xpl_sel->select_type= join->select_lex->type;
+
JOIN_TAB* const first_top_tab= first_breadth_first_tab(join, WALK_OPTIMIZATION_TABS);
for (JOIN_TAB *tab= first_breadth_first_tab(join, WALK_OPTIMIZATION_TABS); tab;
tab= next_breadth_first_tab(join, WALK_OPTIMIZATION_TABS, tab))
{
+ uint select_id;
if (tab->bush_root_tab)
{
JOIN_TAB *first_sibling= tab->bush_root_tab->bush_children->start;
select_id= first_sibling->emb_sj_nest->sj_subq_pred->get_identifier();
- printing_materialize_nest= TRUE;
}
-
+ else
+ select_id= join->select_lex->select_number;
+
TABLE *table=tab->table;
TABLE_LIST *table_list= tab->table->pos_in_table_list;
- char buff[512];
- char buff1[512], buff2[512], buff3[512], buff4[512];
- char keylen_str_buf[64];
+ char buff4[512];
my_bool key_read;
- String extra(buff, sizeof(buff),cs);
char table_name_buffer[SAFE_NAME_LEN];
- String tmp1(buff1,sizeof(buff1),cs);
- String tmp2(buff2,sizeof(buff2),cs);
- String tmp3(buff3,sizeof(buff3),cs);
String tmp4(buff4,sizeof(buff4),cs);
- char hash_key_prefix[]= "#hash#";
KEY *key_info= 0;
uint key_len= 0;
- bool is_hj= tab->type == JT_HASH || tab->type ==JT_HASH_NEXT;
-
- extra.length(0);
- tmp1.length(0);
- tmp2.length(0);
- tmp3.length(0);
tmp4.length(0);
quick_type= -1;
QUICK_SELECT_I *quick= NULL;
@@ -22702,28 +22898,19 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags,
tab= pre_sort_join_tab;
}
- item_list.empty();
+ Explain_table_access *eta= new (output->mem_root) Explain_table_access;
+ xpl_sel->add_table(eta);
+ eta->key.set(thd->mem_root, NULL, (uint)-1);
+ eta->quick_info= NULL;
+
/* id */
- item_list.push_back(new Item_uint((uint32)select_id));
+ if (tab->bush_root_tab)
+ eta->sjm_nest_select_id= select_id;
+ else
+ eta->sjm_nest_select_id= 0;
+
/* select_type */
- const char* stype= printing_materialize_nest? "MATERIALIZED" :
- 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 && tab->use_quick != 2)
- {
- quick= tab->select->quick;
- quick_type= tab->select->quick->get_type();
- if ((quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE) ||
- (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;
- else
- tab_type= tab->type == JT_ALL ? JT_RANGE : JT_HASH_RANGE;
- }
+ xpl_sel->select_type= join->select_lex->type;
/* table */
if (table->derived_select_number)
@@ -22732,7 +22919,7 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags,
int len= my_snprintf(table_name_buffer, sizeof(table_name_buffer)-1,
"<derived%u>",
table->derived_select_number);
- item_list.push_back(new Item_string(table_name_buffer, len, cs));
+ eta->table_name.copy(table_name_buffer, len, cs);
}
else if (tab->bush_children)
{
@@ -22742,59 +22929,53 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags,
sizeof(table_name_buffer)-1,
"<subquery%d>",
ctab->emb_sj_nest->sj_subq_pred->get_identifier());
- item_list.push_back(new Item_string(table_name_buffer, len, cs));
+ eta->table_name.copy(table_name_buffer, len, cs);
}
else
{
TABLE_LIST *real_table= table->pos_in_table_list;
- item_list.push_back(new Item_string(real_table->alias,
- strlen(real_table->alias), cs));
+ eta->table_name.copy(real_table->alias, strlen(real_table->alias), cs);
}
+
/* "partitions" column */
- if (explain_flags & DESCRIBE_PARTITIONS)
{
#ifdef WITH_PARTITION_STORAGE_ENGINE
partition_info *part_info;
if (!table->derived_select_number &&
(part_info= table->part_info))
{
- Item_string *item_str= new Item_string(cs);
- make_used_partitions_str(part_info, &item_str->str_value);
- item_list.push_back(item_str);
+ make_used_partitions_str(part_info, &eta->used_partitions);
+ eta->used_partitions_set= true;
}
else
- item_list.push_back(item_null);
+ eta->used_partitions_set= false;
#else
/* just produce empty column if partitioning is not compiled in */
- item_list.push_back(item_null);
+ eta->used_partitions_set= false;
#endif
}
+
/* "type" column */
- 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())
- {
- uint j;
- for (j=0 ; j < table->s->keys ; j++)
- {
- if (tab->keys.is_set(j))
- {
- if (tmp1.length())
- tmp1.append(',');
- tmp1.append(table->key_info[j].name,
- strlen(table->key_info[j].name),
- system_charset_info);
- }
- }
+ enum join_type tab_type= tab->type;
+ if ((tab->type == JT_ALL || tab->type == JT_HASH) &&
+ tab->select && tab->select->quick && tab->use_quick != 2)
+ {
+ quick= tab->select->quick;
+ quick_type= tab->select->quick->get_type();
+ if ((quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE) ||
+ (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;
+ else
+ tab_type= tab->type == JT_ALL ? JT_RANGE : JT_HASH_RANGE;
}
- if (tmp1.length())
- item_list.push_back(new Item_string(tmp1.ptr(),tmp1.length(),cs));
- else
- item_list.push_back(item_null);
+ eta->type= tab_type;
+
+ /* Build "possible_keys" value */
+ append_possible_keys(&eta->possible_keys_str, table, tab->keys);
- /* Build "key", "key_len", and "ref" values and add them to item_list */
+ /* Build "key", "key_len", and "ref" */
if (tab_type == JT_NEXT)
{
key_info= table->key_info+tab->index;
@@ -22805,15 +22986,20 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags,
key_info= tab->get_keyinfo_by_key_no(tab->ref.key);
key_len= tab->ref.key_length;
}
- if (key_info)
+
+ /*
+ In STRAIGHT_JOIN queries, there can be join tabs with JT_CONST type
+ that still have quick selects.
+ */
+ if (tab->select && tab->select->quick && tab_type != JT_CONST)
+ {
+ eta->quick_info= tab->select->quick->get_explain(thd->mem_root);
+ }
+
+ if (key_info) /* 'index' or 'ref' access */
{
- register uint length;
- if (is_hj)
- tmp2.append(hash_key_prefix, strlen(hash_key_prefix), cs);
- tmp2.append(key_info->name, strlen(key_info->name), cs);
- length= (longlong10_to_str(key_len, keylen_str_buf, 10) -
- keylen_str_buf);
- tmp3.append(keylen_str_buf, length, cs);
+ eta->key.set(thd->mem_root, key_info->name, key_len);
+
if (tab->ref.key_parts && tab_type != JT_FT)
{
store_key **ref=tab->ref.key_copy;
@@ -22832,37 +23018,23 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags,
}
}
}
- if (is_hj && tab_type != JT_HASH)
+
+ if (tab_type == JT_HASH_NEXT) /* full index scan + hash join */
{
- tmp2.append(':');
- tmp3.append(':');
+ eta->hash_next_key.set(thd->mem_root,
+ table->key_info[tab->index].name,
+ table->key_info[tab->index].key_length);
}
- if (tab_type == JT_HASH_NEXT)
+
+ if (key_info)
{
- register uint length;
- key_info= table->key_info+tab->index;
- key_len= key_info->key_length;
- tmp2.append(key_info->name, strlen(key_info->name), cs);
- length= (longlong10_to_str(key_len, keylen_str_buf, 10) -
- keylen_str_buf);
- tmp3.append(keylen_str_buf, length, cs);
- }
- if (tab->type != JT_CONST && tab->select && quick)
- tab->select->quick->add_keys_and_lengths(&tmp2, &tmp3);
- if (key_info || (tab->select && quick))
- {
- if (tmp2.length())
- item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length(),cs));
- else
- item_list.push_back(item_null);
- if (tmp3.length())
- 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)
- item_list.push_back(new Item_string(tmp4.ptr(),tmp4.length(),cs));
+ {
+ eta->ref.copy(tmp4);
+ eta->ref_set= true;
+ }
else
- item_list.push_back(item_null);
+ eta->ref_set= false;
}
else
{
@@ -22872,66 +23044,61 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags,
{
const char *tmp_buff;
int f_idx;
+ StringBuffer<64> key_name_buf;
if (table_list->has_db_lookup_value)
{
+ /* The "key" has the name of the column referring to the database */
f_idx= table_list->schema_table->idx_field1;
tmp_buff= table_list->schema_table->fields_info[f_idx].field_name;
- tmp2.append(tmp_buff, strlen(tmp_buff), cs);
+ key_name_buf.append(tmp_buff, strlen(tmp_buff), cs);
}
if (table_list->has_table_lookup_value)
{
if (table_list->has_db_lookup_value)
- tmp2.append(',');
+ key_name_buf.append(',');
+
f_idx= table_list->schema_table->idx_field2;
tmp_buff= table_list->schema_table->fields_info[f_idx].field_name;
- tmp2.append(tmp_buff, strlen(tmp_buff), cs);
+ key_name_buf.append(tmp_buff, strlen(tmp_buff), cs);
}
- if (tmp2.length())
- item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length(),cs));
- else
- item_list.push_back(item_null);
+
+ if (key_name_buf.length())
+ eta->key.set(thd->mem_root, key_name_buf.c_ptr_safe(), -1);
}
- else
- item_list.push_back(item_null);
- item_list.push_back(item_null);
- item_list.push_back(item_null);
+ eta->ref_set= false;
}
- /* Add "rows" field to item_list. */
+ /* "rows" */
if (table_list /* SJM bushes don't have table_list */ &&
table_list->schema_table)
{
- /* in_rows */
- if (explain_flags & DESCRIBE_EXTENDED)
- item_list.push_back(item_null);
- /* rows */
- item_list.push_back(item_null);
+ /* I_S tables have rows=extra=NULL */
+ eta->rows_set= false;
+ eta->filtered_set= false;
}
else
{
double examined_rows= tab->get_examined_rows();
- item_list.push_back(new Item_int((longlong) (ulonglong) examined_rows,
- MY_INT64_NUM_DECIMAL_DIGITS));
+ eta->rows_set= true;
+ eta->rows= examined_rows;
- /* Add "filtered" field to item_list. */
- if (explain_flags & DESCRIBE_EXTENDED)
+ /* "filtered" */
+ float f= 0.0;
+ if (examined_rows)
{
- float f= 0.0;
- if (examined_rows)
- {
- double pushdown_cond_selectivity= tab->cond_selectivity;
- if (pushdown_cond_selectivity == 1.0)
- f= (float) (100.0 * tab->records_read / examined_rows);
- else
- f= (float) (100.0 * pushdown_cond_selectivity);
- }
- set_if_smaller(f, 100.0);
- item_list.push_back(new Item_float(f, 2));
+ double pushdown_cond_selectivity= tab->cond_selectivity;
+ if (pushdown_cond_selectivity == 1.0)
+ f= (float) (100.0 * tab->records_read / examined_rows);
+ else
+ f= (float) (100.0 * pushdown_cond_selectivity);
}
+ set_if_smaller(f, 100.0);
+ eta->filtered_set= true;
+ eta->filtered= f;
}
- /* Build "Extra" field and add it to item_list. */
+ /* Build "Extra" field and save it */
key_read=table->key_read;
if ((tab_type == JT_NEXT || tab_type == JT_CONST) &&
table->covering_keys.is_set(tab->index))
@@ -22941,24 +23108,17 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags,
key_read=1;
if (tab->info)
- item_list.push_back(new Item_string(tab->info,strlen(tab->info),cs));
+ {
+ eta->push_extra(tab->info);
+ }
else if (tab->packed_info & TAB_INFO_HAVE_VALUE)
{
if (tab->packed_info & TAB_INFO_USING_INDEX)
- extra.append(STRING_WITH_LEN("; Using index"));
+ eta->push_extra(ET_USING_INDEX);
if (tab->packed_info & TAB_INFO_USING_WHERE)
- extra.append(STRING_WITH_LEN("; Using where"));
+ eta->push_extra(ET_USING_WHERE);
if (tab->packed_info & TAB_INFO_FULL_SCAN_ON_NULL)
- extra.append(STRING_WITH_LEN("; Full scan on NULL key"));
- /* Skip initial "; "*/
- const char *str= extra.ptr();
- uint32 len= extra.length();
- if (len)
- {
- str += 2;
- len -= 2;
- }
- item_list.push_back(new Item_string(str, len, cs));
+ eta->push_extra(ET_FULL_SCAN_ON_NULL_KEY);
}
else
{
@@ -22970,28 +23130,23 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags,
if (keyno != MAX_KEY && keyno == table->file->pushed_idx_cond_keyno &&
table->file->pushed_idx_cond)
- extra.append(STRING_WITH_LEN("; Using index condition"));
+ eta->push_extra(ET_USING_INDEX_CONDITION);
else if (tab->cache_idx_cond)
- extra.append(STRING_WITH_LEN("; Using index condition(BKA)"));
+ eta->push_extra(ET_USING_INDEX_CONDITION_BKA);
if (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION ||
quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT ||
quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT ||
quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE)
{
- extra.append(STRING_WITH_LEN("; Using "));
- tab->select->quick->add_info_string(&extra);
+ eta->push_extra(ET_USING);
}
if (tab->select)
{
if (tab->use_quick == 2)
{
- /* 4 bits per 1 hex digit + terminating '\0' */
- char buf[MAX_KEY / 4 + 1];
- extra.append(STRING_WITH_LEN("; Range checked for each "
- "record (index map: 0x"));
- extra.append(tab->keys.print(buf));
- extra.append(')');
+ eta->push_extra(ET_RANGE_CHECKED_FOR_EACH_RECORD);
+ eta->range_checked_map= tab->keys;
}
else if (tab->select->cond)
{
@@ -23003,16 +23158,19 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags,
HA_MUST_USE_TABLE_CONDITION_PUSHDOWN)) &&
pushed_cond)
{
- extra.append(STRING_WITH_LEN("; Using where with pushed "
- "condition"));
+ eta->push_extra(ET_USING_WHERE_WITH_PUSHED_CONDITION);
+ /*
+ psergey-todo: what to do? This was useful with NDB only.
+
if (explain_flags & DESCRIBE_EXTENDED)
{
extra.append(STRING_WITH_LEN(": "));
((COND *)pushed_cond)->print(&extra, QT_ORDINARY);
}
+ */
}
else
- extra.append(STRING_WITH_LEN("; Using where"));
+ eta->push_extra(ET_USING_WHERE);
}
}
if (table_list /* SJM bushes don't have table_list */ &&
@@ -23020,19 +23178,20 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags,
table_list->schema_table->i_s_requested_object & OPTIMIZE_I_S_TABLE)
{
if (!table_list->table_open_method)
- extra.append(STRING_WITH_LEN("; Skip_open_table"));
+ eta->push_extra(ET_SKIP_OPEN_TABLE);
else if (table_list->table_open_method == OPEN_FRM_ONLY)
- extra.append(STRING_WITH_LEN("; Open_frm_only"));
+ eta->push_extra(ET_OPEN_FRM_ONLY);
else
- extra.append(STRING_WITH_LEN("; Open_full_table"));
+ eta->push_extra(ET_OPEN_FULL_TABLE);
+ /* psergey-note: the following has a bug.*/
if (table_list->has_db_lookup_value &&
table_list->has_table_lookup_value)
- extra.append(STRING_WITH_LEN("; Scanned 0 databases"));
+ eta->push_extra(ET_SCANNED_0_DATABASES);
else if (table_list->has_db_lookup_value ||
table_list->has_table_lookup_value)
- extra.append(STRING_WITH_LEN("; Scanned 1 database"));
+ eta->push_extra(ET_SCANNED_1_DATABASE);
else
- extra.append(STRING_WITH_LEN("; Scanned all databases"));
+ eta->push_extra(ET_SCANNED_ALL_DATABASES);
}
if (key_read)
{
@@ -23040,69 +23199,52 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags,
{
QUICK_GROUP_MIN_MAX_SELECT *qgs=
(QUICK_GROUP_MIN_MAX_SELECT *) tab->select->quick;
- extra.append(STRING_WITH_LEN("; Using index for group-by"));
- qgs->append_loose_scan_type(&extra);
+ eta->push_extra(ET_USING_INDEX_FOR_GROUP_BY);
+ eta->loose_scan_is_scanning= qgs->loose_scan_is_scanning();
}
else
- extra.append(STRING_WITH_LEN("; Using index"));
+ eta->push_extra(ET_USING_INDEX);
}
if (table->reginfo.not_exists_optimize)
- extra.append(STRING_WITH_LEN("; Not exists"));
+ eta->push_extra(ET_NOT_EXISTS);
- /*
- if (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE &&
- !(((QUICK_RANGE_SELECT*)(tab->select->quick))->mrr_flags &
- HA_MRR_USE_DEFAULT_IMPL))
- {
- extra.append(STRING_WITH_LEN("; Using MRR"));
- }
- */
if (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE)
{
- char mrr_str_buf[128];
- mrr_str_buf[0]=0;
- int len;
- uint mrr_flags=
- ((QUICK_RANGE_SELECT*)(tab->select->quick))->mrr_flags;
- len= table->file->multi_range_read_explain_info(mrr_flags,
- mrr_str_buf,
- sizeof(mrr_str_buf));
- if (len > 0)
- {
- extra.append(STRING_WITH_LEN("; "));
- extra.append(mrr_str_buf, len);
- }
+ explain_append_mrr_info((QUICK_RANGE_SELECT*)(tab->select->quick),
+ &eta->mrr_type);
+ if (eta->mrr_type.length() > 0)
+ eta->push_extra(ET_USING_MRR);
}
if (need_tmp_table)
{
need_tmp_table=0;
- extra.append(STRING_WITH_LEN("; Using temporary"));
+ xpl_sel->using_temporary= true;
}
if (need_order)
{
need_order=0;
- extra.append(STRING_WITH_LEN("; Using filesort"));
+ xpl_sel->using_filesort= true;
}
if (distinct & test_all_bits(used_tables,
join->select_list_used_tables))
- extra.append(STRING_WITH_LEN("; Distinct"));
+ eta->push_extra(ET_DISTINCT);
if (tab->loosescan_match_tab)
{
- extra.append(STRING_WITH_LEN("; LooseScan"));
+ eta->push_extra(ET_LOOSESCAN);
}
if (tab->first_weedout_table)
- extra.append(STRING_WITH_LEN("; Start temporary"));
+ eta->push_extra(ET_START_TEMPORARY);
if (tab->check_weed_out_table)
- extra.append(STRING_WITH_LEN("; End temporary"));
+ eta->push_extra(ET_END_TEMPORARY);
else if (tab->do_firstmatch)
{
if (tab->do_firstmatch == /*join->join_tab*/ first_top_tab - 1)
- extra.append(STRING_WITH_LEN("; FirstMatch"));
+ eta->push_extra(ET_FIRST_MATCH);
else
{
- extra.append(STRING_WITH_LEN("; FirstMatch("));
+ eta->push_extra(ET_FIRST_MATCH);
TABLE *prev_table=tab->do_firstmatch->table;
if (prev_table->derived_select_number)
{
@@ -23111,11 +23253,10 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags,
int len= my_snprintf(namebuf, sizeof(namebuf)-1,
"<derived%u>",
prev_table->derived_select_number);
- extra.append(namebuf, len);
+ eta->firstmatch_table_name.append(namebuf, len);
}
else
- extra.append(prev_table->pos_in_table_list->alias);
- extra.append(STRING_WITH_LEN(")"));
+ eta->firstmatch_table_name.append(prev_table->pos_in_table_list->alias);
}
}
@@ -23123,26 +23264,16 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags,
{
if (tab->ref.cond_guards[part])
{
- extra.append(STRING_WITH_LEN("; Full scan on NULL key"));
+ eta->push_extra(ET_FULL_SCAN_ON_NULL_KEY);
break;
}
}
if (tab->cache)
{
- extra.append(STRING_WITH_LEN("; Using join buffer"));
- tab->cache->print_explain_comment(&extra);
- }
-
- /* Skip initial "; "*/
- const char *str= extra.ptr();
- uint32 len= extra.length();
- if (len)
- {
- str += 2;
- len -= 2;
+ eta->push_extra(ET_USING_JOIN_BUFFER);
+ tab->cache->save_explain_data(&eta->bka_type);
}
- item_list.push_back(new Item_string(str, len, cs));
}
if (saved_join_tab)
@@ -23150,16 +23281,49 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags,
// For next iteration
used_tables|=table->map;
- if (result->send_data(item_list))
- error= 1;
+ }
+ output->add_node(xpl_sel);
+ }
+
+ for (SELECT_LEX_UNIT *unit= join->select_lex->first_inner_unit();
+ unit;
+ unit= unit->next_unit())
+ {
+ /*
+ Display subqueries only if
+ (1) they are not parts of ON clauses that were eliminated by table
+ elimination.
+ (2) they are not merged derived tables
+ */
+ if (!(unit->item && unit->item->eliminated) && // (1)
+ (!unit->derived || unit->derived->is_materialized_derived())) // (2)
+ {
+ explain_node->add_child(unit->first_select()->select_number);
}
}
+
+ if (!error && select_lex->is_top_level_node())
+ output->query_plan_ready();
+
+
DBUG_RETURN(error);
}
/*
- See st_select_lex::print_explain() for the SHOW EXPLAIN counterpart
+ This function serves as "shortcut point" for EXPLAIN queries.
+
+ The EXPLAIN statement executes just like its SELECT counterpart would
+ execute, except that JOIN::exec() will call select_describe() instead of
+ actually executing the query.
+
+ Inside select_describe():
+ - Query plan is updated with latest QEP choices made at the start of
+ JOIN::exec().
+ - the proces of "almost execution" is invoked for the children subqueries.
+
+ Overall, select_describe() is a legacy of old EXPLAIN implementation and
+ should be removed.
*/
static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
@@ -23168,10 +23332,15 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
THD *thd=join->thd;
select_result *result=join->result;
DBUG_ENTER("select_describe");
- join->error= join->print_explain(result, thd->lex->describe,
- FALSE, /* Not on-the-fly */
- need_tmp_table, need_order, distinct,
- message);
+
+ /* Update the QPF with latest values of using_temporary, using_filesort */
+ Explain_select *explain_sel;
+ uint select_nr= join->select_lex->select_number;
+ if ((explain_sel= thd->lex->explain->get_select(select_nr)))
+ {
+ explain_sel->using_temporary= need_tmp_table;
+ explain_sel->using_filesort= need_order;
+ }
for (SELECT_LEX_UNIT *unit= join->select_lex->first_inner_unit();
unit;
@@ -23221,7 +23390,7 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
if (unit->is_union())
{
- unit->fake_select_lex->select_number= UINT_MAX; // jost for initialization
+ unit->fake_select_lex->select_number= FAKE_SELECT_LEX_ID; // jost for initialization
unit->fake_select_lex->type= "UNION RESULT";
unit->fake_select_lex->options|= SELECT_DESCRIBE;
if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK | SELECT_DESCRIBE)))
@@ -24282,6 +24451,8 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table,
@param table Table to find a key
@param select Pointer to access/update select->quick (if any)
@param limit LIMIT clause parameter
+ @param [out] scanned_limit How many records we expect to scan
+ Valid if *need_sort=FALSE.
@param [out] need_sort TRUE if filesort needed
@param [out] reverse
TRUE if the key is reversed again given ORDER (undefined if key == MAX_KEY)
@@ -24299,7 +24470,8 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table,
*/
uint get_index_for_order(ORDER *order, TABLE *table, SQL_SELECT *select,
- ha_rows limit, bool *need_sort, bool *reverse)
+ ha_rows limit, ha_rows *scanned_limit,
+ bool *need_sort, bool *reverse)
{
if (!order)
{
@@ -24341,6 +24513,7 @@ uint get_index_for_order(ORDER *order, TABLE *table, SQL_SELECT *select,
{
select->set_quick(reverse_quick);
*need_sort= FALSE;
+ *scanned_limit= select->quick->records;
return select->quick->index;
}
else
@@ -24369,6 +24542,7 @@ uint get_index_for_order(ORDER *order, TABLE *table, SQL_SELECT *select,
!is_key_used(table, key, table->write_set))
{
*need_sort= FALSE;
+ *scanned_limit= limit;
*reverse= (direction < 0);
return key;
}
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 3353b3749e4..9db553e8ceb 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -189,6 +189,12 @@ int rr_sequential(READ_RECORD *info);
int rr_sequential_and_unpack(READ_RECORD *info);
+#include "sql_explain.h"
+
+/**************************************************************************************
+ * New EXPLAIN structures END
+ *************************************************************************************/
+
class JOIN_CACHE;
class SJ_TMP_TABLE;
class JOIN_TAB_RANGE;
@@ -243,7 +249,8 @@ typedef struct st_join_table {
JOIN_TAB_RANGE *bush_children;
/* Special content for EXPLAIN 'Extra' column or NULL if none */
- const char *info;
+ enum explain_extra_tag info;
+
/*
Bitmap of TAB_INFO_* bits that encodes special line for EXPLAIN 'Extra'
column, or 0 if there is no info.
@@ -1325,6 +1332,8 @@ public:
pre_sort_join_tab= NULL;
emb_sjm_nest= NULL;
sjm_lookup_tables= 0;
+
+ exec_saved_explain= false;
/*
The following is needed because JOIN::cleanup(true) may be called for
joins for which JOIN::optimize was aborted with an error before a proper
@@ -1333,6 +1342,13 @@ public:
table_access_tabs= NULL;
}
+ /*
+ TRUE <=> There was a JOIN::exec() call, which saved this JOIN's EXPLAIN.
+ The idea is that we also save at the end of JOIN::optimize(), but that
+ might not be the final plan.
+ */
+ bool exec_saved_explain;
+
int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num,
COND *conds, uint og_num, ORDER *order, ORDER *group,
Item *having, ORDER *proc_param, SELECT_LEX *select,
@@ -1457,11 +1473,11 @@ public:
{
return (unit->item && unit->item->is_in_predicate());
}
-
- 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);
+ void save_explain_data(Explain_query *output, bool can_overwrite,
+ bool need_tmp_table, bool need_order, bool distinct);
+ int save_explain_data_intern(Explain_query *output, bool need_tmp_table,
+ bool need_order, bool distinct,
+ const char *message);
private:
/**
TRUE if the query contains an aggregate function but has no GROUP
@@ -1817,7 +1833,8 @@ int print_fake_select_lex_join(select_result_sink *result, bool on_the_fly,
SELECT_LEX *select_lex, uint8 select_options);
uint get_index_for_order(ORDER *order, TABLE *table, SQL_SELECT *select,
- ha_rows limit, bool *need_sort, bool *reverse);
+ ha_rows limit, ha_rows *scanned_limit,
+ bool *need_sort, bool *reverse);
ORDER *simple_remove_const(ORDER *order, COND *where);
bool const_expression_in_where(COND *cond, Item *comp_item,
Field *comp_field= NULL,
@@ -1833,6 +1850,29 @@ void push_index_cond(JOIN_TAB *tab, uint keyno);
#define OPT_LINK_EQUAL_FIELDS 1
+/* EXPLAIN-related utility functions */
+int print_explain_message_line(select_result_sink *result,
+ uint8 options,
+ uint select_number,
+ const char *select_type,
+ ha_rows *rows,
+ const char *message);
+void explain_append_mrr_info(QUICK_RANGE_SELECT *quick, String *res);
+int print_explain_row(select_result_sink *result,
+ uint8 options,
+ uint select_number,
+ const char *select_type,
+ const char *table_name,
+ const char *partitions,
+ enum join_type jtype,
+ const char *possible_keys,
+ const char *index,
+ const char *key_len,
+ const char *ref,
+ ha_rows *rows,
+ const char *extra);
+void make_possible_keys_line(TABLE *table, key_map possible_keys, String *line);
+
/****************************************************************************
Temporary table support for SQL Runtime
***************************************************************************/
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index cecafcedf51..446069c14e9 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -2360,8 +2360,8 @@ void Show_explain_request::call_in_target_thread()
DBUG_ASSERT(current_thd == target_thd);
set_current_thd(request_thd);
- if (target_thd->lex->unit.print_explain(explain_buf, 0 /* explain flags*/,
- &printed_anything))
+ if (target_thd->lex->print_explain(explain_buf, 0 /* explain flags*/,
+ &printed_anything))
{
failed_to_produce= TRUE;
}
@@ -2392,6 +2392,86 @@ int select_result_explain_buffer::send_data(List<Item> &items)
DBUG_RETURN(test(res));
}
+bool select_result_text_buffer::send_result_set_metadata(List<Item> &fields, uint flag)
+{
+ n_columns= fields.elements;
+ return append_row(fields, true /*send item names */);
+ return send_data(fields);
+}
+
+
+int select_result_text_buffer::send_data(List<Item> &items)
+{
+ return append_row(items, false /*send item values */);
+}
+
+int select_result_text_buffer::append_row(List<Item> &items, bool send_names)
+{
+ List_iterator<Item> it(items);
+ Item *item;
+ char **row;
+ int column= 0;
+
+ if (!(row= (char**) thd->alloc(sizeof(char*) * n_columns)))
+ return true;
+ rows.push_back(row);
+
+ while ((item= it++))
+ {
+ DBUG_ASSERT(column < n_columns);
+ StringBuffer<32> buf;
+ const char *data_ptr;
+ size_t data_len;
+ if (send_names)
+ {
+ data_ptr= item->name;
+ data_len= strlen(item->name);
+ }
+ else
+ {
+ String *res;
+ res= item->val_str(&buf);
+ if (item->null_value)
+ {
+ data_ptr= "NULL";
+ data_len=4;
+ }
+ else
+ {
+ data_ptr= res->c_ptr_safe();
+ data_len= res->length();
+ }
+ }
+
+ char *ptr= (char*)thd->alloc(data_len + 1);
+ memcpy(ptr, data_ptr, data_len + 1);
+ row[column]= ptr;
+
+ column++;
+ }
+ return false;
+}
+
+
+void select_result_text_buffer::save_to(String *res)
+{
+ List_iterator<char*> it(rows);
+ char **row;
+ res->append("## <explain>\n");
+ while ((row= it++))
+ {
+ res->append("## ");
+ for (int i=0; i < n_columns; i++)
+ {
+ if (i)
+ res->append('\t');
+ res->append(row[i]);
+ }
+ res->append("\n");
+ }
+ res->append("## </explain>\n");
+}
+
/*
Store the SHOW EXPLAIN output in the temporary table.
diff --git a/sql/sql_string.h b/sql/sql_string.h
index 14509218ab5..7687490c8aa 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -520,6 +520,38 @@ public:
}
};
+
+// The following class is a backport from MySQL 5.6:
+/**
+ String class wrapper with a preallocated buffer of size buff_sz
+
+ This class allows to replace sequences of:
+ char buff[12345];
+ String str(buff, sizeof(buff));
+ str.length(0);
+ with a simple equivalent declaration:
+ StringBuffer<12345> str;
+*/
+
+template<size_t buff_sz>
+class StringBuffer : public String
+{
+ char buff[buff_sz];
+
+public:
+ StringBuffer() : String(buff, buff_sz, &my_charset_bin) { length(0); }
+ explicit StringBuffer(const CHARSET_INFO *cs) : String(buff, buff_sz, cs)
+ {
+ length(0);
+ }
+ StringBuffer(const char *str, size_t length, const CHARSET_INFO *cs)
+ : String(buff, buff_sz, cs)
+ {
+ set(str, length, cs);
+ }
+};
+
+
static inline bool check_if_only_end_space(CHARSET_INFO *cs,
const char *str,
const char *end)
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index d7987a62a14..2523e03b4e3 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -622,6 +622,7 @@ bool st_select_lex_unit::exec()
ulonglong add_rows=0;
ha_rows examined_rows= 0;
DBUG_ENTER("st_select_lex_unit::exec");
+ bool was_executed= executed;
if (executed && !uncacheable && !describe)
DBUG_RETURN(FALSE);
@@ -630,6 +631,11 @@ bool st_select_lex_unit::exec()
item->make_const();
saved_error= optimize();
+
+ create_explain_query_if_not_exists(thd->lex, thd->mem_root);
+
+ if (!saved_error && !was_executed)
+ save_union_explain(thd->lex->explain);
if (uncacheable || !item || !item->assigned() || describe)
{
@@ -777,6 +783,9 @@ bool st_select_lex_unit::exec()
*/
if (!fake_select_lex->ref_pointer_array)
fake_select_lex->n_child_sum_items+= global_parameters->n_sum_items;
+
+ if (!was_executed)
+ save_union_explain_part2(thd->lex->explain);
saved_error= mysql_select(thd, &fake_select_lex->ref_pointer_array,
&result_table_list,
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index b91215bcedd..889eaf5fceb 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -260,7 +260,7 @@ int mysql_update(THD *thd,
bool can_compare_record;
int res;
int error, loc_error;
- uint used_index, dup_key_found;
+ uint dup_key_found;
bool need_sort= TRUE;
bool reverse= FALSE;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -270,14 +270,18 @@ int mysql_update(THD *thd,
ha_rows updated, found;
key_map old_covering_keys;
TABLE *table;
- SQL_SELECT *select;
+ SQL_SELECT *select= NULL;
READ_RECORD info;
SELECT_LEX *select_lex= &thd->lex->select_lex;
ulonglong id;
List<Item> all_fields;
killed_state killed_status= NOT_KILLED;
+ Update_plan query_plan(thd->mem_root);
+ query_plan.index= MAX_KEY;
+ query_plan.using_filesort= FALSE;
DBUG_ENTER("mysql_update");
+ create_explain_query(thd->lex, thd->mem_root);
if (open_tables(thd, &table_list, &table_count, 0))
DBUG_RETURN(1);
@@ -310,10 +314,14 @@ int mysql_update(THD *thd,
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "UPDATE");
DBUG_RETURN(1);
}
+ query_plan.updating_a_view= test(table_list->view);
+
/* Calculate "table->covering_keys" based on the WHERE */
table->covering_keys= table->s->keys_in_use;
table->quick_keys.clear_all();
+ query_plan.select_lex= &thd->lex->select_lex;
+ query_plan.table= table;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* Force privilege re-checking for views after they have been opened. */
want_privilege= (table_list->view ? UPDATE_ACL :
@@ -370,7 +378,12 @@ int mysql_update(THD *thd,
Item::cond_result cond_value;
conds= remove_eq_conds(thd, conds, &cond_value);
if (cond_value == Item::COND_FALSE)
+ {
limit= 0; // Impossible WHERE
+ query_plan.set_impossible_where();
+ if (thd->lex->describe)
+ goto exit_without_my_ok;
+ }
}
/*
@@ -388,6 +401,11 @@ int mysql_update(THD *thd,
if (prune_partitions(thd, table, conds))
{
free_underlaid_joins(thd, select_lex);
+
+ query_plan.set_no_partitions();
+ if (thd->lex->describe)
+ goto exit_without_my_ok;
+
my_ok(thd); // No matching records
DBUG_RETURN(0);
}
@@ -400,6 +418,10 @@ int mysql_update(THD *thd,
if (error || !limit || thd->is_error() ||
(select && select->check_quick(thd, safe_update, limit)))
{
+ query_plan.set_impossible_where();
+ if (thd->lex->describe)
+ goto exit_without_my_ok;
+
delete select;
free_underlaid_joins(thd, select_lex);
/*
@@ -434,20 +456,25 @@ int mysql_update(THD *thd,
table->update_const_key_parts(conds);
order= simple_remove_const(order, conds);
+ query_plan.scanned_rows= select? select->records: table->file->stats.records;
if (select && select->quick && select->quick->unique_key_range())
{ // Single row select (always "ordered"): Ok to use with key field UPDATE
need_sort= FALSE;
- used_index= MAX_KEY;
+ query_plan.index= MAX_KEY;
used_key_is_modified= FALSE;
}
else
{
- used_index= get_index_for_order(order, table, select, limit,
- &need_sort, &reverse);
+ ha_rows scanned_limit= query_plan.scanned_rows;
+ query_plan.index= get_index_for_order(order, table, select, limit,
+ &scanned_limit, &need_sort, &reverse);
+ if (!need_sort)
+ query_plan.scanned_rows= scanned_limit;
+
if (select && select->quick)
{
- DBUG_ASSERT(need_sort || used_index == select->quick->index);
+ DBUG_ASSERT(need_sort || query_plan.index == select->quick->index);
used_key_is_modified= (!select->quick->unique_key_range() &&
select->quick->is_keys_used(table->write_set));
}
@@ -455,18 +482,47 @@ int mysql_update(THD *thd,
{
if (need_sort)
{ // Assign table scan index to check below for modified key fields:
- used_index= table->file->key_used_on_scan;
+ query_plan.index= table->file->key_used_on_scan;
}
- if (used_index != MAX_KEY)
+ if (query_plan.index != MAX_KEY)
{ // Check if we are modifying a key that we are used to search with:
- used_key_is_modified= is_key_used(table, used_index, table->write_set);
+ used_key_is_modified= is_key_used(table, query_plan.index, table->write_set);
}
}
}
-
+
+ /*
+ Query optimization is finished at this point.
+ - Save the decisions in the query plan
+ - if we're running EXPLAIN UPDATE, get out
+ */
+ query_plan.select= select;
+ query_plan.possible_keys= select? select->possible_keys: key_map(0);
+
if (used_key_is_modified || order ||
partition_key_modified(table, table->write_set))
{
+ if (order && (need_sort || used_key_is_modified))
+ query_plan.using_filesort= true;
+ else
+ query_plan.using_io_buffer= true;
+ }
+
+
+ /*
+ Ok, we have generated a query plan for the UPDATE.
+ - if we're running EXPLAIN UPDATE, goto produce explain output
+ - otherwise, execute the query plan
+ */
+ if (thd->lex->describe)
+ goto exit_without_my_ok;
+ query_plan.save_explain_data(thd->lex->explain);
+
+ DBUG_EXECUTE_IF("show_explain_probe_update_exec_start",
+ dbug_serve_apcs(thd, 1););
+
+ if (query_plan.using_filesort || query_plan.using_io_buffer)
+ {
/*
We can't update table directly; We must first search after all
matching rows before updating the table!
@@ -474,13 +530,13 @@ int mysql_update(THD *thd,
MY_BITMAP *save_read_set= table->read_set;
MY_BITMAP *save_write_set= table->write_set;
- if (used_index < MAX_KEY && old_covering_keys.is_set(used_index))
- table->add_read_columns_used_by_index(used_index);
+ if (query_plan.index < MAX_KEY && old_covering_keys.is_set(query_plan.index))
+ table->add_read_columns_used_by_index(query_plan.index);
else
table->use_all_columns();
/* note: We avoid sorting if we sort on the used index */
- if (order && (need_sort || used_key_is_modified))
+ if (query_plan.using_filesort)
{
/*
Doing an ORDER BY; Let filesort find and sort the rows we are going
@@ -535,22 +591,22 @@ int mysql_update(THD *thd,
/*
When we get here, we have one of the following options:
- A. used_index == MAX_KEY
+ A. query_plan.index == MAX_KEY
This means we should use full table scan, and start it with
init_read_record call
- B. used_index != MAX_KEY
+ B. query_plan.index != MAX_KEY
B.1 quick select is used, start the scan with init_read_record
B.2 quick select is not used, this is full index scan (with LIMIT)
Full index scan must be started with init_read_record_idx
*/
- if (used_index == MAX_KEY || (select && select->quick))
+ if (query_plan.index == MAX_KEY || (select && select->quick))
{
if (init_read_record(&info, thd, table, select, 0, 1, FALSE))
goto err;
}
else
- init_read_record_idx(&info, thd, table, 1, used_index, reverse);
+ init_read_record_idx(&info, thd, table, 1, query_plan.index, reverse);
THD_STAGE_INFO(thd, stage_searching_rows_for_update);
ha_rows tmp_limit= limit;
@@ -616,6 +672,7 @@ int mysql_update(THD *thd,
select= new SQL_SELECT;
select->head=table;
}
+ //psergey-todo: disable SHOW EXPLAIN because the plan was deleted?
if (reinit_io_cache(&tempfile,READ_CACHE,0L,0,0))
error=1; /* purecov: inspected */
select->file=tempfile; // Read row ptrs from this file
@@ -966,11 +1023,21 @@ int mysql_update(THD *thd,
DBUG_RETURN((error >= 0 || thd->is_error()) ? 1 : 0);
err:
+
delete select;
free_underlaid_joins(thd, select_lex);
table->disable_keyread();
thd->abort_on_warning= 0;
DBUG_RETURN(1);
+
+exit_without_my_ok:
+ query_plan.save_explain_data(thd->lex->explain);
+
+ int err2= thd->lex->explain->send_explain(thd);
+
+ delete select;
+ free_underlaid_joins(thd, select_lex);
+ DBUG_RETURN((err2 || thd->is_error()) ? 1 : 0);
}
/*
@@ -1391,17 +1458,16 @@ bool mysql_multi_update(THD *thd,
{
bool res;
DBUG_ENTER("mysql_multi_update");
-
+
if (!(*result= new multi_update(table_list,
- &thd->lex->select_lex.leaf_tables,
- fields, values,
- handle_duplicates, ignore)))
+ &thd->lex->select_lex.leaf_tables,
+ fields, values,
+ handle_duplicates, ignore)))
{
DBUG_RETURN(TRUE);
}
thd->abort_on_warning= thd->is_strict_mode();
-
List<Item> total_list;
res= mysql_select(thd, &select_lex->ref_pointer_array,
@@ -1417,6 +1483,11 @@ bool mysql_multi_update(THD *thd,
res|= thd->is_error();
if (unlikely(res))
(*result)->abort_result_set();
+ else
+ {
+ if (thd->lex->describe)
+ res= thd->lex->explain->send_explain(thd);
+ }
thd->abort_on_warning= 0;
DBUG_RETURN(res);
}
@@ -1431,7 +1502,7 @@ multi_update::multi_update(TABLE_LIST *table_list,
tmp_tables(0), updated(0), found(0), fields(field_list),
values(value_list), table_count(0), copy_field(0),
handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(1),
- transactional_tables(0), ignore(ignore_arg), error_handled(0)
+ transactional_tables(0), ignore(ignore_arg), error_handled(0), prepared(0)
{}
@@ -1454,6 +1525,10 @@ int multi_update::prepare(List<Item> &not_used_values,
List_iterator<TABLE_LIST> ti(*leaves);
DBUG_ENTER("multi_update::prepare");
+ if (prepared)
+ DBUG_RETURN(0);
+ prepared= true;
+
thd->count_cuted_fields= CHECK_FIELD_WARN;
thd->cuted_fields=0L;
THD_STAGE_INFO(thd, stage_updating_main_table);
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index f464142f544..6f030d28678 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -1310,8 +1310,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
underlying tables.
Skip this step if we are opening view for prelocking only.
*/
- if (!table->prelocking_placeholder &&
- (old_lex->sql_command == SQLCOM_SELECT && old_lex->describe))
+ if (!table->prelocking_placeholder && (old_lex->describe))
{
/*
The user we run EXPLAIN as (either the connected user who issued
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 4dd2621b088..52865bc99de 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1848,6 +1848,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
definer_opt no_definer definer get_diagnostics
parse_vcol_expr vcol_opt_specifier vcol_opt_attribute
vcol_opt_attribute_list vcol_attribute
+ explainable_command
END_OF_INPUT
%type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt
@@ -12565,13 +12566,21 @@ describe:
}
| describe_command opt_extended_describe
{ Lex->describe|= DESCRIBE_NORMAL; }
- select
+ explainable_command
{
LEX *lex=Lex;
lex->select_lex.options|= SELECT_DESCRIBE;
}
;
+explainable_command:
+ select
+ | insert
+ | replace
+ | update
+ | delete
+ ;
+
describe_command:
DESC
| DESCRIBE
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 05ee72c0c6b..a03a0a0e5f5 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -4289,11 +4289,12 @@ static Sys_var_ulong Sys_log_slow_rate_limit(
SESSION_VAR(log_slow_rate_limit), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(1, UINT_MAX), DEFAULT(1), BLOCK_SIZE(1));
-static const char *log_slow_verbosity_names[]= { "innodb", "query_plan", 0 };
+static const char *log_slow_verbosity_names[]= { "innodb", "query_plan",
+ "explain", 0 };
static Sys_var_set Sys_log_slow_verbosity(
"log_slow_verbosity",
"log-slow-verbosity=[value[,value ...]] where value is one of "
- "'innodb', 'query_plan'",
+ "'innodb', 'query_plan', 'explain' ",
SESSION_VAR(log_slow_verbosity), CMD_LINE(REQUIRED_ARG),
log_slow_verbosity_names, DEFAULT(LOG_SLOW_VERBOSITY_INIT));
diff --git a/support-files/build-tags b/support-files/build-tags
index 9c43e021c42..a7fca4b42f4 100755
--- a/support-files/build-tags
+++ b/support-files/build-tags
@@ -6,7 +6,7 @@ filter='\.cc$\|\.c$\|\.h$\|sql_yacc\.yy$'
list="find . -type f"
bzr root >/dev/null 2>/dev/null && list="bzr ls --from-root -R --kind=file --versioned"
-$list |grep $filter |while read f;
+$list |grep $filter | grep -v gen-cpp |while read f;
do
etags -o TAGS --append $f
done