diff options
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> ¬_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 |