1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00

MDEV-41179 MAX_KEY_PARTS ranges in select causing SEGV

When a select containing 32 ranges is made on a table containing a
compound key with 32 parts, the range optimizer can run off the end
of a stack variable, invalidly overwriting subsequent stack variables.

In the struct st_sel_arg_range_seq, we have an array
  RANGE_SEQ_ENTRY stack[MAX_REF_PARTS];

MAX_REF_PARTS is 32.

check_quick_select
  / sel_arg_range_seq_init
    initialises stack[0] as NOT a key part
  / sel_arg_range_seq_next
    iterates through the key parts, adding key part n to stack[n+1]

key part #32 gets referenced by step_down_to(), setting seq->i off the
end of the array.

Fix: RANGE_SEQ_ENTRY stack[MAX_REF_PARTS+1];

The above change exposed an issue with key length calculation on
MS Windows.  Calling make_prev_keypart_map(32) caused the resultant
bitmap to be calculated as (1UL << 32) - 1.  Using the MSVC compiler
this resulted in an empty key length calculation during
handler::index_read_map, causing an assertion in ha_innobase::index_read().

As we only need 32 bits to represent our key map, we change the type thus
-typedef ulong key_part_map;
+typedef uint32 key_part_map;

We correct make_keypart_map() and make_prev_keypart_map() to call our
overflow safe my_set_bits().  We also correct bka_range_seq_next()
and bkah_range_seq_next() to use make_prev_keypart_map().

We also add some DBUG_ASSERTS in key_part_map processing elsewhere,
exposing some issues in our BNLH implementation.  We cap the number of
keyuse parts here, altering the explain output of 2 of our tests.

Numerous places needed bit shift operations altered to use
make*keymap_part and various format strings needed to be corrected.
This commit is contained in:
Rex Johnston
2026-09-28 15:22:48 +13:00
committed by Rex Johnston
parent 8bee0f3610
commit 378d5bd10e
20 changed files with 290 additions and 44 deletions

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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 #

View File

@@ -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;

View File

@@ -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;
#

View File

@@ -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;

View File

@@ -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

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -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.

View File

@@ -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;

View File

@@ -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")))

View File

@@ -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;

View File

@@ -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 <sql_const.h>
#include <set>
#include <algorithm>

View File

@@ -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;
/*

View File

@@ -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),

View File

@@ -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 !=

View File

@@ -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;

View File

@@ -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);