diff options
author | Jorgen Loland <jorgen.loland@oracle.com> | 2013-04-12 09:39:56 +0200 |
---|---|---|
committer | Jorgen Loland <jorgen.loland@oracle.com> | 2013-04-12 09:39:56 +0200 |
commit | 2c780b461dc62924b3f35bd9e17ec7237dfd31d8 (patch) | |
tree | aa5317b60cfb82be31d8db4fa8c861fc5f593b1b | |
parent | d20ec0f5ba3d80900de59d5de180240a72774f93 (diff) | |
download | mariadb-git-2c780b461dc62924b3f35bd9e17ec7237dfd31d8.tar.gz |
Bug#16540042: WRONG QUERY RESULT WHEN USING RANGE OVER
PARTIAL INDEX
Consider the following table definition:
CREATE TABLE t (
my_col CHAR(10),
...
INDEX my_idx (my_col(1))
)
The my_idx index is not able to distinguish between rows with
equal first-character my_col-values (e.g. "f", "foo", "fee").
Prior to this CS, the range optimizer would translate
"WHERE my_col NOT IN ('f', 'h')" into (optimizer trace syntax)
"ranges": [
"NULL < my_col < f",
"f < my_col"
]
But this was not correct because the rows with values "foo"
and "fee" would not belong to any of those ranges. However, the
predicate "my_col != 'f' AND my_col != 'h'" would translate
to
"ranges": [
"NULL < my_col"
]
because get_mm_leaf() changes from "<" to "<=" for partial
keyparts. This CS changes the range optimizer implementation
for NOT IN to behave like a conjunction of NOT EQUAL: it
replaces "<" with "<=" for all but the first range when the
keypart is partial.
-rw-r--r-- | sql/opt_range.cc | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 9604ed1e3b3..b8f583a66ed 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -5345,6 +5345,34 @@ static SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Item_func *cond_func, { new_interval->min_value= last_val->max_value; new_interval->min_flag= NEAR_MIN; + + /* + If the interval is over a partial keypart, the + interval must be "c_{i-1} <= X < c_i" instead of + "c_{i-1} < X < c_i". Reason: + + Consider a table with a column "my_col VARCHAR(3)", + and an index with definition + "INDEX my_idx my_col(1)". If the table contains rows + with my_col values "f" and "foo", the index will not + distinguish the two rows. + + Note that tree_or() below will effectively merge + this range with the range created for c_{i-1} and + we'll eventually end up with only one range: + "NULL < X". + + Partitioning indexes are never partial. + */ + if (param->using_real_indexes) + { + const KEY key= + param->table->key_info[param->real_keynr[idx]]; + const KEY_PART_INFO *kpi= key.key_part + new_interval->part; + + if (kpi->key_part_flag & HA_PART_KEY_SEG) + new_interval->min_flag= 0; + } } } /* @@ -5827,6 +5855,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, if (key_part->image_type == Field::itMBR) { + // @todo: use is_spatial_operator() instead? switch (type) { case Item_func::SP_EQUALS_FUNC: case Item_func::SP_DISJOINT_FUNC: |