Commit ba0b6685 authored by Alexander Barkov's avatar Alexander Barkov

A clean-up for MDEV-7950:

- Turning get_mm_tree_for_const() from a static function into
  a protected method in Item.
- Adding a new class Item_bool_func2_with_rev, for the functions and operators
  that have a reverse function and can use the range optimizer for
  to optimize "value OP field" as "field REV_OP value". Deriving
  Item_bool_rowready_func2 and Item_funt_spatial_rel from the new class.
- Removing Item_bool_func2::have_rev_func().
parent 100d77e6
......@@ -656,6 +656,8 @@ class Item: public Value_source,
*/
String str_value;
SEL_TREE *get_mm_tree_for_const(RANGE_OPT_PARAM *param);
public:
/*
Cache val_str() into the own buffer, e.g. to evaluate constant
......
......@@ -144,12 +144,42 @@ class Item_bool_func :public Item_int_func
virtual SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param,
Field *field, Item *value)
{
DBUG_ENTER("Item_bool_func2::get_func_mm_tree");
DBUG_ENTER("Item_bool_func::get_func_mm_tree");
DBUG_ASSERT(0);
DBUG_RETURN(0);
}
/*
Return the full select tree for "field_item" and "value":
- a single SEL_TREE if the field is not in a multiple equality, or
- a conjuction of all SEL_TREEs for all fields from
the same multiple equality with "field_item".
*/
SEL_TREE *get_full_func_mm_tree(RANGE_OPT_PARAM *param,
Item_field *field_item, Item *value);
/**
Test if "item" and "value" are suitable for the range optimization
and get their full select tree.
"Suitable" means:
- "item" is a field or a field reference
- "value" is NULL (e.g. WHERE field IS NULL), or
"value" is an unexpensive item (e.g. WHERE field OP value)
@param item - the argument that is checked to be a field
@param value - the other argument
@returns - NULL if the arguments are not suitable for the range optimizer.
@returns - the full select tree if the arguments are suitable.
*/
SEL_TREE *get_full_func_mm_tree_for_args(RANGE_OPT_PARAM *param,
Item *item, Item *value)
{
DBUG_ENTER("Item_bool_func::get_full_func_mm_tree_for_args");
Item *field= item->real_item();
if (field->type() == Item::FIELD_ITEM && !field->const_item() &&
(!value || !value->is_expensive()))
DBUG_RETURN(get_full_func_mm_tree(param, (Item_field *) field, value));
DBUG_RETURN(NULL);
}
SEL_TREE *get_mm_parts(RANGE_OPT_PARAM *param, Field *field,
Item_func::Functype type, Item *value);
SEL_TREE *get_ne_mm_tree(RANGE_OPT_PARAM *param,
......@@ -324,33 +354,15 @@ class Item_in_optimizer: public Item_bool_func
*/
class Item_bool_func2 :public Item_bool_func
{ /* Bool with 2 string args */
bool have_rev_func() const { return rev_functype() != UNKNOWN_FUNC; }
protected:
void add_key_fields_optimize_op(JOIN *join, KEY_FIELD **key_fields,
uint *and_level, table_map usable_tables,
SARGABLE_PARAM **sargables, bool equal_func);
SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param,
Field *field, Item *value)
{
DBUG_ENTER("Item_bool_func2::get_func_mm_tree");
/*
Here the function for the following predicates are processed:
<, <=, =, <=>, >=, >, LIKE, spatial relations
If the predicate is of the form (value op field) it is handled
as the equivalent predicate (field rev_op value), e.g.
2 <= a is handled as a >= 2.
*/
Item_func::Functype func_type=
(value != arguments()[0]) ? functype() : rev_functype();
DBUG_RETURN(get_mm_parts(param, field, func_type, value));
}
public:
Item_bool_func2(THD *thd, Item *a, Item *b):
Item_bool_func(thd, a, b) { }
virtual enum Functype rev_functype() const { return UNKNOWN_FUNC; }
bool is_null() { return MY_TEST(args[0]->is_null() || args[1]->is_null()); }
SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
COND *remove_eq_conds(THD *thd, Item::cond_result *cond_value,
bool top_level);
bool count_sargable_conds(uchar *arg);
......@@ -368,15 +380,87 @@ class Item_bool_func2 :public Item_bool_func
*/
return STRING_RESULT;
}
SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
{
DBUG_ENTER("Item_bool_func2::get_mm_tree");
DBUG_ASSERT(arg_count == 2);
SEL_TREE *ftree= get_full_func_mm_tree_for_args(param, args[0], args[1]);
if (!ftree)
ftree= Item_func::get_mm_tree(param, cond_ptr);
DBUG_RETURN(ftree);
}
};
/**
A class for functions and operators that can use the range optimizer and
have a reverse function/operator that can also use the range optimizer,
so this condition:
WHERE value OP field
can be optimized as equivalent to:
WHERE field REV_OP value
This class covers:
- scalar comparison predicates: <, <=, =, <=>, >=, >
- MBR and precise spatial relation predicates (e.g. SP_TOUCHES(x,y))
For example:
WHERE 10 > field
can be optimized as:
WHERE field < 10
*/
class Item_bool_func2_with_rev :public Item_bool_func2
{
protected:
SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param,
Field *field, Item *value)
{
DBUG_ENTER("Item_bool_func2_with_rev::get_func_mm_tree");
Item_func::Functype func_type=
(value != arguments()[0]) ? functype() : rev_functype();
DBUG_RETURN(get_mm_parts(param, field, func_type, value));
}
public:
Item_bool_func2_with_rev(THD *thd, Item *a, Item *b):
Item_bool_func2(thd, a, b) { }
virtual enum Functype rev_functype() const= 0;
SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
{
DBUG_ENTER("Item_bool_func2_with_rev::get_mm_tree");
DBUG_ASSERT(arg_count == 2);
SEL_TREE *ftree;
/*
Even if get_full_func_mm_tree_for_args(param, args[0], args[1]) will not
return a range predicate it may still be possible to create one
by reversing the order of the operands. Note that this only
applies to predicates where both operands are fields. Example: A
query of the form
WHERE t1.a OP t2.b
In this case, args[0] == t1.a and args[1] == t2.b.
When creating range predicates for t2,
get_full_func_mm_tree_for_args(param, args[0], args[1])
will return NULL because 'field' belongs to t1 and only
predicates that applies to t2 are of interest. In this case a
call to get_full_func_mm_tree_for_args() with reversed operands
may succeed.
*/
if (!(ftree= get_full_func_mm_tree_for_args(param, args[0], args[1])) &&
!(ftree= get_full_func_mm_tree_for_args(param, args[1], args[0])))
ftree= Item_func::get_mm_tree(param, cond_ptr);
DBUG_RETURN(ftree);
}
};
class Item_bool_rowready_func2 :public Item_bool_func2
class Item_bool_rowready_func2 :public Item_bool_func2_with_rev
{
protected:
Arg_comparator cmp;
public:
Item_bool_rowready_func2(THD *thd, Item *a, Item *b):
Item_bool_func2(thd, a, b), cmp(tmp_arg, tmp_arg + 1)
Item_bool_func2_with_rev(thd, a, b), cmp(tmp_arg, tmp_arg + 1)
{
allowed_arg_cols= 0; // Fetch this value from first argument
}
......@@ -1495,7 +1579,14 @@ class Item_func_null_predicate :public Item_bool_func
Item_func_null_predicate(THD *thd, Item *a): Item_bool_func(thd, a) { }
void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
table_map usable_tables, SARGABLE_PARAM **sargables);
SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
{
DBUG_ENTER("Item_func_null_predicate::get_mm_tree");
SEL_TREE *ftree= get_full_func_mm_tree_for_args(param, args[0], NULL);
if (!ftree)
ftree= Item_func::get_mm_tree(param, cond_ptr);
DBUG_RETURN(ftree);
}
CHARSET_INFO *compare_collation() const
{ return args[0]->collation.collation; }
void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=0; }
......@@ -1608,6 +1699,12 @@ class Item_func_like :public Item_bool_func2
String cmp_value1, cmp_value2;
bool with_sargable_pattern() const;
protected:
SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param,
Field *field, Item *value)
{
DBUG_ENTER("Item_func_like::get_func_mm_tree");
DBUG_RETURN(get_mm_parts(param, field, LIKE_FUNC, value));
}
SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, Field *field,
KEY_PART *key_part,
Item_func::Functype type, Item *value);
......
......@@ -130,7 +130,11 @@ class Item_func :public Item_func_or_sum, public Used_tables_and_const_cache
COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
bool link_item_fields,
COND_EQUAL **cond_equal_ref);
SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
{
DBUG_ENTER("Item_func::get_mm_tree");
DBUG_RETURN(const_item() ? get_mm_tree_for_const(param) : NULL);
}
bool eq(const Item *item, bool binary_cmp) const;
virtual Item *key_item() const { return args[0]; }
virtual bool const_item() const { return const_item_cache; }
......
......@@ -275,7 +275,7 @@ class Item_func_spatial_collection: public Item_geometry_func
Spatial relations
*/
class Item_func_spatial_rel: public Item_bool_func2
class Item_func_spatial_rel: public Item_bool_func2_with_rev
{
protected:
enum Functype spatial_rel;
......@@ -285,7 +285,7 @@ class Item_func_spatial_rel: public Item_bool_func2
Item_func::Functype type, Item *value);
public:
Item_func_spatial_rel(THD *thd, Item *a, Item *b, enum Functype sp_rel):
Item_bool_func2(thd, a, b), spatial_rel(sp_rel)
Item_bool_func2_with_rev(thd, a, b), spatial_rel(sp_rel)
{
maybe_null= true;
}
......
......@@ -7423,10 +7423,10 @@ SEL_TREE *Item_cond::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
}
static SEL_TREE *get_mm_tree_for_const(RANGE_OPT_PARAM *param, Item *cond)
SEL_TREE *Item::get_mm_tree_for_const(RANGE_OPT_PARAM *param)
{
DBUG_ENTER("get_mm_tree_for_const");
if (cond->is_expensive())
if (is_expensive())
DBUG_RETURN(0);
/*
During the cond->val_int() evaluation we can come across a subselect
......@@ -7437,7 +7437,7 @@ static SEL_TREE *get_mm_tree_for_const(RANGE_OPT_PARAM *param, Item *cond)
MEM_ROOT *tmp_root= param->mem_root;
param->thd->mem_root= param->old_root;
SEL_TREE *tree;
tree= cond->val_int() ? new(tmp_root) SEL_TREE(SEL_TREE::ALWAYS) :
tree= val_int() ? new(tmp_root) SEL_TREE(SEL_TREE::ALWAYS) :
new(tmp_root) SEL_TREE(SEL_TREE::IMPOSSIBLE);
param->thd->mem_root= tmp_root;
DBUG_RETURN(tree);
......@@ -7448,7 +7448,7 @@ SEL_TREE *Item::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
{
DBUG_ENTER("Item::get_mm_tree");
if (const_item())
DBUG_RETURN(get_mm_tree_for_const(param, this));
DBUG_RETURN(get_mm_tree_for_const(param));
/*
Here we have a not-constant non-function Item.
......@@ -7474,7 +7474,7 @@ Item_func_between::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
{
DBUG_ENTER("Item_func_between::get_mm_tree");
if (const_item())
DBUG_RETURN(get_mm_tree_for_const(param, this));
DBUG_RETURN(get_mm_tree_for_const(param));
SEL_TREE *tree= 0;
SEL_TREE *ftree= 0;
......@@ -7521,7 +7521,7 @@ SEL_TREE *Item_func_in::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
{
DBUG_ENTER("Item_func_in::get_mm_tree");
if (const_item())
DBUG_RETURN(get_mm_tree_for_const(param, this));
DBUG_RETURN(get_mm_tree_for_const(param));
if (key_item()->real_item()->type() != Item::FIELD_ITEM)
DBUG_RETURN(0);
......@@ -7535,7 +7535,7 @@ SEL_TREE *Item_equal::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
{
DBUG_ENTER("Item_equal::get_mm_tree");
if (const_item())
DBUG_RETURN(get_mm_tree_for_const(param, this));
DBUG_RETURN(get_mm_tree_for_const(param));
SEL_TREE *tree= 0;
SEL_TREE *ftree= 0;
......@@ -7562,77 +7562,6 @@ SEL_TREE *Item_equal::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
}
SEL_TREE *Item_func::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
{
DBUG_ENTER("Item_func::get_mm_tree");
DBUG_RETURN(const_item() ? get_mm_tree_for_const(param, this) : NULL);
}
SEL_TREE *Item_func_null_predicate::get_mm_tree(RANGE_OPT_PARAM *param,
Item **cond_ptr)
{
DBUG_ENTER("Item_func_null_predicate::get_mm_tree");
if (const_item())
DBUG_RETURN(get_mm_tree_for_const(param, this));
if (args[0]->real_item()->type() == Item::FIELD_ITEM)
{
Item_field *field_item= (Item_field*) args[0]->real_item();
if (!field_item->const_item())
DBUG_RETURN(get_full_func_mm_tree(param, field_item, NULL));
}
DBUG_RETURN(NULL);
}
SEL_TREE *Item_bool_func2::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
{
DBUG_ENTER("Item_bool_func2::get_mm_tree");
if (const_item())
DBUG_RETURN(get_mm_tree_for_const(param, this));
SEL_TREE *ftree= 0;
DBUG_ASSERT(arg_count == 2);
if (arguments()[0]->real_item()->type() == Item::FIELD_ITEM)
{
Item_field *field_item= (Item_field*) (arguments()[0]->real_item());
Item *value= arguments()[1];
if (value && value->is_expensive())
DBUG_RETURN(0);
if (!arguments()[0]->real_item()->const_item())
ftree= get_full_func_mm_tree(param, field_item, value);
}
/*
Even if get_full_func_mm_tree() was executed above and did not
return a range predicate it may still be possible to create one
by reversing the order of the operands. Note that this only
applies to predicates where both operands are fields. Example: A
query of the form
WHERE t1.a OP t2.b
In this case, arguments()[0] == t1.a and arguments()[1] == t2.b.
When creating range predicates for t2, get_full_func_mm_tree()
above will return NULL because 'field' belongs to t1 and only
predicates that applies to t2 are of interest. In this case a
call to get_full_func_mm_tree() with reversed operands (see
below) may succeed.
*/
if (!ftree && have_rev_func() &&
arguments()[1]->real_item()->type() == Item::FIELD_ITEM)
{
Item_field *field_item= (Item_field*) (arguments()[1]->real_item());
Item *value= arguments()[0];
if (value && value->is_expensive())
DBUG_RETURN(0);
if (!arguments()[1]->real_item()->const_item())
ftree= get_full_func_mm_tree(param, field_item, value);
}
DBUG_RETURN(ftree);
}
SEL_TREE *
Item_bool_func::get_mm_parts(RANGE_OPT_PARAM *param, Field *field,
Item_func::Functype type, Item *value)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment