Skip to content

Commit 787c5cf

Browse files
bodyhedia44mariadb-RexJohnston
authored andcommitted
MDEV-24931: Fix Bitmap<64>::is_prefix assertion with >64-column NATURAL JOIN on derived table
When a NATURAL JOIN operates on a derived table (or view with derived_merge=off) having more than 64 columns, the optimizer's generate_derived_keys_for_table() would: 1) Overflow a 32-bit shift: (key_part_map)(1 << parts) when parts >= 32 2) Create a derived key with more parts than Bitmap<64>/key_part_map can hold 3) Crash on DBUG_ASSERT(prefix_size <= width) in Bitmap<64>::is_prefix(65) Fix: cap the number of hash-join KEYUSE entries for a materialized derived table at the handler's max_key_parts(). Excess columns are excluded from the key, so generate_derived_keys_for_table() never builds a key with more parts than key_part_map (64 bits) or Bitmap<64> can represent. Also fix the shift to cast before shifting: (key_part_map) 1 << parts.
1 parent b13341f commit 787c5cf

3 files changed

Lines changed: 91 additions & 1 deletion

File tree

mysql-test/main/derived_opt.result

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,4 +567,36 @@ DROP TABLE t1, t2;
567567
#
568568
# End of 10.3 tests
569569
#
570+
#
571+
# MDEV-24931: Assertion `prefix_size <= width' failed in
572+
# Bitmap<64>::is_prefix with >64-column NATURAL JOIN on derived table
573+
#
574+
CREATE TABLE t1 (
575+
c1 INT, c2 INT, c3 INT, c4 INT, c5 INT, c6 INT, c7 INT, c8 INT,
576+
c9 INT, c10 INT, c11 INT, c12 INT, c13 INT, c14 INT, c15 INT, c16 INT,
577+
c17 INT, c18 INT, c19 INT, c20 INT, c21 INT, c22 INT, c23 INT, c24 INT,
578+
c25 INT, c26 INT, c27 INT, c28 INT, c29 INT, c30 INT, c31 INT, c32 INT,
579+
c33 INT, c34 INT, c35 INT, c36 INT, c37 INT, c38 INT, c39 INT, c40 INT,
580+
c41 INT, c42 INT, c43 INT, c44 INT, c45 INT, c46 INT, c47 INT, c48 INT,
581+
c49 INT, c50 INT, c51 INT, c52 INT, c53 INT, c54 INT, c55 INT, c56 INT,
582+
c57 INT, c58 INT, c59 INT, c60 INT, c61 INT, c62 INT, c63 INT, c64 INT,
583+
c65 INT
584+
) ENGINE=InnoDB;
585+
CREATE VIEW v1 AS SELECT * FROM t1;
586+
set optimizer_switch='derived_merge=off';
587+
# Derived table subquery
588+
SELECT * FROM t1 AS a NATURAL JOIN (SELECT * FROM t1) AS b;
589+
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 c33 c34 c35 c36 c37 c38 c39 c40 c41 c42 c43 c44 c45 c46 c47 c48 c49 c50 c51 c52 c53 c54 c55 c56 c57 c58 c59 c60 c61 c62 c63 c64 c65
590+
# View
591+
SELECT * FROM v1 NATURAL JOIN t1;
592+
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 c33 c34 c35 c36 c37 c38 c39 c40 c41 c42 c43 c44 c45 c46 c47 c48 c49 c50 c51 c52 c53 c54 c55 c56 c57 c58 c59 c60 c61 c62 c63 c64 c65
593+
# CTE
594+
WITH cte AS (SELECT * FROM t1) SELECT * FROM t1 NATURAL JOIN cte;
595+
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 c33 c34 c35 c36 c37 c38 c39 c40 c41 c42 c43 c44 c45 c46 c47 c48 c49 c50 c51 c52 c53 c54 c55 c56 c57 c58 c59 c60 c61 c62 c63 c64 c65
596+
set optimizer_switch= @save_optimizer_switch;
597+
DROP VIEW v1;
598+
DROP TABLE t1;
599+
#
600+
# End of 10.11 tests
601+
#
570602
set optimizer_switch=@exit_optimizer_switch;

