diff --git a/include/my_base.h b/include/my_base.h index 050ce8755f9..f2d4dcd4374 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -562,7 +562,8 @@ enum ha_base_keytype { #define HA_NAMELEN 64 /* Max length of saved filename */ #define NO_SUCH_KEY (~(uint)0) /* used as a key no. */ -typedef ulong key_part_map; +typedef uint32 key_part_map; +#define MAX_REF_PARTS sizeof(key_part_map)*8 /* Max parts used as ref */ #define HA_WHOLE_KEY (~(key_part_map)0) /* Intern constants in databases */ diff --git a/mysql-test/main/range.result b/mysql-test/main/range.result index 6943a295acb..282106bc472 100644 --- a/mysql-test/main/range.result +++ b/mysql-test/main/range.result @@ -3755,6 +3755,61 @@ id key1 3 2 drop table t1; # +# MDEV-41179 MAX_KEY_PARTS ranges in select causing SEGV +# +CREATE TABLE t1 ( +c0 INT, c1 INT, c2 INT, c3 INT, c4 INT, c5 INT, c6 INT, c7 INT, +c8 INT, c9 INT, c10 INT, c11 INT, c12 INT, c13 INT, c14 INT, c15 INT, +c16 INT, c17 INT, c18 INT, c19 INT, c20 INT, c21 INT, c22 INT, c23 INT, +c24 INT, c25 INT, c26 INT, c27 INT, c28 INT, c29 INT, c30 INT, c31 INT, +c32 INT, +KEY k32(c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17, +c18,c19,c20,c21,c22,c23,c24,c25,c26,c27,c28,c29,c30,c31) +); +INSERT INTO t1 (c0) VALUES (1), (2); +SELECT * FROM t1 +WHERE c0=1 AND c1=2 AND c2=3 AND c3=4 AND c4=5 AND c5=6 AND c6=7 AND c7=8 +AND c8=9 AND c9=10 AND c10=11 AND c11=12 AND c12=13 AND c13=14 AND c14=15 +AND c15=16 AND c16=17 AND c17=18 AND c18=19 AND c19=20 AND c20=21 AND c21=22 +AND c22=23 AND c23=24 AND c24=25 AND c25=26 AND c26=27 AND c27=28 AND c28=29 +AND c29=30 AND c30=31 AND c31=32; +c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 c31 c32 +SELECT * FROM t1 +WHERE c0=1 AND c1=2 AND c2=3 AND c3=4 AND c4=5 AND c5=6 AND c6=7 AND c7=8 +AND c8=9 AND c9=10 AND c10=11 AND c11=12 AND c12=13 AND c13=14 AND c14=15 +AND c15=16 AND c16=17 AND c17=18 AND c18=19 AND c19=20 AND c20=21 AND c21=22 +AND c22=23 AND c23=24 AND c24=25 AND c25=26 AND c26=27 AND c27=28 AND c28=29 +AND c29=30 AND c30=31 AND c31=32 AND c32=33; +c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 c31 c32 +truncate t1; +# test best_access_path, non default OPTIMIZER_ADJ_FIX_REUSE_RANGE_FOR_REF +INSERT INTO t1 ( +c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, +c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31 +) +SELECT 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +IF(seq<=3, NULL, seq%5) FROM seq_1_to_2000; +CREATE TABLE t2 (x INT); +INSERT INTO t2 VALUES (1),(2); +ANALYZE TABLE t1, t2 PERSISTENT FOR ALL; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status Table is already up to date +test.t2 analyze status Engine-independent statistics collected +test.t2 analyze status OK +SET optimizer_adjust_secondary_key_costs='fix_card_multiplier'; +EXPLAIN SELECT COUNT(*) FROM t2 STRAIGHT_JOIN t1 FORCE INDEX(k32) +WHERE t1.c0=1 AND t1.c1=1 AND t1.c2=1 AND t1.c3=1 AND t1.c4=1 AND t1.c5=1 AND +t1.c6=1 AND t1.c7=1 AND t1.c8=1 AND t1.c9=1 AND t1.c10=1 AND t1.c11=1 AND +t1.c12=1 AND t1.c13=1 AND t1.c14=1 AND t1.c15=1 AND t1.c16=1 AND t1.c17=1 AND +t1.c18=1 AND t1.c19=1 AND t1.c20=1 AND t1.c21=1 AND t1.c22=1 AND t1.c23=1 AND +t1.c24=1 AND t1.c25=1 AND t1.c26=1 AND t1.c27=1 AND t1.c28=1 AND t1.c29=1 AND +t1.c30=1 AND (t1.c31=t2.x OR t1.c31 IS NULL) AND t1.c31 < 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 2 +1 SIMPLE t1 ref_or_null k32 k32 160 const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,test.t2.x 798 Using where; Using index +DROP TABLE t1, t2; +# # End of 10.11 tests # set global innodb_stats_persistent= @innodb_stats_persistent_save; diff --git a/mysql-test/main/range.test b/mysql-test/main/range.test index a77cef34e4c..8d263b67397 100644 --- a/mysql-test/main/range.test +++ b/mysql-test/main/range.test @@ -1,4 +1,5 @@ --source include/no_valgrind_without_big.inc +--source include/have_sequence.inc # # Problem with range optimizer # @@ -2556,6 +2557,61 @@ evalp $query; drop table t1; +--echo # +--echo # MDEV-41179 MAX_KEY_PARTS ranges in select causing SEGV +--echo # + +CREATE TABLE t1 ( + c0 INT, c1 INT, c2 INT, c3 INT, c4 INT, c5 INT, c6 INT, c7 INT, + c8 INT, c9 INT, c10 INT, c11 INT, c12 INT, c13 INT, c14 INT, c15 INT, + c16 INT, c17 INT, c18 INT, c19 INT, c20 INT, c21 INT, c22 INT, c23 INT, + c24 INT, c25 INT, c26 INT, c27 INT, c28 INT, c29 INT, c30 INT, c31 INT, + c32 INT, + KEY k32(c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17, + c18,c19,c20,c21,c22,c23,c24,c25,c26,c27,c28,c29,c30,c31) +); + +INSERT INTO t1 (c0) VALUES (1), (2); + +SELECT * FROM t1 +WHERE c0=1 AND c1=2 AND c2=3 AND c3=4 AND c4=5 AND c5=6 AND c6=7 AND c7=8 + AND c8=9 AND c9=10 AND c10=11 AND c11=12 AND c12=13 AND c13=14 AND c14=15 + AND c15=16 AND c16=17 AND c17=18 AND c18=19 AND c19=20 AND c20=21 AND c21=22 + AND c22=23 AND c23=24 AND c24=25 AND c25=26 AND c26=27 AND c27=28 AND c28=29 + AND c29=30 AND c30=31 AND c31=32; + +SELECT * FROM t1 +WHERE c0=1 AND c1=2 AND c2=3 AND c3=4 AND c4=5 AND c5=6 AND c6=7 AND c7=8 + AND c8=9 AND c9=10 AND c10=11 AND c11=12 AND c12=13 AND c13=14 AND c14=15 + AND c15=16 AND c16=17 AND c17=18 AND c18=19 AND c19=20 AND c20=21 AND c21=22 + AND c22=23 AND c23=24 AND c24=25 AND c25=26 AND c26=27 AND c27=28 AND c28=29 + AND c29=30 AND c30=31 AND c31=32 AND c32=33; + +truncate t1; + +--echo # test best_access_path, non default OPTIMIZER_ADJ_FIX_REUSE_RANGE_FOR_REF +INSERT INTO t1 ( + c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, + c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31 +) +SELECT 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + IF(seq<=3, NULL, seq%5) FROM seq_1_to_2000; + +CREATE TABLE t2 (x INT); +INSERT INTO t2 VALUES (1),(2); +ANALYZE TABLE t1, t2 PERSISTENT FOR ALL; +SET optimizer_adjust_secondary_key_costs='fix_card_multiplier'; + +EXPLAIN SELECT COUNT(*) FROM t2 STRAIGHT_JOIN t1 FORCE INDEX(k32) +WHERE t1.c0=1 AND t1.c1=1 AND t1.c2=1 AND t1.c3=1 AND t1.c4=1 AND t1.c5=1 AND +t1.c6=1 AND t1.c7=1 AND t1.c8=1 AND t1.c9=1 AND t1.c10=1 AND t1.c11=1 AND +t1.c12=1 AND t1.c13=1 AND t1.c14=1 AND t1.c15=1 AND t1.c16=1 AND t1.c17=1 AND +t1.c18=1 AND t1.c19=1 AND t1.c20=1 AND t1.c21=1 AND t1.c22=1 AND t1.c23=1 AND +t1.c24=1 AND t1.c25=1 AND t1.c26=1 AND t1.c27=1 AND t1.c28=1 AND t1.c29=1 AND +t1.c30=1 AND (t1.c31=t2.x OR t1.c31 IS NULL) AND t1.c31 < 1; + +DROP TABLE t1, t2; + --echo # --echo # End of 10.11 tests --echo # diff --git a/mysql-test/main/range_mrr_icp.result b/mysql-test/main/range_mrr_icp.result index 7a5a1405c73..14e200d2516 100644 --- a/mysql-test/main/range_mrr_icp.result +++ b/mysql-test/main/range_mrr_icp.result @@ -3744,6 +3744,61 @@ id key1 3 2 drop table t1; # +# MDEV-41179 MAX_KEY_PARTS ranges in select causing SEGV +# +CREATE TABLE t1 ( +c0 INT, c1 INT, c2 INT, c3 INT, c4 INT, c5 INT, c6 INT, c7 INT, +c8 INT, c9 INT, c10 INT, c11 INT, c12 INT, c13 INT, c14 INT, c15 INT, +c16 INT, c17 INT, c18 INT, c19 INT, c20 INT, c21 INT, c22 INT, c23 INT, +c24 INT, c25 INT, c26 INT, c27 INT, c28 INT, c29 INT, c30 INT, c31 INT, +c32 INT, +KEY k32(c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17, +c18,c19,c20,c21,c22,c23,c24,c25,c26,c27,c28,c29,c30,c31) +); +INSERT INTO t1 (c0) VALUES (1), (2); +SELECT * FROM t1 +WHERE c0=1 AND c1=2 AND c2=3 AND c3=4 AND c4=5 AND c5=6 AND c6=7 AND c7=8 +AND c8=9 AND c9=10 AND c10=11 AND c11=12 AND c12=13 AND c13=14 AND c14=15 +AND c15=16 AND c16=17 AND c17=18 AND c18=19 AND c19=20 AND c20=21 AND c21=22 +AND c22=23 AND c23=24 AND c24=25 AND c25=26 AND c26=27 AND c27=28 AND c28=29 +AND c29=30 AND c30=31 AND c31=32; +c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 c31 c32 +SELECT * FROM t1 +WHERE c0=1 AND c1=2 AND c2=3 AND c3=4 AND c4=5 AND c5=6 AND c6=7 AND c7=8 +AND c8=9 AND c9=10 AND c10=11 AND c11=12 AND c12=13 AND c13=14 AND c14=15 +AND c15=16 AND c16=17 AND c17=18 AND c18=19 AND c19=20 AND c20=21 AND c21=22 +AND c22=23 AND c23=24 AND c24=25 AND c25=26 AND c26=27 AND c27=28 AND c28=29 +AND c29=30 AND c30=31 AND c31=32 AND c32=33; +c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 c31 c32 +truncate t1; +# test best_access_path, non default OPTIMIZER_ADJ_FIX_REUSE_RANGE_FOR_REF +INSERT INTO t1 ( +c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, +c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31 +) +SELECT 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +IF(seq<=3, NULL, seq%5) FROM seq_1_to_2000; +CREATE TABLE t2 (x INT); +INSERT INTO t2 VALUES (1),(2); +ANALYZE TABLE t1, t2 PERSISTENT FOR ALL; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status Table is already up to date +test.t2 analyze status Engine-independent statistics collected +test.t2 analyze status OK +SET optimizer_adjust_secondary_key_costs='fix_card_multiplier'; +EXPLAIN SELECT COUNT(*) FROM t2 STRAIGHT_JOIN t1 FORCE INDEX(k32) +WHERE t1.c0=1 AND t1.c1=1 AND t1.c2=1 AND t1.c3=1 AND t1.c4=1 AND t1.c5=1 AND +t1.c6=1 AND t1.c7=1 AND t1.c8=1 AND t1.c9=1 AND t1.c10=1 AND t1.c11=1 AND +t1.c12=1 AND t1.c13=1 AND t1.c14=1 AND t1.c15=1 AND t1.c16=1 AND t1.c17=1 AND +t1.c18=1 AND t1.c19=1 AND t1.c20=1 AND t1.c21=1 AND t1.c22=1 AND t1.c23=1 AND +t1.c24=1 AND t1.c25=1 AND t1.c26=1 AND t1.c27=1 AND t1.c28=1 AND t1.c29=1 AND +t1.c30=1 AND (t1.c31=t2.x OR t1.c31 IS NULL) AND t1.c31 < 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 2 +1 SIMPLE t1 ref_or_null k32 k32 160 const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,const,test.t2.x 798 Using where; Using index +DROP TABLE t1, t2; +# # End of 10.11 tests # set global innodb_stats_persistent= @innodb_stats_persistent_save; diff --git a/mysql-test/main/selectivity_innodb.result b/mysql-test/main/selectivity_innodb.result index c7eb4ac2608..c7e96a06e8a 100644 --- a/mysql-test/main/selectivity_innodb.result +++ b/mysql-test/main/selectivity_innodb.result @@ -2167,10 +2167,40 @@ TEXT36 TEXT,TEXT37 TEXT,TEXT38 TEXT,TEXT39 TEXT,TEXT40 TEXT, TEXT41 TEXT,TEXT42 TEXT,TEXT43 TEXT,TEXT44 TEXT,TEXT45 TEXT, TEXT46 TEXT,TEXT47 TEXT,TEXT48 TEXT,TEXT49 TEXT,TEXT50 TEXT ) ENGINE=InnoDB; +insert into t1 ( +TEXT1, TEXT2, TEXT3, TEXT4, TEXT5, +TEXT6, TEXT7, TEXT8, TEXT9, TEXT10, +TEXT11, TEXT12,TEXT13,TEXT14,TEXT15, +TEXT16,TEXT17,TEXT18,TEXT19,TEXT20, +TEXT21,TEXT22,TEXT23,TEXT24,TEXT25, +TEXT26,TEXT27,TEXT28,TEXT29,TEXT30, +TEXT31,TEXT32,TEXT33,TEXT34,TEXT35, +TEXT36,TEXT37,TEXT38,TEXT39,TEXT40, +TEXT41,TEXT42,TEXT43,TEXT44,TEXT45, +TEXT46,TEXT47,TEXT48,TEXT49,TEXT50 +) values ( +"TEXT1", "TEXT2", "TEXT3", "TEXT4", "TEXT5", +"TEXT6", "TEXT7", "TEXT8", "TEXT9", "TEXT10", +"TEXT11", "TEXT12","TEXT13","TEXT14","TEXT15", +"TEXT16","TEXT17","TEXT18","TEXT19","TEXT20", +"TEXT21","TEXT22","TEXT23","TEXT24","TEXT25", +"TEXT26","TEXT27","TEXT28","TEXT29","TEXT30", +"TEXT31","TEXT32","TEXT33","TEXT34","TEXT35", +"TEXT36","TEXT37","TEXT38","TEXT39","TEXT40", +"TEXT41","TEXT42","TEXT43","TEXT44","TEXT45", +"TEXT46","TEXT47","TEXT48","TEXT49","TEXT50" +); +# A second row, differing only in a column outside the hash key +INSERT INTO t1 SELECT * FROM t1; +UPDATE t1 SET TEXT50= 'X' LIMIT 1; +SELECT 1 FROM t1 NATURAL JOIN t1 AS t2; +1 +1 +1 EXPLAIN SELECT 1 FROM t1 NATURAL JOIN t1 AS t2; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 1 Using where -1 SIMPLE t2 hash_ALL NULL #hash#$hj 150 test.t1.TEXT1,test.t1.TEXT2,test.t1.TEXT3,test.t1.TEXT4,test.t1.TEXT5,test.t1.TEXT6,test.t1.TEXT7,test.t1.TEXT8,test.t1.TEXT9,test.t1.TEXT10,test.t1.TEXT11,test.t1.TEXT12,test.t1.TEXT13,test.t1.TEXT14,test.t1.TEXT15,test.t1.TEXT16,test.t1.TEXT17,test.t1.TEXT18,test.t1.TEXT19,test.t1.TEXT20,test.t1.TEXT21,test.t1.TEXT22,test.t1.TEXT23,test.t1.TEXT24,test.t1.TEXT25,test.t1.TEXT26,test.t1.TEXT27,test.t1.TEXT28,test.t1.TEXT29,test.t1.TEXT30,test.t1.TEXT31,test.t1.TEXT32,test.t1.TEXT33,test.t1.TEXT34,test.t1.TEXT35,test.t1.TEXT36,test.t1.TEXT37,test.t1.TEXT38,test.t1.TEXT39,test.t1.TEXT40,test.t1.TEXT41,test.t1.TEXT42,test.t1.TEXT43,test.t1.TEXT44,test.t1.TEXT45,test.t1.TEXT46,test.t1.TEXT47,test.t1.TEXT48,test.t1.TEXT49,test.t1.TEXT50 1 Using where; Using join buffer (flat, BNLH join) +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where +1 SIMPLE t2 hash_ALL NULL #hash#$hj 96 test.t1.TEXT1,test.t1.TEXT2,test.t1.TEXT3,test.t1.TEXT4,test.t1.TEXT5,test.t1.TEXT6,test.t1.TEXT7,test.t1.TEXT8,test.t1.TEXT9,test.t1.TEXT10,test.t1.TEXT11,test.t1.TEXT12,test.t1.TEXT13,test.t1.TEXT14,test.t1.TEXT15,test.t1.TEXT16,test.t1.TEXT17,test.t1.TEXT18,test.t1.TEXT19,test.t1.TEXT20,test.t1.TEXT21,test.t1.TEXT22,test.t1.TEXT23,test.t1.TEXT24,test.t1.TEXT25,test.t1.TEXT26,test.t1.TEXT27,test.t1.TEXT28,test.t1.TEXT29,test.t1.TEXT30,test.t1.TEXT31,test.t1.TEXT32 2 Using where; Using join buffer (flat, BNLH join) set join_cache_level=@tmp_jcl; drop table t1; # diff --git a/mysql-test/main/selectivity_innodb.test b/mysql-test/main/selectivity_innodb.test index c970e7d871d..06e33863dad 100644 --- a/mysql-test/main/selectivity_innodb.test +++ b/mysql-test/main/selectivity_innodb.test @@ -211,6 +211,7 @@ drop table t1; --echo # SET join_cache_level=3; + CREATE TABLE t1 ( TEXT1 TEXT, TEXT2 TEXT, TEXT3 TEXT, TEXT4 TEXT, TEXT5 TEXT, TEXT6 TEXT, TEXT7 TEXT, TEXT8 TEXT, TEXT9 TEXT, TEXT10 TEXT, @@ -223,6 +224,36 @@ CREATE TABLE t1 ( TEXT41 TEXT,TEXT42 TEXT,TEXT43 TEXT,TEXT44 TEXT,TEXT45 TEXT, TEXT46 TEXT,TEXT47 TEXT,TEXT48 TEXT,TEXT49 TEXT,TEXT50 TEXT ) ENGINE=InnoDB; + +insert into t1 ( + TEXT1, TEXT2, TEXT3, TEXT4, TEXT5, + TEXT6, TEXT7, TEXT8, TEXT9, TEXT10, + TEXT11, TEXT12,TEXT13,TEXT14,TEXT15, + TEXT16,TEXT17,TEXT18,TEXT19,TEXT20, + TEXT21,TEXT22,TEXT23,TEXT24,TEXT25, + TEXT26,TEXT27,TEXT28,TEXT29,TEXT30, + TEXT31,TEXT32,TEXT33,TEXT34,TEXT35, + TEXT36,TEXT37,TEXT38,TEXT39,TEXT40, + TEXT41,TEXT42,TEXT43,TEXT44,TEXT45, + TEXT46,TEXT47,TEXT48,TEXT49,TEXT50 +) values ( + "TEXT1", "TEXT2", "TEXT3", "TEXT4", "TEXT5", + "TEXT6", "TEXT7", "TEXT8", "TEXT9", "TEXT10", + "TEXT11", "TEXT12","TEXT13","TEXT14","TEXT15", + "TEXT16","TEXT17","TEXT18","TEXT19","TEXT20", + "TEXT21","TEXT22","TEXT23","TEXT24","TEXT25", + "TEXT26","TEXT27","TEXT28","TEXT29","TEXT30", + "TEXT31","TEXT32","TEXT33","TEXT34","TEXT35", + "TEXT36","TEXT37","TEXT38","TEXT39","TEXT40", + "TEXT41","TEXT42","TEXT43","TEXT44","TEXT45", + "TEXT46","TEXT47","TEXT48","TEXT49","TEXT50" +); + +--echo # A second row, differing only in a column outside the hash key +INSERT INTO t1 SELECT * FROM t1; +UPDATE t1 SET TEXT50= 'X' LIMIT 1; + +SELECT 1 FROM t1 NATURAL JOIN t1 AS t2; EXPLAIN SELECT 1 FROM t1 NATURAL JOIN t1 AS t2; set join_cache_level=@tmp_jcl; diff --git a/mysql-test/main/selectivity_no_engine.result b/mysql-test/main/selectivity_no_engine.result index 00e2b8fc397..9df22720c5b 100644 --- a/mysql-test/main/selectivity_no_engine.result +++ b/mysql-test/main/selectivity_no_engine.result @@ -312,7 +312,7 @@ EXPLAIN SELECT * FROM t1 AS a NATURAL JOIN t1 AS b; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE a ALL NULL NULL NULL NULL 5 Using where -1 SIMPLE b hash_ALL NULL #hash#$hj 1341 test.a.Host,test.a.User,test.a.Password,test.a.Select_priv,test.a.Insert_priv,test.a.Update_priv,test.a.Delete_priv,test.a.Create_priv,test.a.Drop_priv,test.a.Reload_priv,test.a.Shutdown_priv,test.a.Process_priv,test.a.File_priv,test.a.Grant_priv,test.a.References_priv,test.a.Index_priv,test.a.Alter_priv,test.a.Show_db_priv,test.a.Super_priv,test.a.Create_tmp_table_priv,test.a.Lock_tables_priv,test.a.Execute_priv,test.a.Repl_slave_priv,test.a.Repl_client_priv,test.a.Create_view_priv,test.a.Show_view_priv,test.a.Create_routine_priv,test.a.Alter_routine_priv,test.a.Create_user_priv,test.a.Event_priv,test.a.Trigger_priv,test.a.Create_tablespace_priv,test.a.Delete_history_priv,test.a.ssl_type,test.a.ssl_cipher,test.a.x509_issuer,test.a.x509_subject,test.a.max_questions,test.a.max_updates,test.a.max_connections,test.a.max_user_connections,test.a.plugin,test.a.authentication_string,test.a.password_expired,test.a.is_role,test.a.default_role,test.a.max_statement_time 5 Using where; Using join buffer (flat, BNLH join) +1 SIMPLE b hash_ALL NULL #hash#$hj 1268 test.a.Host,test.a.User,test.a.Password,test.a.Select_priv,test.a.Insert_priv,test.a.Update_priv,test.a.Delete_priv,test.a.Create_priv,test.a.Drop_priv,test.a.Reload_priv,test.a.Shutdown_priv,test.a.Process_priv,test.a.File_priv,test.a.Grant_priv,test.a.References_priv,test.a.Index_priv,test.a.Alter_priv,test.a.Show_db_priv,test.a.Super_priv,test.a.Create_tmp_table_priv,test.a.Lock_tables_priv,test.a.Execute_priv,test.a.Repl_slave_priv,test.a.Repl_client_priv,test.a.Create_view_priv,test.a.Show_view_priv,test.a.Create_routine_priv,test.a.Alter_routine_priv,test.a.Create_user_priv,test.a.Event_priv,test.a.Trigger_priv,test.a.Create_tablespace_priv 5 Using where; Using join buffer (flat, BNLH join) DROP TABLE t1,t2,t3; # # MDEV-31199: Assertion `field->table->stats_is_read' fails with hash_join_cardinality=on diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index e1e04c35921..411e1d30fe1 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -6474,7 +6474,7 @@ int ha_partition::multi_range_key_create_key(RANGE_SEQ_IF *seq, DBUG_PRINT("info",("partition range->range_flag: %u", range->range_flag)); DBUG_PRINT("info",("partition start_key->key: %p", start_key->key)); DBUG_PRINT("info",("partition start_key->length: %u", start_key->length)); - DBUG_PRINT("info",("partition start_key->keypart_map: %lu", + DBUG_PRINT("info",("partition start_key->keypart_map: %u", start_key->keypart_map)); DBUG_PRINT("info",("partition start_key->flag: %u", start_key->flag)); @@ -6499,7 +6499,7 @@ int ha_partition::multi_range_key_create_key(RANGE_SEQ_IF *seq, end_key= &range->end_key; DBUG_PRINT("info",("partition end_key->key: %p", end_key->key)); DBUG_PRINT("info",("partition end_key->length: %u", end_key->length)); - DBUG_PRINT("info",("partition end_key->keypart_map: %lu", + DBUG_PRINT("info",("partition end_key->keypart_map: %u", end_key->keypart_map)); DBUG_PRINT("info",("partition end_key->flag: %u", end_key->flag)); if (end_key->key) diff --git a/sql/handler.h b/sql/handler.h index f81b26a7642..cb408d1b262 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -3053,7 +3053,8 @@ uint calculate_key_len(TABLE *, uint, const uchar *, key_part_map); */ inline key_part_map make_keypart_map(uint N) { - return ((key_part_map)2 << (N)) - 1; + DBUG_ASSERT(N < MAX_REF_PARTS); + return (key_part_map) my_set_bits(N + 1); } /* @@ -3062,7 +3063,9 @@ inline key_part_map make_keypart_map(uint N) */ inline key_part_map make_prev_keypart_map(uint N) { - return ((key_part_map)1 << (N)) - 1; + DBUG_ASSERT(N <= MAX_REF_PARTS); + // do NOT call my_set_bit(0), 1<<-1 is undefined/compiler/overflow dependent + return N ? (key_part_map) my_set_bits(N) : 0; } diff --git a/sql/opt_range_mrr.cc b/sql/opt_range_mrr.cc index 452a6864f06..f944a7ac119 100644 --- a/sql/opt_range_mrr.cc +++ b/sql/opt_range_mrr.cc @@ -50,7 +50,7 @@ typedef struct st_sel_arg_range_seq KEY_PART *key_parts; SEL_ARG *start; /* Root node of the traversed SEL_ARG* graph */ - RANGE_SEQ_ENTRY stack[MAX_REF_PARTS]; + RANGE_SEQ_ENTRY stack[MAX_REF_PARTS+1]; int i; /* Index of last used element in the above array */ bool at_start; /* TRUE <=> The traversal has just started */ diff --git a/sql/sql_const.h b/sql/sql_const.h index 0f41719a361..55512ee2edb 100644 --- a/sql/sql_const.h +++ b/sql/sql_const.h @@ -32,7 +32,6 @@ #define MAX_FIELD_NAME (NAME_LEN+1) /* Max colum name length +1 */ #define MAX_SYS_VAR_LENGTH 32 #define MAX_KEY MAX_INDEXES /* Max used keys */ -#define MAX_REF_PARTS 32 /* Max parts used as ref */ /* Maximum length of the data part of an index lookup key. diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc index 34686976d46..f605342644a 100644 --- a/sql/sql_join_cache.cc +++ b/sql/sql_join_cache.cc @@ -4085,7 +4085,7 @@ void bka_range_seq_key_info(void *init_params, uint *length, { TABLE_REF *ref= &(((JOIN_CACHE*)init_params)->join_tab->ref); *length= ref->key_length; - *map= (key_part_map(1) << ref->key_parts) - 1; + *map= make_prev_keypart_map(ref->key_parts); } @@ -4150,7 +4150,7 @@ bool bka_range_seq_next(range_seq_t rseq, KEY_MULTI_RANGE *range) key_range *start_key= &range->start_key; if ((start_key->length= cache->get_next_key((uchar **) &start_key->key))) { - start_key->keypart_map= (1 << ref->key_parts) - 1; + start_key->keypart_map= make_prev_keypart_map(ref->key_parts); start_key->flag= HA_READ_KEY_EXACT; range->end_key= *start_key; range->end_key.flag= HA_READ_AFTER_KEY; @@ -4631,7 +4631,7 @@ bool bkah_range_seq_next(range_seq_t rseq, KEY_MULTI_RANGE *range) key_range *start_key= &range->start_key; if ((start_key->length= cache->get_next_key((uchar **) &start_key->key))) { - start_key->keypart_map= (1 << ref->key_parts) - 1; + start_key->keypart_map= make_prev_keypart_map(ref->key_parts); start_key->flag= HA_READ_KEY_EXACT; range->end_key= *start_key; range->end_key.flag= HA_READ_AFTER_KEY; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1161a555868..2bd102821b0 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7213,7 +7213,7 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array, KEY_FIELD *key_field) MDEV-24931: For materialized derived tables, don't add hash-join KEYUSE entries beyond max_key_parts(). Excess entries would cause generate_derived_keys_for_table() to build a key with more parts - than key_part_map (64 bits) or Bitmap<64> can represent. + than key_part_map can represent. */ if (form->pos_in_table_list && form->pos_in_table_list->is_materialized_derived()) @@ -9017,9 +9017,10 @@ best_access_path(JOIN *join, all_parts_used= table->opt_range[key].key_parts <= max_const_parts; } else - all_parts_used= (bool) (const_part & - ((key_part_map)1 - << table->opt_range[key].key_parts)); + all_parts_used= (table->opt_range[key].key_parts < + MAX_REF_PARTS) && + (const_part & ((key_part_map)1 + << table->opt_range[key].key_parts)); if (all_parts_used) { trace_access_idx.add("used_range_estimates", true); @@ -10689,8 +10690,8 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s, */ if (!is_hash_join_key_no(key) && table->opt_range_keys.is_set(key)) { - key_part_map quick_key_map= (key_part_map(1) << - table->opt_range[key].key_parts) - 1; + key_part_map quick_key_map= + make_prev_keypart_map(table->opt_range[key].key_parts); if (table->opt_range[key].rows && !(quick_key_map & ~table->const_key_parts[key])) { @@ -12729,8 +12730,9 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab, are_tables_local(join_tab, curr->used_tables)) break; } - if (curr == keyuse) - key_parts++; + if (curr == keyuse && + ++key_parts >= MAX_REF_PARTS) + break; } } first_keyuse= FALSE; @@ -12782,6 +12784,13 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab, } } } + if (add_key_part && + (uint) (key_part_info - keyinfo->key_part) >= key_parts) + { + /* Key is full (capped at MAX_REF_PARTS above); not used by ref */ + keyuse->keypart= NO_KEYPART; + add_key_part= FALSE; + } if (add_key_part) { Field *field= table->field[keyuse->keypart]; @@ -12893,6 +12902,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, } keyuse++; } while (keyuse->table == table && keyuse->key == key); + DBUG_ASSERT(keyparts <= MAX_REF_PARTS); if (!keyparts && allow_full_scan) { @@ -12971,7 +12981,10 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, Item *real= (keyuse->val)->real_item(); if (keyuse->null_rejecting && (real->type() == Item::FIELD_ITEM) && ((Item_field*)real)->field->maybe_null()) + { + DBUG_ASSERT(i < MAX_REF_PARTS); j->ref.null_rejecting|= (key_part_map)1 << i; + } keyuse_uses_no_tables= keyuse_uses_no_tables && !keyuse->used_tables; j->ref.uses_splitting |= (keyuse->validity_ref != NULL); @@ -13188,6 +13201,7 @@ static void add_not_null_conds(JOIN *join) { for (uint keypart= 0; keypart < tab->ref.key_parts; keypart++) { + DBUG_ASSERT(keypart < MAX_REF_PARTS); if (tab->ref.null_rejecting & ((key_part_map)1 << keypart)) { Item *item= tab->ref.items[keypart]; @@ -29837,6 +29851,7 @@ bool JOIN_TAB::save_explain_data(Explain_table_access *eta, store_key **key_ref= ref.key_copy; for (uint kp= 0; kp < ref.key_parts; kp++) { + DBUG_ASSERT(kp < MAX_REF_PARTS); if ((key_part_map(1) << kp) & ref.const_ref_part_map) { if (!(eta->ref_list.append_str(thd->mem_root, "const"))) diff --git a/sql/table.cc b/sql/table.cc index 6535801ef6a..d4cb5a79162 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -8498,7 +8498,7 @@ bool TABLE::alloc_keys(uint key_count) { memmove(new_key_info, s->key_info, sizeof(*key_info) * s->keys); memmove(new_const_key_parts, const_key_parts, - s->keys * sizeof(const_key_parts)); + s->keys * sizeof(*const_key_parts)); } s->key_info= key_info= new_key_info; const_key_parts= new_const_key_parts; diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 30064666b91..cfb35707ff1 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -48,6 +48,7 @@ Created 1/8/1996 Heikki Tuuri #include "fil0fil.h" #include "fil0crypt.h" #include "mysql_com.h" +#include "my_base.h" #include #include #include diff --git a/storage/maria/ma_range.c b/storage/maria/ma_range.c index 525bf27b90c..36bef0e3051 100644 --- a/storage/maria/ma_range.c +++ b/storage/maria/ma_range.c @@ -20,6 +20,7 @@ #include "maria_def.h" #include "ma_rt_index.h" +#include "my_bit.h" static ha_rows _ma_record_pos(MARIA_HA *,const uchar *, key_part_map, enum ha_rkey_function, ulonglong *); @@ -145,11 +146,12 @@ static ha_rows _ma_record_pos(MARIA_HA *info, const uchar *key_data, key_buff= info->lastkey_buff+info->s->base.max_key_length; _ma_pack_key(info, &key, inx, key_buff, key_data, keypart_map, (HA_KEYSEG**) 0); + DBUG_ASSERT(key.keyinfo->keysegs); DBUG_EXECUTE("key", _ma_print_key(DBUG_FILE, &key);); nextflag=maria_read_vec[search_flag]; /* Indicate if we're doing a search on a key prefix */ - if (((((key_part_map)1) << key.keyinfo->keysegs) - 1) != keypart_map) + if ((key_part_map) my_set_bits(key.keyinfo->keysegs) != keypart_map) nextflag |= SEARCH_PART_KEY; /* diff --git a/storage/mroonga/lib/mrn_count_skip_checker.cpp b/storage/mroonga/lib/mrn_count_skip_checker.cpp index cd22be31ef2..5b37601b08a 100644 --- a/storage/mroonga/lib/mrn_count_skip_checker.cpp +++ b/storage/mroonga/lib/mrn_count_skip_checker.cpp @@ -283,7 +283,7 @@ namespace mrn { } else { GRN_LOG(ctx_, GRN_LOG_DEBUG, "[mroonga][count-skip][false] " - "field's index are out of key part map: %u:%lu: <%s>:<%s>", + "field's index are out of key part map: %u:%u: <%s>:<%s>", i, target_key_part_map_, *(field->table_name), diff --git a/storage/rocksdb/ha_rocksdb.cc b/storage/rocksdb/ha_rocksdb.cc index bef1a8bfe43..08730fd3f8e 100644 --- a/storage/rocksdb/ha_rocksdb.cc +++ b/storage/rocksdb/ha_rocksdb.cc @@ -8376,8 +8376,7 @@ bool ha_rocksdb::is_using_full_key(key_part_map keypart_map, uint actual_key_parts) { return (keypart_map == HA_WHOLE_KEY) || - (keypart_map == ((key_part_map(1) << actual_key_parts) - - 1)); + (keypart_map == make_prev_keypart_map(actual_key_parts)); } /* @@ -8552,9 +8551,8 @@ int ha_rocksdb::index_read_map_impl(uchar *const buf, const uchar *const key, if (active_index != table->s->primary_key && table->key_info[active_index].flags & HA_NOSAME && find_flag == HA_READ_KEY_EXACT && using_full_key) { - key_part_map tmp_map = (key_part_map(1) << table->key_info[active_index] - .user_defined_key_parts) - - 1; + key_part_map tmp_map = make_prev_keypart_map(table->key_info[active_index] + .user_defined_key_parts); packed_size = kd.pack_index_tuple(table, m_pack_buffer, m_sk_packed_tuple, m_record_buffer, key, tmp_map); if (table->key_info[active_index].user_defined_key_parts != diff --git a/storage/spider/spd_db_conn.cc b/storage/spider/spd_db_conn.cc index ea3d2978cf0..f524127d4c6 100644 --- a/storage/spider/spd_db_conn.cc +++ b/storage/spider/spd_db_conn.cc @@ -1389,8 +1389,8 @@ int spider_db_append_key_columns( start_key_part_map = start_key->keypart_map & full_key_part_map; DBUG_PRINT("info", ("spider spider_user_defined_key_parts=%u", spider_user_defined_key_parts(key_info))); - DBUG_PRINT("info", ("spider full_key_part_map=%lu", full_key_part_map)); - DBUG_PRINT("info", ("spider start_key_part_map=%lu", start_key_part_map)); + DBUG_PRINT("info", ("spider full_key_part_map=%u", full_key_part_map)); + DBUG_PRINT("info", ("spider start_key_part_map=%u", start_key_part_map)); if (!start_key_part_map) DBUG_RETURN(0); @@ -1536,9 +1536,9 @@ int spider_db_append_key_where_internal( } DBUG_PRINT("info", ("spider spider_user_defined_key_parts=%u", key_info ? spider_user_defined_key_parts(key_info) : 0)); - DBUG_PRINT("info", ("spider full_key_part_map=%lu", full_key_part_map)); - DBUG_PRINT("info", ("spider start_key_part_map=%lu", start_key_part_map)); - DBUG_PRINT("info", ("spider end_key_part_map=%lu", end_key_part_map)); + DBUG_PRINT("info", ("spider full_key_part_map=%u", full_key_part_map)); + DBUG_PRINT("info", ("spider start_key_part_map=%u", start_key_part_map)); + DBUG_PRINT("info", ("spider end_key_part_map=%u", end_key_part_map)); #ifndef DBUG_OFF MY_BITMAP *tmp_map = dbug_tmp_use_all_columns(table, &table->read_set); @@ -1562,7 +1562,7 @@ int spider_db_append_key_where_internal( another_key = start_key; tgt_key_part_map = end_key_part_map; } - DBUG_PRINT("info", ("spider tgt_key_part_map=%lu", tgt_key_part_map)); + DBUG_PRINT("info", ("spider tgt_key_part_map=%u", tgt_key_part_map)); if (start_key_part_map == end_key_part_map) result_list->use_both_key = TRUE; @@ -1584,7 +1584,7 @@ int spider_db_append_key_where_internal( key_part++, key_count++ ) { - DBUG_PRINT("info", ("spider tgt_key_part_map=%lu", tgt_key_part_map)); + DBUG_PRINT("info", ("spider tgt_key_part_map=%u", tgt_key_part_map)); bool rev = key_part->key_part_flag & HA_REVERSE_SORT; store_length = key_part->store_length; field = key_part->field; diff --git a/storage/spider/spd_db_mysql.cc b/storage/spider/spd_db_mysql.cc index 2858b56c360..7ac8e8f341b 100644 --- a/storage/spider/spd_db_mysql.cc +++ b/storage/spider/spd_db_mysql.cc @@ -7769,8 +7769,8 @@ int spider_mbase_handler::append_key_column_types( start_key_part_map = start_key->keypart_map & full_key_part_map; DBUG_PRINT("info", ("spider spider_user_defined_key_parts=%u", spider_user_defined_key_parts(key_info))); - DBUG_PRINT("info", ("spider full_key_part_map=%lu", full_key_part_map)); - DBUG_PRINT("info", ("spider start_key_part_map=%lu", start_key_part_map)); + DBUG_PRINT("info", ("spider full_key_part_map=%u", full_key_part_map)); + DBUG_PRINT("info", ("spider start_key_part_map=%u", start_key_part_map)); if (!start_key_part_map) DBUG_RETURN(0); @@ -7836,8 +7836,8 @@ int spider_mbase_handler::append_key_join_columns_for_bka( start_key_part_map = start_key->keypart_map & full_key_part_map; DBUG_PRINT("info", ("spider spider_user_defined_key_parts=%u", spider_user_defined_key_parts(key_info))); - DBUG_PRINT("info", ("spider full_key_part_map=%lu", full_key_part_map)); - DBUG_PRINT("info", ("spider start_key_part_map=%lu", start_key_part_map)); + DBUG_PRINT("info", ("spider full_key_part_map=%u", full_key_part_map)); + DBUG_PRINT("info", ("spider start_key_part_map=%u", start_key_part_map)); if (!start_key_part_map) DBUG_RETURN(0); @@ -9495,8 +9495,8 @@ int spider_mbase_handler::append_key_column_values( start_key_part_map = start_key->keypart_map & full_key_part_map; DBUG_PRINT("info", ("spider spider_user_defined_key_parts=%u", spider_user_defined_key_parts(key_info))); - DBUG_PRINT("info", ("spider full_key_part_map=%lu", full_key_part_map)); - DBUG_PRINT("info", ("spider start_key_part_map=%lu", start_key_part_map)); + DBUG_PRINT("info", ("spider full_key_part_map=%u", full_key_part_map)); + DBUG_PRINT("info", ("spider start_key_part_map=%u", start_key_part_map)); if (!start_key_part_map) DBUG_RETURN(0); @@ -9574,8 +9574,8 @@ int spider_mbase_handler::append_key_column_values_with_name( start_key_part_map = start_key->keypart_map & full_key_part_map; DBUG_PRINT("info", ("spider spider_user_defined_key_parts=%u", spider_user_defined_key_parts(key_info))); - DBUG_PRINT("info", ("spider full_key_part_map=%lu", full_key_part_map)); - DBUG_PRINT("info", ("spider start_key_part_map=%lu", start_key_part_map)); + DBUG_PRINT("info", ("spider full_key_part_map=%u", full_key_part_map)); + DBUG_PRINT("info", ("spider start_key_part_map=%u", start_key_part_map)); if (!start_key_part_map) DBUG_RETURN(0);