summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJorgen Loland <jorgen.loland@oracle.com>2013-04-12 09:39:56 +0200
committerJorgen Loland <jorgen.loland@oracle.com>2013-04-12 09:39:56 +0200
commit2c780b461dc62924b3f35bd9e17ec7237dfd31d8 (patch)
treeaa5317b60cfb82be31d8db4fa8c861fc5f593b1b
parentd20ec0f5ba3d80900de59d5de180240a72774f93 (diff)
downloadmariadb-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.cc29
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: