mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
Bug #54802: 'NOT BETWEEN' evaluation is incorrect
Queries involving predicates of the form "const NOT BETWEEN not_indexed_column AND indexed_column" could return wrong data due to incorrect handling by the range optimizer. For "c NOT BETWEEN f1 AND f2" predicates, get_mm_tree() produces a disjunction of the SEL_ARG trees for "f1 > c" and "f2 < c". If one of the trees is empty (i.e. one of the arguments is not sargable) the resulting tree should be empty as well, since the whole expression in this case is not sargable. The above logic is implemented in get_mm_tree() as follows. The initial state of the resulting tree is NULL (aka empty). We then iterate through arguments and compute the corresponding SEL_ARG tree (either "f1 > c" or "f2 < c"). If the resulting tree is NULL, it is simply replaced by the generated tree. Otherwise it is replaced by a disjunction of itself and the generated tree. The obvious flaw in this implementation is that if the first argument is not sargable and thus produces a NULL tree, the resulting tree will simply be replaced by the tree for the second argument. As a result, "c NOT BETWEEN f1 AND f2" will end up as just "f2 < c". Fixed by adding a check so that when the first argument produces an empty tree for the NOT BETWEEN case, the loop is aborted with an empty tree as a result. The whole idea of using a loop for 2 arguments does not make much sense, but it was probably used to avoid code duplication for several BETWEEN variants.
This commit is contained in:
parent
bc05efd8aa
commit
e7b2688271
3 changed files with 29 additions and 0 deletions
|
@ -1653,4 +1653,17 @@ a b
|
|||
0 0
|
||||
1 1
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Bug #54802: 'NOT BETWEEN' evaluation is incorrect
|
||||
#
|
||||
CREATE TABLE t1 (c_key INT, c_notkey INT, KEY(c_key));
|
||||
INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3);
|
||||
EXPLAIN SELECT * FROM t1 WHERE 2 NOT BETWEEN c_notkey AND c_key;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL c_key NULL NULL NULL 3 Using where
|
||||
SELECT * FROM t1 WHERE 2 NOT BETWEEN c_notkey AND c_key;
|
||||
c_key c_notkey
|
||||
1 1
|
||||
3 3
|
||||
DROP TABLE t1;
|
||||
End of 5.1 tests
|
||||
|
|
|
@ -1313,4 +1313,16 @@ SELECT * FROM t1 FORCE INDEX (PRIMARY)
|
|||
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #
|
||||
--echo # Bug #54802: 'NOT BETWEEN' evaluation is incorrect
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (c_key INT, c_notkey INT, KEY(c_key));
|
||||
INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3);
|
||||
|
||||
EXPLAIN SELECT * FROM t1 WHERE 2 NOT BETWEEN c_notkey AND c_key;
|
||||
SELECT * FROM t1 WHERE 2 NOT BETWEEN c_notkey AND c_key;
|
||||
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo End of 5.1 tests
|
||||
|
|
|
@ -5526,7 +5526,11 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond)
|
|||
SEL_TREE *tmp= get_full_func_mm_tree(param, cond_func,
|
||||
field_item, (Item*)(intptr)i, inv);
|
||||
if (inv)
|
||||
{
|
||||
tree= !tree ? tmp : tree_or(param, tree, tmp);
|
||||
if (tree == NULL)
|
||||
break;
|
||||
}
|
||||
else
|
||||
tree= tree_and(param, tree, tmp);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue