Skip to content

Commit f003cc8

Browse files
committed
Fixed bug mdev-8603.
When building different range and index-merge trees the range optimizer could build an index-merge tree with an index scan containing less ranges then needed. This index-merge could be chosen as the best. Following this index-merge the executioner missed some rows in the result set. The invalid index scan was built due to an inconsistency in the code back-ported from mysql into 5.3 that fixed mysql bug #11765831: the code added to key_or() could change shared keys of the second ored tree. Partially the problem was fixed in the patch for mariadb bug #823301, but it turned out that only partially.
1 parent b948b5f commit f003cc8

File tree

5 files changed

+141
-21
lines changed

5 files changed

+141
-21
lines changed

mysql-test/r/range_vs_index_merge.result

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,11 @@ id select_type table type possible_keys key key_len ref rows Extra
6060
EXPLAIN
6161
SELECT * FROM City
6262
WHERE Population > 100000 AND Name LIKE 'Aba%' OR
63-
Country IN ('CAN', 'ARG') AND ID < 3800 OR
64-
Country < 'U' AND Name LIKE 'Zhu%' OR
65-
ID BETWEEN 3800 AND 3810;
63+
Country IN ('CAN', 'ARG') AND ID BETWEEN 120 AND 130 OR
64+
Country <= 'ALB' AND Name LIKE 'L%' OR
65+
ID BETWEEN 3807 AND 3810;
6666
id select_type table type possible_keys key key_len ref rows Extra
67-
1 SIMPLE City index_merge PRIMARY,Population,Country,Name Name,Country,PRIMARY 35,3,4 NULL 132 Using sort_union(Name,Country,PRIMARY); Using where
67+
1 SIMPLE City index_merge PRIMARY,Population,Country,Name Name,PRIMARY,Country 35,4,3 NULL 31 Using sort_union(Name,PRIMARY,Country); Using where
6868
EXPLAIN
6969
SELECT * FROM City
7070
WHERE (Population > 101000 AND Population < 115000);
@@ -1763,4 +1763,42 @@ a b
17631763
167 9999
17641764
168 10000
17651765
DROP TABLE t1;
1766+
#
1767+
# MDEV-8603: Wrong result OR/AND condition over index fields
1768+
#
1769+
CREATE TABLE t1 (
1770+
id INT NOT NULL,
1771+
state VARCHAR(64),
1772+
capital VARCHAR(64),
1773+
UNIQUE KEY (id),
1774+
KEY state (state,id),
1775+
KEY capital (capital, id)
1776+
);
1777+
INSERT INTO t1 VALUES
1778+
(1,'Arizona','Phoenix'),
1779+
(2,'Hawaii','Honolulu'),
1780+
(3,'Georgia','Atlanta'),
1781+
(4,'Florida','Tallahassee'),
1782+
(5,'Alaska','Juneau'),
1783+
(6,'Michigan','Lansing'),
1784+
(7,'Pennsylvania','Harrisburg'),
1785+
(8,'Virginia','Richmond')
1786+
;
1787+
EXPLAIN
1788+
SELECT * FROM t1 FORCE KEY (state,capital)
1789+
WHERE ( state = 'Alabama' OR state >= 'Colorado' ) AND id != 9
1790+
OR ( capital >= 'Topeka' OR state = 'Kansas' ) AND state != 'Texas';
1791+
id select_type table type possible_keys key key_len ref rows Extra
1792+
1 SIMPLE t1 range state,capital state 71 NULL 12 Using index condition; Using where
1793+
SELECT * FROM t1 FORCE KEY (state,capital)
1794+
WHERE ( state = 'Alabama' OR state >= 'Colorado' ) AND id != 9
1795+
OR ( capital >= 'Topeka' OR state = 'Kansas' ) AND state != 'Texas';
1796+
id state capital
1797+
4 Florida Tallahassee
1798+
3 Georgia Atlanta
1799+
2 Hawaii Honolulu
1800+
6 Michigan Lansing
1801+
7 Pennsylvania Harrisburg
1802+
8 Virginia Richmond
1803+
DROP TABLE t1;
17661804
set session optimizer_switch='index_merge_sort_intersection=default';

mysql-test/r/range_vs_index_merge_innodb,innodb_plugin.rdiff

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
--- ./r/range_vs_index_merge_innodb.result 2012-11-21 19:35:14.000000000 +0100
2-
+++ ./r/range_vs_index_merge_innodb,innodb_plugin.reject 2012-11-21 20:56:00.000000000 +0100
1+
--- range_vs_index_merge_innodb.result 2017-01-17 15:00:18.039148421 -0800
2+
+++ range_vs_index_merge_innodb,innodb_plugin.result 2017-01-17 14:58:45.129148312 -0800
33
@@ -50,14 +50,14 @@
44
WHERE (Population >= 100000 OR Name LIKE 'P%') AND Country='CAN' OR
55
(Population < 100000 OR Name Like 'T%') AND Country='ARG';
@@ -278,3 +278,12 @@
278278
FLUSH STATUS;
279279
SELECT * FROM City
280280
WHERE ((Name > 'Ca' AND Name < 'Cf') OR (Country > 'E' AND Country < 'H'))
281+
@@ -1790,7 +1790,7 @@
282+
WHERE ( state = 'Alabama' OR state >= 'Colorado' ) AND id != 9
283+
OR ( capital >= 'Topeka' OR state = 'Kansas' ) AND state != 'Texas';
284+
id select_type table type possible_keys key key_len ref rows Extra
285+
-1 SIMPLE t1 range state,capital state 71 NULL 10 Using index condition; Using where
286+
+1 SIMPLE t1 range state,capital state 71 NULL 10 Using where
287+
SELECT * FROM t1 FORCE KEY (state,capital)
288+
WHERE ( state = 'Alabama' OR state >= 'Colorado' ) AND id != 9
289+
OR ( capital >= 'Topeka' OR state = 'Kansas' ) AND state != 'Texas';

