MDEV-34870: implement join order hints

This commit implements optimizer hints allowing to affect the order
of joining tables:

 - JOIN_FIXED_ORDER similar to existing STRAIGHT_JOIN hint;
 - JOIN_ORDER to apply the specified table order;
 - JOIN_PREFIX to hint what tables should be first in the join;
 - JOIN_SUFFIX to hint what tables should be last in the join.
This commit is contained in:
Oleg Smirnov 2025-01-30 20:56:36 +07:00
parent c4fe794d22
commit 349f5bf2da
18 changed files with 4198 additions and 1311 deletions

View File

@ -230,7 +230,7 @@ a
1
2
Warnings:
Warning 4207 Hint BKA("A") is ignored as conflicting/duplicated
Warning 4210 Hint BKA("A") is ignored as conflicting/duplicated
DROP TABLE t1;
#
# End of 11.7 tests

View File

@ -49,7 +49,7 @@ SELECT /*+ MAX_EXECUTION_TIME(10) MAX_EXECUTION_TIME(100) */ count(*) FROM t1;
count(*)
512
Warnings:
Warning 4207 Hint MAX_EXECUTION_TIME(100) is ignored as conflicting/duplicated
Warning 4210 Hint MAX_EXECUTION_TIME(100) is ignored as conflicting/duplicated
# Wrong values
SELECT /*+ MAX_EXECUTION_TIME(0) */ count(*) FROM t1;
count(*)
@ -102,7 +102,7 @@ SELECT /*+ MAX_EXECUTION_TIME(30) */ count(*) FROM t1;
count(*)
512
Warnings:
Warning 4207 Hint MAX_EXECUTION_TIME(30) is ignored as conflicting/duplicated
Warning 4210 Hint MAX_EXECUTION_TIME(30) is ignored as conflicting/duplicated
SELECT count(*) FROM t1
UNION
SELECT /*+ MAX_EXECUTION_TIME(30) */ count(*) FROM t1;

View File

