summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergei Petrunia <sergey@mariadb.com>2023-04-26 21:41:49 +0300
committerSergei Petrunia <sergey@mariadb.com>2023-04-27 13:48:43 +0300
commitcbd36645b7c4ba0ef0db97fd640cf89326d0746e (patch)
treefd31ea3b952970cc76c9005e9632abc839fac558
parent9c287c0a90fcb6637417bd118f62c78de78f75ee (diff)
downloadmariadb-git-bb-11.0-MDEV-31022-variant2.tar.gz
MDEV-31022 SIGSEGV in maria_create from create_internal_tmp_tablebb-11.0-MDEV-31022-variant2
Make create_internal_tmp_table() handle the case where the created table has multiple indexes.
-rw-r--r--mysql-test/main/derived.result28
-rw-r--r--mysql-test/main/derived.test24
-rw-r--r--sql/sql_select.cc50
3 files changed, 86 insertions, 16 deletions
diff --git a/mysql-test/main/derived.result b/mysql-test/main/derived.result
index 112a72a2bf6..b5b4341ce5e 100644
--- a/mysql-test/main/derived.result
+++ b/mysql-test/main/derived.result
@@ -1476,5 +1476,33 @@ a
2
drop table t1;
#
+# MDEV-31022: SIGSEGV in maria_create from create_internal_tmp_table
+# keydef incorrectly allocated on the stack in create_internal_tmp_table()
+#
+CREATE TABLE t1 (c CHAR(1) NULL) ENGINE=MyISAM;
+INSERT INTO t1 (c) VALUES (1);
+SET statement
+optimizer_where_cost=1,
+big_tables=1,
+in_predicate_conversion_threshold=2
+FOR
+SELECT * FROM t1 WHERE c IN ('','');
+c
+Warnings:
+Warning 1287 '@@big_tables' is deprecated and will be removed in a future release
+Warning 1287 '@@big_tables' is deprecated and will be removed in a future release
+SET statement
+optimizer_where_cost=1,
+big_tables=1,
+in_predicate_conversion_threshold=2,
+sql_mode=''
+FOR
+SELECT * FROM t1 WHERE c IN ('','');
+c
+Warnings:
+Warning 1287 '@@big_tables' is deprecated and will be removed in a future release
+Warning 1287 '@@big_tables' is deprecated and will be removed in a future release
+DROP TABLE t1;
+#
# End of 11.0 tests
#
diff --git a/mysql-test/main/derived.test b/mysql-test/main/derived.test
index e5f01e15821..b26472d41c0 100644
--- a/mysql-test/main/derived.test
+++ b/mysql-test/main/derived.test
@@ -1244,5 +1244,29 @@ SELECT a FROM t1 WHERE a IN ( 1, 1, 2, 194 );
drop table t1;
--echo #
+--echo # MDEV-31022: SIGSEGV in maria_create from create_internal_tmp_table
+--echo # keydef incorrectly allocated on the stack in create_internal_tmp_table()
+--echo #
+
+CREATE TABLE t1 (c CHAR(1) NULL) ENGINE=MyISAM;
+INSERT INTO t1 (c) VALUES (1);
+SET statement
+ optimizer_where_cost=1,
+ big_tables=1,
+ in_predicate_conversion_threshold=2
+FOR
+SELECT * FROM t1 WHERE c IN ('','');
+
+SET statement
+ optimizer_where_cost=1,
+ big_tables=1,
+ in_predicate_conversion_threshold=2,
+ sql_mode=''
+FOR
+SELECT * FROM t1 WHERE c IN ('','');
+
+DROP TABLE t1;
+
+--echo #
--echo # End of 11.0 tests
--echo #
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 26987c9072e..7c384bf2959 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -21766,14 +21766,17 @@ bool open_tmp_table(TABLE *table)
SYNOPSIS
create_internal_tmp_table()
table Table object that descrimes the table to be created
- keyinfo Description of the index (there is always one index)
+ keyinfo Description of the index(es)
start_recinfo engine's column descriptions
recinfo INOUT End of engine's column descriptions
options Option bits
DESCRIPTION
- Create an internal emporary table according to passed description. The is
- assumed to have one unique index or constraint.
+ Create an internal temporary table according to passed description. The
+ table may have indexes:
+ - a unique index or constraint used to handle GROUP BY or DISTINCT, or
+ - a non-unique index created by derived_with_keys optimization
+ - or, starting from 11.0: both of the above.
The passed array or TMP_ENGINE_COLUMNDEF structures must have this form:
@@ -21791,20 +21794,35 @@ bool open_tmp_table(TABLE *table)
*/
-bool create_internal_tmp_table(TABLE *table, KEY *keyinfo,
+bool create_internal_tmp_table(TABLE *table, KEY *all_key_info,
TMP_ENGINE_COLUMNDEF *start_recinfo,
TMP_ENGINE_COLUMNDEF **recinfo,
ulonglong options)
{
int error;
- MARIA_KEYDEF keydef;
+ MARIA_KEYDEF *keydef= nullptr;
MARIA_UNIQUEDEF uniquedef;
TABLE_SHARE *share= table->s;
MARIA_CREATE_INFO create_info;
+ uint keyno;
DBUG_ENTER("create_internal_tmp_table");
+ // Save the value of share->keys as it might be decremented when converting a
+ // key to a unique constraint.
+ uint original_keys= share->keys;
+
if (share->keys)
- { // Get keys for ni_create
+ {
+ if (!(keydef= (MARIA_KEYDEF*) alloc_root(&table->mem_root,
+ sizeof(*keydef) * share->keys)))
+ goto err;
+ bzero(keydef, sizeof(*keydef) * share->keys);
+ }
+
+ for (keyno= 0; keyno < original_keys; keyno++)
+ {
+ KEY *keyinfo= all_key_info + keyno;
+
bool using_unique_constraint=0;
HA_KEYSEG *seg= (HA_KEYSEG*) alloc_root(&table->mem_root,
sizeof(*seg) * keyinfo->user_defined_key_parts);
@@ -21830,9 +21848,10 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo,
}
/* Can't create a key; Make a unique constraint instead of a key */
- share->keys= 0;
- share->key_parts= share->ext_key_parts= 0;
- share->uniques= 1;
+ share->keys--;
+ share->key_parts -= keyinfo->user_defined_key_parts;
+ share->ext_key_parts -= keyinfo->user_defined_key_parts;
+ share->uniques=1;
using_unique_constraint=1;
bzero((char*) &uniquedef,sizeof(uniquedef));
uniquedef.keysegs=keyinfo->user_defined_key_parts;
@@ -21853,10 +21872,9 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo,
else
{
/* Create a key */
- bzero((char*) &keydef,sizeof(keydef));
- keydef.flag= keyinfo->flags & HA_NOSAME;
- keydef.keysegs= keyinfo->user_defined_key_parts;
- keydef.seg= seg;
+ keydef[keyno].flag= keyinfo->flags & HA_NOSAME;
+ keydef[keyno].keysegs= keyinfo->user_defined_key_parts;
+ keydef[keyno].seg= seg;
}
for (uint i=0; i < keyinfo->user_defined_key_parts ; i++,seg++)
{
@@ -21893,11 +21911,11 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo,
on INSERT be regarded at the same value
*/
if (!using_unique_constraint)
- keydef.flag|= HA_NULL_ARE_EQUAL;
+ keydef[keyno].flag|= HA_NULL_ARE_EQUAL;
}
}
if (share->keys)
- keyinfo->index_flags= table->file->index_flags(0, 0, 1);
+ keyinfo->index_flags= table->file->index_flags(keyno, 0, 1);
}
bzero((char*) &create_info,sizeof(create_info));
create_info.data_file_length= table->in_use->variables.tmp_disk_table_size;
@@ -21943,7 +21961,7 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo,
}
if (unlikely((error= maria_create(share->path.str, file_type, share->keys,
- &keydef, (uint) (*recinfo-start_recinfo),
+ keydef, (uint) (*recinfo-start_recinfo),
start_recinfo, share->uniques, &uniquedef,
&create_info, create_flags))))
{