mysql-test/r/range_vs_index_merge_innodb.result

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,11 @@ id select_type table type possible_keys key key_len ref rows Extra
6161
EXPLAIN
6262
SELECT * FROM City
6363
WHERE Population > 100000 AND Name LIKE 'Aba%' OR
64-
Country IN ('CAN', 'ARG') AND ID < 3800 OR
65-
Country < 'U' AND Name LIKE 'Zhu%' OR
66-
ID BETWEEN 3800 AND 3810;
64+
Country IN ('CAN', 'ARG') AND ID BETWEEN 120 AND 130 OR
65+
Country <= 'ALB' AND Name LIKE 'L%' OR
66+
ID BETWEEN 3807 AND 3810;
6767
id select_type table type possible_keys key key_len ref rows Extra
68-
1 SIMPLE City index_merge PRIMARY,Population,Country,Name Name,Country,PRIMARY 35,3,4 NULL 125 Using sort_union(Name,Country,PRIMARY); Using where
68+
1 SIMPLE City index_merge PRIMARY,Population,Country,Name Name,Country,PRIMARY 35,3,4 NULL 33 Using sort_union(Name,Country,PRIMARY); Using where
6969
EXPLAIN
7070
SELECT * FROM City
7171
WHERE (Population > 101000 AND Population < 115000);
@@ -369,7 +369,7 @@ WHERE ((ID < 200) AND (Name LIKE 'Ha%' OR (Country > 'A' AND Country < 'ARG')))
369369
OR ((ID BETWEEN 100 AND 200) AND
370370
(Name LIKE 'Pa%' OR (Population > 103000 AND Population < 104000)));
371371
id select_type table type possible_keys key key_len ref rows Extra
372-
1 SIMPLE City range PRIMARY,Population,Country,Name PRIMARY 4 NULL 200 Using where
372+
1 SIMPLE City index_merge PRIMARY,Population,Country,Name Name,Country,PRIMARY 35,3,4 NULL 181 Using sort_union(Name,Country,PRIMARY); Using where
373373
SELECT * FROM City USE INDEX ()
374374
WHERE ((ID < 10) AND (Name LIKE 'H%' OR (Country > 'A' AND Country < 'ARG')))
375375
OR ((ID BETWEEN 100 AND 110) AND
@@ -1764,5 +1764,43 @@ a b
17641764
167 9999
17651765
168 10000
17661766
DROP TABLE t1;
1767+
#
1768+
# MDEV-8603: Wrong result OR/AND condition over index fields
1769+
#
1770+
CREATE TABLE t1 (
1771+
id INT NOT NULL,
1772+
state VARCHAR(64),
1773+
capital VARCHAR(64),
1774+
UNIQUE KEY (id),
1775+
KEY state (state,id),
1776+
KEY capital (capital, id)
1777+
);
1778+
INSERT INTO t1 VALUES
1779+
(1,'Arizona','Phoenix'),
1780+
(2,'Hawaii','Honolulu'),
1781+
(3,'Georgia','Atlanta'),
1782+
(4,'Florida','Tallahassee'),
1783+
(5,'Alaska','Juneau'),
1784+
(6,'Michigan','Lansing'),
1785+
(7,'Pennsylvania','Harrisburg'),
1786+
(8,'Virginia','Richmond')
1787+
;
1788+
EXPLAIN
1789+
SELECT * FROM t1 FORCE KEY (state,capital)
1790+
WHERE ( state = 'Alabama' OR state >= 'Colorado' ) AND id != 9
1791+
OR ( capital >= 'Topeka' OR state = 'Kansas' ) AND state != 'Texas';
1792+
id select_type table type possible_keys key key_len ref rows Extra
1793+
1 SIMPLE t1 range state,capital state 71 NULL 10 Using index condition; Using where
1794+
SELECT * FROM t1 FORCE KEY (state,capital)
1795+
WHERE ( state = 'Alabama' OR state >= 'Colorado' ) AND id != 9
1796+
OR ( capital >= 'Topeka' OR state = 'Kansas' ) AND state != 'Texas';
1797+
id state capital
1798+
4 Florida Tallahassee
1799+
3 Georgia Atlanta
1800+
2 Hawaii Honolulu
1801+
6 Michigan Lansing
1802+
7 Pennsylvania Harrisburg
1803+
8 Virginia Richmond
1804+
DROP TABLE t1;
17671805
set session optimizer_switch='index_merge_sort_intersection=default';
17681806
SET SESSION STORAGE_ENGINE=DEFAULT;

mysql-test/t/range_vs_index_merge.test

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ SELECT * FROM City
5757
EXPLAIN
5858
SELECT * FROM City
5959
WHERE Population > 100000 AND Name LIKE 'Aba%' OR
60-
Country IN ('CAN', 'ARG') AND ID < 3800 OR
61-
Country < 'U' AND Name LIKE 'Zhu%' OR
62-
ID BETWEEN 3800 AND 3810;
60+
Country IN ('CAN', 'ARG') AND ID BETWEEN 120 AND 130 OR
61+
Country <= 'ALB' AND Name LIKE 'L%' OR
62+
ID BETWEEN 3807 AND 3810;
6363

6464
# The output of the next 3 commands tells us about selectivities
6565
# of the conditions utilized in 2 queries following after them
@@ -1203,6 +1203,41 @@ SELECT * FROM t1
12031203

12041204
DROP TABLE t1;
12051205

1206+
1207+
--echo #
1208+
--echo # MDEV-8603: Wrong result OR/AND condition over index fields
1209+
--echo #
1210+
1211+
CREATE TABLE t1 (
1212+
id INT NOT NULL,
1213+
state VARCHAR(64),
1214+
capital VARCHAR(64),
1215+
UNIQUE KEY (id),
1216+
KEY state (state,id),
1217+
KEY capital (capital, id)
1218+
);
1219+
1220+
INSERT INTO t1 VALUES
1221+
(1,'Arizona','Phoenix'),
1222+
(2,'Hawaii','Honolulu'),
1223+
(3,'Georgia','Atlanta'),
1224+
(4,'Florida','Tallahassee'),
1225+
(5,'Alaska','Juneau'),
1226+
(6,'Michigan','Lansing'),
1227+
(7,'Pennsylvania','Harrisburg'),
1228+
(8,'Virginia','Richmond')
1229+
;
1230+
1231+
EXPLAIN
1232+
SELECT * FROM t1 FORCE KEY (state,capital)
1233+
WHERE ( state = 'Alabama' OR state >= 'Colorado' ) AND id != 9
1234+
OR ( capital >= 'Topeka' OR state = 'Kansas' ) AND state != 'Texas';
1235+
SELECT * FROM t1 FORCE KEY (state,capital)
1236+
WHERE ( state = 'Alabama' OR state >= 'Colorado' ) AND id != 9
1237+
OR ( capital >= 'Topeka' OR state = 'Kansas' ) AND state != 'Texas';
1238+
1239+
DROP TABLE t1;
1240+
12061241
#the following command must be the last one in the file
12071242
set session optimizer_switch='index_merge_sort_intersection=default';
12081243

sql/opt_range.cc

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9335,6 +9335,13 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2)
93359335

93369336
if (!tmp->next_key_part)
93379337
{
9338+
if (key2->use_count)
9339+
{
9340+
SEL_ARG *key2_cpy= new SEL_ARG(*key2);
9341+
if (key2_cpy)
9342+
return 0;
9343+
key2= key2_cpy;
9344+
}
93389345
/*
93399346
tmp->next_key_part is empty: cut the range that is covered
93409347
by tmp from key2.
@@ -9366,13 +9373,6 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2)
93669373
key2: [---]
93679374
tmp: [---------]
93689375
*/
9369-
if (key2->use_count)
9370-
{
9371-
SEL_ARG *key2_cpy= new SEL_ARG(*key2);
9372-
if (key2_cpy)
9373-
return 0;
9374-
key2= key2_cpy;
9375-
}
93769376
key2->copy_max_to_min(tmp);
93779377
continue;
93789378
}

0 commit comments

Comments
 (0)