@ -15,25 +15,25 @@ a
1
2
Warnings:
Warning 4210 Unresolved index name `t1`@`select#1` `idx_å` for NO_MRR hint
Warning 4213 Unresolved index name `t1`@`select#1` `idx_å` for NO_MRR hint
SELECT /*+ NO_MRR(t1 idx_a, idx_å, idx_A) */ a FROM t1;
a
1
2
Warnings:
Warning 4207 Hint NO_MRR(`t1` `idx_A`) is ignored as conflicting/duplicated
Warning 4210 Unresolved index name `t1`@`select#1` `idx_å` for NO_MRR hint
Warning 4210 Hint NO_MRR(`t1` `idx_A`) is ignored as conflicting/duplicated
Warning 4213 Unresolved index name `t1`@`select#1` `idx_å` for NO_MRR hint
DROP TABLE t1;
# Testing that query block names are accent sensitive case insensitive
CREATE TABLE t1 (a INT);
SELECT /*+ QB_NAME(a) BKA(t1@a) BKA(t1@A) */ * FROM t1;
a
Warnings:
Warning 4207 Hint BKA(`t1`@`A`) is ignored as conflicting/duplicated
Warning 4210 Hint BKA(`t1`@`A`) is ignored as conflicting/duplicated
SELECT /*+ QB_NAME(a) BKA(t1@a) BKA(t1@å) */ * FROM t1;
a
Warnings:
Warning 4208 Query block name `å` is not found for BKA hint
Warning 4211 Query block name `å` is not found for BKA hint
DROP TABLE t1;
CREATE TABLE t1(f1 INT, f2 INT);
INSERT INTO t1 VALUES
@ -230,7 +230,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t4 ref y_idx y_idx 5 const 1 100.00
1 SIMPLE t5 range x_idx x_idx 5 NULL 2 100.00 Using where; Using join buffer (flat, BNL join)
Warnings:
Warning 4210 Unresolved index name `t5`@`select#2` `z_idx` for NO_ICP hint
Warning 4213 Unresolved index name `t5`@`select#2` `z_idx` for NO_ICP hint
Note 1003 select /*+ NO_ICP(`t5`@`select#2` `y_idx`) NO_ICP(`t5`@`select#2` `x_idx`) */ `test`.`t4`.`x` AS `x`,`test`.`t5`.`y` AS `y` from `test`.`t4` join `test`.`t4` `t5` where `test`.`t4`.`y` = 8 and `test`.`t5`.`x` between 7 and <cache>(8 + 0)
# ICP should still be used
EXPLAIN EXTENDED SELECT * FROM
@ -548,7 +548,7 @@ EXPLAIN EXTENDED SELECT /*+ QB_NAME(qb1) QB_NAME(qb1 ) */ * FROM t2;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 28 100.00
Warnings:
Warning 4207 Hint QB_NAME(`qb1`) is ignored as conflicting/duplicated
Warning 4210 Hint QB_NAME(`qb1`) is ignored as conflicting/duplicated
Note 1003 select /*+ QB_NAME(`qb1`) */ `test`.`t2`.`f1` AS `f1`,`test`.`t2`.`f2` AS `f2`,`test`.`t2`.`f3` AS `f3` from `test`.`t2`
# Should issue warning
EXPLAIN EXTENDED SELECT /*+ BKA(@qb1) QB_NAME(qb1) */ t2.f1, t2.f2, t2.f3 FROM t1,t2
@ -557,7 +557,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
1 SIMPLE t2 ALL f1 NULL NULL NULL 28 25.00 Using where; Using join buffer (flat, BNL join)
Warnings:
Warning 4208 Query block name `qb1` is not found for BKA hint
Warning 4211 Query block name `qb1` is not found for BKA hint
Note 1003 select /*+ QB_NAME(`qb1`) */ `test`.`t2`.`f1` AS `f1`,`test`.`t2`.`f2` AS `f2`,`test`.`t2`.`f3` AS `f3` from `test`.`t1` join `test`.`t2` where `test`.`t2`.`f1` = `test`.`t1`.`f1` and `test`.`t2`.`f2` between `test`.`t1`.`f1` and `test`.`t1`.`f2` and `test`.`t2`.`f2` + 1 >= `test`.`t1`.`f1` + 1
# Should not crash
PREPARE stmt1 FROM "SELECT /*+ BKA(t2) */ t2.f1, t2.f2, t2.f3 FROM t1,t2
@ -601,9 +601,9 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
1 SIMPLE t2 ALL f1 NULL NULL NULL 28 25.00 Using where; Using join buffer (flat, BNL join)
Warnings:
Warning 4209 Unresolved table name `t3`@`select#1` for BKA hint
Warning 4209 Unresolved table name `t3`@`select#1` for NO_RANGE_OPTIMIZATION hint
Warning 4210 Unresolved index name `t3`@`select#1` `idx1` for NO_RANGE_OPTIMIZATION hint
Warning 4212 Unresolved table name `t3`@`select#1` for BKA hint
Warning 4212 Unresolved table name `t3`@`select#1` for NO_RANGE_OPTIMIZATION hint
Warning 4213 Unresolved index name `t3`@`select#1` `idx1` for NO_RANGE_OPTIMIZATION hint
Note 1003 select /*+ BKA(`t2`@`select#1`) NO_BNL(`t1`@`select#1`) */ `test`.`t2`.`f1` AS `f1`,`test`.`t2`.`f2` AS `f2`,`test`.`t2`.`f3` AS `f3` from `test`.`t1` join `test`.`t2` where `test`.`t2`.`f1` = `test`.`t1`.`f1` and `test`.`t2`.`f2` between `test`.`t1`.`f1` and `test`.`t1`.`f2` and `test`.`t2`.`f2` + 1 >= `test`.`t1`.`f1` + 1
# Check illegal syntax
EXPLAIN EXTENDED SELECT /*+ BKA(qb1 t3@qb1) */ f2 FROM
@ -640,7 +640,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE tbl12 ALL NULL NULL NULL NULL 10 100.00 Using where
1 SIMPLE tbl13 hash_ALL a #hash#a 5 test.tbl12.a 1000 0.10 Using where; Using join buffer (flat, BNLH join)
Warnings:
Warning 4209 Unresolved table name `tbl2`@`select#1` for BKA hint
Warning 4212 Unresolved table name `tbl2`@`select#1` for BKA hint
Note 1003 select `test`.`tbl12`.`a` AS `a`,`test`.`tbl12`.`b` AS `b`,`test`.`tbl13`.`a` AS `a`,`test`.`tbl13`.`b` AS `b`,`test`.`tbl13`.`c` AS `c`,`test`.`tbl13`.`filler` AS `filler` from `test`.`t12` `tbl12` join `test`.`t13` `tbl13` where `test`.`tbl13`.`a` = `test`.`tbl12`.`a` and `test`.`tbl13`.`b` + 1 <= `test`.`tbl13`.`b` + 1
# Check that PS and conventional statements give the same result.
FLUSH STATUS;
@ -1476,19 +1476,19 @@ SELECT /*+ BKA() BKA() */ 1;
1
1
Warnings:
Warning 4207 Hint BKA() is ignored as conflicting/duplicated
Warning 4210 Hint BKA() is ignored as conflicting/duplicated
SELECT /*+ BKA(t1) BKA(t1) */ * FROM t1;
i
Warnings:
Warning 4207 Hint BKA(`t1`) is ignored as conflicting/duplicated
Warning 4210 Hint BKA(`t1`) is ignored as conflicting/duplicated
SELECT /*+ QB_NAME(q1) BKA(t1@q1) BKA(t1@q1) */ * FROM t1;
i
Warnings:
Warning 4207 Hint BKA(`t1`@`q1`) is ignored as conflicting/duplicated
Warning 4210 Hint BKA(`t1`@`q1`) is ignored as conflicting/duplicated
SELECT /*+ QB_NAME(q1) NO_ICP(@q1 t1 PRIMARY) NO_ICP(@q1 t1 PRIMARY) */ * FROM t1;
i
Warnings:
Warning 4207 Hint NO_ICP(`t1`@`q1` `PRIMARY`) is ignored as conflicting/duplicated
Warning 4210 Hint NO_ICP(`t1`@`q1` `PRIMARY`) is ignored as conflicting/duplicated
DROP TABLE t1;
#
# Hints inside views are not supported
@ -1497,7 +1497,7 @@ CREATE TABLE t1 (a INT, INDEX idx_a(a));
INSERT INTO t1 VALUES (1),(2);
CREATE VIEW v1 AS SELECT /*+ NO_MRR(t1 idx_a) */ a FROM t1;
Warnings:
Warning 4211 Optimizer hints are not supported inside view definitions
Warning 4214 Optimizer hints are not supported inside view definitions
SELECT * FROM v1;
a
1
@ -1513,13 +1513,13 @@ Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1`
CREATE OR REPLACE VIEW v1 AS SELECT /*+ NO_MRR(t1 idx_a) BKA(t1)*/ a FROM t1;
Warnings:
Warning 4211 Optimizer hints are not supported inside view definitions
Warning 4214 Optimizer hints are not supported inside view definitions
SHOW CREATE VIEW v1;
View Create View character_set_client collation_connection
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a` from `t1` utf8mb4 utf8mb4_uca1400_ai_ci
ALTER VIEW v1 AS SELECT /*+ QB_NAME(q1)*/ a FROM t1;
Warnings:
Warning 4211 Optimizer hints are not supported inside view definitions
Warning 4214 Optimizer hints are not supported inside view definitions
SHOW CREATE VIEW v1;
View Create View character_set_client collation_connection
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a` from `t1` utf8mb4 utf8mb4_uca1400_ai_ci
@ -1686,15 +1686,15 @@ Warning 1064 Optimizer hint syntax error near 'b) */ 1 FROM t1 a, t1 b' at lin
SELECT /*+ NO_ICP(i1) */ 1 FROM t1;
1
Warnings:
Warning 4209 Unresolved table name `i1`@`select#1` for NO_ICP hint
Warning 4212 Unresolved table name `i1`@`select#1` for NO_ICP hint
SELECT /*+ NO_ICP(i1 i2) */ 1 FROM t1;
1
Warnings:
Warning 4210 Unresolved index name `i1`@`select#1` `i2` for NO_ICP hint
Warning 4213 Unresolved index name `i1`@`select#1` `i2` for NO_ICP hint
SELECT /*+ NO_ICP(@qb ident) */ 1 FROM t1;
1
Warnings:
Warning 4208 Query block name `qb` is not found for NO_ICP hint
Warning 4211 Query block name `qb` is not found for NO_ICP hint
# valid hint sequences, no warnings expected:
@ -1749,49 +1749,49 @@ CREATE INDEX 3rd_index ON t1(i, j);
SELECT /*+ NO_ICP(3rd_index) */ 1 FROM t1;
1
Warnings:
Warning 4209 Unresolved table name `3rd_index`@`select#1` for NO_ICP hint
Warning 4212 Unresolved table name `3rd_index`@`select#1` for NO_ICP hint
CREATE INDEX $index ON t1(j, i);
SELECT /*+ NO_ICP($index) */ 1 FROM t1;
1
Warnings:
Warning 4209 Unresolved table name `$index`@`select#1` for NO_ICP hint
Warning 4212 Unresolved table name `$index`@`select#1` for NO_ICP hint
CREATE TABLE ` quoted name test` (i INT);
SELECT /*+ BKA(` quoted name test`) */ 1 FROM t1;
1
Warnings:
Warning 4209 Unresolved table name ` quoted name test`@`select#1` for BKA hint
Warning 4212 Unresolved table name ` quoted name test`@`select#1` for BKA hint
SELECT /*+ BKA(` quoted name test`@`select#1`) */ 1 FROM t1;
1
Warnings:
Warning 4208 Query block name `select#1` is not found for BKA hint
Warning 4211 Query block name `select#1` is not found for BKA hint
DROP TABLE ` quoted name test`;
SET SQL_MODE = 'ANSI_QUOTES';
CREATE TABLE " quoted name test" (i INT);
SELECT /*+ BKA(" quoted name test") */ 1 FROM t1;
1
Warnings:
Warning 4209 Unresolved table name " quoted name test"@"select#1" for BKA hint
Warning 4212 Unresolved table name " quoted name test"@"select#1" for BKA hint
SELECT /*+ BKA(" quoted name test"@"select#1") */ 1 FROM t1;
1
Warnings:
Warning 4208 Query block name "select#1" is not found for BKA hint
Warning 4211 Query block name "select#1" is not found for BKA hint
CREATE TABLE `test1``test2``` (i INT);
SELECT /*+ BKA(`test1``test2```) */ 1;
1
1
Warnings:
Warning 4209 Unresolved table name "test1`test2`"@"select#1" for BKA hint
Warning 4212 Unresolved table name "test1`test2`"@"select#1" for BKA hint
SELECT /*+ BKA("test1""test2""") */ 1;
1
1
Warnings:
Warning 4209 Unresolved table name "test1""test2"""@"select#1" for BKA hint
Warning 4212 Unresolved table name "test1""test2"""@"select#1" for BKA hint
SET SQL_MODE = '';
# should warn:
SELECT /*+ BKA(" quoted name test") */ 1 FROM t1;
1
Warnings:
Warning 4209 Unresolved table name ` quoted name test`@`select#1` for BKA hint
Warning 4212 Unresolved table name ` quoted name test`@`select#1` for BKA hint
DROP TABLE ` quoted name test`;
DROP TABLE `test1``test2```;
# Valid hints, no warning:
@ -1843,29 +1843,29 @@ CREATE TABLE tableТ (i INT);
SELECT /*+ BKA(tableТ) */ 1 FROM t1;
1
Warnings:
Warning 4209 Unresolved table name `tableТ`@`select#1` for BKA hint
Warning 4212 Unresolved table name `tableТ`@`select#1` for BKA hint
SELECT /*+ BKA(test@tableТ) */ 1 FROM t1;
1
Warnings:
Warning 4208 Query block name `tableТ` is not found for BKA hint
Warning 4211 Query block name `tableТ` is not found for BKA hint
DROP TABLE tableТ;
CREATE TABLE таблица (i INT);
SELECT /*+ BKA(`таблица`) */ 1 FROM t1;
1
Warnings:
Warning 4209 Unresolved table name `таблица`@`select#1` for BKA hint
Warning 4212 Unresolved table name `таблица`@`select#1` for BKA hint
SELECT /*+ BKA(таблица) */ 1 FROM t1;
1
Warnings:
Warning 4209 Unresolved table name `таблица`@`select#1` for BKA hint
Warning 4212 Unresolved table name `таблица`@`select#1` for BKA hint
SELECT /*+ BKA(test@таблица) */ 1 FROM t1;
1
Warnings:
Warning 4208 Query block name `таблица` is not found for BKA hint
Warning 4211 Query block name `таблица` is not found for BKA hint
SELECT /*+ NO_ICP(`\D1`) */ 1 FROM t1;
1
Warnings:
Warning 4209 Unresolved table name `\D1`@`select#1` for NO_ICP hint
Warning 4212 Unresolved table name `\D1`@`select#1` for NO_ICP hint
DROP TABLE таблица;
# derived tables and other subqueries:
@ -1966,7 +1966,7 @@ NO_ICP(@qb ident)
1
1
Warnings:
Warning 4208 Query block name `qb` is not found for NO_ICP hint
Warning 4211 Query block name `qb` is not found for NO_ICP hint
SELECT /*+
? bad syntax
*/ 1;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,791 @@
--source include/have_innodb.inc
--enable_prepare_warnings
--disable_view_protocol # Since optimizer hints are not supported inside views
set default_storage_engine=innodb;
CREATE TABLE t1 (f1 INT NOT NULL);
INSERT INTO t1 VALUES (9),(0), (7);
CREATE TABLE t2 (f1 INT NOT NULL);
INSERT INTO t2 VALUES
(5),(3),(0),(3),(1),(0),(1),(7),(1),(0),(0),(8),(4),(9),(0),(2),(0),(8),(5),(1);
CREATE TABLE t3 (f1 INT NOT NULL);
INSERT INTO t3 VALUES (9),(0), (7), (4), (5);
CREATE TABLE t4 (f1 INT NOT NULL);
INSERT INTO t4 VALUES (0), (7);
CREATE TABLE t5 (f1 INT NOT NULL, PRIMARY KEY(f1));
INSERT INTO t5 VALUES (7);
CREATE TABLE t6(f1 INT NOT NULL, PRIMARY KEY(f1));
INSERT INTO t6 VALUES (7);
ANALYZE TABLE t1, t2, t3, t4, t5, t6;
set join_cache_level = 8;
--echo # Warning expected: hint must be ignored as malformed (no table names)
EXPLAIN EXTENDED
SELECT /*+ JOIN_PREFIX()*/ count(*) FROM t1, t2;
EXPLAIN EXTENDED
SELECT /*+ QB_NAME(q1) JOIN_PREFIX(@q1)*/ count(*) FROM t1, t2;
--echo # Hint must be ignored as malformed (table names are not allowed for the fixed order)
EXPLAIN EXTENDED
SELECT /*+ JOIN_FIXED_ORDER(t2)*/ count(*) FROM t1, t2;
--echo # Hint is applied: QB name is allowed for the fixed order
EXPLAIN EXTENDED
SELECT /*+ QB_NAME(qb1) JOIN_FIXED_ORDER(@qb1)*/ count(*) FROM t2, t1;
--echo # Invalid QB name for the fixed order
EXPLAIN EXTENDED
SELECT /*+ QB_NAME(qb1) JOIN_FIXED_ORDER(@qb3)*/ count(*) FROM t2, t1;
EXPLAIN EXTENDED
SELECT /*+ JOIN_FIXED_ORDER()*/ STRAIGHT_JOIN count(*) FROM t1, t2;
--echo # JOIN_FIXED_ORDER() cannot be combined with other join order hints
EXPLAIN EXTENDED
SELECT /*+ JOIN_PREFIX(t2) JOIN_FIXED_ORDER()*/ count(*) FROM t1, t2;
EXPLAIN EXTENDED
SELECT /*+ JOIN_FIXED_ORDER() JOIN_PREFIX(t2)*/ count(*) FROM t1, t2;
--echo # Multiple join order hints of same type are not allowed (except JOIN_ORDER())
EXPLAIN EXTENDED
SELECT /*+ JOIN_PREFIX(t1) JOIN_PREFIX(t2)*/ count(*) FROM t1, t2;
EXPLAIN EXTENDED
SELECT /*+ JOIN_SUFFIX(t1) JOIN_SUFFIX(t2)*/ count(*) FROM t1, t2;
--echo # Multiple JOIN_ORDER() hints are applied
EXPLAIN EXTENDED
SELECT /*+ QB_NAME(q1) JOIN_ORDER(t2,t1) JOIN_ORDER(@q1 t3,t2)*/ count(*)
FROM t1, t2, t3;
--echo # Variation of last syntax
EXPLAIN EXTENDED
SELECT /*+ QB_NAME(q1) JOIN_ORDER(t2@q1, t1) JOIN_ORDER(t3, t2@q1)*/ count(*)
FROM t1, t2, t3;
--echo # Invalid mix of notations
EXPLAIN EXTENDED
SELECT /*+ QB_NAME(q1) JOIN_PREFIX(@q1 t2, t1@q1)*/ count(*)
FROM t1, t2, t3;
--echo # Hint is correct
EXPLAIN EXTENDED
SELECT /*+ QB_NAME(qb1) JOIN_SUFFIX(t1@qb1, t2)*/ count(*) FROM t1, t2;
EXPLAIN EXTENDED
SELECT /*+ QB_NAME(qb1) JOIN_PREFIX(@qb1, t2)*/ count(*) FROM t1, t2;
--echo # Invalid table name
EXPLAIN EXTENDED
SELECT /*+ JOIN_SUFFIX(t3)*/ count(*) FROM t1, t2;
--echo # Invalid query block name
EXPLAIN EXTENDED
SELECT /*+ QB_NAME(qb1) JOIN_SUFFIX(@qbXXX t1)*/ count(*) FROM t1, t2;
EXPLAIN EXTENDED
SELECT /*+ QB_NAME(qb1) JOIN_SUFFIX(t1, t2@qb3)*/ count(*) FROM t1, t2;
EXPLAIN EXTENDED
SELECT /*+ QB_NAME(qb1) JOIN_FIXED_ORDER(@qbXXX)*/ count(*) FROM t2, t1;
--echo # Warning expected as the hint must not confuse `t2` in the subquery
--echo # with `t2` in the join
EXPLAIN EXTENDED
SELECT /*+ JOIN_PREFIX(t2@subq)*/ (SELECT /*+ QB_NAME(subq)*/ max(f1) FROM t2) as SQ, f1
FROM t2;
--echo # No more than 64 join order hints are allowed. It is hard to construct
--echo # a test case where 64 hints will be applicable and only one, exceeding
--echo # the maximum, will produce a warning. Usually so many hints will conflict
--echo # with each other and generate warnings.
--echo # But in the case below we can observe that the first warning
--echo # is about JOIN_ORDER(t1,t2,t3,t4,t5,t6) which is actually
--echo # the last hint in the list, and it is the 65th in order.
--echo # This happens because the check for exceeding the maximum is performed
--echo # during the preparation phase, while other checks are performed during
--echo # hints application. So, if JOIN_ORDER(t1,t2,t3,t4,t5,t6)
--echo # is mentioned first in the list of warnings, the test case passes.
EXPLAIN EXTENDED
SELECT /*+
JOIN_PREFIX(t2,t1) JOIN_SUFFIX(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2)
JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2)
JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2)
JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2)
JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2)
JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2)
JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2)
JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2)
JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2)
JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2)
JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2)
JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2)
JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2)
JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2)
JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2)
JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2) JOIN_ORDER(t2,t1) JOIN_ORDER(t3,t2)
JOIN_ORDER(t1,t2,t3,t4,t5,t6) */
count(*) FROM t1, t2, t3;
--echo # Original query with no hints
let $query= SELECT count(*) FROM t1 JOIN t2 JOIN t3
WHERE t1.f1 IN (SELECT f1 FROM t4) AND t2.f1 IN (SELECT f1 FROM t5);
eval $query;
eval explain extended $query;
--echo # Check name resolving
let $query= SELECT /*+ QB_NAME(q1) JOIN_PREFIX(t3, t2, t2@subq2) */ count(*) FROM t1 JOIN t2 JOIN t3
WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t2) AND
t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t2);
eval $query;
eval explain extended $query;
--echo # Check conflicting hints
--echo # Second JOIN_PREFIX is conflicting
let $query= SELECT /*+ JOIN_PREFIX(t3, t2, t1) JOIN_PREFIX(t2, t1) */ count(*) FROM t1 JOIN t2 JOIN t3
WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4)
AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5);
eval $query;
eval explain extended $query;
--echo # Second JOIN_SUFFIX is conflicting
let $query= SELECT /*+ JOIN_SUFFIX(t3, t2) JOIN_SUFFIX(t2, t1) */ count(*) FROM t1 JOIN t2 JOIN t3
WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4)
AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5);
eval $query;
eval explain extended $query;
--echo # Both JOIN_ORDERs applicable
let $query= SELECT /*+ JOIN_ORDER(t3, t2) JOIN_ORDER(t1, t2, t5@subq2) */ count(*)
FROM t1 JOIN t2 JOIN t3
WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4)
AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5);
eval $query;
eval explain extended $query;
--echo # Unresolved table name t7 in JOIN_ORDER hint, hint ignored
let $query= SELECT /*+ JOIN_ORDER(t1, t7, t5) */ count(*) FROM t1 JOIN t2 JOIN t3
WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4)
AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5);
eval $query;
eval explain extended $query;
--echo # All hints are applicable
let $query= SELECT /*+ JOIN_PREFIX(t2, t5@subq2, t4@subq1)
JOIN_ORDER(t4@subq1, t3) JOIN_SUFFIX(t1) */ count(*)
FROM t1 JOIN t2 JOIN t3
WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4)
AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5);
eval $query;
eval explain extended $query;
--echo # Second JOIN_ORDER is ignored
let $query= SELECT /*+ JOIN_ORDER(t3, t2) JOIN_ORDER(t2, t3) */ count(*) FROM t1 JOIN t2 JOIN t3
WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4)
AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5);
eval $query;
eval explain extended $query;
--echo # JOIN_SUFFIX is ignored
let $query= SELECT /*+ JOIN_ORDER(t3, t2) JOIN_SUFFIX(t3) */ count(*) FROM t1 JOIN t2 JOIN t3
WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4)
AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5);
eval $query;
eval explain extended $query;
--echo # JOIN_PREFIX is ignored
let $query= SELECT /*+ JOIN_ORDER(t3, t2) JOIN_PREFIX(t2) */ count(*) FROM t1 JOIN t2 JOIN t3
WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4)
AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5);
eval $query;
eval explain extended $query;
--echo # All hints are applicable
let $query= SELECT /*+ JOIN_ORDER(t4@subq1, t3) JOIN_SUFFIX(t1) JOIN_PREFIX(t2, t5@subq2, t4@subq1) */ count(*)
FROM t1 JOIN t2 JOIN t3
WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4)
AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5);
eval $query;
eval explain extended $query;
--echo # JOIN_PREFIX with all tables.
let $query= SELECT /*+ JOIN_PREFIX(t2, t5@subq2, t4@subq1, t3, t1) */ count(*)
FROM t1 JOIN t2 JOIN t3
WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4)
AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5);
eval $query;
eval explain extended $query;
--echo # JOIN_SUFFIX with all tables.
let $query= SELECT /*+ JOIN_SUFFIX(t2, t5@subq2, t4@subq1, t3, t1) */ count(*)
FROM t1 JOIN t2 JOIN t3
WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4)
AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5);
eval $query;
eval explain extended $query;
--echo # JOIN_ORDER with all tables.
let $query= SELECT /*+ JOIN_ORDER(t2, t5@subq2, t4@subq1, t3, t1) */ count(*)
FROM t1 JOIN t2 JOIN t3
WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4)
AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5);
eval $query;
eval explain extended $query;
--echo # JOIN_PREFIX, JOIN_ORDER, JOIN_SUFFIX with all tables.
let $query= SELECT /*+ JOIN_SUFFIX(t2, t5@subq2, t4@subq1, t3, t1)
JOIN_ORDER(t2, t5@subq2, t4@subq1, t3, t1)
JOIN_PREFIX(t2, t5@subq2, t4@subq1, t3, t1) */ count(*)
FROM t1 JOIN t2 JOIN t3
WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4)
AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5);
eval $query;
eval explain extended $query;
--echo # JOIN_ORDER is ignored due to STRAIGHT_JOIN.
let $query= SELECT /*+ QB_NAME(q1) JOIN_ORDER(t2, t1) */ STRAIGHT_JOIN count(*)
FROM t1 JOIN t2 JOIN t3
WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4)
AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5);
eval $query;
eval explain extended $query;
--echo # Test JOIN_FIXED_ORDER.
let $query= SELECT /*+ QB_NAME(q1) JOIN_FIXED_ORDER(@q1) */ count(*) FROM t1 JOIN t2 JOIN t3
WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4)
AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5);
eval $query;
eval explain extended $query;
let $query= SELECT /*+ JOIN_FIXED_ORDER() */ count(*) FROM t1 JOIN t2 JOIN t3
WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4)
AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5);
eval $query;
eval explain extended $query;
let $query= SELECT /*+ QB_NAME(q1) */ count(*) FROM t1 JOIN t2 JOIN t3
WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4)
AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5);
eval $query;
eval explain extended $query;
--echo # Testing STRAIGHT_JOIN
let $query= SELECT count(*) FROM t1 JOIN t2 STRAIGHT_JOIN t3
WHERE t1.f1 IN (SELECT f1 FROM t4) AND t2.f1 IN (SELECT f1 FROM t5);
eval $query;
eval explain extended $query;
--echo # t3 can not be first
let $query= SELECT /*+ JOIN_PREFIX(t3, t1) */ count(*) FROM t1 JOIN t2 STRAIGHT_JOIN t3
WHERE t1.f1 IN (SELECT f1 FROM t4) AND t2.f1 IN (SELECT f1 FROM t5);
eval $query;
eval explain extended $query;
--echo # Hint is applicable
let $query= SELECT /*+ JOIN_PREFIX(t1, t2, t3) */ count(*) FROM t1 JOIN t2 STRAIGHT_JOIN t3
WHERE t1.f1 IN (SELECT f1 FROM t4) AND t2.f1 IN (SELECT f1 FROM t5);
eval $query;
eval explain extended $query;
--echo # Hint is applicable
let $query= SELECT /*+ JOIN_SUFFIX(t4, t5) */ count(*) FROM t1 JOIN t2 STRAIGHT_JOIN t3
WHERE t1.f1 IN (SELECT f1 FROM t4) AND t2.f1 IN (SELECT f1 FROM t5);
eval $query;
eval explain extended $query;
--echo # Alternative syntax
let $query= SELECT /*+ QB_NAME(q1) JOIN_ORDER(@q1 t2, t3, t1) */ count(*)
FROM t1 JOIN t2 JOIN t3
WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4)
AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5);
eval $query;
eval explain extended $query;
--echo # Alternative syntax
let $query= SELECT /*+ QB_NAME(q1) JOIN_PREFIX(@q1 t2, t3, t1) */ count(*)
FROM t1 JOIN t2 JOIN t3
WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4)
AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5);
eval $query;
eval explain extended $query;
--echo # Alternative syntax
let $query= SELECT /*+ QB_NAME(q1) JOIN_SUFFIX(@q1 t2, t3, t1) */ count(*)
FROM t1 JOIN t2 JOIN t3
WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4)
AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5);
eval $query;
eval explain extended $query;
DROP TABLE t1, t2, t3, t4 ,t5, t6;
--echo # Testing embedded join
CREATE TABLE t1 (f1 INT);
CREATE TABLE t2 (f1 INT);
CREATE TABLE t3 (f1 INT);
CREATE TABLE t4 (f1 INT);
EXPLAIN EXTENDED SELECT /*+ JOIN_ORDER(t2, t4, t1) */ 1 FROM t1
JOIN t2 ON 1
RIGHT JOIN t3 ON 1
JOIN t4 ON 1;
EXPLAIN EXTENDED SELECT /*+ JOIN_ORDER(t2, t1, t4) */ 1 FROM t1
JOIN t2 ON 1
RIGHT JOIN t3 ON 1
JOIN t4 ON 1;
EXPLAIN EXTENDED SELECT /*+ JOIN_ORDER(t4, t1, t2) */ 1 FROM t1
JOIN t2 ON 1
RIGHT JOIN t3 ON 1
JOIN t4 ON 1;
EXPLAIN EXTENDED SELECT /*+ JOIN_ORDER(t3, t4) */ 1 FROM t1
JOIN t2 ON 1
RIGHT JOIN t3 ON 1
JOIN t4 ON 1;
EXPLAIN SELECT /*+ JOIN_ORDER(t4, t3) */ 1 FROM t1
JOIN t2 ON 1
RIGHT JOIN t3 ON 1
JOIN t4 ON 1;
EXPLAIN EXTENDED SELECT /*+ JOIN_SUFFIX(t1) */ 1 FROM t1
JOIN t2 ON 1
RIGHT JOIN t3 ON 1
JOIN t4 ON 1;
EXPLAIN EXTENDED SELECT /*+ JOIN_SUFFIX(t2, t1) */ 1 FROM t1
JOIN t2 ON 1
RIGHT JOIN t3 ON 1
JOIN t4 ON 1;
DROP TABLE t1, t2, t3, t4;
CREATE TABLE t1
(
f1 INT(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (f1)
);
INSERT INTO t1 VALUES (1),(2),(3);
CREATE TABLE t2
(
f1 INT(11) DEFAULT NULL
);
INSERT INTO t2 VALUES (0),(1),(2);
CREATE TABLE t3
(
f1 INT(11) DEFAULT NULL
);
INSERT INTO t3 VALUES (0),(1),(2);
--echo # Original query
EXPLAIN EXTENDED DELETE
FROM ta1.* USING t1 AS ta1 JOIN t1 AS ta2 ON 1
RIGHT OUTER JOIN t2 ON (ta1.f1 = t2.f1)
WHERE (9) IN (SELECT f1 FROM t3);
--echo # Applicable hint
EXPLAIN EXTENDED DELETE /*+ JOIN_PREFIX(t2, t3, ta2) */
FROM ta1.* USING t1 AS ta1 JOIN t1 AS ta2 ON 1
RIGHT OUTER JOIN t2 ON (ta1.f1 = t2.f1)
WHERE (9) IN (SELECT f1 FROM t3);
--echo # Applicable hint
EXPLAIN EXTENDED DELETE /*+ JOIN_PREFIX(t2, t3, ta1, ta2) */
FROM ta1.* USING t1 AS ta1 JOIN t1 AS ta2 ON 1
RIGHT OUTER JOIN t2 ON (ta1.f1 = t2.f1)
WHERE (9) IN (SELECT f1 FROM t3);
--echo # Applicable hint
EXPLAIN EXTENDED DELETE /*+ JOIN_PREFIX(t2, t3, ta2, ta1) */
FROM ta1.* USING t1 AS ta1 JOIN t1 AS ta2 ON 1
RIGHT OUTER JOIN t2 ON (ta1.f1 = t2.f1)
WHERE (9) IN (SELECT f1 FROM t3);
--echo # Hint should be ignored
EXPLAIN EXTENDED DELETE /*+ JOIN_SUFFIX(ta2, t3, ta1) */
FROM ta1.* USING t1 AS ta1 JOIN t1 AS ta2 ON 1
RIGHT OUTER JOIN t2 ON (ta1.f1 = t2.f1)
WHERE (9) IN (SELECT f1 FROM t3);
--echo # Both hints are ignored
EXPLAIN EXTENDED DELETE /*+ JOIN_PREFIX(ta1, t2, t3) JOIN_SUFFIX(t3, ta2) */
FROM ta1.* USING t1 AS ta1 JOIN t1 AS ta2 ON 1
RIGHT OUTER JOIN t2 ON (ta1.f1 = t2.f1)
WHERE (9) IN (SELECT f1 FROM t3);
DROP TABLE t1, t2, t3;
--echo # Const table behavior, table order is not changed, hint is applicable.
--echo # Note: Const tables are excluded from the process of dependency setting
--echo # since they are always first in the table order. Note that it
--echo # does not prevent the hint from being applied to the non-const
--echo # tables of the hint.
CREATE TABLE t1(f1 INT) ENGINE=MyISAM;
INSERT INTO t1 VALUES (1);
CREATE TABLE t2(f1 INT) ENGINE=InnoDB;
INSERT INTO t2 VALUES (1);
EXPLAIN EXTENDED SELECT /*+ JOIN_PREFIX(t1, t2) */ 1 FROM t1 JOIN t2 ON t1.f1 = t2.f1;
EXPLAIN EXTENDED SELECT /*+ JOIN_PREFIX(t2, t1) */ 1 FROM t1 JOIN t2 ON t1.f1 = t2.f1;
DROP TABLE t1, t2;
--echo #
--echo # Bug#23144274 WL9158:ASSERTION `JOIN->BEST_READ < DOUBLE(1.79769313486231570815E+308L)' FAILED
--echo #
CREATE TABLE t1 (
f1 int(11) NOT NULL AUTO_INCREMENT,
f2 varchar(255) DEFAULT NULL,
PRIMARY KEY (f1));
CREATE TABLE t2 (
f1 int(11) NOT NULL AUTO_INCREMENT,
f2 varchar(255) CHARACTER SET utf8mb3 DEFAULT NULL,
f3 varchar(10) DEFAULT NULL,
PRIMARY KEY (f1),
KEY f3(f3));
EXPLAIN SELECT /*+ JOIN_SUFFIX(t1, t2) */ t2.f3 FROM t2 LEFT JOIN t1
ON t2.f1 = t1.f1 WHERE t1.f2 NOT LIKE ('FMGAU') OR t2.f2 > 't';
DROP TABLE t1, t2;
CREATE TABLE t1
(
f1 int(11) DEFAULT NULL,
KEY f1 (f1)
);
CREATE TABLE t2
(
f1 int(11) DEFAULT NULL,
f2 varchar(255) CHARACTER SET utf8mb3 DEFAULT NULL,
KEY f2 (f2),
KEY f1 (f1)
);
CREATE TABLE t3 (
f1 int(11) DEFAULT NULL,
f2 varchar(255) CHARACTER SET cp932 DEFAULT NULL,
KEY f1 (f1),
KEY f2 (f2)
);
EXPLAIN EXTENDED SELECT /*+ JOIN_ORDER(t2, t3) JOIN_ORDER(t1, t2) */ t3.f1
FROM ( t2 INNER JOIN t3 ON t3.f2 = t2.f2 LEFT JOIN t1 ON t1.f1 = t3.f1 )
WHERE NOT (t2.f1 >= 7);
EXPLAIN EXTENDED SELECT /*+ JOIN_ORDER(t1, t2) JOIN_ORDER(t2, t3) */ t3.f1
FROM ( t2 INNER JOIN t3 ON t3.f2 = t2.f2 LEFT JOIN t1 ON t1.f1 = t3.f1 )
WHERE NOT (t2.f1 >= 7);
DROP TABLE t1, t2, t3;
CREATE TABLE t1 (
f1 INT(11) NOT NULL AUTO_INCREMENT,
f2 INT(11) DEFAULT NULL,
PRIMARY KEY (f1)
);
CREATE TABLE t2 (
f1 INT(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (f1)
);
EXPLAIN EXTENDED SELECT /*+ JOIN_PREFIX(t1, t1) */ t2.f1 FROM t1 JOIN t2 ON t1.f2 = t2.f1;
DROP TABLE t1, t2;
CREATE TABLE t1
(
f1 DATETIME,
f2 DATE,
f3 VARCHAR(1),
KEY (f1)
) ENGINE=myisam;
CREATE TABLE t2
(
f1 VARCHAR(1),
f2 INT,
f3 VARCHAR(1),
KEY (f1)
) ENGINE=innodb;
CREATE TABLE t3
(
f1 VARCHAR(1),
f2 DATE,
f3 DATETIME,
f4 INT
) ENGINE=myisam;
# Warning "Field or reference 'test.als2.f2' of SELECT #2 was resolved in SELECT #1"
# is generated during both PREPARE and EXECUTE of a prepared statement, so disable
# the PS protocol for this test
--disable_ps_protocol
EXPLAIN EXTENDED
UPDATE /*+ JOIN_ORDER(t2, als1, als3) JOIN_FIXED_ORDER() */ t3 AS als1
JOIN t1 AS als2 ON (als1.f3 = als2 .f1)
JOIN t1 AS als3 ON (als1.f1 = als3.f3)
RIGHT OUTER JOIN t3 AS als4 ON (als1.f3 = als4.f2)
SET als1.f4 = 'eogqjvbhzodzimqahyzlktkbexkhdwxwgifikhcgblhgswxyutepc'
WHERE ('i','b') IN (SELECT f3, f1 FROM t2 WHERE f2 <> f2 AND als2.f2 IS NULL);
--enable_ps_protocol
DROP TABLE t1, t2, t3;
CREATE TABLE t1(
f1 VARCHAR(1)) ENGINE=myisam;
CREATE TABLE t2(
f1 VARCHAR(1),
f2 VARCHAR(1),
f3 DATETIME,
KEY(f2)) ENGINE=innodb;
CREATE TABLE t3(
f1 INT,
f2 DATE,
f3 VARCHAR(1),
KEY(f3)) ENGINE=myisam;
CREATE TABLE t4(
f1 VARCHAR(1),
KEY(f1)) ENGINE=innodb;
ALTER TABLE t4 DISABLE KEYS;
INSERT INTO t4 VALUES ('x'), (NULL), ('d'), ('x'), ('u');
ALTER TABLE t4 ENABLE KEYS;
CREATE TABLE t5(
f1 VARCHAR(1),
KEY(f1) ) ENGINE=myisam;
INSERT INTO t5 VALUES (NULL), ('s'), ('c'), ('x'), ('z');
EXPLAIN EXTENDED UPDATE /*+ JOIN_ORDER(t4, alias1, alias3) */ t3 AS alias1
JOIN t5 ON (alias1.f3 = t5.f1)
JOIN t3 AS alias3 ON (alias1.f2 = alias3.f2 )
RIGHT OUTER JOIN t1 ON (alias1.f3 = t1.f1)
SET alias1.f1 = -1
WHERE ( 'v', 'o' ) IN
(SELECT DISTINCT t2.f1, t2.f2 FROM t4 RIGHT OUTER JOIN t2 ON (t4.f1 = t2.f1)
WHERE t2.f3 BETWEEN '2001-10-04' AND '2003-05-15');
DROP TABLE t1, t2, t3, t4, t5;
CREATE TABLE t1 (
f1 INT(11) DEFAULT NULL,
f3 VARCHAR(1) DEFAULT NULL,
f2 INT(11) DEFAULT NULL,
KEY (f1)
) ENGINE=MyISAM;
CREATE TABLE t2(
f1 INT(11) DEFAULT NULL
) ENGINE=MyISAM;
CREATE TABLE t3 (
f1 VARCHAR(1) DEFAULT NULL,
f2 VARCHAR(1) DEFAULT NULL,
KEY (f2)
) ENGINE=InnoDB;
# Warning "Field or reference 'test.ta2.f3' of SELECT #2 was resolved in SELECT #1"
# is generated during both PREPARE and EXECUTE of a prepared statement, so disable
# the PS protocol for this test
--disable_ps_protocol
EXPLAIN EXTENDED UPDATE /*+ JOIN_SUFFIX(ta1, t2) */
t1 AS ta1 JOIN t1 AS ta2 ON ta1.f1 = ta2.f1 RIGHT JOIN t2 ON (ta1.f1 = t2.f1)
SET ta1.f2 = '', ta2.f3 = ''
WHERE ('n', 'r') IN (SELECT f2, f1 FROM t3 WHERE f1 <> f2 XOR ta2.f3 IS NULL);
--enable_ps_protocol
DROP TABLE t1, t2, t3;
CREATE TABLE t2(f1 VARCHAR(255) DEFAULT NULL, f2 INT(11) DEFAULT NULL,
KEY (f1), KEY (f2)) charset latin1 ENGINE=MyISAM;
CREATE TABLE t4(f1 INT(11) DEFAULT NULL, f2 INT(11) DEFAULT NULL, KEY (f1))
charset latin1 ENGINE=MyISAM;
CREATE TABLE t5(f1 INT(11) NOT NULL AUTO_INCREMENT, f2 INT(11) DEFAULT NULL, PRIMARY KEY (f1))
charset latin1 ENGINE=InnoDB;
CREATE TABLE t6(f1 INT(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (f1))
charset latin1 ENGINE=InnoDB;
CREATE TABLE t7 (f1 VARCHAR(255) DEFAULT NULL)
charset latin1 ENGINE=InnoDB;
CREATE TABLE t10(f1 INT(11) NOT NULL AUTO_INCREMENT,f2 INT(11) DEFAULT NULL,f3 VARCHAR(10) DEFAULT NULL,
PRIMARY KEY (f1),KEY (f2),KEY (f3)) charset latin1 ENGINE=MyISAM;
CREATE TABLE t11(f1 INT(11) DEFAULT NULL,f2 VARCHAR(10) DEFAULT NULL,
KEY (f1),KEY (f2)) charset latin1 ENGINE=InnoDB;
EXPLAIN EXTENDED
SELECT /*+ JOIN_ORDER(alias11, alias8) */ 1
FROM t4 AS alias4
LEFT JOIN t5 AS alias5 JOIN t6 AS alias6 ON alias5.f2 = alias6.f1
LEFT JOIN t7 AS alias7 JOIN t2 AS alias8 ON alias7.f1 = alias8.f1
ON alias5.f1 = alias8.f2 ON alias4.f2 = alias6.f1
JOIN t10 AS alias10 JOIN t11 AS alias11 ON alias10.f1 = alias11.f1
ON alias4.f2 = alias11.f2;
EXPLAIN EXTENDED
SELECT /*+ JOIN_ORDER(alias11, alias10, alias8, alias7) */ 1
FROM t4 AS alias4
LEFT JOIN t5 AS alias5 JOIN t6 AS alias6 ON alias5.f2 = alias6.f1
LEFT JOIN t7 AS alias7 JOIN t2 AS alias8 ON alias7.f1 = alias8.f1
ON alias5.f1 = alias8.f2 ON alias4.f2 = alias6.f1
JOIN t10 AS alias10 JOIN t11 AS alias11 ON alias10.f1 = alias11.f1
ON alias4.f2 = alias11.f2;
DROP TABLES t2, t4, t5, t6, t7, t10, t11;
CREATE TABLE t1 (f1 VARCHAR(255) DEFAULT NULL, f2 VARCHAR(255) DEFAULT NULL,
KEY (f1), KEY (f2)) ENGINE=InnoDB;
CREATE TABLE t2(f1 VARCHAR(255) DEFAULT NULL, f2 INT(11) DEFAULT NULL,
KEY (f1), KEY (f2)) ENGINE=InnoDB;
CREATE TABLE t3(
f1 INT(11) NOT NULL AUTO_INCREMENT, f2 VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (f1), KEY (f2)) ENGINE=InnoDB;
CREATE TABLE t4(f1 INT(11) DEFAULT NULL, f2 INT(11) DEFAULT NULL, KEY (f1)) ENGINE=InnoDB;
CREATE TABLE t6(f1 INT(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (f1)) ENGINE=InnoDB;
CREATE TABLE t7 (f1 VARCHAR(255) DEFAULT NULL) ENGINE=InnoDB;
CREATE TABLE t10(f1 INT(11) NOT NULL AUTO_INCREMENT,f2 INT(11) DEFAULT NULL,f3 VARCHAR(10) DEFAULT NULL,
PRIMARY KEY (f1),KEY (f2),KEY (f3)) ENGINE=InnoDB;
EXPLAIN EXTENDED SELECT /*+ JOIN_ORDER(alias8, alias6) */ 1
FROM t1 AS alias1
LEFT JOIN t7 alias7
JOIN t2 AS alias2
LEFT JOIN t3 AS alias3 JOIN t4 AS alias4 ON alias4.f2 = alias3.f1
ON alias4.f1 = alias2.f1
ON alias2.f2 = alias7.f1
JOIN t10 AS alias5
LEFT JOIN t6 AS alias6 JOIN t2 AS alias8 ON alias6.f1 = alias8.f2
ON alias6.f1 = alias5.f1
ON alias5.f3 = alias7.f1
ON alias1.f2 = alias7.f1;
DROP TABLES t1, t2, t3, t4, t6, t7, t10;
--echo #
--echo # Bug#23144230 WL#9158 : OPT_HINTS_QB::APPLY_JOIN_ORDER_HINTS - MYSQLD GOT SIGNAL 11
--echo #
CREATE TABLE t1 (
f1 int(11) NOT NULL AUTO_INCREMENT,
f2 int(11) DEFAULT NULL,
f3 int(11) DEFAULT NULL,
PRIMARY KEY (f1),
KEY f2 (f2))
ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
CREATE TABLE t2 (
f1 int(11) NOT NULL AUTO_INCREMENT,
f2 int(11) DEFAULT NULL,
f3 int(11) DEFAULT NULL,
PRIMARY KEY (f1),
KEY f2 (f2))
ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
EXPLAIN EXTENDED SELECT /*+ JOIN_PREFIX(alias1) */ alias2.f3 AS field1
FROM ( SELECT * FROM t1 ) AS alias1 JOIN ( SELECT * FROM t2 ) AS alias2
ON alias1.f2 = alias2.f3
WHERE alias2.f2 IS NULL HAVING (field1 != 3 AND field1 >= 8);
DROP TABLE t1, t2;
--echo #
--echo # Bug#23651098 WL#9158 : ASSERTION `!(SJ_NEST->SJ_INNER_TABLES & JOIN->CONST_TABLE_MAP)' FAILED
--echo #
CREATE TABLE t1
(
f1 INT(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (f1)
) ENGINE=InnoDB;
CREATE TABLE t2
(
f1 VARCHAR(1) DEFAULT NULL
) ENGINE=MyISAM;
CREATE TABLE t3
(
f1 VARCHAR(1) DEFAULT NULL
) ENGINE=MyISAM;
EXPLAIN EXTENDED SELECT /*+ JOIN_PREFIX(t2, t1) */ t1.f1 FROM t1, t2
WHERE t2.f1 IN (SELECT t3.f1 FROM t3) AND t1.f1 = 183;
DROP TABLE t1, t2, t3;
--echo #
--echo # Bug23715779 SELECT QUERY WITH JOIN_PREFIX() HINT RETURNS INCORRECT RESULT
--echo #
CREATE TABLE t1(f1 INT(11) NOT NULL);
INSERT INTO t1 VALUES (10);
CREATE TABLE t2
(
f1 INT(11) NOT NULL AUTO_INCREMENT,
f2 INT(11) DEFAULT NULL,
PRIMARY KEY (f1),
KEY (f2)
);
INSERT INTO t2 VALUES (1, 7), (2, 1), (4, 7);
CREATE TABLE t4(f1 INT DEFAULT NULL);
INSERT INTO t4 VALUES (2);
ANALYZE TABLE t1, t2, t4;
let $query=
SELECT
COUNT(*) FROM t1 JOIN t2 AS ta3 JOIN t2 AS ta4
WHERE ta4.f1 IN (SELECT /*+ QB_NAME(qb1) */ f1 FROM t4) AND
ta3.f2 IN (SELECT /*+ QB_NAME(qb2) */ f2 FROM t2);
eval $query;
eval explain extended $query;
let $query=
SELECT /*+ JOIN_PREFIX(t2@qb2, t4@qb1, ta3, ta4) */
COUNT(*) FROM t1 JOIN t2 AS ta3 JOIN t2 AS ta4
WHERE ta4.f1 IN (SELECT /*+ QB_NAME(qb1) */ f1 FROM t4) AND
ta3.f2 IN (SELECT /*+ QB_NAME(qb2) */ f2 FROM t2);
eval $query;
eval explain extended $query;
DROP TABLE t1, t2, t4;

View File

@ -158,7 +158,7 @@ a
3
4
Warnings:
Warning 4208 Query block name `qb1` is not found for SUBQUERY hint
Warning 4211 Query block name `qb1` is not found for SUBQUERY hint
SELECT /*+ SUBQUERY() */ a FROM t1;
a
1
@ -195,15 +195,15 @@ SELECT /*+ SEMIJOIN() SEMIJOIN(dupsweedout) NO_SEMIJOIN(firstmatch)*/ a FROM t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index
Warnings:
Warning 4207 Hint SEMIJOIN(DUPSWEEDOUT) is ignored as conflicting/duplicated
Warning 4207 Hint NO_SEMIJOIN(FIRSTMATCH) is ignored as conflicting/duplicated
Warning 4210 Hint SEMIJOIN(DUPSWEEDOUT) is ignored as conflicting/duplicated
Warning 4210 Hint NO_SEMIJOIN(FIRSTMATCH) is ignored as conflicting/duplicated
Note 1003 select /*+ SEMIJOIN(@`select#1`) */ `test`.`t1`.`a` AS `a` from `test`.`t1`
EXPLAIN EXTENDED
SELECT /*+ SEMIJOIN(loosescan,materialization) SEMIJOIN(dupsweedout)*/ a FROM t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index
Warnings:
Warning 4207 Hint SEMIJOIN(DUPSWEEDOUT) is ignored as conflicting/duplicated
Warning 4210 Hint SEMIJOIN(DUPSWEEDOUT) is ignored as conflicting/duplicated
Note 1003 select /*+ SEMIJOIN(@`select#1` LOOSESCAN, MATERIALIZATION) */ `test`.`t1`.`a` AS `a` from `test`.`t1`
EXPLAIN EXTENDED
SELECT /*+ NO_SEMIJOIN(firstmatch,loosescan,materialization) SEMIJOIN() NO_SEMIJOIN()*/ a
@ -211,8 +211,8 @@ FROM t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index
Warnings:
Warning 4207 Hint SEMIJOIN() is ignored as conflicting/duplicated
Warning 4207 Hint NO_SEMIJOIN() is ignored as conflicting/duplicated
Warning 4210 Hint SEMIJOIN() is ignored as conflicting/duplicated
Warning 4210 Hint NO_SEMIJOIN() is ignored as conflicting/duplicated
Note 1003 select /*+ NO_SEMIJOIN(@`select#1` FIRSTMATCH, LOOSESCAN, MATERIALIZATION) */ `test`.`t1`.`a` AS `a` from `test`.`t1`
EXPLAIN EXTENDED
SELECT /*+ QB_NAME(qb1) SEMIJOIN(@qb1) SEMIJOIN(loosescan) NO_SEMIJOIN(@qb1 dupsweedout)*/ a
@ -220,36 +220,36 @@ FROM t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index
Warnings:
Warning 4207 Hint SEMIJOIN(LOOSESCAN) is ignored as conflicting/duplicated
Warning 4207 Hint NO_SEMIJOIN(@`qb1` DUPSWEEDOUT) is ignored as conflicting/duplicated
Warning 4210 Hint SEMIJOIN(LOOSESCAN) is ignored as conflicting/duplicated
Warning 4210 Hint NO_SEMIJOIN(@`qb1` DUPSWEEDOUT) is ignored as conflicting/duplicated
Note 1003 select /*+ QB_NAME(`qb1`) SEMIJOIN(@`qb1`) */ `test`.`t1`.`a` AS `a` from `test`.`t1`
EXPLAIN EXTENDED SELECT /*+ SEMIJOIN(firstmatch) NO_SEMIJOIN()*/ a FROM t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index
Warnings:
Warning 4207 Hint NO_SEMIJOIN() is ignored as conflicting/duplicated
Warning 4210 Hint NO_SEMIJOIN() is ignored as conflicting/duplicated
Note 1003 select /*+ SEMIJOIN(@`select#1` FIRSTMATCH) */ `test`.`t1`.`a` AS `a` from `test`.`t1`
EXPLAIN EXTENDED
SELECT /*+ SUBQUERY(materialization) SUBQUERY(intoexists)*/ a FROM t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index
Warnings:
Warning 4207 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated
Warning 4210 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated
Note 1003 select /*+ SUBQUERY(@`select#1` MATERIALIZATION) */ `test`.`t1`.`a` AS `a` from `test`.`t1`
EXPLAIN EXTENDED
SELECT /*+ SEMIJOIN() SUBQUERY(materialization) SUBQUERY(intoexists)*/ a FROM t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index
Warnings:
Warning 4207 Hint SUBQUERY(MATERIALIZATION) is ignored as conflicting/duplicated
Warning 4207 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated
Warning 4210 Hint SUBQUERY(MATERIALIZATION) is ignored as conflicting/duplicated
Warning 4210 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated
Note 1003 select /*+ SEMIJOIN(@`select#1`) */ `test`.`t1`.`a` AS `a` from `test`.`t1`
EXPLAIN EXTENDED
SELECT /*+ SUBQUERY(materialization) SUBQUERY(intoexists)*/ a FROM t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index
Warnings:
Warning 4207 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated
Warning 4210 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated
Note 1003 select /*+ SUBQUERY(@`select#1` MATERIALIZATION) */ `test`.`t1`.`a` AS `a` from `test`.`t1`
EXPLAIN EXTENDED
SELECT /*+ SUBQUERY(materialization) SUBQUERY(intoexists) SUBQUERY(materialization)*/ a
@ -257,32 +257,32 @@ FROM t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index
Warnings:
Warning 4207 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated
Warning 4207 Hint SUBQUERY(MATERIALIZATION) is ignored as conflicting/duplicated
Warning 4210 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated
Warning 4210 Hint SUBQUERY(MATERIALIZATION) is ignored as conflicting/duplicated
Note 1003 select /*+ SUBQUERY(@`select#1` MATERIALIZATION) */ `test`.`t1`.`a` AS `a` from `test`.`t1`
EXPLAIN EXTENDED
SELECT /*+ SUBQUERY(materialization) SEMIJOIN(firstmatch) SUBQUERY(intoexists)*/ a FROM t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index
Warnings:
Warning 4207 Hint SEMIJOIN(FIRSTMATCH) is ignored as conflicting/duplicated
Warning 4207 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated
Warning 4210 Hint SEMIJOIN(FIRSTMATCH) is ignored as conflicting/duplicated
Warning 4210 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated
Note 1003 select /*+ SUBQUERY(@`select#1` MATERIALIZATION) */ `test`.`t1`.`a` AS `a` from `test`.`t1`
EXPLAIN EXTENDED
SELECT /*+ QB_NAME(qb1) SEMIJOIN(@qb1) SUBQUERY(@qb1 materialization) SUBQUERY(intoexists)*/ a FROM t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index
Warnings:
Warning 4207 Hint SUBQUERY(@`qb1` MATERIALIZATION) is ignored as conflicting/duplicated
Warning 4207 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated
Warning 4210 Hint SUBQUERY(@`qb1` MATERIALIZATION) is ignored as conflicting/duplicated
Warning 4210 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated
Note 1003 select /*+ QB_NAME(`qb1`) SEMIJOIN(@`qb1`) */ `test`.`t1`.`a` AS `a` from `test`.`t1`
EXPLAIN EXTENDED
SELECT /*+ QB_NAME(qb1) SUBQUERY(@qb1 materialization) SEMIJOIN(@qb1 firstmatch) SUBQUERY(intoexists)*/ a FROM t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 100.00 Using index
Warnings:
Warning 4207 Hint SEMIJOIN(@`qb1` FIRSTMATCH) is ignored as conflicting/duplicated
Warning 4207 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated
Warning 4210 Hint SEMIJOIN(@`qb1` FIRSTMATCH) is ignored as conflicting/duplicated
Warning 4210 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated
Note 1003 select /*+ QB_NAME(`qb1`) SUBQUERY(@`qb1` MATERIALIZATION) */ `test`.`t1`.`a` AS `a` from `test`.`t1`
EXPLAIN EXTENDED
SELECT /*+ SEMIJOIN(@qb1) SEMIJOIN(loosescan) NO_SEMIJOIN(@qb1 dupsweedout)*/ a
@ -291,7 +291,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 4 100.00
2 DERIVED t2 index NULL a 4 NULL 4 100.00 Using index
Warnings:
Warning 4207 Hint NO_SEMIJOIN(@`qb1` DUPSWEEDOUT) is ignored as conflicting/duplicated
Warning 4210 Hint NO_SEMIJOIN(@`qb1` DUPSWEEDOUT) is ignored as conflicting/duplicated
Note 1003 /* select#1 */ select /*+ SEMIJOIN(@`qb1`) SEMIJOIN(@`select#1` LOOSESCAN) */ `tt`.`a` AS `a` from (/* select#2 */ select /*+ QB_NAME(`qb1`) */ `test`.`t2`.`a` AS `a` from `test`.`t2`) `tt`
DROP TABLE t1, t2 ,t3;
set optimizer_switch=default;
@ -1434,7 +1434,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index
2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index
Warnings:
Warning 4207 Hint SEMIJOIN() is ignored as conflicting/duplicated
Warning 4210 Hint SEMIJOIN() is ignored as conflicting/duplicated
Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`select#2`) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <expr_cache><`test`.`t2`.`a`>(<in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))))
# Try opposite order
EXPLAIN EXTENDED
@ -1444,7 +1444,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 index PRIMARY PRIMARY 4 NULL 4 100.00 Using index
1 PRIMARY t2 ref a a 4 test.t1.a 1 100.00 Using index
Warnings:
Warning 4207 Hint NO_SEMIJOIN() is ignored as conflicting/duplicated
Warning 4210 Hint NO_SEMIJOIN() is ignored as conflicting/duplicated
Note 1003 select /*+ SEMIJOIN(@`select#2`) */ `test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where `test`.`t2`.`a` = `test`.`t1`.`a`
# Specify at different levels, hint inside block has effect
EXPLAIN EXTENDED
@ -1454,7 +1454,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 index PRIMARY PRIMARY 4 NULL 4 100.00 Using index
1 PRIMARY t2 ref a a 4 test.t1.a 1 100.00 Using index
Warnings:
Warning 4207 Hint NO_SEMIJOIN(@`subq` ) is ignored as conflicting/duplicated
Warning 4210 Hint NO_SEMIJOIN(@`subq` ) is ignored as conflicting/duplicated
Note 1003 select /*+ SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where `test`.`t2`.`a` = `test`.`t1`.`a`
# Specify at different levels, opposite order
EXPLAIN EXTENDED
@ -1464,7 +1464,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index
2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index
Warnings:
Warning 4207 Hint SEMIJOIN(@`subq` ) is ignored as conflicting/duplicated
Warning 4210 Hint SEMIJOIN(@`subq` ) is ignored as conflicting/duplicated
Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <expr_cache><`test`.`t2`.`a`>(<in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))))
# Duplicate hints also gives warning, but hint has effect
EXPLAIN EXTENDED
@ -1474,7 +1474,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 index PRIMARY PRIMARY 4 NULL 4 100.00 Using index
1 PRIMARY t2 ref a a 4 test.t1.a 1 100.00 Using index
Warnings:
Warning 4207 Hint SEMIJOIN(@`subq` ) is ignored as conflicting/duplicated
Warning 4210 Hint SEMIJOIN(@`subq` ) is ignored as conflicting/duplicated
Note 1003 select /*+ SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where `test`.`t2`.`a` = `test`.`t1`.`a`
EXPLAIN EXTENDED
SELECT /*+ NO_SEMIJOIN(@subq) */ * FROM t2
@ -1483,7 +1483,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index
2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index
Warnings:
Warning 4207 Hint NO_SEMIJOIN(@`subq` ) is ignored as conflicting/duplicated
Warning 4210 Hint NO_SEMIJOIN(@`subq` ) is ignored as conflicting/duplicated
Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <expr_cache><`test`.`t2`.`a`>(<in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))))
# Multiple subqueries with conflicting hints
EXPLAIN EXTENDED
@ -1495,8 +1495,8 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; Start temporary; End temporary
2 DEPENDENT SUBQUERY t3 index_subquery a a 4 func 1 100.00 Using index
Warnings:
Warning 4207 Hint SEMIJOIN(@`subq1` LOOSESCAN) is ignored as conflicting/duplicated
Warning 4207 Hint SEMIJOIN(@`subq2` FIRSTMATCH) is ignored as conflicting/duplicated
Warning 4210 Hint SEMIJOIN(@`subq1` LOOSESCAN) is ignored as conflicting/duplicated
Warning 4210 Hint SEMIJOIN(@`subq2` FIRSTMATCH) is ignored as conflicting/duplicated
Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq1`) SEMIJOIN(@`subq2` LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t2`) where `test`.`t2`.`a` = `test`.`t1`.`b` and <expr_cache><`test`.`t1`.`a`>(<in_optimizer>(`test`.`t1`.`a`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`a`) in t3 on a))))
EXPLAIN EXTENDED
SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN) SEMIJOIN(@subq2 FIRSTMATCH) */ * FROM t1
@ -1507,8 +1507,8 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t3 ref a a 4 test.t1.a 1 100.00 Using index; FirstMatch(t1)
1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; Start temporary; End temporary
Warnings:
Warning 4207 Hint SEMIJOIN(@`subq1` LOOSESCAN) is ignored as conflicting/duplicated
Warning 4207 Hint SEMIJOIN(@`subq2` FIRSTMATCH) is ignored as conflicting/duplicated
Warning 4210 Hint SEMIJOIN(@`subq1` LOOSESCAN) is ignored as conflicting/duplicated
Warning 4210 Hint SEMIJOIN(@`subq2` FIRSTMATCH) is ignored as conflicting/duplicated
Note 1003 select /*+ NO_SEMIJOIN(@`subq1` LOOSESCAN) SEMIJOIN(@`subq2` LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t3`.`a` = `test`.`t1`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b`
# Conflicting hints in same hint comment
EXPLAIN EXTENDED
@ -1520,7 +1520,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.a 1 25.00 Using where
1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; FirstMatch(t1)
Warnings:
Warning 4207 Hint SEMIJOIN(@`subq1` FIRSTMATCH) is ignored as conflicting/duplicated
Warning 4210 Hint SEMIJOIN(@`subq1` FIRSTMATCH) is ignored as conflicting/duplicated
Note 1003 select /*+ SEMIJOIN(@`subq1` LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t1`.`a` = `test`.`t3`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b`
EXPLAIN EXTENDED
SELECT /*+ SEMIJOIN(@subq1 LOOSESCAN) NO_SEMIJOIN(@subq1 LOOSESCAN) */ *
@ -1532,7 +1532,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t3.a 1 25.00 Using where
1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; FirstMatch(t1)
Warnings:
Warning 4207 Hint NO_SEMIJOIN(@`subq1` LOOSESCAN) is ignored as conflicting/duplicated
Warning 4210 Hint NO_SEMIJOIN(@`subq1` LOOSESCAN) is ignored as conflicting/duplicated
Note 1003 select /*+ SEMIJOIN(@`subq1` LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t1`.`a` = `test`.`t3`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b`
EXPLAIN EXTENDED
SELECT /*+ NO_SEMIJOIN(@subq1 LOOSESCAN) NO_SEMIJOIN(@subq1 FIRSTMATCH) */ *
@ -1544,7 +1544,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t3 ref a a 4 test.t1.a 1 100.00 Using index; FirstMatch(t1)
1 PRIMARY t2 ref a a 4 test.t1.b 1 66.67 Using index; FirstMatch(t3)
Warnings:
Warning 4207 Hint NO_SEMIJOIN(@`subq1` FIRSTMATCH) is ignored as conflicting/duplicated
Warning 4210 Hint NO_SEMIJOIN(@`subq1` FIRSTMATCH) is ignored as conflicting/duplicated
Note 1003 select /*+ NO_SEMIJOIN(@`subq1` LOOSESCAN) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t3`) semi join (`test`.`t2`) where `test`.`t3`.`a` = `test`.`t1`.`a` and `test`.`t2`.`a` = `test`.`t1`.`b`
# Non-supported strategies should give warnings
EXPLAIN EXTENDED
@ -1770,7 +1770,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index
2 MATERIALIZED t1 index NULL PRIMARY 4 NULL 4 100.00 Using index
Warnings:
Warning 4207 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated
Warning 4210 Hint SUBQUERY(INTOEXISTS) is ignored as conflicting/duplicated
Note 1003 /* select#1 */ select /*+ SUBQUERY(@`select#2` MATERIALIZATION) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <expr_cache><`test`.`t2`.`a`>(<in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (/* select#2 */ select `test`.`t1`.`a` from `test`.`t1` ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on distinct_key where `test`.`t2`.`a` = `<subquery2>`.`a`))))
# Try opposite order
EXPLAIN EXTENDED
@ -1781,7 +1781,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index
2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index
Warnings:
Warning 4207 Hint SUBQUERY(MATERIALIZATION) is ignored as conflicting/duplicated
Warning 4210 Hint SUBQUERY(MATERIALIZATION) is ignored as conflicting/duplicated
Note 1003 /* select#1 */ select /*+ SUBQUERY(@`select#2` INTOEXISTS) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <expr_cache><`test`.`t2`.`a`>(<in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))))
# Specify at different levels, hint inside block has effect
EXPLAIN EXTENDED
@ -1791,7 +1791,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index
2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index
Warnings:
Warning 4207 Hint SUBQUERY(@`subq` MATERIALIZATION) is ignored as conflicting/duplicated
Warning 4210 Hint SUBQUERY(@`subq` MATERIALIZATION) is ignored as conflicting/duplicated
Note 1003 /* select#1 */ select /*+ SUBQUERY(@`subq` INTOEXISTS) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <expr_cache><`test`.`t2`.`a`>(<in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))))
# Specify at different levels, opposite order
EXPLAIN EXTENDED
@ -1801,7 +1801,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index
2 MATERIALIZED t1 index NULL PRIMARY 4 NULL 4 100.00 Using index
Warnings:
Warning 4207 Hint SUBQUERY(@`subq` INTOEXISTS) is ignored as conflicting/duplicated
Warning 4210 Hint SUBQUERY(@`subq` INTOEXISTS) is ignored as conflicting/duplicated
Note 1003 /* select#1 */ select /*+ SUBQUERY(@`subq` MATERIALIZATION) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <expr_cache><`test`.`t2`.`a`>(<in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (/* select#2 */ select /*+ QB_NAME(`subq`) */ `test`.`t1`.`a` from `test`.`t1` ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on distinct_key where `test`.`t2`.`a` = `<subquery2>`.`a`))))
# Specifying combinations of SUBQUERY and SEMIJOIN/NO_SEMIJOIN
# for same query block gives warning
@ -1813,7 +1813,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index
2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index
Warnings:
Warning 4207 Hint SEMIJOIN() is ignored as conflicting/duplicated
Warning 4210 Hint SEMIJOIN() is ignored as conflicting/duplicated
Note 1003 /* select#1 */ select /*+ SUBQUERY(@`select#2` INTOEXISTS) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <expr_cache><`test`.`t2`.`a`>(<in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))))
# Try opposite order
EXPLAIN EXTENDED
@ -1823,7 +1823,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index
2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index
Warnings:
Warning 4207 Hint SUBQUERY(MATERIALIZATION) is ignored as conflicting/duplicated
Warning 4210 Hint SUBQUERY(MATERIALIZATION) is ignored as conflicting/duplicated
Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`select#2`) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <expr_cache><`test`.`t2`.`a`>(<in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))))
# Specify at different levels, hint inside block has effect
EXPLAIN EXTENDED
@ -1833,7 +1833,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 index PRIMARY PRIMARY 4 NULL 4 100.00 Using index
1 PRIMARY t2 ref a a 4 test.t1.a 1 100.00 Using index
Warnings:
Warning 4207 Hint SUBQUERY(@`subq` MATERIALIZATION) is ignored as conflicting/duplicated
Warning 4210 Hint SUBQUERY(@`subq` MATERIALIZATION) is ignored as conflicting/duplicated
Note 1003 select /*+ SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where `test`.`t2`.`a` = `test`.`t1`.`a`
EXPLAIN EXTENDED
SELECT /*+ SUBQUERY(@subq INTOEXISTS) */ * FROM t2
@ -1842,7 +1842,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index
2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index
Warnings:
Warning 4207 Hint SUBQUERY(@`subq` INTOEXISTS) is ignored as conflicting/duplicated
Warning 4210 Hint SUBQUERY(@`subq` INTOEXISTS) is ignored as conflicting/duplicated
Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq`) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <expr_cache><`test`.`t2`.`a`>(<in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))))
EXPLAIN EXTENDED
SELECT /*+ SEMIJOIN(@subq FIRSTMATCH) */ * FROM t2
@ -1851,6 +1851,6 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 index NULL a 4 NULL 6 100.00 Using where; Using index
2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index
Warnings:
Warning 4207 Hint SEMIJOIN(@`subq` FIRSTMATCH) is ignored as conflicting/duplicated
Warning 4210 Hint SEMIJOIN(@`subq` FIRSTMATCH) is ignored as conflicting/duplicated
Note 1003 /* select#1 */ select /*+ SUBQUERY(@`subq` INTOEXISTS) */ `test`.`t2`.`a` AS `a` from `test`.`t2` where <expr_cache><`test`.`t2`.`a`>(<in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))))
DROP TABLE t1,t2,t3;

File diff suppressed because it is too large Load Diff

View File

@ -53,16 +53,6 @@ explain select * from t1 where a=1 or b=1 {
]
}
},
{
"table_dependencies": [
{
"table": "t1",
"row_may_be_null": false,
"map_bit": 0,
"depends_on_map_bits": []
}
]
},
{
"ref_optimizer_key_uses": []
},
@ -205,6 +195,16 @@ explain select * from t1 where a=1 or b=1 {
}
]
},
{
"table_dependencies": [
{
"table": "t1",
"row_may_be_null": false,
"map_bit": 0,
"depends_on_map_bits": []
}
]
},
{
"considered_execution_plans": [
{

View File

@ -61,16 +61,6 @@ explain select * from t1 where pk1 != 0 and key1 = 1 {
]
}
},
{
"table_dependencies": [
{
"table": "t1",
"row_may_be_null": false,
"map_bit": 0,
"depends_on_map_bits": []
}
]
},
{
"ref_optimizer_key_uses": [
{
@ -199,6 +189,16 @@ explain select * from t1 where pk1 != 0 and key1 = 1 {
}
]
},
{
"table_dependencies": [
{
"table": "t1",
"row_may_be_null": false,
"map_bit": 0,
"depends_on_map_bits": []
}
]
},
{
"considered_execution_plans": [
{

View File

@ -64,16 +64,6 @@ select * from db1.t1 {
"join_optimization": {
"select_id": 1,
"steps": [
{
"table_dependencies": [
{
"table": "t1",
"row_may_be_null": false,
"map_bit": 0,
"depends_on_map_bits": []
}
]
},
{
"rows_estimation": [
{
@ -86,6 +76,16 @@ select * from db1.t1 {
}
]
},
{
"table_dependencies": [
{
"table": "t1",
"row_may_be_null": false,
"map_bit": 0,
"depends_on_map_bits": []
}
]
},
{
"considered_execution_plans": [
{
@ -206,16 +206,6 @@ select * from db1.v1 {
"join_optimization": {
"select_id": 1,
"steps": [
{
"table_dependencies": [
{
"table": "t1",
"row_may_be_null": false,
"map_bit": 0,
"depends_on_map_bits": []
}
]
},
{
"rows_estimation": [
{
@ -228,6 +218,16 @@ select * from db1.v1 {
}
]
},
{
"table_dependencies": [
{
"table": "t1",
"row_may_be_null": false,
"map_bit": 0,
"depends_on_map_bits": []
}
]
},
{
"considered_execution_plans": [
{

File diff suppressed because it is too large Load Diff

View File

@ -39,6 +39,8 @@
Currently, this process is done at the parser stage. (This is one of the
causes why hints do not work across VIEW bounds, here or in MySQL).
Query-block level hints can be reached through SELECT_LEX::opt_hints_qb.
== Hint "fixing" ==
During Name Resolution, hints are attached the real objects they control:
@ -64,10 +66,17 @@
== API for checking hints ==
The optimizer checks hints' instructions using these calls:
The optimizer checks hints' instructions using these calls for table/index
level hints:
hint_table_state()
hint_table_state_or_fallback()
hint_key_state()
For query block-level hints:
opt_hints_qb->semijoin_enabled()
opt_hints_qb->sj_enabled_strategies()
opt_hints_qb->apply_join_order_hints(join) - This adds extra dependencies
between tables that ensure that the optimizer picks a join order
prescribed by the hints.
*/
@ -90,32 +99,15 @@
struct LEX;
struct TABLE;
/**
Hint types, MAX_HINT_ENUM should be always last.
This enum should be synchronized with opt_hint_info
array(see opt_hints.cc).
*/
enum opt_hints_enum
{
BKA_HINT_ENUM= 0,
BNL_HINT_ENUM,
ICP_HINT_ENUM,
MRR_HINT_ENUM,
NO_RANGE_HINT_ENUM,
QB_NAME_HINT_ENUM,
MAX_EXEC_TIME_HINT_ENUM,
SEMIJOIN_HINT_ENUM,
SUBQUERY_HINT_ENUM,
MAX_HINT_ENUM // This one must be the last in the list
};
struct st_opt_hint_info
{
LEX_CSTRING hint_type; // Hint "type", like "BKA" or "MRR".
bool check_upper_lvl; // true if upper level hint check is needed (for hints
// which can be specified on more than one level).
bool has_arguments; // true if hint has additional arguments.
bool irregular_hint; // true if hint requires some special handling.
// Currently it's used only for join order hints
// since they need a special printing procedure.
};
typedef Optimizer_hint_parser Parser;
@ -137,24 +129,11 @@ public:
hints_specified.clear_all();
}
/**
Check if hint is specified.
@param type_arg hint type
@return true if hint is specified,
false otherwise
*/
my_bool is_specified(opt_hints_enum type_arg) const
{
return hints_specified.is_set(type_arg);
}
/**
Set switch value and set hint into specified state.
@param type_arg hint type
@param switch_state_arg switch value
*/
void set_switch(opt_hints_enum type_arg,
bool switch_state_arg)
{
@ -164,13 +143,7 @@ public:
hints.clear_bit(type_arg);
hints_specified.set_bit(type_arg);
}
/**
Get switch value.
@param type_arg hint type
@return switch value.
*/
bool is_switched_on(opt_hints_enum type_arg) const
{
return hints.is_set(type_arg);
@ -364,6 +337,15 @@ protected:
DBUG_ASSERT(0);
return 0;
}
/**
Function prints hints which are non-standard and don't
fit into existing hint infrastructure.
@param thd pointer to THD object
@param str pointer to String object
*/
virtual void print_irregular_hints(THD *thd, String *str) {}
};
@ -416,6 +398,10 @@ class Opt_hints_table;
present after that)
- [NO_]SEMIJOIN
- SUBQUERY
- JOIN_PREFIX
- JOIN_SUFFIX
- JOIN_ORDER
- JOIN_FIXED_ORDER
*/
class Opt_hints_qb : public Opt_hints
@ -424,6 +410,14 @@ class Opt_hints_qb : public Opt_hints
LEX_CSTRING sys_name; // System QB name
char buff[32]; // Buffer to hold sys name
// Array of join order hints
Mem_root_array<Parser::Join_order_hint *, false> join_order_hints;
// Bitmap marking ignored hints
ulonglong join_order_hints_ignored;
// Max capacity to avoid overflowing of join_order_hints_ignored bitmap
static const uint MAX_ALLOWED_JOIN_ORDER_HINTS=
sizeof(join_order_hints_ignored) * 8;
public:
Opt_hints_qb(Opt_hints *opt_hints_arg,
MEM_ROOT *mem_root_arg,
@ -454,15 +448,7 @@ public:
}
void append_hint_arguments(THD *thd, opt_hints_enum hint,
String *str) override
{
if (hint == SUBQUERY_HINT_ENUM)
subquery_hint->append_args(thd, str);
else if (hint == SEMIJOIN_HINT_ENUM)
semijoin_hint->append_args(thd, str);
else
DBUG_ASSERT(0);
}
String *str) override;
/**
Function finds Opt_hints_table object corresponding to
@ -478,6 +464,14 @@ public:
Opt_hints_table *fix_hints_for_table(TABLE *table,
const Lex_ident_table &alias);
/**
Checks if join order hints are applicable and
applies table dependencies if possible.
@param join JOIN object
*/
void apply_join_order_hints(JOIN *join);
/**
Returns whether semi-join is enabled for this query block
@ -507,7 +501,7 @@ public:
const Parser::Semijoin_hint* semijoin_hint= nullptr;
/*
/**
Bitmap of strategies listed in the SEMIJOIN/NO_SEMIJOIN hint body, e.g.
FIRSTMATCH | LOOSESCAN
*/
@ -516,6 +510,32 @@ public:
const Parser::Subquery_hint *subquery_hint= nullptr;
uint subquery_strategy= SUBS_NOT_TRANSFORMED;
/**
Returns TRUE if the query block has at least one of the hints
JOIN_PREFIX(), JOIN_SUFFIX(), JOIN_ORDER() (but not JOIN_FIXED_ORDER()!)
*/
bool has_join_order_hints() const
{
return join_order_hints.size() > 0;
}
/*
Adds a join order hint to the array if the capacity is not exceeded.
Returns FALSE on success,
TRUE on failure (capacity exceeded)
*/
bool add_join_order_hint(Parser::Join_order_hint *hint_arg)
{
if (join_order_hints.size() >= MAX_ALLOWED_JOIN_ORDER_HINTS)
return true;
join_order_hints.push_back(hint_arg);
return false;
}
const Parser::Join_order_hint *join_prefix= nullptr;
const Parser::Join_order_hint *join_suffix= nullptr;
const Parser::Join_order_hint *join_fixed_order= nullptr;
void trace_hints(THD *thd)
{
if (unlikely(thd->trace_started()))
@ -528,6 +548,18 @@ public:
obj.add("hints", str.c_ptr_safe());
}
}
private:
bool set_join_hint_deps(JOIN *join, const Parser::Join_order_hint *hint);
void update_nested_join_deps(JOIN *join, const JOIN_TAB *hint_tab,
table_map hint_tab_map);
table_map get_other_dep(JOIN *join, opt_hints_enum type,
table_map hint_tab_map, table_map table_map);
bool compare_table_name(const Parser::Table_name_and_Qb *hint_table_and_qb,
const TABLE_LIST *table);
void print_irregular_hints(THD *thd, String *str) override;
void print_join_order_warn(THD *thd, opt_hints_enum type,
const Parser::Table_name_and_Qb &tbl_name);
};

View File

@ -16,16 +16,42 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
*/
#include "opt_hints_parser.h"
#include "sql_error.h"
#include "mysqld_error.h"
#include "sql_class.h"
#include "sql_show.h"
#include "opt_hints.h"
using Parser= Optimizer_hint_parser;
extern struct st_opt_hint_info opt_hint_info[];
// Forward declaration of functions
void print_warn(THD *thd, uint err_code, opt_hints_enum hint_type,
bool hint_state,
const Lex_ident_sys *qb_name_arg,
const Lex_ident_sys *table_name_arg,
const Lex_ident_sys *key_name_arg,
const Printable_parser_rule *hint);
Opt_hints_qb *get_qb_hints(Parse_context *pc);
Opt_hints_qb *find_qb_hints(Parse_context *pc,
const Lex_ident_sys &qb_name,
opt_hints_enum hint_type,
bool hint_state);
Opt_hints_global *get_global_hints(Parse_context *pc);
Opt_hints_table *get_table_hints(Parse_context *pc,
const Lex_ident_sys &table_name,
Opt_hints_qb *qb);
void append_table_name(THD *thd, String *str, const LEX_CSTRING &table_name,
const LEX_CSTRING &qb_name);
static const Lex_ident_sys null_ident_sys;
Parse_context::Parse_context(THD *thd, st_select_lex *select)
: thd(thd),
@ -74,6 +100,8 @@ Optimizer_hint_tokenizer::find_keyword(const LEX_CSTRING &str)
return TokenID::keyword_FIRSTMATCH;
else if ("INTOEXISTS"_Lex_ident_column.streq(str))
return TokenID::keyword_INTOEXISTS;
else if ("JOIN_ORDER"_Lex_ident_column.streq(str))
return TokenID::keyword_JOIN_ORDER;
break;
case 11:
@ -81,6 +109,10 @@ Optimizer_hint_tokenizer::find_keyword(const LEX_CSTRING &str)
return TokenID::keyword_NO_SEMIJOIN;
else if ("DUPSWEEDOUT"_Lex_ident_column.streq(str))
return TokenID::keyword_DUPSWEEDOUT;
else if ("JOIN_PREFIX"_Lex_ident_column.streq(str))
return TokenID::keyword_JOIN_PREFIX;
else if ("JOIN_SUFFIX"_Lex_ident_column.streq(str))
return TokenID::keyword_JOIN_SUFFIX;
break;
case 15:
@ -88,6 +120,11 @@ Optimizer_hint_tokenizer::find_keyword(const LEX_CSTRING &str)
return TokenID::keyword_MATERIALIZATION;
break;
case 16:
if ("JOIN_FIXED_ORDER"_Lex_ident_column.streq(str))
return TokenID::keyword_JOIN_FIXED_ORDER;
break;
case 18:
if ("MAX_EXECUTION_TIME"_Lex_ident_column.streq(str))
return TokenID::keyword_MAX_EXECUTION_TIME;
@ -164,7 +201,7 @@ Optimizer_hint_tokenizer::get_token(CHARSET_INFO *cs)
// This method is for debug purposes
bool Optimizer_hint_parser::parse_token_list(THD *thd)
bool Parser::parse_token_list(THD *thd)
{
for ( ; ; m_look_ahead_token= get_token(m_cs))
{
@ -182,8 +219,7 @@ bool Optimizer_hint_parser::parse_token_list(THD *thd)
return true; // Success
}
void Optimizer_hint_parser::push_warning_syntax_error(THD *thd,
uint start_lineno)
void Parser::push_warning_syntax_error(THD *thd, uint start_lineno)
{
DBUG_ASSERT(m_start <= m_ptr);
DBUG_ASSERT(m_ptr <= m_end);
@ -202,9 +238,8 @@ void Optimizer_hint_parser::push_warning_syntax_error(THD *thd,
bool
Optimizer_hint_parser::
Table_name_list_container::add(Optimizer_hint_parser *p,
Table_name &&elem)
Parser::Table_name_list_container::add(Optimizer_hint_parser *p,
Table_name &&elem)
{
Table_name *pe= (Table_name*) p->m_thd->alloc(sizeof(*pe));
if (!pe)
@ -214,10 +249,8 @@ Optimizer_hint_parser::
}
bool
Optimizer_hint_parser::
Hint_param_table_list_container::add(Optimizer_hint_parser *p,
Hint_param_table &&elem)
bool Parser::Hint_param_table_list_container::add(Optimizer_hint_parser *p,
Hint_param_table &&elem)
{
Hint_param_table *pe= (Hint_param_table*) p->m_thd->alloc(sizeof(*pe));
if (!pe)
@ -227,10 +260,8 @@ Optimizer_hint_parser::
}
bool
Optimizer_hint_parser::
Hint_param_index_list_container::add(Optimizer_hint_parser *p,
Hint_param_index &&elem)
bool Parser::Hint_param_index_list_container::add(Optimizer_hint_parser *p,
Hint_param_index &&elem)
{
Hint_param_index *pe= (Hint_param_index*) p->m_thd->alloc(sizeof(*pe));
if (!pe)
@ -240,10 +271,7 @@ Optimizer_hint_parser::
}
bool
Optimizer_hint_parser::
Hint_list_container::add(Optimizer_hint_parser *p,
Hint &&elem)
bool Parser::Hint_list_container::add(Optimizer_hint_parser *p, Hint &&elem)
{
Hint *pe= new (p->m_thd->mem_root) Hint;
if (!pe)
@ -253,10 +281,8 @@ Optimizer_hint_parser::
}
bool
Optimizer_hint_parser::
Semijoin_strategy_list_container::add(Optimizer_hint_parser *p,
Semijoin_strategy &&elem)
bool Parser::Semijoin_strategy_list_container::add(Optimizer_hint_parser *p,
Semijoin_strategy &&elem)
{
Semijoin_strategy *pe= (Semijoin_strategy*) p->m_thd->alloc(sizeof(*pe));
if (!pe)
@ -264,3 +290,774 @@ Optimizer_hint_parser::
*pe= std::move(elem);
return push_back(pe, p->m_thd->mem_root);
}
/*
Resolve a parsed table level hint, i.e. set up proper Opt_hint_* structures
which will be used later during query preparation and optimization.
Return value:
- false: no critical errors, warnings on duplicated hints,
unresolved query block names, etc. are allowed
- true: critical errors detected, break further hints processing
*/
bool Parser::Table_level_hint::resolve(Parse_context *pc) const
{
const Table_level_hint_type &table_level_hint_type= *this;
opt_hints_enum hint_type;
bool hint_state; // ON or OFF
switch (table_level_hint_type.id())
{
case TokenID::keyword_BNL:
hint_type= BNL_HINT_ENUM;
hint_state= true;
break;
case TokenID::keyword_NO_BNL:
hint_type= BNL_HINT_ENUM;
hint_state= false;
break;
case TokenID::keyword_BKA:
hint_type= BKA_HINT_ENUM;
hint_state= true;
break;
case TokenID::keyword_NO_BKA:
hint_type= BKA_HINT_ENUM;
hint_state= false;
break;
default:
DBUG_ASSERT(0);
return true;
}
if (const At_query_block_name_opt_table_name_list &
at_query_block_name_opt_table_name_list= *this)
{
// this is @ query_block_name opt_table_name_list
const Lex_ident_sys qb_name_sys= Query_block_name::to_ident_sys(pc->thd);
Opt_hints_qb *qb= find_qb_hints(pc, qb_name_sys, hint_type, hint_state);
if (qb == NULL)
return false;
if (at_query_block_name_opt_table_name_list.is_empty())
{
// e.g. BKA(@qb1)
if (qb->set_switch(hint_state, hint_type, false))
{
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
&qb_name_sys, nullptr, nullptr, nullptr);
}
return false;
}
else
{
// e.g. BKA(@qb1 t1, t2, t3)
const Opt_table_name_list &opt_table_name_list= *this;
for (const Table_name &table : opt_table_name_list)
{
const Lex_ident_sys table_name_sys= table.to_ident_sys(pc->thd);
Opt_hints_table *tab= get_table_hints(pc, table_name_sys, qb);
if (!tab)
return false;
if (tab->set_switch(hint_state, hint_type, true))
{
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
&qb_name_sys, &table_name_sys, nullptr,
nullptr);
}
}
}
}
else
{
// this is opt_hint_param_table_list
const Opt_hint_param_table_list &opt_hint_param_table_list= *this;
Opt_hints_qb *qb= find_qb_hints(pc, Lex_ident_sys(), hint_type, hint_state);
if (qb == NULL)
return false;
if (opt_hint_param_table_list.is_empty())
{
// e.g. BKA()
if (qb->set_switch(hint_state, hint_type, false))
{
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
&null_ident_sys, nullptr, nullptr, nullptr);
}
return false;
}
for (const Hint_param_table &table : opt_hint_param_table_list)
{
// e.g. BKA(t1@qb1, t2@qb2, t3)
const Lex_ident_sys qb_name_sys= table.Query_block_name::
to_ident_sys(pc->thd);
Opt_hints_qb *qb= find_qb_hints(pc, qb_name_sys, hint_type, hint_state);
if (qb == NULL)
return false;
const Lex_ident_sys table_name_sys= table.Table_name::
to_ident_sys(pc->thd);
Opt_hints_table *tab= get_table_hints(pc, table_name_sys, qb);
if (!tab)
return false;
if (tab->set_switch(hint_state, hint_type, true))
{
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
&qb_name_sys, &table_name_sys, nullptr, nullptr);
}
}
}
return false;
}
/*
Resolve a parsed index level hint, i.e. set up proper Opt_hint_* structures
which will be used later during query preparation and optimization.
Return value:
- false: no critical errors, warnings on duplicated hints,
unresolved query block names, etc. are allowed
- true: critical errors detected, break further hints processing
*/
bool Parser::Index_level_hint::resolve(Parse_context *pc) const
{
const Index_level_hint_type &index_level_hint_type= *this;
opt_hints_enum hint_type;
bool hint_state; // ON or OFF
switch (index_level_hint_type.id())
{
case TokenID::keyword_NO_ICP:
hint_type= ICP_HINT_ENUM;
hint_state= false;
break;
case TokenID::keyword_MRR:
hint_type= MRR_HINT_ENUM;
hint_state= true;
break;
case TokenID::keyword_NO_MRR:
hint_type= MRR_HINT_ENUM;
hint_state= false;
break;
case TokenID::keyword_NO_RANGE_OPTIMIZATION:
hint_type= NO_RANGE_HINT_ENUM;
hint_state= true;
break;
default:
DBUG_ASSERT(0);
return true;
}
const Hint_param_table_ext &table_ext= *this;
const Lex_ident_sys qb_name_sys= table_ext.Query_block_name::
to_ident_sys(pc->thd);
const Lex_ident_sys table_name_sys= table_ext.Table_name::
to_ident_sys(pc->thd);
Opt_hints_qb *qb= find_qb_hints(pc, qb_name_sys, hint_type, hint_state);
if (qb == NULL)
return false;
Opt_hints_table *tab= get_table_hints(pc, table_name_sys, qb);
if (!tab)
return false;
if (is_empty()) // Table level hint
{
if (tab->set_switch(hint_state, hint_type, false))
{
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
&qb_name_sys, &table_name_sys, nullptr, nullptr);
}
return false;
}
for (const Hint_param_index &index_name : *this)
{
const Lex_ident_sys index_name_sys= index_name.to_ident_sys(pc->thd);
Opt_hints_key *idx= (Opt_hints_key *)tab->find_by_name(index_name_sys);
if (!idx)
{
idx= new (pc->thd->mem_root)
Opt_hints_key(index_name_sys, tab, pc->thd->mem_root);
tab->register_child(idx);
}
if (idx->set_switch(hint_state, hint_type, true))
{
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
&qb_name_sys, &table_name_sys, &index_name_sys, nullptr);
}
}
return false;
}
/*
Resolve a parsed query block name hint, i.e. set up proper Opt_hint_*
structures which will be used later during query preparation and optimization.
Return value:
- false: no critical errors, warnings on duplicated hints,
unresolved query block names, etc. are allowed
- true: critical errors detected, break further hints processing
*/
bool Parser::Qb_name_hint::resolve(Parse_context *pc) const
{
Opt_hints_qb *qb= pc->select->opt_hints_qb;
DBUG_ASSERT(qb);
const Lex_ident_sys qb_name_sys= Query_block_name::to_ident_sys(pc->thd);
if (qb->get_name().str || // QB name is already set
qb->get_parent()->find_by_name(qb_name_sys)) // Name is already used
{
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, QB_NAME_HINT_ENUM, true,
&qb_name_sys, nullptr, nullptr, nullptr);
return false;
}
qb->set_name(qb_name_sys);
return false;
}
void Parser::Semijoin_hint::fill_strategies_map(Opt_hints_qb *qb) const
{
// Loop for hints like SEMIJOIN(firstmatch, dupsweedout)
const Hint_param_opt_sj_strategy_list &hint_param_strategy_list= *this;
for (const Semijoin_strategy &strat : hint_param_strategy_list)
add_strategy_to_map(strat.id(), qb);
// Loop for hints like SEMIJOIN(@qb1 firstmatch, dupsweedout)
const Opt_sj_strategy_list &opt_sj_strategy_list= *this;
for (const Semijoin_strategy &strat : opt_sj_strategy_list)
add_strategy_to_map(strat.id(), qb);
}
void Parser::Semijoin_hint::add_strategy_to_map(TokenID token_id,
Opt_hints_qb *qb) const
{
switch(token_id)
{
case TokenID::keyword_DUPSWEEDOUT:
qb->semijoin_strategies_map |= OPTIMIZER_SWITCH_DUPSWEEDOUT;
break;
case TokenID::keyword_FIRSTMATCH:
qb->semijoin_strategies_map |= OPTIMIZER_SWITCH_FIRSTMATCH;
break;
case TokenID::keyword_LOOSESCAN:
qb->semijoin_strategies_map |= OPTIMIZER_SWITCH_LOOSE_SCAN;
break;
case TokenID::keyword_MATERIALIZATION:
qb->semijoin_strategies_map |= OPTIMIZER_SWITCH_MATERIALIZATION;
break;
default:
DBUG_ASSERT(0);
}
}
/*
Resolve a parsed semijoin hint, i.e. set up proper Opt_hint_* structures
which will be used later during query preparation and optimization.
Return value:
- false: no critical errors, warnings on duplicated hints,
unresolved query block names, etc. are allowed
- true: critical errors detected, break further hints processing
*/
bool Parser::Semijoin_hint::resolve(Parse_context *pc) const
{
const Semijoin_hint_type &semijoin_hint_type= *this;
bool hint_state; // true - SEMIJOIN(), false - NO_SEMIJOIN()
if (semijoin_hint_type.id() == TokenID::keyword_SEMIJOIN)
hint_state= true;
else
hint_state= false;
Opt_hints_qb *qb;
if (const At_query_block_name_opt_strategy_list &
at_query_block_name_opt_strategy_list __attribute__((unused)) = *this)
{
/*
This is @ query_block_name opt_strategy_list,
e.g. SEMIJOIN(@qb1) or SEMIJOIN(@qb1 firstmatch, loosescan)
*/
const Lex_ident_sys qb_name= Query_block_name::to_ident_sys(pc->thd);
qb= resolve_for_qb_name(pc, hint_state, &qb_name);
}
else
{
// This is opt_strategy_list, e.g. SEMIJOIN(loosescan, dupsweedout)
Lex_ident_sys empty_qb_name= Lex_ident_sys();
qb= resolve_for_qb_name(pc, hint_state, &empty_qb_name);
}
if (qb)
qb->semijoin_hint= this;
return false;
}
/*
Helper function to be called by Semijoin_hint::resolve().
Return value:
- pointer to Opt_hints_qb if the hint was resolved successfully
- NULL if the hint was ignored
*/
Opt_hints_qb* Parser::Semijoin_hint::
resolve_for_qb_name(Parse_context *pc, bool hint_state,
const Lex_ident_sys *qb_name) const
{
Opt_hints_qb *qb= find_qb_hints(pc, *qb_name, SEMIJOIN_HINT_ENUM, hint_state);
if (!qb)
return nullptr;
if (qb->subquery_hint)
{
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, SEMIJOIN_HINT_ENUM,
hint_state, qb_name, nullptr, nullptr, this);
return nullptr;
}
if (qb->set_switch(hint_state, SEMIJOIN_HINT_ENUM, false))
{
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, SEMIJOIN_HINT_ENUM,
hint_state, qb_name, nullptr, nullptr, this);
return nullptr;
}
fill_strategies_map(qb);
return qb;
}
void Parser::Semijoin_hint::append_args(THD *thd, String *str) const
{
// Loop for hints without query block name, e.g. SEMIJOIN(firstmatch, dupsweedout)
const Hint_param_opt_sj_strategy_list &hint_param_strategy_list= *this;
uint32 len_before= str->length();
for (const Semijoin_strategy &strat : hint_param_strategy_list)
{
if (str->length() > len_before)
str->append(STRING_WITH_LEN(", "));
append_strategy_name(strat.id(), str);
}
// Loop for hints with query block name, e.g. SEMIJOIN(@qb1 firstmatch, dupsweedout)
const Opt_sj_strategy_list &opt_sj_strategy_list= *this;
for (const Semijoin_strategy &strat : opt_sj_strategy_list)
{
if (str->length() > len_before)
str->append(STRING_WITH_LEN(", "));
append_strategy_name(strat.id(), str);
}
}
void Parser::Semijoin_hint::
append_strategy_name(TokenID token_id, String *str) const
{
switch(token_id)
{
case TokenID::keyword_DUPSWEEDOUT:
str->append(STRING_WITH_LEN("DUPSWEEDOUT"));
break;
case TokenID::keyword_FIRSTMATCH:
str->append(STRING_WITH_LEN("FIRSTMATCH"));
break;
case TokenID::keyword_LOOSESCAN:
str->append(STRING_WITH_LEN("LOOSESCAN"));
break;
case TokenID::keyword_MATERIALIZATION:
str->append(STRING_WITH_LEN("MATERIALIZATION"));
break;
default:
DBUG_ASSERT(0);
}
}
/*
Resolve a parsed subquery hint, i.e. set up proper Opt_hint_* structures
which will be used later during query preparation and optimization.
Return value:
- false: no critical errors, warnings on duplicated hints,
unresolved query block names, etc. are allowed
- true: critical errors detected, break further hints processing
*/
bool Parser::Subquery_hint::resolve(Parse_context *pc) const
{
Opt_hints_qb *qb;
if (const At_query_block_name_subquery_strategy &
at_query_block_name_subquery_strategy= *this)
{
/*
This is @ query_block_name subquery_strategy,
e.g. SUBQUERY(@qb1 INTOEXISTS)
*/
const Lex_ident_sys qb_name= Query_block_name::to_ident_sys(pc->thd);
const Subquery_strategy &strat= at_query_block_name_subquery_strategy;
qb= resolve_for_qb_name(pc, strat.id(), &qb_name);
}
else
{
// This is subquery_strategy, e.g. SUBQUERY(MATERIALIZATION)
Lex_ident_sys empty_qb_name= Lex_ident_sys();
const Hint_param_subquery_strategy &strat= *this;
qb= resolve_for_qb_name(pc, strat.id(), &empty_qb_name);
}
if (qb)
qb->subquery_hint= this;
return false;
}
/*
Helper function to be called by Subquery_hint::resolve().
Return value:
- pointer to Opt_hints_qb if the hint was resolved successfully
- NULL if the hint was ignored
*/
Opt_hints_qb* Parser::Subquery_hint::
resolve_for_qb_name(Parse_context *pc, TokenID token_id,
const Lex_ident_sys *qb_name) const
{
Opt_hints_qb *qb= find_qb_hints(pc, *qb_name, SUBQUERY_HINT_ENUM, true);
if (!qb)
return nullptr;
if (qb->semijoin_hint)
{
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, SUBQUERY_HINT_ENUM,
true, qb_name, nullptr, nullptr, this);
return nullptr;
}
if (qb->set_switch(true, SUBQUERY_HINT_ENUM, false))
{
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, SUBQUERY_HINT_ENUM,
true, qb_name, nullptr, nullptr, this);
return nullptr;
}
set_subquery_strategy(token_id, qb);
return qb;
}
void Parser::Subquery_hint::set_subquery_strategy(TokenID token_id,
Opt_hints_qb *qb) const
{
switch(token_id)
{
case TokenID::keyword_INTOEXISTS:
qb->subquery_strategy= SUBS_IN_TO_EXISTS;
break;
case TokenID::keyword_MATERIALIZATION:
qb->subquery_strategy= SUBS_MATERIALIZATION;
break;
default:
DBUG_ASSERT(0);
}
}
void Parser::Subquery_hint::append_args(THD *thd, String *str) const
{
TokenID token_id;
if (const At_query_block_name_subquery_strategy &
at_query_block_name_subquery_strategy= *this)
{
const Subquery_strategy &strat= at_query_block_name_subquery_strategy;
token_id= strat.id();
}
else
{
const Hint_param_subquery_strategy& hint_param_strat= *this;
token_id= hint_param_strat.id();
}
switch(token_id)
{
case TokenID::keyword_INTOEXISTS:
str->append(STRING_WITH_LEN("INTOEXISTS"));
break;
case TokenID::keyword_MATERIALIZATION:
str->append(STRING_WITH_LEN("MATERIALIZATION"));
break;
default:
DBUG_ASSERT(0);
}
}
/*
This is the first step of MAX_EXECUTION_TIME() hint resolution. It is invoked
during the parsing phase, but at this stage some essential information is
not yet available, preventing a full validation of the hint.
Particularly, the type of SQL command, mark of a stored procedure execution
or whether SELECT_LEX is not top-level (i.e., a subquery) are not yet set.
However, some basic checks like the numeric argument validation or hint
duplication check can still be performed.
The second step of hint validation is performed during the JOIN preparation
phase, within Opt_hints_global::resolve(). By this point, all necessary
information is up-to-date, allowing the hint to be fully resolved
*/
bool Parser::Max_execution_time_hint::resolve(Parse_context *pc) const
{
const Unsigned_Number& hint_arg= *this;
const ULonglong_null time_ms= hint_arg.get_ulonglong();
if (time_ms.is_null() || time_ms.value() == 0 || time_ms.value() > INT_MAX32)
{
print_warn(pc->thd, ER_BAD_OPTION_VALUE, MAX_EXEC_TIME_HINT_ENUM,
true, NULL, NULL, NULL, this);
return false;
}
Opt_hints_global *global_hint= get_global_hints(pc);
if (global_hint->is_specified(MAX_EXEC_TIME_HINT_ENUM))
{
// Hint duplication: /*+ MAX_EXECUTION_TIME ... MAX_EXECUTION_TIME */
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, MAX_EXEC_TIME_HINT_ENUM, true,
NULL, NULL, NULL, this);
return false;
}
global_hint->set_switch(true, MAX_EXEC_TIME_HINT_ENUM, false);
global_hint->max_exec_time_hint= this;
global_hint->max_exec_time_select_lex= pc->select;
return false;
}
void Parser::Join_order_hint::append_args(THD *thd, String *str) const
{
bool first_table_name= true;
for (const Parser::Table_name_and_Qb& tbl : table_names)
{
if (!first_table_name)
str->append(STRING_WITH_LEN(","));
append_table_name(thd, str, tbl.table_name, tbl.qb_name);
first_table_name= false;
}
}
/*
Resolve a parsed join order hint, i.e. set up proper Opt_hint_* structures
which will be used later during query preparation and optimization.
Return value:
- false: no critical errors, warnings on duplicated hints,
unresolved query block names, etc. are allowed
- true: critical errors detected, break further hints processing
*/
bool Parser::Join_order_hint::resolve(Parse_context *pc)
{
const Join_order_hint_type &join_order_hint_type= *this;
switch (join_order_hint_type.id())
{
case TokenID::keyword_JOIN_FIXED_ORDER:
hint_type= JOIN_FIXED_ORDER_HINT_ENUM;
break;
case TokenID::keyword_JOIN_ORDER:
hint_type= JOIN_ORDER_HINT_ENUM;
break;
case TokenID::keyword_JOIN_PREFIX:
hint_type= JOIN_PREFIX_HINT_ENUM;
break;
case TokenID::keyword_JOIN_SUFFIX:
hint_type= JOIN_SUFFIX_HINT_ENUM;
break;
default:
DBUG_ASSERT(0);
return true;
}
Opt_hints_qb *qb= nullptr;
Lex_ident_sys qb_name;
if (const At_query_block_name_opt_table_name_list &at_qb_tab_list= *this)
{
// this is @ query_block_name opt_table_name_list
qb_name= Query_block_name::to_ident_sys(pc->thd);
qb= find_qb_hints(pc, qb_name, hint_type, true);
// Compose `tables_names` list for warnings and final hints resolving
const Opt_table_name_list &opt_table_name_list= at_qb_tab_list;
for (const Table_name &table : opt_table_name_list)
{
Parser::Table_name_and_Qb *tbl_qb= new (pc->mem_root)
Parser::Table_name_and_Qb(table.to_ident_sys(pc->thd), Lex_ident_sys());
if (!tbl_qb)
return true;
table_names.push_back(tbl_qb, pc->mem_root);
}
}
else
{
// this is opt_hint_param_table_list, query block name is not specified
qb= find_qb_hints(pc, Lex_ident_sys(), hint_type, true);
const Opt_hint_param_table_list &opt_hint_param_table_list= *this;
for (const Hint_param_table &table : opt_hint_param_table_list)
{
// e.g. JOIN_ORDER(t1@qb1, t2@qb2, t3)
Parser::Table_name_and_Qb *tbl_qb=
new (pc->mem_root) Parser::Table_name_and_Qb(
table.Table_name::to_ident_sys(pc->thd),
table.Query_block_name::to_ident_sys(pc->thd));
table_names.push_back(tbl_qb, pc->mem_root);
}
}
if (qb == nullptr)
return false;
if ((hint_type != JOIN_FIXED_ORDER_HINT_ENUM && table_names.is_empty()) ||
(hint_type == JOIN_FIXED_ORDER_HINT_ENUM && !table_names.is_empty()))
{
/*
Skipping table name(s) only allowed and required for the
JOIN_FIXED_ORDER hint and is not allowed for other hint types
*/
print_warn(pc->thd, ER_WARN_MALFORMED_HINT, hint_type, true,
&qb_name, nullptr, nullptr, this);
return false;
}
if (hint_type == JOIN_FIXED_ORDER_HINT_ENUM)
{
/*
This is JOIN_ORDER_FIXED() or JOIN_ORDER_FIXED(@qb1)
There can be only one JOIN_ORDER_FIXED hint in a query block,
other hints are not allowed in this case
*/
if (qb->has_join_order_hints()|| qb->join_fixed_order)
{
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, true,
&qb_name, nullptr, nullptr, this);
return false;
}
qb->join_fixed_order= this;
qb->set_switch(true, hint_type, false);
pc->select->options |= SELECT_STRAIGHT_JOIN;
return false;
}
// Finished with processing of JOIN_FIXED_ORDER()
DBUG_ASSERT(hint_type != JOIN_FIXED_ORDER_HINT_ENUM);
/*
Hints except JOIN_ORDER() must not duplicate. If there is JOIN_ORDER_FIXED()
already, then other hints are not allowed for this query block
*/
if ((qb->get_switch(hint_type) && hint_type != JOIN_ORDER_HINT_ENUM) ||
qb->join_fixed_order)
{
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, true,
&qb_name, nullptr, nullptr, this);
return false;
}
switch(hint_type)
{
case JOIN_PREFIX_HINT_ENUM:
if (qb->join_prefix || qb->add_join_order_hint(this))
{
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, true,
&qb_name, nullptr, nullptr, this);
return false;
}
qb->join_prefix= this;
qb->set_switch(true, JOIN_PREFIX_HINT_ENUM, false);
break;
case JOIN_SUFFIX_HINT_ENUM:
if (qb->join_suffix || qb->add_join_order_hint(this))
{
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, true,
&qb_name, nullptr, nullptr, this);
return false;
}
qb->join_suffix= this;
qb->set_switch(true, JOIN_SUFFIX_HINT_ENUM, false);
break;
case JOIN_ORDER_HINT_ENUM:
// Multiple JOIN_ORDER() hints are allowed
if (qb->add_join_order_hint(this))
{
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, true,
&qb_name, nullptr, nullptr, this);
return false;
}
qb->set_switch(true, JOIN_ORDER_HINT_ENUM, false);
break;
default:
DBUG_ASSERT(0);
}
return false;
}
void Parser::Max_execution_time_hint::append_args(THD *thd, String *str) const
{
const Unsigned_Number& hint_arg= *this;
str->append(ErrConvString(hint_arg.str, hint_arg.length,
&my_charset_latin1).lex_cstring());
}
ulonglong Parser::Max_execution_time_hint::get_milliseconds() const
{
const Unsigned_Number& hint_arg= *this;
return hint_arg.get_ulonglong().value();
}
bool Parser::Hint_list::resolve(Parse_context *pc) const
{
if (pc->thd->lex->create_view)
{
// we're creating or modifying a view, hints are not allowed here
push_warning(pc->thd, Sql_condition::WARN_LEVEL_WARN,
ER_HINTS_INSIDE_VIEWS_NOT_SUPPORTED,
ER_THD(pc->thd, ER_HINTS_INSIDE_VIEWS_NOT_SUPPORTED));
return false;
}
if (!get_qb_hints(pc))
return true;
for (Hint_list::iterator li= this->begin(); li != this->end(); ++li)
{
Parser::Hint &hint= *li;
if (const Table_level_hint &table_hint= hint)
{
if (table_hint.resolve(pc))
return true;
}
else if (const Index_level_hint &index_hint= hint)
{
if (index_hint.resolve(pc))
return true;
}
else if (const Qb_name_hint &qb_hint= hint)
{
if (qb_hint.resolve(pc))
return true;
}
else if (const Max_execution_time_hint &max_hint= hint)
{
if (max_hint.resolve(pc))
return true;
}
else if (const Semijoin_hint &sj_hint= hint)
{
if (sj_hint.resolve(pc))
return true;
}
else if (const Subquery_hint &subq_hint= hint)
{
if (subq_hint.resolve(pc))
return true;
}
else if (Join_order_hint &join_order_hint= hint)
{
if (join_order_hint.resolve(pc))
return true;
}
else {
DBUG_ASSERT(0);
}
}
return false;
}

View File

@ -28,6 +28,29 @@
class st_select_lex;
class Opt_hints_qb;
/**
Hint types, MAX_HINT_ENUM should be always last.
This enum should be synchronized with opt_hint_info
array(see opt_hints.cc).
*/
enum opt_hints_enum
{
BKA_HINT_ENUM= 0,
BNL_HINT_ENUM,
ICP_HINT_ENUM,
MRR_HINT_ENUM,
NO_RANGE_HINT_ENUM,
QB_NAME_HINT_ENUM,
MAX_EXEC_TIME_HINT_ENUM,
SEMIJOIN_HINT_ENUM,
SUBQUERY_HINT_ENUM,
JOIN_PREFIX_HINT_ENUM,
JOIN_SUFFIX_HINT_ENUM,
JOIN_ORDER_HINT_ENUM,
JOIN_FIXED_ORDER_HINT_ENUM,
MAX_HINT_ENUM // This one must be the last in the list
};
/**
Environment data for the name resolution phase
*/
@ -63,9 +86,12 @@ public:
tAT= '@',
tLPAREN= '(',
tRPAREN= ')',
// Other token types
tIDENT= 'i',
tUNSIGNED_NUMBER= 'n',
// Keywords
keyword_BKA,
keyword_BKA = 256, // Value must be greater than any of the above
keyword_BNL,
keyword_NO_BKA,
keyword_NO_BNL,
@ -83,10 +109,10 @@ public:
keyword_LOOSESCAN,
keyword_DUPSWEEDOUT,
keyword_INTOEXISTS,
// Other token types
tIDENT,
tUNSIGNED_NUMBER
keyword_JOIN_PREFIX,
keyword_JOIN_SUFFIX,
keyword_JOIN_ORDER,
keyword_JOIN_FIXED_ORDER
};
class Token: public Lex_cstring
@ -818,6 +844,76 @@ public:
};
/*
join_order_hint_type ::= JOIN_FIXED_ORDER
| JOIN_ORDER
| JOIN_PREFIX
| JOIN_SUFFIX
*/
class Join_order_hint_type_cond
{
public:
static bool allowed_token_id(TokenID id)
{
return id == TokenID::keyword_JOIN_FIXED_ORDER ||
id == TokenID::keyword_JOIN_ORDER ||
id == TokenID::keyword_JOIN_PREFIX ||
id == TokenID::keyword_JOIN_SUFFIX;
}
};
class Join_order_hint_type: public TokenChoice<Parser,
Join_order_hint_type_cond>
{
public:
using TokenChoice::TokenChoice;
};
/*
Struct representing table names listed in optimizer hints bodies.
They may optionally include query block names, for example:
t1, t2@qb1, t3, t4@qb5
*/
struct Table_name_and_Qb: public Sql_alloc
{
Lex_ident_sys table_name;
Lex_ident_sys qb_name; // may be empty
Table_name_and_Qb(const Lex_ident_sys& tbl, const Lex_ident_sys& qb) :
table_name(tbl), qb_name(qb)
{}
Table_name_and_Qb(Lex_ident_sys&& tbl, Lex_ident_sys&& qb) :
table_name(std::move(tbl)), qb_name(std::move(qb))
{}
};
/*
join_order_hint ::= join_order_hint_type ( table_level_hint_body )
*/
class Join_order_hint: public AND4<Parser,
Join_order_hint_type,
LParen,
Table_level_hint_body,
RParen>,
public Printable_parser_rule
{
public:
using AND4::AND4;
opt_hints_enum hint_type= MAX_HINT_ENUM;
bool resolve(Parse_context *pc);
void append_args(THD *thd, String *str) const override;
/*
Table names (optionally augmented with query block names) listed in
the hint body.
*/
List<Table_name_and_Qb> table_names;
};
/*
hint ::= index_level_hint
| table_level_hint
@ -825,17 +921,19 @@ public:
| max_execution_time_hint
| semijoin_hint
| subquery_hint
| join_order_hint
*/
class Hint: public OR6<Parser,
class Hint: public OR7<Parser,
Index_level_hint,
Table_level_hint,
Qb_name_hint,
Max_execution_time_hint,
Semijoin_hint,
Subquery_hint>
Subquery_hint,
Join_order_hint>
{
public:
using OR6::OR6;
using OR7::OR7;
};
private:

View File

@ -12324,3 +12324,5 @@ ER_UNRESOLVED_INDEX_HINT_NAME
eng "Unresolved index name %s for %s hint"
ER_HINTS_INSIDE_VIEWS_NOT_SUPPORTED
eng "Optimizer hints are not supported inside view definitions"
ER_WARN_MALFORMED_HINT
eng "Hint %s is ignored as malformed"

View File

@ -519,24 +519,27 @@ protected:
};
/*
A rule consisting of a choice of six rules:
rule ::= rule1 | rule2 | rule3 | rule4 | rule5 | rule6
A rule consisting of a choice of seven rules:
rule ::= rule1 | rule2 | rule3 | rule4 | rule5 | rule6 | rule7
*/
template<class PARSER, class A, class B, class C, class D, class E, class F>
class OR6: public A, public B, public C, public D, public E, public F
template<class PARSER, class A, class B, class C, class D, class E, class F,
class G>
class OR7: public A, public B, public C, public D, public E, public F,
public G
{
public:
OR6()
OR7()
{ }
OR6(OR6 &&rhs)
OR7(OR7 &&rhs)
:A(std::move(static_cast<A&&>(rhs))),
B(std::move(static_cast<B&&>(rhs))),
C(std::move(static_cast<C&&>(rhs))),
D(std::move(static_cast<D&&>(rhs))),
E(std::move(static_cast<E&&>(rhs))),
F(std::move(static_cast<F&&>(rhs)))
F(std::move(static_cast<F&&>(rhs))),
G(std::move(static_cast<G&&>(rhs)))
{ }
OR6 & operator=(OR6 &&rhs)
OR7 & operator=(OR7 &&rhs)
{
A::operator=(std::move(static_cast<A&&>(rhs)));
B::operator=(std::move(static_cast<B&&>(rhs)));
@ -544,9 +547,10 @@ protected:
D::operator=(std::move(static_cast<D&&>(rhs)));
E::operator=(std::move(static_cast<E&&>(rhs)));
F::operator=(std::move(static_cast<F&&>(rhs)));
G::operator=(std::move(static_cast<G&&>(rhs)));
return *this;
}
OR6(PARSER *p)
OR7(PARSER *p)
:A(p),
B(A::operator bool() ? B() : B(p)),
C(A::operator bool() || B::operator bool() ? C() : C(p)),
@ -555,14 +559,18 @@ protected:
E(A::operator bool() || B::operator bool() || C::operator bool() ||
D::operator bool() ? E() : E(p)),
F(A::operator bool() || B::operator bool() || C::operator bool() ||
D::operator bool() || E::operator bool() ? F() : F(p))
D::operator bool() || E::operator bool() ? F() : F(p)),
G(A::operator bool() || B::operator bool() || C::operator bool() ||
D::operator bool() || E::operator bool() || F::operator bool() ?
G() : G(p))
{
DBUG_ASSERT(!operator bool() || !p->is_error());
}
operator bool() const
{
return A::operator bool() || B::operator bool() || C::operator bool() ||
D::operator bool() || E::operator bool() || F::operator bool();
D::operator bool() || E::operator bool() || F::operator bool() ||
G::operator bool();
}
};

View File

@ -5765,54 +5765,12 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
stat_vector[i]=0;
join->outer_join=outer_join;
if (join->outer_join)
if (join->propagate_dependencies(stat))
{
/*
Build transitive closure for relation 'to be dependent on'.
This will speed up the plan search for many cases with outer joins,
as well as allow us to catch illegal cross references/
Warshall's algorithm is used to build the transitive closure.
As we use bitmaps to represent the relation the complexity
of the algorithm is O((number of tables)^2).
The classic form of the Warshall's algorithm would look like:
for (i= 0; i < table_count; i++)
{
for (j= 0; j < table_count; j++)
{
for (k= 0; k < table_count; k++)
{
if (bitmap_is_set(stat[j].dependent, i) &&
bitmap_is_set(stat[i].dependent, k))
bitmap_set_bit(stat[j].dependent, k);
}
}
}
*/
for (s= stat ; s < stat_end ; s++)
{
TABLE *table= s->table;
for (JOIN_TAB *t= stat ; t < stat_end ; t++)
{
if (t->dependent & table->map)
t->dependent |= table->reginfo.join_tab->dependent;
}
if (outer_join & s->table->map)
s->table->maybe_null= 1;
}
/* Catch illegal cross references for outer joins */
for (i= 0, s= stat ; i < table_count ; i++, s++)
{
if (s->dependent & s->table->map)
{
join->table_count=0; // Don't use join->table
my_message(ER_WRONG_OUTER_JOIN,
ER_THD(join->thd, ER_WRONG_OUTER_JOIN), MYF(0));
goto error;
}
s->key_dependent= s->dependent;
}
// Illegal cross-references found
table_count= 0;
my_message(ER_WRONG_OUTER_JOIN, ER_THD(thd, ER_WRONG_OUTER_JOIN), MYF(0));
goto error;
}
{
@ -5826,9 +5784,6 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
}
}
if (unlikely(thd->trace_started()))
trace_table_dependencies(thd, stat, join->table_count);
if (join->conds || outer_join)
{
if (update_ref_and_keys(thd, keyuse_array, stat, join->table_count,
@ -6320,6 +6275,13 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
join->const_tables=const_count;
join->found_const_table_map=found_const_table_map;
if (join->select_lex->opt_hints_qb)
join->select_lex->opt_hints_qb->apply_join_order_hints(join);
join->update_key_dependencies();
if (unlikely(thd->trace_started()))
trace_table_dependencies(thd, join->join_tab, join->table_count);
if (sj_nests)
join->select_lex->update_available_semijoin_strategies(thd);
@ -6413,6 +6375,102 @@ error:
}
/*
Propagate dependencies between tables.
@returns false if success, true if error
Build transitive closure for relation 'to be dependent on'.
This will speed up the plan search for many cases with outer joins,
as well as allow us to catch illegal cross references/
Warshall's algorithm is used to build the transitive closure.
As we use bitmaps to represent the relation the complexity
of the algorithm is O((number of tables)^2).
The classic form of the Warshall's algorithm would look like:
for (i= 0; i < table_count; i++)
{
for (j= 0; j < table_count; j++)
{
for (k= 0; k < table_count; k++)
{
if (bitmap_is_set(stat[j].dependent, i) &&
bitmap_is_set(stat[i].dependent, k))
bitmap_set_bit(stat[j].dependent, k);
}
}
}
*/
bool JOIN::propagate_dependencies(JOIN_TAB *stat)
{
for (JOIN_TAB *s= stat; s < stat + table_count; s++)
{
TABLE *table= s->table;
if (outer_join & s->table->map)
s->table->maybe_null= 1;
if (!table->reginfo.join_tab->dependent)
continue;
// Add my dependencies to other tables depending on me
for (JOIN_TAB *t= stat; t < stat + table_count; t++)
{
if (t->dependent & table->map)
t->dependent |= table->reginfo.join_tab->dependent;
}
}
// Catch illegal cross references
for (JOIN_TAB *s= stat; s < stat + table_count; s++)
{
if (s->dependent & s->table->map)
return true;
}
return false;
}
void JOIN::update_key_dependencies()
{
for (JOIN_TAB *tab= join_tab; tab < join_tab + table_count; tab++)
tab->key_dependent |= tab->dependent;
}
/*
Export dependencies of the JOIN tables to a newly allocated array of bitmaps
(table_map's).
This array may be used to restore the original dependencies
(see restore_table_dependencies())
*/
table_map *JOIN::export_table_dependencies() const
{
table_map *orig_dep_array=
(table_map *)thd->alloc(sizeof(table_map) * table_count);
if (orig_dep_array == nullptr)
return nullptr;
for (uint i= 0; i < table_count; i++)
orig_dep_array[i]= join_tab[i].dependent;
return orig_dep_array;
}
/*
Restore dependencies of the JOIN tables from a previously exported array
of bitmaps (table_map's) (see export_table_dependencies()).
This function overwrites the existing dependencies with those from the array.
*/
void JOIN::restore_table_dependencies(table_map *orig_dep_array)
{
for (uint i = 0; i < table_count; i++)
join_tab[i].dependent= orig_dep_array[i];
}
/*****************************************************************************
Check with keys are used and with tables references with tables
Updates in stat:
@ -11476,12 +11534,17 @@ get_costs_for_tables(JOIN *join, table_map remaining_tables, uint idx,
bool found_eq_ref= 0;
DBUG_ENTER("get_plans_for_tables");
table_map remaining_allowed_tables=
(join->emb_sjm_nest ?
(join->emb_sjm_nest->sj_inner_tables &
~join->const_table_map & remaining_tables):
remaining_tables);
s= *pos;
do
{
table_map real_table_bit= s->table->map;
if ((*allowed_tables & real_table_bit) &&
!(remaining_tables & s->dependent))
!(remaining_allowed_tables & s->dependent))
{
#ifdef DBUG_ASSERT_EXISTS
DBUG_ASSERT(!check_interleaving_with_nj(s));
@ -15723,15 +15786,15 @@ uint check_join_cache_usage(JOIN_TAB *tab,
!(join->allowed_join_cache_types & JOIN_CACHE_INCREMENTAL_BIT);
bool no_hashed_cache=
!(join->allowed_join_cache_types & JOIN_CACHE_HASHED_BIT);
bool no_bnl_cache= !hint_table_state(join->thd, tab->tab_list->table,
BNL_HINT_ENUM, true);
bool hint_disables_bnl= !hint_table_state(join->thd, tab->tab_list->table,
BNL_HINT_ENUM, true);
bool no_bka_cache= !hint_table_state(join->thd, tab->tab_list->table,
BKA_HINT_ENUM, join->allowed_join_cache_types & JOIN_CACHE_BKA_BIT);
bool hint_forces_bka= hint_table_state(join->thd, tab->tab_list->table,
BKA_HINT_ENUM, false);
join->return_tab= 0;
if (tab->no_forced_join_cache || (no_bnl_cache && no_bka_cache))
if (tab->no_forced_join_cache || (hint_disables_bnl && no_bka_cache))
goto no_join_cache;
if (cache_level < 4 && hint_table_state(join->thd, tab->tab_list->table,
@ -15875,7 +15938,7 @@ uint check_join_cache_usage(JOIN_TAB *tab,
case JT_NEXT:
case JT_ALL:
case JT_RANGE:
if (no_bnl_cache)
if (hint_disables_bnl)
goto no_join_cache;
if (cache_level == 1)
prev_cache= 0;
@ -15915,7 +15978,7 @@ uint check_join_cache_usage(JOIN_TAB *tab,
tab->is_ref_for_hash_join() ||
((flags & HA_MRR_NO_ASSOCIATION) && cache_level <=6))
{
if (no_bnl_cache)
if (hint_disables_bnl)
goto no_join_cache;
if (!tab->hash_join_is_possible() ||
tab->make_scan_filter())
@ -32457,6 +32520,15 @@ void JOIN::set_allowed_join_cache_types()
bool JOIN::is_allowed_hash_join_access(const TABLE *table)
{
/*
If both NO_BNL() and NO_BKA() hints are specified then
hash join is not allowed
*/
if (!hint_table_state(thd, table, BNL_HINT_ENUM, true) &&
!hint_table_state(thd, table, BKA_HINT_ENUM, true))
{
return false;
}
return allowed_join_cache_types & JOIN_CACHE_HASHED_BIT &&
(max_allowed_join_cache_level > JOIN_CACHE_HASHED_BIT ||
hint_table_state(thd, table, BNL_HINT_ENUM, false) ||

View File

@ -378,8 +378,9 @@ typedef struct st_join_table {
*/
table_map dependent;
/*
key_dependent is dependent but add those tables that are used to compare
with a key field in a simple expression. See add_key_field().
Normally `key_dependent` is the same as `dependent` but may also include
tables that are used to compare with a key field in a simple expression
(see add_key_field()).
It is only used to prune searches in best_extension_by_limited_search()
*/
table_map key_dependent;
@ -1955,6 +1956,10 @@ public:
bool optimize_upper_rownum_func();
void calc_allowed_top_level_tables(SELECT_LEX *lex);
table_map get_allowed_nj_tables(uint idx);
bool propagate_dependencies(JOIN_TAB *stat);
void update_key_dependencies();
table_map *export_table_dependencies() const;
void restore_table_dependencies(table_map *orig_dep_array);
private:
/**