mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
MDEV-8599 "WHERE varchar_field LIKE temporal_const" does not use range optimizer
This commit is contained in:
parent
6e091dc7ff
commit
9d884fd3d3
5 changed files with 247 additions and 174 deletions
|
@ -227,5 +227,30 @@ Warnings:
|
|||
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where ((`test`.`t1`.`a` = 10.0) and (`test`.`t1`.`a` like 10.00))
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# MDEV-8599 "WHERE varchar_field LIKE temporal_const" does not use range optimizer
|
||||
#
|
||||
CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET latin1, KEY(a)) ENGINE=MyISAM;
|
||||
INSERT INTO t1 VALUES ('00:00:00');
|
||||
INSERT INTO t1 VALUES ('00:00:01');
|
||||
INSERT INTO t1 VALUES ('00:00:02');
|
||||
INSERT INTO t1 VALUES ('00:00:03');
|
||||
INSERT INTO t1 VALUES ('00:00:04');
|
||||
INSERT INTO t1 VALUES ('00:00:05');
|
||||
INSERT INTO t1 VALUES ('00:00:06');
|
||||
INSERT INTO t1 VALUES ('00:00:07');
|
||||
EXPLAIN SELECT * FROM t1 WHERE a LIKE '00:00:00';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range a a 13 NULL 1 Using where; Using index
|
||||
EXPLAIN SELECT * FROM t1 WHERE a LIKE TIME'00:00:00';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range a a 13 NULL 1 Using where; Using index
|
||||
SELECT * FROM t1 WHERE a LIKE '00:00:00';
|
||||
a
|
||||
00:00:00
|
||||
SELECT * FROM t1 WHERE a LIKE TIME'00:00:00';
|
||||
a
|
||||
00:00:00
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# End of 10.1 tests
|
||||
#
|
||||
|
|
|
@ -163,6 +163,25 @@ SELECT * FROM t1 WHERE a=10.0 AND a LIKE 10.00;
|
|||
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=10.0 AND a LIKE 10.00;
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-8599 "WHERE varchar_field LIKE temporal_const" does not use range optimizer
|
||||
--echo #
|
||||
CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET latin1, KEY(a)) ENGINE=MyISAM;
|
||||
INSERT INTO t1 VALUES ('00:00:00');
|
||||
INSERT INTO t1 VALUES ('00:00:01');
|
||||
INSERT INTO t1 VALUES ('00:00:02');
|
||||
INSERT INTO t1 VALUES ('00:00:03');
|
||||
INSERT INTO t1 VALUES ('00:00:04');
|
||||
INSERT INTO t1 VALUES ('00:00:05');
|
||||
INSERT INTO t1 VALUES ('00:00:06');
|
||||
INSERT INTO t1 VALUES ('00:00:07');
|
||||
EXPLAIN SELECT * FROM t1 WHERE a LIKE '00:00:00';
|
||||
EXPLAIN SELECT * FROM t1 WHERE a LIKE TIME'00:00:00';
|
||||
SELECT * FROM t1 WHERE a LIKE '00:00:00';
|
||||
SELECT * FROM t1 WHERE a LIKE TIME'00:00:00';
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # End of 10.1 tests
|
||||
--echo #
|
||||
|
|
|
@ -120,6 +120,10 @@ public:
|
|||
friend class Item_func;
|
||||
};
|
||||
|
||||
|
||||
class SEL_ARG;
|
||||
struct KEY_PART;
|
||||
|
||||
class Item_bool_func :public Item_int_func
|
||||
{
|
||||
protected:
|
||||
|
@ -147,6 +151,9 @@ protected:
|
|||
SEL_TREE *get_ne_mm_tree(RANGE_OPT_PARAM *param,
|
||||
Field *field, Item *lt_value, Item *gt_value,
|
||||
Item_result cmp_type);
|
||||
virtual SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, Field *field,
|
||||
KEY_PART *key_part,
|
||||
Item_func::Functype type, Item *value);
|
||||
public:
|
||||
Item_bool_func() :Item_int_func() {}
|
||||
Item_bool_func(Item *a) :Item_int_func(a) {}
|
||||
|
@ -1437,6 +1444,9 @@ protected:
|
|||
DBUG_ENTER("Item_func_null_predicate::get_func_mm_tree");
|
||||
DBUG_RETURN(get_mm_parts(param, field, functype(), value, cmp_type));
|
||||
}
|
||||
SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, Field *field,
|
||||
KEY_PART *key_part,
|
||||
Item_func::Functype type, Item *value);
|
||||
public:
|
||||
Item_func_null_predicate(Item *a) :Item_bool_func(a) { }
|
||||
void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
|
||||
|
@ -1552,6 +1562,10 @@ class Item_func_like :public Item_bool_func2
|
|||
DTCollation cmp_collation;
|
||||
String cmp_value1, cmp_value2;
|
||||
bool with_sargable_pattern() const;
|
||||
protected:
|
||||
SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, Field *field,
|
||||
KEY_PART *key_part,
|
||||
Item_func::Functype type, Item *value);
|
||||
public:
|
||||
int escape;
|
||||
|
||||
|
|
359
sql/opt_range.cc
359
sql/opt_range.cc
|
@ -945,10 +945,6 @@ class TABLE_READ_PLAN;
|
|||
struct st_index_scan_info;
|
||||
struct st_ror_scan_info;
|
||||
|
||||
static SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param,COND *cond_func,Field *field,
|
||||
KEY_PART *key_part,
|
||||
Item_func::Functype type,Item *value);
|
||||
|
||||
static bool is_key_scan_ror(PARAM *param, uint keynr, uint8 nparts);
|
||||
static ha_rows check_quick_select(PARAM *param, uint idx, bool index_only,
|
||||
SEL_ARG *tree, bool update_tbl_stats,
|
||||
|
@ -8235,7 +8231,19 @@ Item_bool_func::get_mm_parts(RANGE_OPT_PARAM *param, Field *field,
|
|||
DBUG_RETURN(0); // OOM
|
||||
if (!value || !(value->used_tables() & ~param->read_tables))
|
||||
{
|
||||
sel_arg= get_mm_leaf(param,this,key_part->field,key_part,type,value);
|
||||
/*
|
||||
We need to restore the runtime mem_root of the thread in this
|
||||
function because it evaluates the value of its argument, while
|
||||
the argument can be any, e.g. a subselect. The subselect
|
||||
items, in turn, assume that all the memory allocated during
|
||||
the evaluation has the same life span as the item itself.
|
||||
TODO: opt_range.cc should not reset thd->mem_root at all.
|
||||
*/
|
||||
MEM_ROOT *tmp_root= param->mem_root;
|
||||
param->thd->mem_root= param->old_root;
|
||||
sel_arg= get_mm_leaf(param, key_part->field, key_part, type, value);
|
||||
param->thd->mem_root= tmp_root;
|
||||
|
||||
if (!sel_arg)
|
||||
continue;
|
||||
if (sel_arg->type == SEL_ARG::IMPOSSIBLE)
|
||||
|
@ -8263,53 +8271,144 @@ Item_bool_func::get_mm_parts(RANGE_OPT_PARAM *param, Field *field,
|
|||
}
|
||||
|
||||
|
||||
static SEL_ARG *
|
||||
get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
|
||||
KEY_PART *key_part, Item_func::Functype type,Item *value)
|
||||
SEL_ARG *
|
||||
Item_func_null_predicate::get_mm_leaf(RANGE_OPT_PARAM *param,
|
||||
Field *field, KEY_PART *key_part,
|
||||
Item_func::Functype type,
|
||||
Item *value)
|
||||
{
|
||||
MEM_ROOT *alloc= param->mem_root;
|
||||
DBUG_ENTER("Item_func_null_predicate::get_mm_leaf");
|
||||
DBUG_ASSERT(!value);
|
||||
/*
|
||||
No check for field->table->maybe_null. It's perfecly fine to use range
|
||||
access for cases like
|
||||
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON t2.key IS [NOT] NULL
|
||||
|
||||
ON expression is evaluated before considering NULL-complemented rows, so
|
||||
IS [NOT] NULL has regular semantics.
|
||||
*/
|
||||
if (!field->real_maybe_null())
|
||||
DBUG_RETURN(type == ISNULL_FUNC ? &null_element : NULL);
|
||||
SEL_ARG *tree;
|
||||
if (!(tree= new (alloc) SEL_ARG(field, is_null_string, is_null_string)))
|
||||
DBUG_RETURN(0);
|
||||
if (type == Item_func::ISNOTNULL_FUNC)
|
||||
{
|
||||
tree->min_flag=NEAR_MIN; /* IS NOT NULL -> X > NULL */
|
||||
tree->max_flag=NO_MAX_RANGE;
|
||||
}
|
||||
DBUG_RETURN(tree);
|
||||
}
|
||||
|
||||
|
||||
SEL_ARG *
|
||||
Item_func_like::get_mm_leaf(RANGE_OPT_PARAM *param,
|
||||
Field *field, KEY_PART *key_part,
|
||||
Item_func::Functype type, Item *value)
|
||||
{
|
||||
DBUG_ENTER("Item_func_like::get_mm_leaf");
|
||||
DBUG_ASSERT(value);
|
||||
|
||||
if (key_part->image_type != Field::itRAW)
|
||||
DBUG_RETURN(0);
|
||||
|
||||
if (param->using_real_indexes &&
|
||||
!field->optimize_range(param->real_keynr[key_part->key],
|
||||
key_part->part))
|
||||
DBUG_RETURN(0);
|
||||
|
||||
if (field->result_type() == STRING_RESULT &&
|
||||
field->charset() != compare_collation())
|
||||
DBUG_RETURN(0);
|
||||
|
||||
StringBuffer<MAX_FIELD_WIDTH> tmp(value->collation.collation);
|
||||
String *res;
|
||||
|
||||
if (!(res= value->val_str(&tmp)))
|
||||
DBUG_RETURN(&null_element);
|
||||
|
||||
if (field->cmp_type() != STRING_RESULT)
|
||||
DBUG_RETURN(0);
|
||||
|
||||
/*
|
||||
TODO:
|
||||
Check if this was a function. This should have be optimized away
|
||||
in the sql_select.cc
|
||||
*/
|
||||
if (res != &tmp)
|
||||
{
|
||||
tmp.copy(*res); // Get own copy
|
||||
res= &tmp;
|
||||
}
|
||||
|
||||
uint maybe_null= (uint) field->real_maybe_null();
|
||||
uint field_length= field->pack_length() + maybe_null;
|
||||
size_t offset= maybe_null;
|
||||
size_t length= key_part->store_length;
|
||||
|
||||
if (length != key_part->length + maybe_null)
|
||||
{
|
||||
/* key packed with length prefix */
|
||||
offset+= HA_KEY_BLOB_LENGTH;
|
||||
field_length= length - HA_KEY_BLOB_LENGTH;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (unlikely(length < field_length))
|
||||
{
|
||||
/*
|
||||
This can only happen in a table created with UNIREG where one key
|
||||
overlaps many fields
|
||||
*/
|
||||
length= field_length;
|
||||
}
|
||||
else
|
||||
field_length= length;
|
||||
}
|
||||
length+= offset;
|
||||
uchar *min_str,*max_str;
|
||||
if (!(min_str= (uchar*) alloc_root(param->mem_root, length*2)))
|
||||
DBUG_RETURN(0);
|
||||
max_str= min_str + length;
|
||||
if (maybe_null)
|
||||
max_str[0]= min_str[0]=0;
|
||||
|
||||
size_t min_length, max_length;
|
||||
field_length-= maybe_null;
|
||||
if (my_like_range(field->charset(),
|
||||
res->ptr(), res->length(),
|
||||
escape, wild_one, wild_many,
|
||||
field_length,
|
||||
(char*) min_str + offset,
|
||||
(char*) max_str + offset,
|
||||
&min_length, &max_length))
|
||||
DBUG_RETURN(0); // Can't optimize with LIKE
|
||||
|
||||
if (offset != maybe_null) // BLOB or VARCHAR
|
||||
{
|
||||
int2store(min_str + maybe_null, min_length);
|
||||
int2store(max_str + maybe_null, max_length);
|
||||
}
|
||||
SEL_ARG *tree= new (param->mem_root) SEL_ARG(field, min_str, max_str);
|
||||
DBUG_RETURN(tree);
|
||||
}
|
||||
|
||||
|
||||
SEL_ARG *
|
||||
Item_bool_func::get_mm_leaf(RANGE_OPT_PARAM *param,
|
||||
Field *field, KEY_PART *key_part,
|
||||
Item_func::Functype type, Item *value)
|
||||
{
|
||||
uint maybe_null=(uint) field->real_maybe_null();
|
||||
bool optimize_range;
|
||||
SEL_ARG *tree= 0;
|
||||
MEM_ROOT *alloc= param->mem_root;
|
||||
uchar *str;
|
||||
int err;
|
||||
DBUG_ENTER("get_mm_leaf");
|
||||
DBUG_ENTER("Item_bool_func::get_mm_leaf");
|
||||
|
||||
/*
|
||||
We need to restore the runtime mem_root of the thread in this
|
||||
function because it evaluates the value of its argument, while
|
||||
the argument can be any, e.g. a subselect. The subselect
|
||||
items, in turn, assume that all the memory allocated during
|
||||
the evaluation has the same life span as the item itself.
|
||||
TODO: opt_range.cc should not reset thd->mem_root at all.
|
||||
*/
|
||||
param->thd->mem_root= param->old_root;
|
||||
if (!value) // IS NULL or IS NOT NULL
|
||||
{
|
||||
/*
|
||||
No check for field->table->maybe_null. It's perfecly fine to use range
|
||||
access for cases like
|
||||
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON t2.key IS [NOT] NULL
|
||||
|
||||
ON expression is evaluated before considering NULL-complemented rows, so
|
||||
IS [NOT] NULL has regular semantics.
|
||||
*/
|
||||
if (!maybe_null) // Not null field
|
||||
{
|
||||
if (type == Item_func::ISNULL_FUNC)
|
||||
tree= &null_element;
|
||||
goto end;
|
||||
}
|
||||
if (!(tree= new (alloc) SEL_ARG(field,is_null_string,is_null_string)))
|
||||
goto end; // out of memory
|
||||
if (type == Item_func::ISNOTNULL_FUNC)
|
||||
{
|
||||
tree->min_flag=NEAR_MIN; /* IS NOT NULL -> X > NULL */
|
||||
tree->max_flag=NO_MAX_RANGE;
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
DBUG_ASSERT(value); // IS NULL and IS NOT NULL are handled separately
|
||||
|
||||
/*
|
||||
1. Usually we can't use an index if the column collation
|
||||
|
@ -8327,9 +8426,9 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
|
|||
field->match_collation_to_optimize_range() &&
|
||||
value->result_type() == STRING_RESULT &&
|
||||
key_part->image_type == Field::itRAW &&
|
||||
field->charset() != conf_func->compare_collation() &&
|
||||
!((type == Item_func::EQUAL_FUNC || type == Item_func::EQ_FUNC) &&
|
||||
conf_func->compare_collation()->state & MY_CS_BINSORT))
|
||||
field->charset() != compare_collation() &&
|
||||
!((type == EQUAL_FUNC || type == EQ_FUNC) &&
|
||||
compare_collation()->state & MY_CS_BINSORT))
|
||||
goto end;
|
||||
if (value->cmp_type() == TIME_RESULT && field->cmp_type() != TIME_RESULT)
|
||||
goto end;
|
||||
|
@ -8338,14 +8437,14 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
|
|||
{
|
||||
// @todo: use is_spatial_operator() instead?
|
||||
switch (type) {
|
||||
case Item_func::SP_EQUALS_FUNC:
|
||||
case Item_func::SP_DISJOINT_FUNC:
|
||||
case Item_func::SP_INTERSECTS_FUNC:
|
||||
case Item_func::SP_TOUCHES_FUNC:
|
||||
case Item_func::SP_CROSSES_FUNC:
|
||||
case Item_func::SP_WITHIN_FUNC:
|
||||
case Item_func::SP_CONTAINS_FUNC:
|
||||
case Item_func::SP_OVERLAPS_FUNC:
|
||||
case SP_EQUALS_FUNC:
|
||||
case SP_DISJOINT_FUNC:
|
||||
case SP_INTERSECTS_FUNC:
|
||||
case SP_TOUCHES_FUNC:
|
||||
case SP_CROSSES_FUNC:
|
||||
case SP_WITHIN_FUNC:
|
||||
case SP_CONTAINS_FUNC:
|
||||
case SP_OVERLAPS_FUNC:
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
|
@ -8356,95 +8455,11 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
|
|||
}
|
||||
}
|
||||
|
||||
if (param->using_real_indexes)
|
||||
optimize_range= field->optimize_range(param->real_keynr[key_part->key],
|
||||
key_part->part);
|
||||
else
|
||||
optimize_range= TRUE;
|
||||
|
||||
if (type == Item_func::LIKE_FUNC)
|
||||
{
|
||||
bool like_error;
|
||||
char buff1[MAX_FIELD_WIDTH];
|
||||
uchar *min_str,*max_str;
|
||||
String tmp(buff1,sizeof(buff1),value->collation.collation),*res;
|
||||
size_t length, offset, min_length, max_length;
|
||||
uint field_length= field->pack_length()+maybe_null;
|
||||
|
||||
if (!optimize_range)
|
||||
goto end;
|
||||
if (!(res= value->val_str(&tmp)))
|
||||
{
|
||||
tree= &null_element;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*
|
||||
TODO:
|
||||
Check if this was a function. This should have be optimized away
|
||||
in the sql_select.cc
|
||||
*/
|
||||
if (res != &tmp)
|
||||
{
|
||||
tmp.copy(*res); // Get own copy
|
||||
res= &tmp;
|
||||
}
|
||||
if (field->cmp_type() != STRING_RESULT)
|
||||
goto end; // Can only optimize strings
|
||||
|
||||
offset=maybe_null;
|
||||
length=key_part->store_length;
|
||||
|
||||
if (length != key_part->length + maybe_null)
|
||||
{
|
||||
/* key packed with length prefix */
|
||||
offset+= HA_KEY_BLOB_LENGTH;
|
||||
field_length= length - HA_KEY_BLOB_LENGTH;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (unlikely(length < field_length))
|
||||
{
|
||||
/*
|
||||
This can only happen in a table created with UNIREG where one key
|
||||
overlaps many fields
|
||||
*/
|
||||
length= field_length;
|
||||
}
|
||||
else
|
||||
field_length= length;
|
||||
}
|
||||
length+=offset;
|
||||
if (!(min_str= (uchar*) alloc_root(alloc, length*2)))
|
||||
goto end;
|
||||
|
||||
max_str=min_str+length;
|
||||
if (maybe_null)
|
||||
max_str[0]= min_str[0]=0;
|
||||
|
||||
field_length-= maybe_null;
|
||||
like_error= my_like_range(field->charset(),
|
||||
res->ptr(), res->length(),
|
||||
((Item_func_like*)(conf_func))->escape,
|
||||
wild_one, wild_many,
|
||||
field_length,
|
||||
(char*) min_str+offset, (char*) max_str+offset,
|
||||
&min_length, &max_length);
|
||||
if (like_error) // Can't optimize with LIKE
|
||||
goto end;
|
||||
|
||||
if (offset != maybe_null) // BLOB or VARCHAR
|
||||
{
|
||||
int2store(min_str+maybe_null,min_length);
|
||||
int2store(max_str+maybe_null,max_length);
|
||||
}
|
||||
tree= new (alloc) SEL_ARG(field, min_str, max_str);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!optimize_range &&
|
||||
type != Item_func::EQ_FUNC &&
|
||||
type != Item_func::EQUAL_FUNC)
|
||||
if (param->using_real_indexes &&
|
||||
!field->optimize_range(param->real_keynr[key_part->key],
|
||||
key_part->part) &&
|
||||
type != EQ_FUNC &&
|
||||
type != EQUAL_FUNC)
|
||||
goto end; // Can't optimize this
|
||||
|
||||
/*
|
||||
|
@ -8456,7 +8471,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
|
|||
err= value->save_in_field_no_warnings(field, 1);
|
||||
if (err == 2 && field->cmp_type() == STRING_RESULT)
|
||||
{
|
||||
if (type == Item_func::EQ_FUNC)
|
||||
if (type == EQ_FUNC)
|
||||
{
|
||||
tree= new (alloc) SEL_ARG(field, 0, 0);
|
||||
tree->type= SEL_ARG::IMPOSSIBLE;
|
||||
|
@ -8469,7 +8484,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
|
|||
{
|
||||
if (field->cmp_type() != value->result_type())
|
||||
{
|
||||
if ((type == Item_func::EQ_FUNC || type == Item_func::EQUAL_FUNC) &&
|
||||
if ((type == EQ_FUNC || type == EQUAL_FUNC) &&
|
||||
value->result_type() == item_cmp_type(field->result_type(),
|
||||
value->result_type()))
|
||||
{
|
||||
|
@ -8485,8 +8500,8 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
|
|||
*/
|
||||
tree= 0;
|
||||
if (err == 3 && field->type() == FIELD_TYPE_DATE &&
|
||||
(type == Item_func::GT_FUNC || type == Item_func::GE_FUNC ||
|
||||
type == Item_func::LT_FUNC || type == Item_func::LE_FUNC) )
|
||||
(type == GT_FUNC || type == GE_FUNC ||
|
||||
type == LT_FUNC || type == LE_FUNC) )
|
||||
{
|
||||
/*
|
||||
We were saving DATETIME into a DATE column, the conversion went ok
|
||||
|
@ -8519,14 +8534,14 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
|
|||
*/
|
||||
else if (err == 1 && field->result_type() == INT_RESULT)
|
||||
{
|
||||
if (type == Item_func::LT_FUNC && (value->val_int() > 0))
|
||||
type = Item_func::LE_FUNC;
|
||||
else if (type == Item_func::GT_FUNC &&
|
||||
if (type == LT_FUNC && (value->val_int() > 0))
|
||||
type= LE_FUNC;
|
||||
else if (type == GT_FUNC &&
|
||||
(field->type() != FIELD_TYPE_BIT) &&
|
||||
!((Field_num*)field)->unsigned_flag &&
|
||||
!((Item_int*)value)->unsigned_flag &&
|
||||
(value->val_int() < 0))
|
||||
type = Item_func::GE_FUNC;
|
||||
type= GE_FUNC;
|
||||
}
|
||||
}
|
||||
else if (err < 0)
|
||||
|
@ -8540,7 +8555,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
|
|||
Any sargable predicate except "<=>" involving NULL as a constant is always
|
||||
FALSE
|
||||
*/
|
||||
if (type != Item_func::EQUAL_FUNC && field->is_real_null())
|
||||
if (type != EQUAL_FUNC && field->is_real_null())
|
||||
{
|
||||
tree= &null_element;
|
||||
goto end;
|
||||
|
@ -8576,12 +8591,12 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
|
|||
longlong item_val= value->val_int();
|
||||
if (item_val < 0)
|
||||
{
|
||||
if (type == Item_func::LT_FUNC || type == Item_func::LE_FUNC)
|
||||
if (type == LT_FUNC || type == LE_FUNC)
|
||||
{
|
||||
tree->type= SEL_ARG::IMPOSSIBLE;
|
||||
goto end;
|
||||
}
|
||||
if (type == Item_func::GT_FUNC || type == Item_func::GE_FUNC)
|
||||
if (type == GT_FUNC || type == GE_FUNC)
|
||||
{
|
||||
tree= 0;
|
||||
goto end;
|
||||
|
@ -8590,11 +8605,11 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
|
|||
}
|
||||
|
||||
switch (type) {
|
||||
case Item_func::LT_FUNC:
|
||||
case LT_FUNC:
|
||||
if (stored_field_cmp_to_item(param->thd, field, value) == 0)
|
||||
tree->max_flag=NEAR_MAX;
|
||||
/* fall through */
|
||||
case Item_func::LE_FUNC:
|
||||
case LE_FUNC:
|
||||
if (!maybe_null)
|
||||
tree->min_flag=NO_MIN_RANGE; /* From start */
|
||||
else
|
||||
|
@ -8603,61 +8618,61 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
|
|||
tree->min_flag=NEAR_MIN;
|
||||
}
|
||||
break;
|
||||
case Item_func::GT_FUNC:
|
||||
case GT_FUNC:
|
||||
/* Don't use open ranges for partial key_segments */
|
||||
if ((!(key_part->flag & HA_PART_KEY_SEG)) &&
|
||||
(stored_field_cmp_to_item(param->thd, field, value) <= 0))
|
||||
tree->min_flag=NEAR_MIN;
|
||||
tree->max_flag= NO_MAX_RANGE;
|
||||
break;
|
||||
case Item_func::GE_FUNC:
|
||||
case GE_FUNC:
|
||||
/* Don't use open ranges for partial key_segments */
|
||||
if ((!(key_part->flag & HA_PART_KEY_SEG)) &&
|
||||
(stored_field_cmp_to_item(param->thd, field, value) < 0))
|
||||
tree->min_flag= NEAR_MIN;
|
||||
tree->max_flag=NO_MAX_RANGE;
|
||||
break;
|
||||
case Item_func::SP_EQUALS_FUNC:
|
||||
case SP_EQUALS_FUNC:
|
||||
tree->min_flag=GEOM_FLAG | HA_READ_MBR_EQUAL;// NEAR_MIN;//512;
|
||||
tree->max_flag=NO_MAX_RANGE;
|
||||
break;
|
||||
case Item_func::SP_DISJOINT_FUNC:
|
||||
case SP_DISJOINT_FUNC:
|
||||
tree->min_flag=GEOM_FLAG | HA_READ_MBR_DISJOINT;// NEAR_MIN;//512;
|
||||
tree->max_flag=NO_MAX_RANGE;
|
||||
break;
|
||||
case Item_func::SP_INTERSECTS_FUNC:
|
||||
case SP_INTERSECTS_FUNC:
|
||||
tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
|
||||
tree->max_flag=NO_MAX_RANGE;
|
||||
break;
|
||||
case Item_func::SP_TOUCHES_FUNC:
|
||||
case SP_TOUCHES_FUNC:
|
||||
tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
|
||||
tree->max_flag=NO_MAX_RANGE;
|
||||
break;
|
||||
|
||||
case Item_func::SP_CROSSES_FUNC:
|
||||
case SP_CROSSES_FUNC:
|
||||
tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
|
||||
tree->max_flag=NO_MAX_RANGE;
|
||||
break;
|
||||
case Item_func::SP_WITHIN_FUNC:
|
||||
case SP_WITHIN_FUNC:
|
||||
tree->min_flag=GEOM_FLAG | HA_READ_MBR_WITHIN;// NEAR_MIN;//512;
|
||||
tree->max_flag=NO_MAX_RANGE;
|
||||
break;
|
||||
|
||||
case Item_func::SP_CONTAINS_FUNC:
|
||||
case SP_CONTAINS_FUNC:
|
||||
tree->min_flag=GEOM_FLAG | HA_READ_MBR_CONTAIN;// NEAR_MIN;//512;
|
||||
tree->max_flag=NO_MAX_RANGE;
|
||||
break;
|
||||
case Item_func::SP_OVERLAPS_FUNC:
|
||||
case SP_OVERLAPS_FUNC:
|
||||
tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
|
||||
tree->max_flag=NO_MAX_RANGE;
|
||||
break;
|
||||
|
||||
case EQ_FUNC:
|
||||
case EQUAL_FUNC:
|
||||
break;
|
||||
default:
|
||||
DBUG_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
end:
|
||||
param->thd->mem_root= alloc;
|
||||
DBUG_RETURN(tree);
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
class JOIN;
|
||||
class Item_sum;
|
||||
|
||||
typedef struct st_key_part {
|
||||
struct KEY_PART {
|
||||
uint16 key,part;
|
||||
/* See KEY_PART_INFO for meaning of the next two: */
|
||||
uint16 store_length, length;
|
||||
|
@ -50,7 +50,7 @@ typedef struct st_key_part {
|
|||
uint8 flag;
|
||||
Field *field;
|
||||
Field::imagetype image_type;
|
||||
} KEY_PART;
|
||||
};
|
||||
|
||||
class Explain_quick_select;
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue