summaryrefslogtreecommitdiff
path: root/sql/opt_range.cc
diff options
context:
space:
mode:
authorAlexander Nozdrin <alik@sun.com>2009-10-19 17:36:19 +0400
committerAlexander Nozdrin <alik@sun.com>2009-10-19 17:36:19 +0400
commitbd60794fd8e532616f5b5f6d2200af0f4c7bc5ef (patch)
treeab9b420b768d8a6eb5ccda680604108cfee71b81 /sql/opt_range.cc
parent6b684c5806e0728b42c5c0ab7ae9939ab9dfec93 (diff)
parent03bf73de2fc2df414cafff03c8aaf3a58a3e7e48 (diff)
downloadmariadb-git-bd60794fd8e532616f5b5f6d2200af0f4c7bc5ef.tar.gz
Merge from mysql-trunk-merge.
Diffstat (limited to 'sql/opt_range.cc')
-rw-r--r--sql/opt_range.cc80
1 files changed, 76 insertions, 4 deletions
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 52e8d5d61c2..e1c7d4b38aa 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -5881,6 +5881,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
if (type == Item_func::LT_FUNC && (value->val_int() > 0))
type = Item_func::LE_FUNC;
else if (type == Item_func::GT_FUNC &&
+ (field->type() != FIELD_TYPE_BIT) &&
!((Field_num*)field)->unsigned_flag &&
!((Item_int*)value)->unsigned_flag &&
(value->val_int() < 0))
@@ -5918,7 +5919,9 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
*/
if (field->result_type() == INT_RESULT &&
value->result_type() == INT_RESULT &&
- ((Field_num*)field)->unsigned_flag && !((Item_int*)value)->unsigned_flag)
+ ((field->type() == FIELD_TYPE_BIT ||
+ ((Field_num *) field)->unsigned_flag) &&
+ !((Item_int*) value)->unsigned_flag))
{
longlong item_val= value->val_int();
if (item_val < 0)
@@ -6514,6 +6517,63 @@ get_range(SEL_ARG **e1,SEL_ARG **e2,SEL_ARG *root1)
}
+/**
+ Combine two range expression under a common OR. On a logical level, the
+ transformation is key_or( expr1, expr2 ) => expr1 OR expr2.
+
+ Both expressions are assumed to be in the SEL_ARG format. In a logic sense,
+ theformat is reminiscent of DNF, since an expression such as the following
+
+ ( 1 < kp1 < 10 AND p1 ) OR ( 10 <= kp2 < 20 AND p2 )
+
+ where there is a key consisting of keyparts ( kp1, kp2, ..., kpn ) and p1
+ and p2 are valid SEL_ARG expressions over keyparts kp2 ... kpn, is a valid
+ SEL_ARG condition. The disjuncts appear ordered by the minimum endpoint of
+ the first range and ranges must not overlap. It follows that they are also
+ ordered by maximum endpoints. Thus
+
+ ( 1 < kp1 <= 2 AND ( kp2 = 2 OR kp2 = 3 ) ) OR kp1 = 3
+
+ Is a a valid SER_ARG expression for a key of at least 2 keyparts.
+
+ For simplicity, we will assume that expr2 is a single range predicate,
+ i.e. on the form ( a < x < b AND ... ). It is easy to generalize to a
+ disjunction of several predicates by subsequently call key_or for each
+ disjunct.
+
+ The algorithm iterates over each disjunct of expr1, and for each disjunct
+ where the first keypart's range overlaps with the first keypart's range in
+ expr2:
+
+ If the predicates are equal for the rest of the keyparts, or if there are
+ no more, the range in expr2 has its endpoints copied in, and the SEL_ARG
+ node in expr2 is deallocated. If more ranges became connected in expr1, the
+ surplus is also dealocated. If they differ, two ranges are created.
+
+ - The range leading up to the overlap. Empty if endpoints are equal.
+
+ - The overlapping sub-range. May be the entire range if they are equal.
+
+ Finally, there may be one more range if expr2's first keypart's range has a
+ greater maximum endpoint than the last range in expr1.
+
+ For the overlapping sub-range, we recursively call key_or. Thus in order to
+ compute key_or of
+
+ (1) ( 1 < kp1 < 10 AND 1 < kp2 < 10 )
+
+ (2) ( 2 < kp1 < 20 AND 4 < kp2 < 20 )
+
+ We create the ranges 1 < kp <= 2, 2 < kp1 < 10, 10 <= kp1 < 20. For the
+ first one, we simply hook on the condition for the second keypart from (1)
+ : 1 < kp2 < 10. For the second range 2 < kp1 < 10, key_or( 1 < kp2 < 10, 4
+ < kp2 < 20 ) is called, yielding 1 < kp2 < 20. For the last range, we reuse
+ the range 4 < kp2 < 20 from (2) for the second keypart. The result is thus
+
+ ( 1 < kp1 <= 2 AND 1 < kp2 < 10 ) OR
+ ( 2 < kp1 < 10 AND 1 < kp2 < 20 ) OR
+ ( 10 <= kp1 < 20 AND 4 < kp2 < 20 )
+*/
static SEL_ARG *
key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2)
{
@@ -6665,7 +6725,21 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2)
key1=key1->tree_delete(save);
}
last->copy_min(tmp);
- if (last->copy_min(key2) || last->copy_max(key2))
+ bool full_range= last->copy_min(key2);
+ if (!full_range)
+ {
+ if (last->next && key2->cmp_max_to_min(last->next) >= 0)
+ {
+ last->max_value= last->next->min_value;
+ if (last->next->min_flag & NEAR_MIN)
+ last->max_flag&= ~NEAR_MAX;
+ else
+ last->max_flag|= NEAR_MAX;
+ }
+ else
+ full_range= last->copy_max(key2);
+ }
+ if (full_range)
{ // Full range
key1->free_tree();
for (; key2 ; key2=key2->next)
@@ -6675,8 +6749,6 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2)
return 0;
}
}
- key2=key2->next;
- continue;
}
if (cmp >= 0 && tmp->cmp_min_to_min(key2) < 0)