diff --git a/mysql-test/main/lowercase_table.result b/mysql-test/main/lowercase_table.result index eef41327375..0cd89c10d04 100644 --- a/mysql-test/main/lowercase_table.result +++ b/mysql-test/main/lowercase_table.result @@ -208,3 +208,30 @@ DROP PACKAGE test.pkg; # # End of 11.4 tests # +# +# Start of 11.7 tests +# +# +# MDEV-33281 Implement optimizer hints like in MySQL +# +SET NAMES utf8mb4; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1), (2); +SELECT /*+BKA(a) BKA(å)*/ a.a FROM t1 a, t1 å; +a +1 +2 +1 +2 +SELECT a.a, A.a FROM t1 a, t1 A; +ERROR 42000: Not unique table/alias: 'A' +SELECT /*+BKA(a) BKA(A)*/ a.a FROM t1 a; +a +1 +2 +Warnings: +Warning 4202 Hint BKA("A") is ignored as conflicting/duplicated +DROP TABLE t1; +# +# End of 11.7 tests +# diff --git a/mysql-test/main/lowercase_table.test b/mysql-test/main/lowercase_table.test index 0795347a46b..78337aa3c98 100644 --- a/mysql-test/main/lowercase_table.test +++ b/mysql-test/main/lowercase_table.test @@ -204,3 +204,33 @@ DROP PACKAGE test.pkg; --echo # --echo # End of 11.4 tests --echo # + + +--echo # +--echo # Start of 11.7 tests +--echo # + +--echo # +--echo # MDEV-33281 Implement optimizer hints like in MySQL +--echo # + +SET NAMES utf8mb4; + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1), (2); + +# Test that aliases are accent sensitive with lowercase-table-names=1 +# Test that table names in hints are also accent sensitive +SELECT /*+BKA(a) BKA(å)*/ a.a FROM t1 a, t1 å; + +# Test that aliases are case insensitive with lowercase-table-names=1 +--error ER_NONUNIQ_TABLE +SELECT a.a, A.a FROM t1 a, t1 A; +# Test that table names in hints are also case insensitive +SELECT /*+BKA(a) BKA(A)*/ a.a FROM t1 a; + +DROP TABLE t1; + +--echo # +--echo # End of 11.7 tests +--echo # diff --git a/mysql-test/main/lowercase_table5.result b/mysql-test/main/lowercase_table5.result index 9a2a02b50e0..ff5098ebdd3 100644 --- a/mysql-test/main/lowercase_table5.result +++ b/mysql-test/main/lowercase_table5.result @@ -189,3 +189,28 @@ DROP DATABASE MYSQL; # # End of 10.5 tests # +# +# Start of 11.7 tests +# +# +# MDEV-33281 Implement optimizer hints like in MySQL +# +SET NAMES utf8mb4; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1), (2); +SELECT /*+BKA(a) BKA(å)*/ a.a, å.a FROM t1 a, t1 å; +a a +1 1 +2 1 +1 2 +2 2 +SELECT /*+BKA(a) BKA(A)*/ a.a, A.a FROM t1 a, t1 A; +a a +1 1 +2 1 +1 2 +2 2 +DROP TABLE t1; +# +# End of 11.7 tests +# diff --git a/mysql-test/main/lowercase_table5.test b/mysql-test/main/lowercase_table5.test index fcbb3fefb33..a51be6677cf 100644 --- a/mysql-test/main/lowercase_table5.test +++ b/mysql-test/main/lowercase_table5.test @@ -187,3 +187,30 @@ DROP DATABASE MYSQL; --echo # --echo # End of 10.5 tests --echo # + +--echo # +--echo # Start of 11.7 tests +--echo # + +--echo # +--echo # MDEV-33281 Implement optimizer hints like in MySQL +--echo # + +SET NAMES utf8mb4; + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1), (2); + +# Test that table aliases are accent sensitive with lowercase-table-names=0 +# Test that table names in hints are also accent sensitive +SELECT /*+BKA(a) BKA(å)*/ a.a, å.a FROM t1 a, t1 å; + +# Test that table aliases are case sensitive with lowercase-table-names=0 +# Test that table names in hints are also case sensitive +SELECT /*+BKA(a) BKA(A)*/ a.a, A.a FROM t1 a, t1 A; + +DROP TABLE t1; + +--echo # +--echo # End of 11.7 tests +--echo # diff --git a/mysql-test/main/opt_hints.result b/mysql-test/main/opt_hints.result index 5a678d8fe9f..c0c64c2de57 100644 --- a/mysql-test/main/opt_hints.result +++ b/mysql-test/main/opt_hints.result @@ -1,4 +1,40 @@ -# WL#8017 Infrastructure for Optimizer Hints +SET NAMES utf8mb4; +# Testing that index names in hints are accent sensitive case insensitive +CREATE TABLE t1 (a INT, ä INT, INDEX idx_a(a), INDEX idx_ä(ä)); +INSERT INTO t1 VALUES (1,1),(2,2); +SELECT /*+ NO_MRR(t1 idx_a) */ a FROM t1; +a +1 +2 +SELECT /*+ NO_MRR(t1 idx_A) */ a FROM t1; +a +1 +2 +SELECT /*+ NO_MRR(t1 idx_å) */ a FROM t1; +a +1 +2 +Warnings: +Warning 4205 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 4202 Hint NO_MRR(`t1` `idx_A`) is ignored as conflicting/duplicated +Warning 4205 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 4202 Hint BKA(`t1`@`A`) is ignored as conflicting/duplicated +SELECT /*+ QB_NAME(a) BKA(t1@a) BKA(t1@å) */ * FROM t1; +a +Warnings: +Warning 4203 Query block name `å` is not found for BKA hint +DROP TABLE t1; CREATE TABLE t1(f1 INT, f2 INT); INSERT INTO t1 VALUES (1,1),(2,2),(3,3); @@ -77,32 +113,78 @@ Warnings: Note 1003 select `test`.`t3`.`f1` AS `f1` from `test`.`t3` where `test`.`t3`.`f1` > 30 and `test`.`t3`.`f1` < 33 # Turn off range access for PRIMARY key # Should use range access by f2_idx key -EXPLAIN EXTENDED SELECT /*+ NO_RANGE_OPTIMIZATION(t3 PRIMARY) */ f1 FROM t3 WHERE f1 > 30 AND f1 < 33; +EXPLAIN EXTENDED SELECT /*+ NO_RANGE_OPTIMIZATION(t3 PRIMARY) */ f1 +FROM t3 WHERE f1 > 30 AND f1 < 33; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 range PRIMARY,f2_idx f2_idx 4 NULL 2 100.00 Using where; Using index Warnings: Note 1003 select /*+ NO_RANGE_OPTIMIZATION(`t3`@`select#1` `PRIMARY`) */ `test`.`t3`.`f1` AS `f1` from `test`.`t3` where `test`.`t3`.`f1` > 30 and `test`.`t3`.`f1` < 33 # Turn off range access for PRIMARY & f2_idx keys # Should use index access -EXPLAIN EXTENDED SELECT /*+ NO_RANGE_OPTIMIZATION(t3 PRIMARY, f2_idx) */ f1 FROM t3 WHERE f1 > 30 AND f1 < 33; +EXPLAIN EXTENDED SELECT /*+ NO_RANGE_OPTIMIZATION(t3 PRIMARY, f2_idx) */ f1 +FROM t3 WHERE f1 > 30 AND f1 < 33; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 index PRIMARY,f2_idx PRIMARY 4 NULL 56 4.11 Using where; Using index Warnings: Note 1003 select /*+ NO_RANGE_OPTIMIZATION(`t3`@`select#1` `PRIMARY`) NO_RANGE_OPTIMIZATION(`t3`@`select#1` `f2_idx`) */ `test`.`t3`.`f1` AS `f1` from `test`.`t3` where `test`.`t3`.`f1` > 30 and `test`.`t3`.`f1` < 33 # Turn off range access for all keys # Should use index access -EXPLAIN EXTENDED SELECT /*+ NO_RANGE_OPTIMIZATION(t3) */ f1 FROM t3 WHERE f1 > 30 AND f1 < 33; +EXPLAIN EXTENDED SELECT /*+ NO_RANGE_OPTIMIZATION(t3) */ f1 +FROM t3 WHERE f1 > 30 AND f1 < 33; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 index PRIMARY,f2_idx PRIMARY 4 NULL 56 4.11 Using where; Using index Warnings: Note 1003 select /*+ NO_RANGE_OPTIMIZATION(`t3`@`select#1`) */ `test`.`t3`.`f1` AS `f1` from `test`.`t3` where `test`.`t3`.`f1` > 30 and `test`.`t3`.`f1` < 33 # Turn off range access for PRIMARY & f2_idx keys # Should use index access -EXPLAIN EXTENDED SELECT /*+ NO_RANGE_OPTIMIZATION(t3 PRIMARY) NO_RANGE_OPTIMIZATION(t3 f2_idx) */ f1 FROM t3 WHERE f1 > 30 AND f1 < 33; +EXPLAIN EXTENDED SELECT /*+ NO_RANGE_OPTIMIZATION(t3 PRIMARY) NO_RANGE_OPTIMIZATION(t3 f2_idx) */ f1 +FROM t3 WHERE f1 > 30 AND f1 < 33; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 index PRIMARY,f2_idx PRIMARY 4 NULL 56 4.11 Using where; Using index Warnings: Note 1003 select /*+ NO_RANGE_OPTIMIZATION(`t3`@`select#1` `PRIMARY`) NO_RANGE_OPTIMIZATION(`t3`@`select#1` `f2_idx`) */ `test`.`t3`.`f1` AS `f1` from `test`.`t3` where `test`.`t3`.`f1` > 30 and `test`.`t3`.`f1` < 33 +# Create a clone of t3 with cyrillic names +CREATE TABLE таблица (f1 INT NOT NULL, поле2 INT, поле3 VARCHAR(32), +PRIMARY KEY(f1), KEY f2_индекс(f1), KEY f3_индекс(поле3)) +AS SELECT * FROM t3; +ANALYZE TABLE таблица; +Table Op Msg_type Msg_text +test.таблица analyze status Engine-independent statistics collected +test.таблица analyze status Table is already up to date +# Turn off range access for PRIMARY key +# Should use range access by f2_индекс key +EXPLAIN EXTENDED SELECT /*+ NO_RANGE_OPTIMIZATION(таблица PRIMARY) */ f1 +FROM таблица WHERE f1 > 30 AND f1 < 33; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE таблица range PRIMARY,f2_индекс f2_индекс 4 NULL 2 100.00 Using where; Using index +Warnings: +Note 1003 select /*+ NO_RANGE_OPTIMIZATION(`таблица`@`select#1` `PRIMARY`) */ `test`.`таблица`.`f1` AS `f1` from `test`.`таблица` where `test`.`таблица`.`f1` > 30 and `test`.`таблица`.`f1` < 33 +# Turn off range access for PRIMARY & f2_индекс keys +# Should use index access +EXPLAIN EXTENDED SELECT /*+ NO_RANGE_OPTIMIZATION(таблица PRIMARY, f2_индекс) */ f1 +FROM таблица WHERE f1 > 30 AND f1 < 33; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE таблица index PRIMARY,f2_индекс PRIMARY 4 NULL 56 4.11 Using where; Using index +Warnings: +Note 1003 select /*+ NO_RANGE_OPTIMIZATION(`таблица`@`select#1` `PRIMARY`) NO_RANGE_OPTIMIZATION(`таблица`@`select#1` `f2_индекс`) */ `test`.`таблица`.`f1` AS `f1` from `test`.`таблица` where `test`.`таблица`.`f1` > 30 and `test`.`таблица`.`f1` < 33 +# Turn off range access for all keys +# Should use index access +EXPLAIN EXTENDED SELECT /*+ NO_RANGE_OPTIMIZATION(таблица) */ f1 +FROM таблица WHERE f1 > 30 AND f1 < 33; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE таблица index PRIMARY,f2_индекс PRIMARY 4 NULL 56 4.11 Using where; Using index +Warnings: +Note 1003 select /*+ NO_RANGE_OPTIMIZATION(`таблица`@`select#1`) */ `test`.`таблица`.`f1` AS `f1` from `test`.`таблица` where `test`.`таблица`.`f1` > 30 and `test`.`таблица`.`f1` < 33 +# Turn off range access for PRIMARY & f2_индекс keys +# Should use index access +EXPLAIN EXTENDED +SELECT /*+ NO_RANGE_OPTIMIZATION(таблица PRIMARY) NO_RANGE_OPTIMIZATION(таблица f2_индекс) */ f1 +FROM таблица WHERE f1 > 30 AND f1 < 33; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE таблица index PRIMARY,f2_индекс PRIMARY 4 NULL 56 4.11 Using where; Using index +Warnings: +Note 1003 select /*+ NO_RANGE_OPTIMIZATION(`таблица`@`select#1` `PRIMARY`) NO_RANGE_OPTIMIZATION(`таблица`@`select#1` `f2_индекс`) */ `test`.`таблица`.`f1` AS `f1` from `test`.`таблица` where `test`.`таблица`.`f1` > 30 and `test`.`таблица`.`f1` < 33 +DROP TABLE таблица; # NO_ICP hint testing set optimizer_switch='index_condition_pushdown=on'; CREATE TABLE t4 (x INT, y INT, KEY x_idx(x), KEY y_idx(y)); @@ -131,6 +213,15 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t5 range x_idx x_idx 5 NULL 2 100.00 Using where; Using join buffer (flat, BNL join) Warnings: Note 1003 select /*+ NO_ICP(`t5`@`QB1` `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 (8 + 0) +# Cyrillic query block name +EXPLAIN EXTENDED SELECT /*+ NO_ICP(t5@блок1 x_idx) */ * FROM +(SELECT /*+ QB_NAME(блок1) */ t4.x, t5.y FROM t4, t4 t5 +WHERE t4.y = 8 AND t5.x BETWEEN 7 AND t4.y+0) AS TD; +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: +Note 1003 select /*+ NO_ICP(`t5`@`блок1` `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 (8 + 0) # Expected warning for z_idx key, unresolved name. EXPLAIN EXTENDED SELECT * FROM (SELECT /*+ NO_ICP(t5 y_idx, x_idx, z_idx) */ t4.x, t5.y FROM t4, t4 t5 @@ -299,7 +390,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t13 hash_ALL a #hash#a 5 test.t12.a 1000 0.10 Using where; Using join buffer (flat, BNLH join) Warnings: Note 1003 select /*+ QB_NAME(`QB1`) NO_BKA(`t13`@`QB1`) */ `test`.`t12`.`a` AS `a`,`test`.`t12`.`b` AS `b`,`test`.`t13`.`a` AS `a`,`test`.`t13`.`b` AS `b`,`test`.`t13`.`c` AS `c`,`test`.`t13`.`filler` AS `filler` from `test`.`t12` join `test`.`t13` where `test`.`t13`.`a` = `test`.`t12`.`a` and `test`.`t13`.`b` + 1 <= `test`.`t13`.`b` + 1 -# UPDATE|DELETE|INSERT hint testing +# UPDATE|DELETE|INSERT|REPLACE hint testing EXPLAIN EXTENDED UPDATE t3 SET f3 = 'mnbv' WHERE f1 > 30 AND f1 < 33 AND (t3.f1, t3.f2, t3.f3) IN (SELECT t2.f1, t2.f2, t2.f3 FROM t1,t2 WHERE t1.f1=t2.f1 AND @@ -390,13 +481,48 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t5 range x_idx x_idx 5 NULL 2 100.00 Using where; Using join buffer (flat, BNL join) Warnings: Note 1003 (insert into `test`.`t3`(f1,f2,f3) select /*+ QB_NAME(`qb1`) NO_ICP(`t5`@`qb1` `x_idx`) */ `test`.`t4`.`x` AS `x`,`test`.`t5`.`y` AS `y`,'filler' AS `filler` from `test`.`t4` join `test`.`t4` `t5` where `test`.`t4`.`y` = 8 and `test`.`t5`.`x` between 7 and (8 + 0)) +# Make sure ICP is expected to be used when there are no hints +EXPLAIN EXTENDED REPLACE INTO t3(f1, f2, f3) +(SELECT t4.x, t5.y, 'filler' FROM t4, t4 t5 WHERE t4.y = 8 AND t5.x BETWEEN 7 AND t4.y+0); +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 index condition; Using where; Using join buffer (flat, BNL join) +Warnings: +Note 1003 (replace into `test`.`t3`(f1,f2,f3) select `test`.`t4`.`x` AS `x`,`test`.`t5`.`y` AS `y`,'filler' AS `filler` from `test`.`t4` join `test`.`t4` `t5` where `test`.`t4`.`y` = 8 and `test`.`t5`.`x` between 7 and (8 + 0)) +# Turn off ICP. ICP should not be used. +EXPLAIN EXTENDED REPLACE INTO t3(f1, f2, f3) +(SELECT /*+ NO_ICP(t5) */t4.x, t5.y, 'filler' FROM t4, t4 t5 +WHERE t4.y = 8 AND t5.x BETWEEN 7 AND t4.y+0); +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: +Note 1003 (replace into `test`.`t3`(f1,f2,f3) select /*+ NO_ICP(`t5`@`select#2`) */ `test`.`t4`.`x` AS `x`,`test`.`t5`.`y` AS `y`,'filler' AS `filler` from `test`.`t4` join `test`.`t4` `t5` where `test`.`t4`.`y` = 8 and `test`.`t5`.`x` between 7 and (8 + 0)) +# Turn off ICP for a particular table +EXPLAIN EXTENDED REPLACE /*+ NO_ICP(t5@QB1) */ INTO t3(f1, f2, f3) +(SELECT /*+ QB_NAME(qb1) */ t4.x, t5.y, 'filler' FROM t4, t4 t5 +WHERE t4.y = 8 AND t5.x BETWEEN 7 AND t4.y+0); +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: +Note 1003 (replace into `test`.`t3`(f1,f2,f3) select /*+ QB_NAME(`qb1`) NO_ICP(`t5`@`qb1`) */ `test`.`t4`.`x` AS `x`,`test`.`t5`.`y` AS `y`,'filler' AS `filler` from `test`.`t4` join `test`.`t4` `t5` where `test`.`t4`.`y` = 8 and `test`.`t5`.`x` between 7 and (8 + 0)) +# Turn off ICP for a particular table and a key +EXPLAIN EXTENDED REPLACE /*+ NO_ICP(t5@QB1 x_idx) */ INTO t3(f1, f2, f3) +(SELECT /*+ QB_NAME(qb1) */ t4.x, t5.y, 'filler' FROM t4, t4 t5 +WHERE t4.y = 8 AND t5.x BETWEEN 7 AND t4.y+0); +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: +Note 1003 (replace into `test`.`t3`(f1,f2,f3) select /*+ QB_NAME(`qb1`) NO_ICP(`t5`@`qb1` `x_idx`) */ `test`.`t4`.`x` AS `x`,`test`.`t5`.`y` AS `y`,'filler' AS `filler` from `test`.`t4` join `test`.`t4` `t5` where `test`.`t4`.`y` = 8 and `test`.`t5`.`x` between 7 and (8 + 0)) # Misc tests # Should issue warning 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 4197 Hint QB_NAME(`qb1`) is ignored as conflicting/duplicated +Warning 4202 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 @@ -462,7 +588,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra Warnings: Warning 1064 Optimizer hint syntax error near 't3@qb1) */ f2 FROM (SELECT /*+ QB_NAME(qb1) */ f2, f3, f1 FROM t3 WHERE f1 > ...' at line 1 -Note 1003 select `test`.`t3`.`f2` AS `f2` from `test`.`t3` where `test`.`t3`.`f3` = 'poiu' and `test`.`t3`.`f1` > 2 and `test`.`t3`.`f1` > 2 +Note 1003 select `test`.`t3`.`f2` AS `f2` from `test`.`t3` where `test`.`t3`.`f1` > 2 and `test`.`t3`.`f3` = 'poiu' and `test`.`t3`.`f1` > 2 # Check illegal syntax EXPLAIN EXTENDED SELECT * FROM (SELECT /*+ QB_NAME(qb1) BKA(@qb1 t1@qb1, t2@qb1, t3) */ t2.f1, t2.f2, t2.f3 FROM t1,t2,t3) tt; @@ -471,7 +597,7 @@ 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 Using join buffer (flat, BNL join) 1 SIMPLE t3 index NULL PRIMARY 4 NULL 56 100.00 Using index; Using join buffer (incremental, BNL join) Warnings: -Warning 1064 Optimizer hint syntax error near 'qb1, t2@qb1, t3) */ t2.f1, t2.f2, t2.f3 FROM t1,t2,t3) tt' at line 2 +Warning 1064 Optimizer hint syntax error near '@qb1, t2@qb1, t3) */ t2.f1, t2.f2, t2.f3 FROM t1,t2,t3) tt' at line 2 Note 1003 select `test`.`t2`.`f1` AS `f1`,`test`.`t2`.`f2` AS `f2`,`test`.`t2`.`f3` AS `f3` from `test`.`t1` join `test`.`t2` join `test`.`t3` # Check '@qb_name table_name' syntax EXPLAIN EXTENDED SELECT /*+ BKA(@qb1 t13) */ * FROM (SELECT /*+ QB_NAME(QB1) */ t12.a, t13.b FROM t12, t13 @@ -831,7 +957,7 @@ CREATE PROCEDURE p() SELECT /*+ NO_MRR(t1) */ * FROM t1 WHERE f2 <= 3 AND 3 <= f SHOW CREATE PROCEDURE p; Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation p STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION CREATE DEFINER=`root`@`localhost` PROCEDURE `p`() -SELECT /*+ NO_MRR(t1) */ * FROM t1 WHERE f2 <= 3 AND 3 <= f3 latin1 latin1_swedish_ci latin1_swedish_ci +SELECT /*+ NO_MRR(t1) */ * FROM t1 WHERE f2 <= 3 AND 3 <= f3 utf8mb4 utf8mb4_uca1400_ai_ci utf8mb4_uca1400_ai_ci FLUSH STATUS; CALL p(); f1 f2 f3 @@ -1059,7 +1185,6 @@ Warning 1064 Optimizer hint syntax error near ') */ 1 UNION SELECT 1' at line 1 1 Warnings: Warning 1064 Optimizer hint syntax error near ') */ 1) UNION (SELECT 1)' at line 1 -# OLEGS: this one does not issue a warning although should: ((SELECT /* + NO_ICP() */ 1)); 1 1 @@ -1099,7 +1224,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 UNION NULL NULL NULL NULL NULL NULL NULL NULL No tables used NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL Warnings: -Note 1003 /* select#1 */ select /*+ QB_NAME(`qb1`) */ 1 AS `1` union /* select#2 */ select 1 AS `1` +Note 1003 /* select#1 */ select /*+ QB_NAME(`qb1`) */ 1 AS `1` union /* select#2 */ select /*+ QB_NAME(`qb2`) */ 1 AS `1` EXPLAIN EXTENDED (SELECT /*+ QB_NAME(qb1) */ 1) UNION (SELECT /*+ QB_NAME(qb2) */ 1); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used @@ -1152,39 +1277,39 @@ CREATE TABLE ` quoted name test` (i INT); SELECT /*+ BKA(` quoted name test`) */ 1 FROM t1; 1 Warnings: -Warning 4199 Unresolved name ` quoted name test`@`select#1` for BKA hint +Warning 4204 Unresolved table name ` quoted name test`@`select#1` for BKA hint SELECT /*+ BKA(` quoted name test`@`select#1`) */ 1 FROM t1; 1 Warnings: -Warning 4198 Query block name `select#1` is not found for BKA hint +Warning 4203 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 4199 Unresolved name " quoted name test"@"select#1" for BKA hint +Warning 4204 Unresolved table name " quoted name test"@"select#1" for BKA hint SELECT /*+ BKA(" quoted name test"@"select#1") */ 1 FROM t1; 1 Warnings: -Warning 4198 Query block name "select#1" is not found for BKA hint +Warning 4203 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 4199 Unresolved name "test1`test2`"@"select#1" for BKA hint +Warning 4204 Unresolved table name "test1`test2`"@"select#1" for BKA hint SELECT /*+ BKA("test1""test2""") */ 1; 1 1 Warnings: -Warning 4199 Unresolved name "test1""test2"""@"select#1" for BKA hint +Warning 4204 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 4204 Unresolved table name `" quoted name test"`@`select#1` for BKA hint +Warning 4204 Unresolved table name ` quoted name test`@`select#1` for BKA hint DROP TABLE ` quoted name test`; DROP TABLE `test1``test2```; # Valid hints, no warning: @@ -1238,7 +1363,7 @@ CREATE TABLE таблица (i INT); SELECT /*+ BKA(`таблица`) */ 1 FROM t1; 1 Warnings: -Warning 4199 Unresolved name `таблица`@`select#1` for BKA hint +Warning 4204 Unresolved table name `таблица`@`select#1` for BKA hint SELECT /*+ BKA(таблица) */ 1 FROM t1; 1 Warnings: @@ -1250,7 +1375,7 @@ Warning 4203 Query block name `таблица` is not found for BKA hint SELECT /*+ NO_ICP(`\D1`) */ 1 FROM t1; 1 Warnings: -Warning 4199 Unresolved name `\D1`@`select#1` for NO_ICP hint +Warning 4204 Unresolved table name `\D1`@`select#1` for NO_ICP hint DROP TABLE таблица; # derived tables and other subqueries: diff --git a/mysql-test/main/opt_hints.test b/mysql-test/main/opt_hints.test index 437b8dbbb17..8ba894323aa 100644 --- a/mysql-test/main/opt_hints.test +++ b/mysql-test/main/opt_hints.test @@ -1,6 +1,22 @@ ---echo # WL#8017 Infrastructure for Optimizer Hints --enable_prepare_warnings +SET NAMES utf8mb4; + +--echo # Testing that index names in hints are accent sensitive case insensitive +CREATE TABLE t1 (a INT, ä INT, INDEX idx_a(a), INDEX idx_ä(ä)); +INSERT INTO t1 VALUES (1,1),(2,2); +SELECT /*+ NO_MRR(t1 idx_a) */ a FROM t1; +SELECT /*+ NO_MRR(t1 idx_A) */ a FROM t1; +SELECT /*+ NO_MRR(t1 idx_å) */ a FROM t1; +SELECT /*+ NO_MRR(t1 idx_a, idx_å, idx_A) */ a FROM t1; +DROP TABLE t1; + +--echo # 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; +SELECT /*+ QB_NAME(a) BKA(t1@a) BKA(t1@å) */ * FROM t1; +DROP TABLE t1; + CREATE TABLE t1(f1 INT, f2 INT); INSERT INTO t1 VALUES (1,1),(2,2),(3,3); @@ -31,7 +47,6 @@ ANALYZE TABLE t1; ANALYZE TABLE t2; ANALYZE TABLE t3; - --echo # NO_RANGE_OPTIMIZATION hint testing set optimizer_switch=default; @@ -50,16 +65,44 @@ SHOW STATUS LIKE 'handler_read%'; EXPLAIN EXTENDED SELECT f1 FROM t3 WHERE f1 > 30 AND f1 < 33; --echo # Turn off range access for PRIMARY key --echo # Should use range access by f2_idx key -EXPLAIN EXTENDED SELECT /*+ NO_RANGE_OPTIMIZATION(t3 PRIMARY) */ f1 FROM t3 WHERE f1 > 30 AND f1 < 33; +EXPLAIN EXTENDED SELECT /*+ NO_RANGE_OPTIMIZATION(t3 PRIMARY) */ f1 + FROM t3 WHERE f1 > 30 AND f1 < 33; --echo # Turn off range access for PRIMARY & f2_idx keys --echo # Should use index access -EXPLAIN EXTENDED SELECT /*+ NO_RANGE_OPTIMIZATION(t3 PRIMARY, f2_idx) */ f1 FROM t3 WHERE f1 > 30 AND f1 < 33; +EXPLAIN EXTENDED SELECT /*+ NO_RANGE_OPTIMIZATION(t3 PRIMARY, f2_idx) */ f1 + FROM t3 WHERE f1 > 30 AND f1 < 33; --echo # Turn off range access for all keys --echo # Should use index access -EXPLAIN EXTENDED SELECT /*+ NO_RANGE_OPTIMIZATION(t3) */ f1 FROM t3 WHERE f1 > 30 AND f1 < 33; +EXPLAIN EXTENDED SELECT /*+ NO_RANGE_OPTIMIZATION(t3) */ f1 + FROM t3 WHERE f1 > 30 AND f1 < 33; --echo # Turn off range access for PRIMARY & f2_idx keys --echo # Should use index access -EXPLAIN EXTENDED SELECT /*+ NO_RANGE_OPTIMIZATION(t3 PRIMARY) NO_RANGE_OPTIMIZATION(t3 f2_idx) */ f1 FROM t3 WHERE f1 > 30 AND f1 < 33; +EXPLAIN EXTENDED SELECT /*+ NO_RANGE_OPTIMIZATION(t3 PRIMARY) NO_RANGE_OPTIMIZATION(t3 f2_idx) */ f1 + FROM t3 WHERE f1 > 30 AND f1 < 33; + +--echo # Create a clone of t3 with cyrillic names +CREATE TABLE таблица (f1 INT NOT NULL, поле2 INT, поле3 VARCHAR(32), + PRIMARY KEY(f1), KEY f2_индекс(f1), KEY f3_индекс(поле3)) + AS SELECT * FROM t3; +ANALYZE TABLE таблица; +--echo # Turn off range access for PRIMARY key +--echo # Should use range access by f2_индекс key +EXPLAIN EXTENDED SELECT /*+ NO_RANGE_OPTIMIZATION(таблица PRIMARY) */ f1 + FROM таблица WHERE f1 > 30 AND f1 < 33; +--echo # Turn off range access for PRIMARY & f2_индекс keys +--echo # Should use index access +EXPLAIN EXTENDED SELECT /*+ NO_RANGE_OPTIMIZATION(таблица PRIMARY, f2_индекс) */ f1 + FROM таблица WHERE f1 > 30 AND f1 < 33; +--echo # Turn off range access for all keys +--echo # Should use index access +EXPLAIN EXTENDED SELECT /*+ NO_RANGE_OPTIMIZATION(таблица) */ f1 + FROM таблица WHERE f1 > 30 AND f1 < 33; +--echo # Turn off range access for PRIMARY & f2_индекс keys +--echo # Should use index access +EXPLAIN EXTENDED + SELECT /*+ NO_RANGE_OPTIMIZATION(таблица PRIMARY) NO_RANGE_OPTIMIZATION(таблица f2_индекс) */ f1 + FROM таблица WHERE f1 > 30 AND f1 < 33; +DROP TABLE таблица; --echo # NO_ICP hint testing set optimizer_switch='index_condition_pushdown=on'; @@ -79,6 +122,12 @@ EXPLAIN EXTENDED SELECT /*+ NO_ICP(t5@qb1 x_idx) */ * FROM (SELECT /*+ QB_NAME(QB1) */ t4.x, t5.y FROM t4, t4 t5 WHERE t4.y = 8 AND t5.x BETWEEN 7 AND t4.y+0) AS TD; +--echo # Cyrillic query block name +EXPLAIN EXTENDED SELECT /*+ NO_ICP(t5@блок1 x_idx) */ * FROM + (SELECT /*+ QB_NAME(блок1) */ t4.x, t5.y FROM t4, t4 t5 + WHERE t4.y = 8 AND t5.x BETWEEN 7 AND t4.y+0) AS TD; + + --echo # Expected warning for z_idx key, unresolved name. EXPLAIN EXTENDED SELECT * FROM (SELECT /*+ NO_ICP(t5 y_idx, x_idx, z_idx) */ t4.x, t5.y FROM t4, t4 t5 @@ -157,7 +206,7 @@ EXPLAIN EXTENDED SELECT /*+ NO_BKA(t12) */ * FROM t12, t13 EXPLAIN EXTENDED SELECT /*+ QB_NAME(QB1) NO_BKA(t13@QB1) */ * FROM t12, t13 WHERE t12.a=t13.a AND (t13.b+1 <= t13.b+1); ---echo # UPDATE|DELETE|INSERT hint testing +--echo # UPDATE|DELETE|INSERT|REPLACE hint testing EXPLAIN EXTENDED UPDATE t3 SET f3 = 'mnbv' WHERE f1 > 30 AND f1 < 33 AND (t3.f1, t3.f2, t3.f3) IN (SELECT t2.f1, t2.f2, t2.f3 FROM t1,t2 WHERE t1.f1=t2.f1 AND @@ -207,6 +256,25 @@ EXPLAIN EXTENDED INSERT /*+ NO_ICP(t5@QB1 x_idx) */ INTO t3(f1, f2, f3) (SELECT /*+ QB_NAME(qb1) */ t4.x, t5.y, 'filler' FROM t4, t4 t5 WHERE t4.y = 8 AND t5.x BETWEEN 7 AND t4.y+0); +--echo # Make sure ICP is expected to be used when there are no hints +EXPLAIN EXTENDED REPLACE INTO t3(f1, f2, f3) + (SELECT t4.x, t5.y, 'filler' FROM t4, t4 t5 WHERE t4.y = 8 AND t5.x BETWEEN 7 AND t4.y+0); + +--echo # Turn off ICP. ICP should not be used. +EXPLAIN EXTENDED REPLACE INTO t3(f1, f2, f3) + (SELECT /*+ NO_ICP(t5) */t4.x, t5.y, 'filler' FROM t4, t4 t5 + WHERE t4.y = 8 AND t5.x BETWEEN 7 AND t4.y+0); + +--echo # Turn off ICP for a particular table +EXPLAIN EXTENDED REPLACE /*+ NO_ICP(t5@QB1) */ INTO t3(f1, f2, f3) + (SELECT /*+ QB_NAME(qb1) */ t4.x, t5.y, 'filler' FROM t4, t4 t5 + WHERE t4.y = 8 AND t5.x BETWEEN 7 AND t4.y+0); + +--echo # Turn off ICP for a particular table and a key +EXPLAIN EXTENDED REPLACE /*+ NO_ICP(t5@QB1 x_idx) */ INTO t3(f1, f2, f3) + (SELECT /*+ QB_NAME(qb1) */ t4.x, t5.y, 'filler' FROM t4, t4 t5 + WHERE t4.y = 8 AND t5.x BETWEEN 7 AND t4.y+0); + --echo # Misc tests --echo # Should issue warning @@ -475,7 +543,6 @@ SELECT /*+ NO_ICP ( ) */ 1; SELECT /*+ NO_ICP() */ 1 UNION SELECT 1; (SELECT /*+ NO_ICP() */ 1) UNION (SELECT 1); ---echo # OLEGS: this one does not issue a warning although should: ((SELECT /* + NO_ICP() */ 1)); UPDATE /*+ NO_ICP() */ t1 SET i = 10; diff --git a/mysql-test/suite/gcol/inc/gcol_select.inc b/mysql-test/suite/gcol/inc/gcol_select.inc index 72fe76d5f25..f0d702db012 100644 --- a/mysql-test/suite/gcol/inc/gcol_select.inc +++ b/mysql-test/suite/gcol/inc/gcol_select.inc @@ -895,7 +895,7 @@ CREATE TABLE t ( INSERT INTO t(a,b) VALUES(1,'cccc'); let $query= -SELECT /*+ bka() */ 1 AS c FROM t AS b RIGHT JOIN t AS c ON b.a > c.c +SELECT 1 AS c FROM t AS b RIGHT JOIN t AS c ON b.a > c.c WHERE b.b>c.a; eval EXPLAIN $query; eval $query; @@ -1022,13 +1022,12 @@ VALUES (1, 'j'), (2, 'c'), (0, 'a'); ANALYZE TABLE t1, t2, t3, t4; -# Hint is added to avoid materialization of the subquery let query= -SELECT /*+ NO_SEMIJOIN(@subq1) */ t1.c1, t2.i1 +SELECT t1.c1, t2.i1 FROM t1 STRAIGHT_JOIN t3 STRAIGHT_JOIN t2 WHERE ( t3.pk IN ( - SELECT /*+ QB_NAME(subq1) */ t4.i1 + SELECT t4.i1 FROM t4 WHERE t4.c1 < 'o' ) @@ -1049,13 +1048,12 @@ if ($support_virtual_index) ALTER TABLE t3 ADD INDEX v_idx2 (i2_key, i1); } -# Hint is added to avoid materialization of the subquery let query= -SELECT /*+ NO_SEMIJOIN(@subq1) */ t1.c1, t2.i1 +SELECT t1.c1, t2.i1 FROM t1 STRAIGHT_JOIN t3 STRAIGHT_JOIN t2 WHERE ( t3.pk IN ( - SELECT /*+ QB_NAME(subq1) */ t4.i1 + SELECT t4.i1 FROM t4 WHERE t4.c1 < 'o' ) @@ -1079,11 +1077,11 @@ ALTER TABLE t3 DROP INDEX v_idx; # Hint is added to avoid materialization of the subquery let query= -SELECT /*+ NO_SEMIJOIN(@subq1) */ t1.c1, t2.i1 +SELECT t1.c1, t2.i1 FROM t1 STRAIGHT_JOIN t3 STRAIGHT_JOIN t2 WHERE ( t3.pk IN ( - SELECT /*+ QB_NAME(subq1) */ t4.i1 + SELECT t4.i1 FROM t4 WHERE t4.c1 < 'o' ) @@ -1117,11 +1115,11 @@ VALUES (10,1), (11,1), (12,1), (13,1), (14,1),(15,1), (16,1),(17,1), (18,1), --echo # non-covering. # Hint is added to avoid materialization of the subquery let query= -SELECT /*+ NO_SEMIJOIN(@subq1) */ t1.c1, t2.i1, t3.i1 +SELECT t1.c1, t2.i1, t3.i1 FROM t1 STRAIGHT_JOIN t3 STRAIGHT_JOIN t2 WHERE ( t3.pk IN ( - SELECT /*+ QB_NAME(subq1) */ t4.i1 + SELECT t4.i1 FROM t4 WHERE t4.c1 < 'o' ) @@ -1154,11 +1152,11 @@ eval $query; # an extra query condition is added to the subquery. # Hint is added to avoid materialization of the subquery let query= -SELECT /*+ NO_SEMIJOIN(@subq1) */ t1.c1, t2.i1 +SELECT t1.c1, t2.i1 FROM t1 STRAIGHT_JOIN t3 STRAIGHT_JOIN t2 WHERE ( t3.pk IN ( - SELECT /*+ QB_NAME(subq1) */ t4.i1 + SELECT t4.i1 FROM t4 WHERE t4.c1 < 'o' and t4.i1 < (t2.i1 + 1) ) diff --git a/mysql-test/suite/gcol/r/gcol_bugfixes.result b/mysql-test/suite/gcol/r/gcol_bugfixes.result index 21b6a71ea84..c790658ccaa 100644 --- a/mysql-test/suite/gcol/r/gcol_bugfixes.result +++ b/mysql-test/suite/gcol/r/gcol_bugfixes.result @@ -444,7 +444,7 @@ Note 1265 Data truncated for column 'c13' at row 1 Note 1265 Data truncated for column 'c11' at row 2 Note 1265 Data truncated for column 'c13' at row 2 CREATE VIEW view_C AS SELECT * FROM C; -SELECT /*+ NO_BNL(t1) */ t1.c13 FROM C AS t2 STRAIGHT_JOIN C AS t1 FORCE INDEX(c13); +SELECT t1.c13 FROM C AS t2 STRAIGHT_JOIN C AS t1 FORCE INDEX(c13); c13 00:00:00 00:00:00 diff --git a/mysql-test/suite/gcol/r/gcol_select_innodb.result b/mysql-test/suite/gcol/r/gcol_select_innodb.result index fb79c79032c..5c12c139a42 100644 --- a/mysql-test/suite/gcol/r/gcol_select_innodb.result +++ b/mysql-test/suite/gcol/r/gcol_select_innodb.result @@ -555,12 +555,12 @@ c BLOB GENERATED ALWAYS AS (a+b) VIRTUAL, UNIQUE KEY i0008 (a) ); INSERT INTO t(a,b) VALUES(1,'cccc'); -EXPLAIN SELECT /*+ bka() */ 1 AS c FROM t AS b RIGHT JOIN t AS c ON b.a > c.c +EXPLAIN SELECT 1 AS c FROM t AS b RIGHT JOIN t AS c ON b.a > c.c WHERE b.b>c.a; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE b ALL i0008 NULL NULL NULL 1 1 SIMPLE c ALL i0008 NULL NULL NULL 1 Range checked for each record (index map: 0x1) -SELECT /*+ bka() */ 1 AS c FROM t AS b RIGHT JOIN t AS c ON b.a > c.c +SELECT 1 AS c FROM t AS b RIGHT JOIN t AS c ON b.a > c.c WHERE b.b>c.a; c Warnings: @@ -689,11 +689,11 @@ test.t3 analyze status Engine-independent statistics collected test.t3 analyze status OK test.t4 analyze status Engine-independent statistics collected test.t4 analyze status OK -EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1) */ t1.c1, t2.i1 +EXPLAIN SELECT t1.c1, t2.i1 FROM t1 STRAIGHT_JOIN t3 STRAIGHT_JOIN t2 WHERE ( t3.pk IN ( -SELECT /*+ QB_NAME(subq1) */ t4.i1 +SELECT t4.i1 FROM t4 WHERE t4.c1 < 'o' ) @@ -704,11 +704,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using join buffer (flat, BNL join) 1 PRIMARY t3 eq_ref PRIMARY PRIMARY 4 test.t4.i1 1 Using where; End temporary 1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using join buffer (flat, BNL join) -SELECT /*+ NO_SEMIJOIN(@subq1) */ t1.c1, t2.i1 +SELECT t1.c1, t2.i1 FROM t1 STRAIGHT_JOIN t3 STRAIGHT_JOIN t2 WHERE ( t3.pk IN ( -SELECT /*+ QB_NAME(subq1) */ t4.i1 +SELECT t4.i1 FROM t4 WHERE t4.c1 < 'o' ) @@ -743,11 +743,11 @@ t 9 # # Test 2: Two alternative covering indexes for the range scan # -EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1) */ t1.c1, t2.i1 +EXPLAIN SELECT t1.c1, t2.i1 FROM t1 STRAIGHT_JOIN t3 STRAIGHT_JOIN t2 WHERE ( t3.pk IN ( -SELECT /*+ QB_NAME(subq1) */ t4.i1 +SELECT t4.i1 FROM t4 WHERE t4.c1 < 'o' ) @@ -758,11 +758,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using join buffer (flat, BNL join) 1 PRIMARY t3 eq_ref PRIMARY PRIMARY 4 test.t4.i1 1 Using where; End temporary 1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using join buffer (flat, BNL join) -SELECT /*+ NO_SEMIJOIN(@subq1) */ t1.c1, t2.i1 +SELECT t1.c1, t2.i1 FROM t1 STRAIGHT_JOIN t3 STRAIGHT_JOIN t2 WHERE ( t3.pk IN ( -SELECT /*+ QB_NAME(subq1) */ t4.i1 +SELECT t4.i1 FROM t4 WHERE t4.c1 < 'o' ) @@ -798,11 +798,11 @@ t 9 # Test 3: One covering index including the base column for the virtual # column # -EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1) */ t1.c1, t2.i1 +EXPLAIN SELECT t1.c1, t2.i1 FROM t1 STRAIGHT_JOIN t3 STRAIGHT_JOIN t2 WHERE ( t3.pk IN ( -SELECT /*+ QB_NAME(subq1) */ t4.i1 +SELECT t4.i1 FROM t4 WHERE t4.c1 < 'o' ) @@ -813,11 +813,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using join buffer (flat, BNL join) 1 PRIMARY t3 eq_ref PRIMARY PRIMARY 4 test.t4.i1 1 Using where; End temporary 1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using join buffer (flat, BNL join) -SELECT /*+ NO_SEMIJOIN(@subq1) */ t1.c1, t2.i1 +SELECT t1.c1, t2.i1 FROM t1 STRAIGHT_JOIN t3 STRAIGHT_JOIN t2 WHERE ( t3.pk IN ( -SELECT /*+ QB_NAME(subq1) */ t4.i1 +SELECT t4.i1 FROM t4 WHERE t4.c1 < 'o' ) @@ -861,11 +861,11 @@ VALUES (10,1), (11,1), (12,1), (13,1), (14,1),(15,1), (16,1),(17,1), (18,1), (28,1), (29,1); # Change the query to read an extra column (t3.i1) making the index # non-covering. -EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1) */ t1.c1, t2.i1, t3.i1 +EXPLAIN SELECT t1.c1, t2.i1, t3.i1 FROM t1 STRAIGHT_JOIN t3 STRAIGHT_JOIN t2 WHERE ( t3.pk IN ( -SELECT /*+ QB_NAME(subq1) */ t4.i1 +SELECT t4.i1 FROM t4 WHERE t4.c1 < 'o' ) @@ -876,11 +876,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using join buffer (flat, BNL join) 1 PRIMARY t3 eq_ref PRIMARY PRIMARY 4 test.t4.i1 1 Using where; End temporary 1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using join buffer (flat, BNL join) -SELECT /*+ NO_SEMIJOIN(@subq1) */ t1.c1, t2.i1, t3.i1 +SELECT t1.c1, t2.i1, t3.i1 FROM t1 STRAIGHT_JOIN t3 STRAIGHT_JOIN t2 WHERE ( t3.pk IN ( -SELECT /*+ QB_NAME(subq1) */ t4.i1 +SELECT t4.i1 FROM t4 WHERE t4.c1 < 'o' ) @@ -916,11 +916,11 @@ t 9 48 # Test 5: Test where the added primary key to secondary indexes is # used after it has been included in the join buffer # -EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1) */ t1.c1, t2.i1 +EXPLAIN SELECT t1.c1, t2.i1 FROM t1 STRAIGHT_JOIN t3 STRAIGHT_JOIN t2 WHERE ( t3.pk IN ( -SELECT /*+ QB_NAME(subq1) */ t4.i1 +SELECT t4.i1 FROM t4 WHERE t4.c1 < 'o' and t4.i1 < (t2.i1 + 1) ) @@ -931,11 +931,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using join buffer (flat, BNL join) 1 PRIMARY t3 eq_ref PRIMARY PRIMARY 4 test.t4.i1 1 Using where 1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using where; End temporary; Using join buffer (flat, BNL join) -SELECT /*+ NO_SEMIJOIN(@subq1) */ t1.c1, t2.i1 +SELECT t1.c1, t2.i1 FROM t1 STRAIGHT_JOIN t3 STRAIGHT_JOIN t2 WHERE ( t3.pk IN ( -SELECT /*+ QB_NAME(subq1) */ t4.i1 +SELECT t4.i1 FROM t4 WHERE t4.c1 < 'o' and t4.i1 < (t2.i1 + 1) ) diff --git a/mysql-test/suite/gcol/r/gcol_select_myisam.result b/mysql-test/suite/gcol/r/gcol_select_myisam.result index 534a62cfc0d..20a8b1764c1 100644 --- a/mysql-test/suite/gcol/r/gcol_select_myisam.result +++ b/mysql-test/suite/gcol/r/gcol_select_myisam.result @@ -1174,14 +1174,14 @@ c BLOB GENERATED ALWAYS AS (a+b) VIRTUAL, UNIQUE KEY i0008 (a) ); INSERT INTO t(a,b) VALUES(1,'cccc'); -EXPLAIN SELECT /*+ bka() */ 1 AS c FROM t AS b RIGHT JOIN t AS c ON b.a > c.c +EXPLAIN SELECT 1 AS c FROM t AS b RIGHT JOIN t AS c ON b.a > c.c WHERE b.b>c.a; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables Warnings: Warning 1292 Truncated incorrect DOUBLE value: 'cccc' Warning 1292 Truncated incorrect DECIMAL value: 'cccc' -SELECT /*+ bka() */ 1 AS c FROM t AS b RIGHT JOIN t AS c ON b.a > c.c +SELECT 1 AS c FROM t AS b RIGHT JOIN t AS c ON b.a > c.c WHERE b.b>c.a; c Warnings: @@ -1315,11 +1315,11 @@ test.t3 analyze status Engine-independent statistics collected test.t3 analyze status OK test.t4 analyze status Engine-independent statistics collected test.t4 analyze status OK -EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1) */ t1.c1, t2.i1 +EXPLAIN SELECT t1.c1, t2.i1 FROM t1 STRAIGHT_JOIN t3 STRAIGHT_JOIN t2 WHERE ( t3.pk IN ( -SELECT /*+ QB_NAME(subq1) */ t4.i1 +SELECT t4.i1 FROM t4 WHERE t4.c1 < 'o' ) @@ -1330,11 +1330,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using join buffer (flat, BNL join) 1 PRIMARY t3 eq_ref PRIMARY,v_idx PRIMARY 4 test.t4.i1 1 Using where; End temporary 1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using join buffer (flat, BNL join) -SELECT /*+ NO_SEMIJOIN(@subq1) */ t1.c1, t2.i1 +SELECT t1.c1, t2.i1 FROM t1 STRAIGHT_JOIN t3 STRAIGHT_JOIN t2 WHERE ( t3.pk IN ( -SELECT /*+ QB_NAME(subq1) */ t4.i1 +SELECT t4.i1 FROM t4 WHERE t4.c1 < 'o' ) @@ -1370,11 +1370,11 @@ t 9 # Test 2: Two alternative covering indexes for the range scan # ALTER TABLE t3 ADD INDEX v_idx2 (i2_key, i1); -EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1) */ t1.c1, t2.i1 +EXPLAIN SELECT t1.c1, t2.i1 FROM t1 STRAIGHT_JOIN t3 STRAIGHT_JOIN t2 WHERE ( t3.pk IN ( -SELECT /*+ QB_NAME(subq1) */ t4.i1 +SELECT t4.i1 FROM t4 WHERE t4.c1 < 'o' ) @@ -1385,11 +1385,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using join buffer (flat, BNL join) 1 PRIMARY t3 eq_ref PRIMARY,v_idx,v_idx2 PRIMARY 4 test.t4.i1 1 Using where; End temporary 1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using join buffer (flat, BNL join) -SELECT /*+ NO_SEMIJOIN(@subq1) */ t1.c1, t2.i1 +SELECT t1.c1, t2.i1 FROM t1 STRAIGHT_JOIN t3 STRAIGHT_JOIN t2 WHERE ( t3.pk IN ( -SELECT /*+ QB_NAME(subq1) */ t4.i1 +SELECT t4.i1 FROM t4 WHERE t4.c1 < 'o' ) @@ -1427,11 +1427,11 @@ t 9 # # Drop the index with only the virtual column ALTER TABLE t3 DROP INDEX v_idx; -EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1) */ t1.c1, t2.i1 +EXPLAIN SELECT t1.c1, t2.i1 FROM t1 STRAIGHT_JOIN t3 STRAIGHT_JOIN t2 WHERE ( t3.pk IN ( -SELECT /*+ QB_NAME(subq1) */ t4.i1 +SELECT t4.i1 FROM t4 WHERE t4.c1 < 'o' ) @@ -1442,11 +1442,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using join buffer (flat, BNL join) 1 PRIMARY t3 eq_ref PRIMARY,v_idx2 PRIMARY 4 test.t4.i1 1 Using where; End temporary 1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using join buffer (flat, BNL join) -SELECT /*+ NO_SEMIJOIN(@subq1) */ t1.c1, t2.i1 +SELECT t1.c1, t2.i1 FROM t1 STRAIGHT_JOIN t3 STRAIGHT_JOIN t2 WHERE ( t3.pk IN ( -SELECT /*+ QB_NAME(subq1) */ t4.i1 +SELECT t4.i1 FROM t4 WHERE t4.c1 < 'o' ) @@ -1493,11 +1493,11 @@ VALUES (10,1), (11,1), (12,1), (13,1), (14,1),(15,1), (16,1),(17,1), (18,1), (28,1), (29,1); # Change the query to read an extra column (t3.i1) making the index # non-covering. -EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1) */ t1.c1, t2.i1, t3.i1 +EXPLAIN SELECT t1.c1, t2.i1, t3.i1 FROM t1 STRAIGHT_JOIN t3 STRAIGHT_JOIN t2 WHERE ( t3.pk IN ( -SELECT /*+ QB_NAME(subq1) */ t4.i1 +SELECT t4.i1 FROM t4 WHERE t4.c1 < 'o' ) @@ -1508,11 +1508,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using join buffer (flat, BNL join) 1 PRIMARY t3 eq_ref PRIMARY,v_idx PRIMARY 4 test.t4.i1 1 Using where; End temporary 1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using join buffer (flat, BNL join) -SELECT /*+ NO_SEMIJOIN(@subq1) */ t1.c1, t2.i1, t3.i1 +SELECT t1.c1, t2.i1, t3.i1 FROM t1 STRAIGHT_JOIN t3 STRAIGHT_JOIN t2 WHERE ( t3.pk IN ( -SELECT /*+ QB_NAME(subq1) */ t4.i1 +SELECT t4.i1 FROM t4 WHERE t4.c1 < 'o' ) @@ -1548,11 +1548,11 @@ t 9 48 # Test 5: Test where the added primary key to secondary indexes is # used after it has been included in the join buffer # -EXPLAIN SELECT /*+ NO_SEMIJOIN(@subq1) */ t1.c1, t2.i1 +EXPLAIN SELECT t1.c1, t2.i1 FROM t1 STRAIGHT_JOIN t3 STRAIGHT_JOIN t2 WHERE ( t3.pk IN ( -SELECT /*+ QB_NAME(subq1) */ t4.i1 +SELECT t4.i1 FROM t4 WHERE t4.c1 < 'o' and t4.i1 < (t2.i1 + 1) ) @@ -1563,11 +1563,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using join buffer (flat, BNL join) 1 PRIMARY t3 eq_ref PRIMARY,v_idx PRIMARY 4 test.t4.i1 1 Using where 1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using where; End temporary; Using join buffer (flat, BNL join) -SELECT /*+ NO_SEMIJOIN(@subq1) */ t1.c1, t2.i1 +SELECT t1.c1, t2.i1 FROM t1 STRAIGHT_JOIN t3 STRAIGHT_JOIN t2 WHERE ( t3.pk IN ( -SELECT /*+ QB_NAME(subq1) */ t4.i1 +SELECT t4.i1 FROM t4 WHERE t4.c1 < 'o' and t4.i1 < (t2.i1 + 1) ) diff --git a/mysql-test/suite/gcol/t/gcol_bugfixes.test b/mysql-test/suite/gcol/t/gcol_bugfixes.test index c4beb69058a..4ff3f7247a7 100644 --- a/mysql-test/suite/gcol/t/gcol_bugfixes.test +++ b/mysql-test/suite/gcol/t/gcol_bugfixes.test @@ -429,7 +429,7 @@ INSERT INTO C (c8,c9) VALUES('1970-01-01',0),('1970-01-01',1); CREATE VIEW view_C AS SELECT * FROM C; -SELECT /*+ NO_BNL(t1) */ t1.c13 FROM C AS t2 STRAIGHT_JOIN C AS t1 FORCE INDEX(c13); +SELECT t1.c13 FROM C AS t2 STRAIGHT_JOIN C AS t1 FORCE INDEX(c13); SELECT DISTINCT t1.c13 FROM C AS t1, view_C AS t2; DROP TABLE C; diff --git a/mysql-test/suite/json/r/json_table_mysql.result b/mysql-test/suite/json/r/json_table_mysql.result index b9f39dbeb3c..a1e806c765d 100644 --- a/mysql-test/suite/json/r/json_table_mysql.result +++ b/mysql-test/suite/json/r/json_table_mysql.result @@ -469,7 +469,7 @@ id jid val 2 1 2 2 2 4 2 3 6 -SELECT /*+ JOIN_ORDER(jt, t1) */ id, jt.* +SELECT id, jt.* FROM t1, JSON_TABLE(jd, '$[*]' COLUMNS (jid FOR ORDINALITY, val INT PATH '$')) AS jt; @@ -480,14 +480,14 @@ id jid val 2 1 2 2 2 4 2 3 6 -EXPLAIN SELECT /*+ JOIN_ORDER(jt, t1) */ id, jt.* +EXPLAIN SELECT id, jt.* FROM t1, JSON_TABLE(jd, '$[*]' COLUMNS (jid FOR ORDINALITY, val INT PATH '$')) AS jt; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 1 SIMPLE jt ALL NULL NULL NULL NULL 40 Table function: json_table -SELECT /*+ JOIN_ORDER(t2,jt) */ t1.id, t2.id, jt.* +SELECT t1.id, t2.id, jt.* FROM t1, JSON_TABLE(t1.jd, '$[*]' COLUMNS (jid FOR ORDINALITY, val INT PATH '$')) AS jt, @@ -514,7 +514,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 1 SIMPLE t2 ALL NULL NULL NULL NULL 2 Using join buffer (flat, BNL join) 1 SIMPLE jt ALL NULL NULL NULL NULL 40 Table function: json_table -EXPLAIN SELECT /*+ JOIN_ORDER(t2,jt) */ t1.id, t2.id, jt.* +EXPLAIN SELECT t1.id, t2.id, jt.* FROM t1, JSON_TABLE(t1.jd, '$[*]' COLUMNS (jid FOR ORDINALITY, val INT PATH '$')) AS jt, diff --git a/mysql-test/suite/json/t/json_table_mysql.test b/mysql-test/suite/json/t/json_table_mysql.test index 1c970eab2d4..6ef834f3e6e 100644 --- a/mysql-test/suite/json/t/json_table_mysql.test +++ b/mysql-test/suite/json/t/json_table_mysql.test @@ -379,18 +379,18 @@ INSERT INTO t1 values (1, '[1,3,5]'),(2,'[2,4,6]'); SELECT id, jt.* FROM t1, JSON_TABLE(jd, '$[*]' COLUMNS (jid FOR ORDINALITY, val INT PATH '$')) AS jt; -SELECT /*+ JOIN_ORDER(jt, t1) */ id, jt.* +SELECT id, jt.* FROM t1, JSON_TABLE(jd, '$[*]' COLUMNS (jid FOR ORDINALITY, val INT PATH '$')) AS jt; -EXPLAIN SELECT /*+ JOIN_ORDER(jt, t1) */ id, jt.* +EXPLAIN SELECT id, jt.* FROM t1, JSON_TABLE(jd, '$[*]' COLUMNS (jid FOR ORDINALITY, val INT PATH '$')) AS jt; --sorted_result -SELECT /*+ JOIN_ORDER(t2,jt) */ t1.id, t2.id, jt.* +SELECT t1.id, t2.id, jt.* FROM t1, JSON_TABLE(t1.jd, '$[*]' COLUMNS (jid FOR ORDINALITY, val INT PATH '$')) AS jt, @@ -402,7 +402,7 @@ EXPLAIN SELECT t1.id, t2.id, jt.* val INT PATH '$')) AS jt, t1 AS t2; -EXPLAIN SELECT /*+ JOIN_ORDER(t2,jt) */ t1.id, t2.id, jt.* +EXPLAIN SELECT t1.id, t2.id, jt.* FROM t1, JSON_TABLE(t1.jd, '$[*]' COLUMNS (jid FOR ORDINALITY, val INT PATH '$')) AS jt, diff --git a/sql/opt_hints.cc b/sql/opt_hints.cc index 215406b3937..f05a2d6b5aa 100644 --- a/sql/opt_hints.cc +++ b/sql/opt_hints.cc @@ -1,4 +1,5 @@ /* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2024, MariaDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -33,13 +34,13 @@ struct st_opt_hint_info opt_hint_info[]= { - {"BKA", true, true}, - {"BNL", true, true}, - {"ICP", true, true}, - {"MRR", true, true}, - {"NO_RANGE_OPTIMIZATION", true, true}, - {"QB_NAME", false, false}, - {0, 0, 0} + {{STRING_WITH_LEN("BKA")}, true, true}, + {{STRING_WITH_LEN("BNL")}, true, true}, + {{STRING_WITH_LEN("ICP")}, true, true}, + {{STRING_WITH_LEN("MRR")}, true, true}, + {{STRING_WITH_LEN("NO_RANGE_OPTIMIZATION")}, true, true}, + {{STRING_WITH_LEN("QB_NAME")}, false, false}, + {null_clex_str, 0, 0} }; /** @@ -49,35 +50,14 @@ struct st_opt_hint_info opt_hint_info[]= const LEX_CSTRING sys_qb_prefix= {"select#", 7}; - -/* - Compare LEX_CSTRING objects. - - @param s Pointer to LEX_CSTRING - @param t Pointer to LEX_CSTRING - - @return 0 if strings are equal - 1 if s is greater - -1 if t is greater -*/ - -static int cmp_lex_string(const LEX_CSTRING *s, - const LEX_CSTRING *t) -{ - return system_charset_info-> - coll->strnncollsp(system_charset_info, - (uchar *) s->str, s->length, - (uchar *) t->str, t->length); -} - - static const Lex_ident_sys null_ident_sys; -static void print_warn(THD *thd, uint err_code, opt_hints_enum hint_type, +static +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/*, PT_hint *hint*/) + const Lex_ident_sys *key_name_arg) { String str; @@ -107,7 +87,14 @@ static void print_warn(THD *thd, uint err_code, opt_hints_enum hint_type, /* Append QB name */ if (qb_name_arg && qb_name_arg->length > 0) { - str.append(STRING_WITH_LEN("@")); + if (hint_type != QB_NAME_HINT_ENUM) + { + /* + Add the delimiter for warnings like "Hint NO_ICP(`t1`@`q1` is ignored". + No need for the delimiter for warnings "Hint QB_NAME(qb1) is ignored" + */ + str.append(STRING_WITH_LEN("@")); + } append_identifier(thd, &str, qb_name_arg->str, qb_name_arg->length); } @@ -118,16 +105,6 @@ static void print_warn(THD *thd, uint err_code, opt_hints_enum hint_type, append_identifier(thd, &str, key_name_arg->str, key_name_arg->length); } - /* Append additional hint arguments if they exist */ - // OLEGS: todo - // if (hint) - // { - // if (qb_name_arg || table_name_arg || key_name_arg) - // str.append(' '); - - // hint->append_args(thd, &str); - // } - str.append(')'); push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, @@ -150,7 +127,10 @@ static Opt_hints_global *get_global_hints(Parse_context *pc) LEX *lex= pc->thd->lex; if (!lex->opt_hints_global) - lex->opt_hints_global= new Opt_hints_global(pc->thd->mem_root); + { + lex->opt_hints_global= new (pc->thd->mem_root) + Opt_hints_global(pc->thd->mem_root); + } if (lex->opt_hints_global) lex->opt_hints_global->set_resolved(); return lex->opt_hints_global; @@ -166,8 +146,8 @@ static Opt_hints_qb *get_qb_hints(Parse_context *pc) if (global_hints == NULL) return NULL; - Opt_hints_qb *qb= new Opt_hints_qb(global_hints, pc->thd->mem_root, - pc->select->select_number); + Opt_hints_qb *qb= new (pc->thd->mem_root) + Opt_hints_qb(global_hints, pc->thd->mem_root, pc->select->select_number); if (qb) { global_hints->register_child(qb); @@ -182,8 +162,9 @@ static Opt_hints_qb *get_qb_hints(Parse_context *pc) if the query block is not found. @param pc pointer to Parse_context object - @param table_name query block name - @param hint processed hint // OLEGS: amend this + @param qb_name query block name + @param hint_type the type of the hint from opt_hints_enum + @param hint_state true: hint enables a feature; false: disables it @return pointer to Opt_hints_table object if found, NULL otherwise @@ -229,7 +210,8 @@ static Opt_hints_table *get_table_hints(Parse_context *pc, static_cast (qb->find_by_name(table_name)); if (!tab) { - tab= new Opt_hints_table(table_name, qb, pc->thd->mem_root); + tab= new (pc->thd->mem_root) + Opt_hints_table(table_name, qb, pc->thd->mem_root); qb->register_child(tab); } @@ -237,12 +219,10 @@ static Opt_hints_table *get_table_hints(Parse_context *pc, } - - bool Opt_hints::get_switch(opt_hints_enum type_arg) const { if (is_specified(type_arg)) - return hints_map.switch_on(type_arg); + return hints_map.is_switched_on(type_arg); if (opt_hint_info[type_arg].check_upper_lvl) return parent->get_switch(type_arg); @@ -255,8 +235,9 @@ Opt_hints* Opt_hints::find_by_name(const LEX_CSTRING &name_arg) const { for (uint i= 0; i < child_array.size(); i++) { - const LEX_CSTRING *name= child_array[i]->get_name(); - if (name && !cmp_lex_string(name, &name_arg)) + const LEX_CSTRING name= child_array[i]->get_name(); + CHARSET_INFO *cs= child_array[i]->charset_info(); + if (name.str && !cs->strnncollsp(name, name_arg)) return child_array[i]; } return NULL; @@ -272,9 +253,6 @@ void Opt_hints::print(THD *thd, String *str) append_hint_type(str, static_cast(i)); str->append(STRING_WITH_LEN("(")); append_name(thd, str); - // OLEGS: - //if (!opt_hint_info[i].switch_hint) - // get_complex_hints(i)->append_args(thd, str); str->append(STRING_WITH_LEN(") ")); } } @@ -286,10 +264,9 @@ void Opt_hints::print(THD *thd, String *str) void Opt_hints::append_hint_type(String *str, opt_hints_enum type) { - const char* hint_name= opt_hint_info[type].hint_name; - if(!hints_map.switch_on(type)) + if(!hints_map.is_switched_on(type)) str->append(STRING_WITH_LEN("NO_")); - str->append(hint_name); + str->append(opt_hint_info[type].hint_name); } @@ -327,13 +304,6 @@ void Opt_hints::check_unresolved(THD *thd) } -PT_hint *Opt_hints_global::get_complex_hints(uint type) -{ - DBUG_ASSERT(0); - return NULL; -} - - Opt_hints_qb::Opt_hints_qb(Opt_hints *opt_hints_arg, MEM_ROOT *mem_root_arg, uint select_number_arg) @@ -360,7 +330,11 @@ Opt_hints_table *Opt_hints_qb::adjust_table_hints(TABLE *table, return tab; } +/* + @brief + For each index IDX, put its hints into keyinfo_array[IDX] +*/ void Opt_hints_table::adjust_key_hints(TABLE *table) { set_resolved(); @@ -370,7 +344,7 @@ void Opt_hints_table::adjust_key_hints(TABLE *table) return; } - /* Make sure that adjustement is called only once. */ + /* Make sure that adjustment is called only once. */ DBUG_ASSERT(keyinfo_array.size() == 0); keyinfo_array.resize(table->s->keys, NULL); @@ -380,7 +354,7 @@ void Opt_hints_table::adjust_key_hints(TABLE *table) KEY *key_info= table->key_info; for (uint j= 0 ; j < table->s->keys ; j++, key_info++) { - if (!cmp_lex_string((*hint)->get_name(), &key_info->name)) + if (key_info->name.streq((*hint)->get_name())) { (*hint)->set_resolved(); keyinfo_array[j]= static_cast(*hint); @@ -445,6 +419,14 @@ static bool get_hint_state(Opt_hints *hint, } +/* + @brief + Check whether a given optimization is enabled for table.keyno. + + @detail + First check if a hint is present, then check optimizer_switch +*/ + bool hint_key_state(const THD *thd, const TABLE *table, uint keyno, opt_hints_enum type_arg, uint optimizer_switch) @@ -543,7 +525,7 @@ bool Optimizer_hint_parser::Table_level_hint::resolve(Parse_context *pc) const // 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, NULL, NULL/*, this*/); + &qb_name_sys, NULL, NULL); return false; } else @@ -555,10 +537,10 @@ bool Optimizer_hint_parser::Table_level_hint::resolve(Parse_context *pc) const 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 true; // OLEGS: why no warning? + return true; 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, NULL/*, this*/); + &qb_name_sys, &table_name_sys, NULL); } } } @@ -575,7 +557,7 @@ bool Optimizer_hint_parser::Table_level_hint::resolve(Parse_context *pc) const // 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, NULL, NULL/*, this*/); + &null_ident_sys, NULL, NULL); return false; } for (const Table_name &table : table_name_list) @@ -584,10 +566,10 @@ bool Optimizer_hint_parser::Table_level_hint::resolve(Parse_context *pc) const 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 true; // OLEGS: no warning? + return true; if (tab->set_switch(hint_state, hint_type, true)) print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state, - &null_ident_sys, &table_name_sys, NULL/*, this*/); + &null_ident_sys, &table_name_sys, NULL); } for (const Hint_param_table &table : opt_hint_param_table_list) @@ -598,16 +580,14 @@ bool Optimizer_hint_parser::Table_level_hint::resolve(Parse_context *pc) const Opt_hints_qb *qb= find_qb_hints(pc, qb_name_sys, hint_type, hint_state); if (qb == NULL) return false; - // OLEGS: todo 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 true; // OLEGS: why no warning? - + return true; 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, NULL/*, this*/); + &qb_name_sys, &table_name_sys, NULL); } } return false; @@ -654,13 +634,13 @@ bool Optimizer_hint_parser::Index_level_hint::resolve(Parse_context *pc) const Opt_hints_table *tab= get_table_hints(pc, table_name_sys, qb); if (!tab) - return true; // OLEGS: why no warning? + return true; 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, NULL/*, this*/); + &qb_name_sys, &table_name_sys, NULL); return false; } @@ -670,13 +650,14 @@ bool Optimizer_hint_parser::Index_level_hint::resolve(Parse_context *pc) const Opt_hints_key *idx= (Opt_hints_key *)tab->find_by_name(index_name_sys); if (!idx) { - idx= new Opt_hints_key(index_name_sys, tab, pc->thd->mem_root); + 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/*, this*/); + &qb_name_sys, &table_name_sys, &index_name_sys); } return false; @@ -691,11 +672,11 @@ bool Optimizer_hint_parser::Qb_name_hint::resolve(Parse_context *pc) const const Lex_ident_sys qb_name_sys= Query_block_name::to_ident_sys(pc->thd); - if (qb->get_name() || // QB name is already set + 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, false, - NULL, NULL, NULL/*, this*/); + print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, QB_NAME_HINT_ENUM, true, + &qb_name_sys, NULL, NULL); return false; } @@ -712,23 +693,20 @@ bool Optimizer_hint_parser::Hint_list::resolve(Parse_context *pc) List_iterator_fast li(*this); while(Optimizer_hint_parser::Hint *hint= li++) { - if (const Table_level_hint &table_hint= - static_cast(*hint)) + if (const Table_level_hint &table_hint= *hint) { if (table_hint.resolve(pc)) return true; } - else if (const Index_level_hint &index_hint= - static_cast(*hint)) + else if (const Index_level_hint &index_hint= *hint) { if (index_hint.resolve(pc)) return true; } - else if (const Qb_name_hint &qb_hint= - static_cast(*hint)) + else if (const Qb_name_hint &qb_hint= *hint) { if (qb_hint.resolve(pc)) - return true; // OLEGS: check this result + return true; } } return false; diff --git a/sql/opt_hints.h b/sql/opt_hints.h index b14cc1b73c3..548a91ed227 100644 --- a/sql/opt_hints.h +++ b/sql/opt_hints.h @@ -1,4 +1,5 @@ /* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2024, MariaDB plc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -53,7 +54,7 @@ enum opt_hints_enum struct st_opt_hint_info { - const char* hint_name; // Hint name. + LEX_CSTRING hint_name; // Hint name. bool check_upper_lvl; // true if upper level hint check is needed (for hints // which can be specified on more than one level). bool switch_hint; // true if hint is not complex. @@ -81,7 +82,7 @@ public: Check if hint is specified. @param type_arg hint type - + @return true if hint is specified, false otherwise */ @@ -111,15 +112,13 @@ public: @return switch value. */ - bool switch_on(opt_hints_enum type_arg) const + bool is_switched_on(opt_hints_enum type_arg) const { return hints.is_set(type_arg); } }; -class PT_hint; -class PT_hint_max_execution_time; class Opt_hints_key; @@ -129,15 +128,16 @@ class Opt_hints_key; Opt_hints_global class is hierarchical structure. It contains information about global hints and also - conains array of QUERY BLOCK level objects (Opt_hints_qb class). + contains array of QUERY BLOCK level objects (Opt_hints_qb class). Each QUERY BLOCK level object contains array of TABLE level hints (class Opt_hints_table). Each TABLE level hint contains array of - KEY lelev hints (Opt_hints_key class). + KEY level hints (Opt_hints_key class). Hint information(specified, on|off state) is stored in hints_map object. */ class Opt_hints : public Sql_alloc { +protected: /* Name of object referred by the hint. This name is empty for global level, @@ -146,6 +146,7 @@ class Opt_hints : public Sql_alloc for key level. */ Lex_ident_sys name; +private: /* Parent object. There is no parent for global level, for query block level parent is Opt_hints_global object, @@ -209,9 +210,14 @@ public: */ bool get_switch(opt_hints_enum type_arg) const; - virtual const LEX_CSTRING *get_name() const + virtual CHARSET_INFO *charset_info() const { - return name.str ? &name : nullptr; + return Lex_ident_column::charset_info(); + } + + const LEX_CSTRING get_name() const + { + return name; } void set_name(const Lex_ident_sys &name_arg) { name= name_arg; } Opt_hints *get_parent() const { return parent; } @@ -230,25 +236,11 @@ public: child_array.push_back(hint_arg); } - // OLEGS: remove it if not used - /** - Returns pointer to complex hint for a given type - - @param type hint type - - @return pointer to complex hint for a given type. - */ - // virtual PT_hint *get_complex_hints(uint type) - // { - // DBUG_ASSERT(0); - // return NULL; /* error C4716: must return a value*/ - // }; - /** Find hint among lower-level hint objects. @param name_arg hint name - + @return hint if found, NULL otherwise */ @@ -303,16 +295,11 @@ class Opt_hints_global : public Opt_hints { public: - PT_hint_max_execution_time *max_exec_time; - Opt_hints_global(MEM_ROOT *mem_root_arg) : Opt_hints(Lex_ident_sys(), NULL, mem_root_arg) - { - max_exec_time= NULL; - } + {} - virtual void append_name(THD *thd, String *str) {} - virtual PT_hint *get_complex_hints(uint type); + virtual void append_name(THD *thd, String *str) override {} }; @@ -334,10 +321,9 @@ public: MEM_ROOT *mem_root_arg, uint select_number_arg); - const LEX_CSTRING *get_print_name() + const LEX_CSTRING get_print_name() { - const LEX_CSTRING *str= Opt_hints::get_name(); - return str ? str : &sys_name; + return name.str ? name : sys_name; } /** @@ -348,10 +334,10 @@ public: */ void append_qb_hint(THD *thd, String *str) { - if (get_name()) + if (name.str) { str->append(STRING_WITH_LEN("QB_NAME(")); - append_identifier(thd, str, get_name()->str, get_name()->length); + append_identifier(thd, str, &name); str->append(STRING_WITH_LEN(") ")); } } @@ -361,10 +347,11 @@ public: @param thd pointer to THD object @param str pointer to String object */ - virtual void append_name(THD *thd, String *str) + virtual void append_name(THD *thd, String *str) override { str->append(STRING_WITH_LEN("@")); - append_identifier(thd, str, get_print_name()->str, get_print_name()->length); + const LEX_CSTRING print_name= get_print_name(); + append_identifier(thd, str, &print_name); } /** @@ -399,15 +386,21 @@ public: keyinfo_array(mem_root_arg) { } + CHARSET_INFO *charset_info() const override + { + return Lex_ident_table::charset_info(); + } + + /** Append table name. @param thd pointer to THD object @param str pointer to String object */ - virtual void append_name(THD *thd, String *str) + virtual void append_name(THD *thd, String *str) override { - append_identifier(thd, str, get_name()->str, get_name()->length); + append_identifier(thd, str, &name); get_parent()->append_name(thd, str); } /** @@ -445,11 +438,11 @@ public: @param thd pointer to THD object @param str pointer to String object */ - virtual void append_name(THD *thd, String *str) + virtual void append_name(THD *thd, String *str) override { get_parent()->append_name(thd, str); str->append(' '); - append_identifier(thd, str, get_name()->str, get_name()->length); + append_identifier(thd, str, &name); } virtual uint get_warn_unresolved_code() const override @@ -507,5 +500,4 @@ bool hint_table_state(const THD *thd, const TABLE *table, bool hint_table_state_or_fallback(const THD *thd, const TABLE *table, opt_hints_enum type_arg, bool fallback_value); - #endif /* OPT_HINTS_INCLUDED */ diff --git a/sql/opt_hints_parser.cc b/sql/opt_hints_parser.cc index f957cda72d7..c86b54effad 100644 --- a/sql/opt_hints_parser.cc +++ b/sql/opt_hints_parser.cc @@ -21,6 +21,7 @@ #include "sql_error.h" #include "mysqld_error.h" #include "sql_class.h" +#include "sql_show.h" extern struct st_opt_hint_info opt_hint_info[]; diff --git a/sql/opt_hints_parser.h b/sql/opt_hints_parser.h index e187f2646e0..4fc9bdc9d0f 100644 --- a/sql/opt_hints_parser.h +++ b/sql/opt_hints_parser.h @@ -21,6 +21,7 @@ #include "lex_ident_sys.h" #include "simple_tokenizer.h" #include "sql_list.h" +#include "sql_string.h" #include "simple_parser.h" class st_select_lex; @@ -565,7 +566,6 @@ private: { public: using OR3::OR3; - }; @@ -579,8 +579,6 @@ private: size_t count() const { return elements; } }; -public: - class Hint_list: public LIST { @@ -590,6 +588,7 @@ public: bool resolve(Parse_context *pc); }; +public: /* The main rule: hints ::= hint_list EOF @@ -608,10 +607,10 @@ public: instead of including the entire opt_hints_parser.h. (forward declarations of qualified nested classes are not possible in C++) */ -class Optimizer_hint_parser_output: public Optimizer_hint_parser::Hint_list +class Optimizer_hint_parser_output: public Optimizer_hint_parser::Hints { public: - using Hint_list::Hint_list; + using Hints::Hints; }; diff --git a/sql/simple_parser.h b/sql/simple_parser.h index 669535496f4..13cd86242bf 100644 --- a/sql/simple_parser.h +++ b/sql/simple_parser.h @@ -196,7 +196,7 @@ protected: /* - A rule consisting of three other rules in a row: + A rule consisting of four other rules in a row: rule ::= rule1 rule2 rule3 rule4 */ template diff --git a/sql/simple_tokenizer.h b/sql/simple_tokenizer.h index bc55c03561b..ec561f202e4 100644 --- a/sql/simple_tokenizer.h +++ b/sql/simple_tokenizer.h @@ -17,7 +17,7 @@ #define SIMPLE_TOKENIZER_INCLUDED -#include "lex_ident.h" +#include "lex_string.h" #include "scan_char.h" /** diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index c0ee7f60e4b..75bdf92c376 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3112,7 +3112,7 @@ void st_select_lex::init_query() pushdown_select= 0; orig_names_of_item_list_elems= 0; opt_hints_qb= 0; - parsed_optimizer_hints= 0; // OLEGS: remove if not used + parsed_optimizer_hints= 0; } void st_select_lex::init_select() @@ -3167,7 +3167,7 @@ void st_select_lex::init_select() orig_names_of_item_list_elems= 0; item_list_usage= MARK_COLUMNS_READ; opt_hints_qb= 0; - parsed_optimizer_hints= 0; // OLEGS: remove if not used + parsed_optimizer_hints= 0; } /* @@ -11107,6 +11107,7 @@ bool LEX::parsed_insert_select(SELECT_LEX *first_select) return true; // fix "main" select + resolve_optimizer_hints_in_last_select(); SELECT_LEX *blt __attribute__((unused))= pop_select(); DBUG_ASSERT(blt == &builtin_select); push_select(first_select); @@ -12900,7 +12901,7 @@ LEX::parse_optimizer_hints(const Lex_comment_st &hints_str) } -void LEX::resolve_optimizer_hints() +void LEX::resolve_optimizer_hints_in_last_select() { SELECT_LEX *select_lex; if (likely(select_stack_top)) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 8b74f3d7512..88362482859 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1390,6 +1390,7 @@ public: uint get_cardinality_of_ref_ptrs_slice(uint order_group_num_arg); void print(THD *thd, String *str, enum_query_type query_type); void print_lock_type(String *str); + void print_hints(THD *thd, String *hint_str); void print_item_list(THD *thd, String *str, enum_query_type query_type); void print_set_clause(THD *thd, String *str, enum_query_type query_type); void print_on_duplicate_key_clause(THD *thd, String *str, @@ -3747,7 +3748,7 @@ public: DBUG_RETURN(select_lex); } - void resolve_optimizer_hints(); + void resolve_optimizer_hints_in_last_select(); SELECT_LEX *current_select_or_default() { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1760635514f..3cf0edfccaf 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -32105,35 +32105,10 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) return; } - char buff[NAME_LEN]; - String hint_str(buff, sizeof(buff), system_charset_info); - hint_str.length(0); - if (thd->lex->opt_hints_global) - { - char tmp_buff[NAME_LEN]; - String hints_tmp(tmp_buff, sizeof(tmp_buff), system_charset_info); - hints_tmp.length(0); - if (select_number == 1) - { - if (opt_hints_qb) - opt_hints_qb->append_qb_hint(thd, &hints_tmp); - thd->lex->opt_hints_global->print(thd, &hints_tmp); - } - else if (opt_hints_qb) - opt_hints_qb->append_qb_hint(thd, &hints_tmp); - - if (hints_tmp.length() > 0) - { - hint_str.append(STRING_WITH_LEN("/*+ ")); - hint_str.append(hints_tmp); - hint_str.append(STRING_WITH_LEN("*/ ")); - } - } - - if (hint_str.length() > 0 && (sel_type == SELECT_CMD || - sel_type == INSERT_CMD || - sel_type == REPLACE_CMD)) - str->append(hint_str); + if (sel_type == SELECT_CMD || + sel_type == INSERT_CMD || + sel_type == REPLACE_CMD) + print_hints(thd, str); /* First add options */ if (options & SELECT_STRAIGHT_JOIN) @@ -32190,8 +32165,7 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) if (sel_type == UPDATE_CMD || sel_type == DELETE_CMD) { str->append(get_explainable_cmd_name(sel_type)); - if (hint_str.length() > 0) - str->append(hint_str); + print_hints(thd, str); } if (sel_type == DELETE_CMD) { @@ -32318,6 +32292,36 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) } +void st_select_lex::print_hints(THD *thd, + String *str) +{ + if (!thd->lex->opt_hints_global) + return; + + constexpr LEX_CSTRING header={STRING_WITH_LEN("/*+ ")}; + str->append(header); + uint32 len_before_hints= str->length(); + if (select_number == 1) + { + if (opt_hints_qb) + opt_hints_qb->append_qb_hint(thd, str); + thd->lex->opt_hints_global->print(thd, str); + } + else if (opt_hints_qb) + opt_hints_qb->append_qb_hint(thd, str); + + if (str->length() > len_before_hints) + { + // Some hints were printed, close the hint string + str->append(STRING_WITH_LEN("*/ ")); + } + else + { + // No hints were added, rollback the previouly added header + str->length(len_before_hints - header.length); + } +} + /** Change the select_result object of the JOIN. diff --git a/sql/sql_string.h b/sql/sql_string.h index dd1da64c94a..b2f9fe3a8fb 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -1015,10 +1015,6 @@ public: { return Binary_string::append(s); } - bool append(const char *s) - { - return append(s, (uint) strlen(s)); - } inline bool append(char chr) { return Binary_string::append_char(chr); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6dd31194d75..e48340ca727 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -9005,6 +9005,7 @@ query_specification: opt_having_clause opt_window_clause { + Lex->resolve_optimizer_hints_in_last_select(); $$= Lex->pop_select(); } ; @@ -9018,6 +9019,7 @@ select_into_query_specification: opt_having_clause opt_window_clause { + Lex->resolve_optimizer_hints_in_last_select(); $$= Lex->pop_select(); } ; @@ -9157,7 +9159,6 @@ query_expression_body: query_simple { Lex->push_select($1); - Lex->resolve_optimizer_hints(); if (!($$= Lex->create_unit($1))) MYSQL_YYABORT; } @@ -13604,7 +13605,7 @@ insert: insert_field_spec opt_insert_update opt_returning insert_stmt_end { - Lex->resolve_optimizer_hints(); + Lex->resolve_optimizer_hints_in_last_select(); Lex->mark_first_table_as_inserting(); thd->get_stmt_da()->reset_current_row_for_warning(0); } @@ -13624,8 +13625,9 @@ replace: Select->set_lock_for_tables($5, true, false); } insert_field_spec opt_returning - stmt_end + insert_stmt_end { + Lex->resolve_optimizer_hints_in_last_select(); Lex->mark_first_table_as_inserting(); thd->get_stmt_da()->reset_current_row_for_warning(0); } @@ -13641,7 +13643,7 @@ insert_start: { ; stmt_end: { - Lex->resolve_optimizer_hints(); + Lex->resolve_optimizer_hints_in_last_select(); Lex->pop_select(); //main select if (Lex->check_main_unit_semantics()) MYSQL_YYABORT; @@ -14008,7 +14010,7 @@ delete: { if (Lex->check_cte_dependencies_and_resolve_references()) MYSQL_YYABORT; - Lex->resolve_optimizer_hints(); + Lex->resolve_optimizer_hints_in_last_select(); } ;