MDEV-3798: [SHOW] EXPLAIN UPDATE/DELETE
- Merge with 10.0-base
This commit is contained in:
commit
1e36cbfa39
@ -100,6 +100,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
|
||||
${GEN_SOURCES}
|
||||
${MYSYS_LIBWRAP_SOURCE}
|
||||
)
|
||||
|
@ -16,4 +16,4 @@ 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.
|
||||
#show_explain : Psergey: random timeout in range-checked-for-each record query.
|
||||
|
833
mysql-test/include/explain_non_select.inc
Normal file
833
mysql-test/include/explain_non_select.inc
Normal file
@ -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
|
161
mysql-test/include/explain_utils.inc
Normal file
161
mysql-test/include/explain_utils.inc
Normal file
@ -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
|
@ -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);
|
||||
|
@ -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
|
||||
|
221
mysql-test/r/explain_non_select.result
Normal file
221
mysql-test/r/explain_non_select.result
Normal file
@ -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 '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;
|
41
mysql-test/r/explain_slowquerylog.result
Normal file
41
mysql-test/r/explain_slowquerylog.result
Normal file
@ -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;
|
178
mysql-test/r/grant_explain_non_select.result
Normal file
178
mysql-test/r/grant_explain_non_select.result
Normal file
@ -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;
|
@ -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
|
||||
|
2907
mysql-test/r/myisam_explain_non_select_all.result
Normal file
2907
mysql-test/r/myisam_explain_non_select_all.result
Normal file
File diff suppressed because it is too large
Load Diff
@ -344,7 +344,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).
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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';
|
||||
|
44
mysql-test/r/show_explain_non_select.result
Normal file
44
mysql-test/r/show_explain_non_select.result
Normal file
@ -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';
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
@ -520,8 +520,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;
|
||||
@ -558,8 +558,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;
|
||||
@ -595,8 +595,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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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`
|
||||
@ -4475,8 +4475,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:
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
200
mysql-test/t/explain_non_select.test
Normal file
200
mysql-test/t/explain_non_select.test
Normal file
@ -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;
|
||||
|
||||
|
1
mysql-test/t/explain_slowquerylog-master.opt
Normal file
1
mysql-test/t/explain_slowquerylog-master.opt
Normal file
@ -0,0 +1 @@
|
||||
--slow-query-log --long-query-time=0.00000 --log-slow-verbosity=query_plan,explain
|
49
mysql-test/t/explain_slowquerylog.test
Normal file
49
mysql-test/t/explain_slowquerylog.test
Normal file
@ -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;
|
258
mysql-test/t/grant_explain_non_select.test
Normal file
258
mysql-test/t/grant_explain_non_select.test
Normal file
@ -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
|
21
mysql-test/t/myisam_explain_non_select_all.test
Normal file
21
mysql-test/t/myisam_explain_non_select_all.test
Normal file
@ -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;
|
@ -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';
|
||||
|
78
mysql-test/t/show_explain_non_select.test
Normal file
78
mysql-test/t/show_explain_non_select.test
Normal file
@ -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';
|
@ -80,6 +80,7 @@ SET (SQL_SOURCE
|
||||
sql_reload.cc
|
||||
|
||||
# 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
|
||||
|
@ -2825,6 +2825,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)
|
||||
|
@ -9258,6 +9258,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);
|
||||
/*
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
148
sql/opt_range.cc
148
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););
|
||||
|
||||
/*
|
||||
@ -10467,6 +10480,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);
|
||||
@ -11960,78 +11974,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)
|
||||
{
|
||||
QUICK_RANGE_SELECT *quick;
|
||||
bool first= TRUE;
|
||||
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
|
||||
|
||||
str->append(STRING_WITH_LEN("sort_union("));
|
||||
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;
|
||||
Explain_quick_select *child_explain;
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
QUICK_RANGE_SELECT *quick;
|
||||
bool first= TRUE;
|
||||
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
|
||||
|
||||
str->append(STRING_WITH_LEN("sort_intersect("));
|
||||
/*
|
||||
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)
|
||||
{
|
||||
Explain_quick_select *res;
|
||||
Explain_quick_select *child_explain;
|
||||
|
||||
if (!(res= new (alloc) Explain_quick_select(get_type())))
|
||||
return NULL;
|
||||
|
||||
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)
|
||||
{
|
||||
QUICK_SELECT_I *quick;
|
||||
bool first= TRUE;
|
||||
List_iterator_fast<QUICK_SELECT_I> it(quick_selects);
|
||||
Explain_quick_select *res;
|
||||
Explain_quick_select *child_explain;
|
||||
|
||||
str->append(STRING_WITH_LEN("union("));
|
||||
if (!(res= new (alloc) Explain_quick_select(get_type())))
|
||||
return NULL;
|
||||
|
||||
QUICK_SELECT_I *quick;
|
||||
List_iterator_fast<QUICK_SELECT_I> it(quick_selects);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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:
|
||||
@ -3021,6 +3037,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)
|
||||
{
|
||||
@ -3228,6 +3246,7 @@ sp_instr_set::execute(THD *thd, uint *nextp)
|
||||
int
|
||||
sp_instr_set::exec_core(THD *thd, uint *nextp)
|
||||
{
|
||||
create_explain_query(thd->lex, thd->mem_root);
|
||||
int res= thd->spcont->set_variable(thd, m_offset, &m_value);
|
||||
|
||||
if (res)
|
||||
@ -3240,6 +3259,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;
|
||||
|
@ -106,6 +106,7 @@ public:
|
||||
|
||||
Elem& at(size_t idx)
|
||||
{
|
||||
DBUG_ASSERT(idx < array.elements);
|
||||
return *(((Elem*)array.buffer) + idx);
|
||||
}
|
||||
|
||||
@ -139,6 +140,23 @@ public:
|
||||
array.elements= n;
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -2089,6 +2089,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));
|
||||
|
@ -3410,6 +3410,11 @@ public:
|
||||
void begin_dataset() {}
|
||||
#endif
|
||||
virtual void update_used_tables() {}
|
||||
|
||||
void reset_offset_limit()
|
||||
{
|
||||
unit->offset_limit_cnt= 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -3438,6 +3443,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
|
||||
@ -4159,7 +4184,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,
|
||||
|
@ -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,11 +219,13 @@ 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");
|
||||
|
||||
if (open_and_lock_tables(thd, table_list, TRUE, 0))
|
||||
@ -92,6 +249,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
|
||||
}
|
||||
thd_proc_info(thd, "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 +328,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 +357,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 +390,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 +424,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 +505,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 +515,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_proc_info(thd, "updating");
|
||||
@ -479,6 +683,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);
|
||||
}
|
||||
|
||||
|
||||
|
948
sql/sql_explain.cc
Normal file
948
sql/sql_explain.cc
Normal file
@ -0,0 +1,948 @@
|
||||
/*
|
||||
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(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(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());
|
||||
|
||||
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;
|
||||
}
|
||||
|
550
sql/sql_explain.h
Normal file
550
sql/sql_explain.h
Normal file
@ -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 a tabular and/or a json EXPLAIN
|
||||
- Have methods that produce a tabular output.
|
||||
|
||||
*************************************************************************************/
|
||||
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
@ -644,6 +645,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
|
||||
|
||||
@ -660,6 +691,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;
|
||||
@ -780,6 +812,17 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
|
||||
/* Restore the current context. */
|
||||
ctx_state.restore_state(context, table_list);
|
||||
|
||||
if (thd->lex->unit.first_select()->optimize_unflattened_subqueries(false))
|
||||
{
|
||||
goto abort;
|
||||
}
|
||||
save_insert_query_plan(thd, table_list);
|
||||
if (thd->lex->describe)
|
||||
{
|
||||
retval= thd->lex->explain->send_explain(thd);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
/*
|
||||
Fill in the given fields and dump it to the table file
|
||||
@ -1134,10 +1177,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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
@ -657,7 +658,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();
|
||||
|
||||
@ -1335,7 +1336,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);
|
||||
};
|
||||
|
||||
|
||||
@ -1426,5 +1427,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);
|
||||
};
|
||||
|
164
sql/sql_lex.cc
164
sql/sql_lex.cc
@ -447,6 +447,8 @@ void lex_start(THD *thd)
|
||||
DBUG_ENTER("lex_start");
|
||||
|
||||
lex->thd= lex->unit.thd= thd;
|
||||
|
||||
lex->explain= NULL;
|
||||
|
||||
lex->context_stack.empty();
|
||||
lex->unit.init_query();
|
||||
@ -2568,7 +2570,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)
|
||||
{
|
||||
|
||||
@ -3510,6 +3513,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)
|
||||
{
|
||||
/*
|
||||
@ -4186,114 +4201,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);
|
||||
|
||||
/* Note: fake_select_lex->join may be NULL or non-NULL at this point */
|
||||
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();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
105
sql/sql_lex.h
105
sql/sql_lex.h
@ -618,7 +618,11 @@ 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);
|
||||
bool print_explain_query(LEX *lex, THD *thd, String *str);
|
||||
|
||||
class st_select_lex_unit: public st_select_lex_node {
|
||||
protected:
|
||||
@ -729,8 +733,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;
|
||||
@ -1026,6 +1031,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);
|
||||
@ -1054,8 +1063,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.
|
||||
@ -2360,6 +2368,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
|
||||
@ -2370,6 +2461,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;
|
||||
@ -2786,6 +2880,9 @@ struct LEX: public Query_tables_list
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int print_explain(select_result_sink *output, uint8 explain_flags,
|
||||
bool *printed_anything);
|
||||
};
|
||||
|
||||
|
||||
|
113
sql/sql_parse.cc
113
sql/sql_parse.cc
@ -598,6 +598,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;
|
||||
@ -807,7 +808,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:
|
||||
DBUG_RETURN(return_value);
|
||||
@ -1117,6 +1120,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))
|
||||
@ -1520,10 +1524,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
|
||||
@ -1532,11 +1541,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 &
|
||||
@ -1559,6 +1572,8 @@ void log_slow_statement(THD *thd)
|
||||
thd->utime_after_query);
|
||||
thd_proc_info(thd, 0);
|
||||
}
|
||||
|
||||
delete_explain_query(thd->lex);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@ -2185,6 +2200,8 @@ mysql_execute_command(THD *thd)
|
||||
/* Release metadata locks acquired in this transaction. */
|
||||
thd->mdl_context.release_transactional_locks();
|
||||
}
|
||||
|
||||
create_explain_query(thd->lex, thd->mem_root);
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
if (lex->sql_command != SQLCOM_SET_OPTION)
|
||||
@ -3156,6 +3173,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;
|
||||
@ -3225,6 +3243,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;
|
||||
@ -3265,7 +3287,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);
|
||||
select_result *result;
|
||||
|
||||
if ((res= multi_delete_precheck(thd, all_tables)))
|
||||
break;
|
||||
@ -3287,25 +3310,34 @@ end_with_restore_list:
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!thd->is_fatal_error &&
|
||||
(del_result= new multi_delete(aux_tables, lex->table_count)))
|
||||
if (!thd->is_fatal_error)
|
||||
{
|
||||
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;
|
||||
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, del_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
|
||||
{
|
||||
@ -4743,8 +4775,8 @@ finish:
|
||||
ha_maria::implicit_commit(thd, FALSE);
|
||||
#endif
|
||||
}
|
||||
|
||||
lex->unit.cleanup();
|
||||
|
||||
/* Free tables */
|
||||
thd_proc_info(thd, "closing tables");
|
||||
close_thread_tables(thd);
|
||||
@ -4819,24 +4851,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, MYSQL_ERROR::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, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
||||
ER_YES, str.c_ptr_safe());
|
||||
}
|
||||
}
|
||||
|
||||
if (res)
|
||||
result->abort_result_set();
|
||||
else
|
||||
|
@ -2491,6 +2491,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)
|
||||
{
|
||||
@ -3931,6 +3932,8 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
|
||||
if (! cursor)
|
||||
cleanup_stmt();
|
||||
|
||||
delete_explain_query(thd->lex);
|
||||
|
||||
thd->set_statement(&stmt_backup);
|
||||
thd->stmt_arena= old_stmt_arena;
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -198,6 +198,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;
|
||||
@ -252,7 +258,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.
|
||||
@ -1334,6 +1341,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
|
||||
@ -1342,6 +1351,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,
|
||||
@ -1466,11 +1482,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
|
||||
@ -1826,7 +1842,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,
|
||||
@ -1842,6 +1859,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
|
||||
***************************************************************************/
|
||||
|
@ -2345,8 +2345,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;
|
||||
}
|
||||
@ -2377,6 +2377,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("#\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("#\n");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Store the SHOW EXPLAIN output in the temporary table.
|
||||
|
@ -516,6 +516,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)
|
||||
|
@ -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);
|
||||
@ -631,6 +632,9 @@ bool st_select_lex_unit::exec()
|
||||
|
||||
saved_error= optimize();
|
||||
|
||||
if (!saved_error && !was_executed && thd->lex->explain)
|
||||
save_union_explain(thd->lex->explain);
|
||||
|
||||
if (uncacheable || !item || !item->assigned() || describe)
|
||||
{
|
||||
for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
|
||||
@ -777,6 +781,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 && thd->lex->explain)
|
||||
save_union_explain_part2(thd->lex->explain);
|
||||
|
||||
saved_error= mysql_select(thd, &fake_select_lex->ref_pointer_array,
|
||||
&result_table_list,
|
||||
|
@ -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,12 +270,15 @@ 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");
|
||||
|
||||
if (open_tables(thd, &table_list, &table_count, 0))
|
||||
@ -310,10 +313,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 +377,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 +400,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 +417,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 +455,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,17 +481,46 @@ 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
|
||||
@ -476,13 +531,13 @@ int mysql_update(THD *thd,
|
||||
DBUG_ASSERT(table->read_set == &table->def_read_set);
|
||||
DBUG_ASSERT(table->write_set == &table->def_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
|
||||
@ -537,22 +592,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_proc_info(thd, "Searching rows for update");
|
||||
ha_rows tmp_limit= limit;
|
||||
@ -618,6 +673,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
|
||||
@ -974,11 +1030,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);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1399,11 +1465,11 @@ 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);
|
||||
}
|
||||
@ -1411,7 +1477,6 @@ bool mysql_multi_update(THD *thd,
|
||||
thd->abort_on_warning= test(thd->variables.sql_mode &
|
||||
(MODE_STRICT_TRANS_TABLES |
|
||||
MODE_STRICT_ALL_TABLES));
|
||||
|
||||
List<Item> total_list;
|
||||
|
||||
res= mysql_select(thd, &select_lex->ref_pointer_array,
|
||||
@ -1427,6 +1492,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);
|
||||
}
|
||||
@ -1441,7 +1511,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)
|
||||
{}
|
||||
|
||||
|
||||
@ -1464,6 +1534,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_proc_info(thd, "updating main table");
|
||||
|
@ -1300,8 +1300,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
|
||||
|
@ -1655,6 +1655,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
|
||||
definer_opt no_definer definer
|
||||
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
|
||||
@ -11969,13 +11970,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
|
||||
|
@ -4111,11 +4111,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));
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user