mysql-test/main/derived_opt.test

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Initialize
2+
--source include/have_innodb.inc
23
--disable_warnings
34
drop table if exists t0,t1,t2,t3;
45
drop database if exists test1;
@@ -439,5 +440,43 @@ DROP TABLE t1, t2;
439440
--echo # End of 10.3 tests
440441
--echo #
441442

443+
--echo #
444+
--echo # MDEV-24931: Assertion `prefix_size <= width' failed in
445+
--echo # Bitmap<64>::is_prefix with >64-column NATURAL JOIN on derived table
446+
--echo #
447+
448+
CREATE TABLE t1 (
449+
c1 INT, c2 INT, c3 INT, c4 INT, c5 INT, c6 INT, c7 INT, c8 INT,
450+
c9 INT, c10 INT, c11 INT, c12 INT, c13 INT, c14 INT, c15 INT, c16 INT,
451+
c17 INT, c18 INT, c19 INT, c20 INT, c21 INT, c22 INT, c23 INT, c24 INT,
452+
c25 INT, c26 INT, c27 INT, c28 INT, c29 INT, c30 INT, c31 INT, c32 INT,
453+
c33 INT, c34 INT, c35 INT, c36 INT, c37 INT, c38 INT, c39 INT, c40 INT,
454+
c41 INT, c42 INT, c43 INT, c44 INT, c45 INT, c46 INT, c47 INT, c48 INT,
455+
c49 INT, c50 INT, c51 INT, c52 INT, c53 INT, c54 INT, c55 INT, c56 INT,
456+
c57 INT, c58 INT, c59 INT, c60 INT, c61 INT, c62 INT, c63 INT, c64 INT,
457+
c65 INT
458+
) ENGINE=InnoDB;
459+
460+
CREATE VIEW v1 AS SELECT * FROM t1;
461+
462+
set optimizer_switch='derived_merge=off';
463+
464+
--echo # Derived table subquery
465+
SELECT * FROM t1 AS a NATURAL JOIN (SELECT * FROM t1) AS b;
466+
467+
--echo # View
468+
SELECT * FROM v1 NATURAL JOIN t1;
469+
470+
--echo # CTE
471+
WITH cte AS (SELECT * FROM t1) SELECT * FROM t1 NATURAL JOIN cte;
472+
473+
set optimizer_switch= @save_optimizer_switch;
474+
DROP VIEW v1;
475+
DROP TABLE t1;
476+
477+
--echo #
478+
--echo # End of 10.11 tests
479+
--echo #
480+
442481
# The following command must be the last one the file
443482
set optimizer_switch=@exit_optimizer_switch;

sql/sql_select.cc

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7209,6 +7209,25 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array, KEY_FIELD *key_field)
72097209
if (field->can_optimize_hash_join(key_field->cond, key_field->val) !=
72107210
Data_type_compatibility::OK)
72117211
return false;
7212+
/*
7213+
MDEV-24931: For materialized derived tables, don't add hash-join
7214+
KEYUSE entries beyond max_key_parts(). Excess entries would cause
7215+
generate_derived_keys_for_table() to build a key with more parts
7216+
than key_part_map (64 bits) or Bitmap<64> can represent.
7217+
*/
7218+
if (form->pos_in_table_list &&
7219+
form->pos_in_table_list->is_materialized_derived())
7220+
{
7221+
uint existing= 0;
7222+
for (uint k= 0; k < keyuse_array->elements; k++)
7223+
{
7224+
KEYUSE *ku= dynamic_element(keyuse_array, k, KEYUSE*);
7225+
if (ku->table == form && is_hash_join_key_no(ku->key))
7226+
existing++;
7227+
}
7228+
if (existing >= form->file->max_key_parts())
7229+
return FALSE;
7230+
}
72127231
if (form->is_splittable())
72137232
form->add_splitting_info_for_key_field(key_field);
72147233
/*
@@ -14078,7 +14097,7 @@ bool generate_derived_keys_for_table(KEYUSE *keyuse, uint count, uint keys)
1407814097
do
1407914098
{
1408014099
keyuse->key= table->s->keys;
14081-
keyuse->keypart_map= (key_part_map) (1 << parts);
14100+
keyuse->keypart_map= (key_part_map) 1 << parts;
1408214101
keyuse++;
1408314102
i++;
1408414103
}

0 commit comments

Comments
 (0)