summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/index_merge_innodb.result30
-rw-r--r--mysql-test/t/index_merge_innodb.test27
-rw-r--r--sql/sql_class.h3
-rw-r--r--sql/uniques.cc11
4 files changed, 70 insertions, 1 deletions
diff --git a/mysql-test/r/index_merge_innodb.result b/mysql-test/r/index_merge_innodb.result
index 0a80fa4171c..657b740a90b 100644
--- a/mysql-test/r/index_merge_innodb.result
+++ b/mysql-test/r/index_merge_innodb.result
@@ -805,3 +805,33 @@ sum(col1)
33632261
drop table t1;
set optimizer_switch=@tmp_optimizer_switch;
+#
+# MDEV-22728: SIGFPE in Unique::get_cost_calc_buff_size from prepare_search_best_index_intersect
+# on optimized builds
+#
+SET @save_sort_buffer_size=@@sort_buffer_size;
+SET @save_innodb_file_format= @@innodb_file_format;
+SET @save_innodb_large_prefix= @@innodb_large_prefix;
+SET sort_buffer_size=2048;
+SET GLOBAL innodb_file_format = BARRACUDA;
+SET GLOBAL innodb_large_prefix = ON;
+CREATE TABLE t1 (
+a VARCHAR(1024) CHARACTER SET UTF8 PRIMARY KEY,
+b INT,
+c INT,
+INDEX (b)
+) ENGINE=InnoDB CHARSET utf8 ROW_FORMAT= DYNAMIC;
+INSERT INTO t1 SELECT seq, seq, seq from seq_1_to_100;
+EXPLAIN SELECT * FROM t1 WHERE a='1' OR b < 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge PRIMARY,b b,PRIMARY 5,3074 NULL 4 Using sort_union(b,PRIMARY); Using where
+SELECT * FROM t1 WHERE a='1' OR b < 5;
+a b c
+2 2 2
+3 3 3
+4 4 4
+1 1 1
+DROP TABLE t1;
+SET GLOBAL innodb_file_format = @save_innodb_file_format;
+SET GLOBAL innodb_large_prefix = @save_innodb_large_prefix;
+SET sort_buffer_size= @save_sort_buffer_size;
diff --git a/mysql-test/t/index_merge_innodb.test b/mysql-test/t/index_merge_innodb.test
index 31ca1c253e4..07306b59c35 100644
--- a/mysql-test/t/index_merge_innodb.test
+++ b/mysql-test/t/index_merge_innodb.test
@@ -198,4 +198,31 @@ SELECT sum(col1) FROM t1 FORCE INDEX (key1,key2) WHERE (key1 between 10 and 819
drop table t1;
set optimizer_switch=@tmp_optimizer_switch;
+--echo #
+--echo # MDEV-22728: SIGFPE in Unique::get_cost_calc_buff_size from prepare_search_best_index_intersect
+--echo # on optimized builds
+--echo #
+
+SET @save_sort_buffer_size=@@sort_buffer_size;
+SET @save_innodb_file_format= @@innodb_file_format;
+SET @save_innodb_large_prefix= @@innodb_large_prefix;
+SET sort_buffer_size=2048;
+SET GLOBAL innodb_file_format = BARRACUDA;
+SET GLOBAL innodb_large_prefix = ON;
+
+CREATE TABLE t1 (
+ a VARCHAR(1024) CHARACTER SET UTF8 PRIMARY KEY,
+ b INT,
+ c INT,
+ INDEX (b)
+) ENGINE=InnoDB CHARSET utf8 ROW_FORMAT= DYNAMIC;
+INSERT INTO t1 SELECT seq, seq, seq from seq_1_to_100;
+EXPLAIN SELECT * FROM t1 WHERE a='1' OR b < 5;
+SELECT * FROM t1 WHERE a='1' OR b < 5;
+DROP TABLE t1;
+
+SET GLOBAL innodb_file_format = @save_innodb_file_format;
+SET GLOBAL innodb_large_prefix = @save_innodb_large_prefix;
+SET sort_buffer_size= @save_sort_buffer_size;
+
disconnect disable_purge;
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 9071a2db516..7ca3896a69d 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -5216,6 +5216,9 @@ public:
{
ulonglong max_elems_in_tree=
max_in_memory_size / ALIGN_SIZE(sizeof(TREE_ELEMENT)+key_size);
+
+ if (max_elems_in_tree == 0)
+ max_elems_in_tree= 1;
return (int) (sizeof(uint)*(1 + nkeys/max_elems_in_tree));
}
diff --git a/sql/uniques.cc b/sql/uniques.cc
index 03f25d31384..27da0fc54c6 100644
--- a/sql/uniques.cc
+++ b/sql/uniques.cc
@@ -317,6 +317,9 @@ double Unique::get_use_cost(uint *buffer, size_t nkeys, uint key_size,
max_elements_in_tree= ((size_t) max_in_memory_size /
ALIGN_SIZE(sizeof(TREE_ELEMENT)+key_size));
+ if (max_elements_in_tree == 0)
+ max_elements_in_tree= 1;
+
n_full_trees= nkeys / max_elements_in_tree;
last_tree_elems= nkeys % max_elements_in_tree;
@@ -781,7 +784,13 @@ bool Unique::get(TABLE *table)
/* Not enough memory; Save the result to file && free memory used by tree */
if (flush())
return 1;
- size_t buff_sz= (max_in_memory_size / full_size + 1) * full_size;
+
+ /*
+ merge_buffer must fit at least MERGEBUFF2 + 1 keys, because
+ merge_index() can merge that many BUFFPEKs at once. The extra space for
+ one key for Sort_param::unique_buff
+ */
+ size_t buff_sz= MY_MAX(MERGEBUFF2+1, max_in_memory_size/full_size+1) * full_size;
if (!(sort_buffer= (uchar*) my_malloc(buff_sz, MYF(MY_THREAD_SPECIFIC|MY_WME))))
return 1;