Skip to content

Commit ba0b668

Browse files
author
Alexander Barkov
committed
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().
1 parent 100d77e commit ba0b668

File tree

5 files changed

+136
-104
lines changed

5 files changed

+136
-104
lines changed

sql/item.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,8 @@ class Item: public Value_source,
656656
*/
657657
String str_value;
658658

659+
SEL_TREE *get_mm_tree_for_const(RANGE_OPT_PARAM *param);
660+
659661
public:
660662
/*
661663
Cache val_str() into the own buffer, e.g. to evaluate constant

sql/item_cmpfunc.h

Lines changed: 119 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -144,12 +144,42 @@ class Item_bool_func :public Item_int_func
144144
virtual SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param,
145145
Field *field, Item *value)
146146
{
147-
DBUG_ENTER("Item_bool_func2::get_func_mm_tree");
147+
DBUG_ENTER("Item_bool_func::get_func_mm_tree");
148148
DBUG_ASSERT(0);
149149
DBUG_RETURN(0);
150150
}
151+
/*
152+
Return the full select tree for "field_item" and "value":
153+
- a single SEL_TREE if the field is not in a multiple equality, or
154+
- a conjuction of all SEL_TREEs for all fields from
155+
the same multiple equality with "field_item".
156+
*/
151157
SEL_TREE *get_full_func_mm_tree(RANGE_OPT_PARAM *param,
152158
Item_field *field_item, Item *value);
159+
/**
160+
Test if "item" and "value" are suitable for the range optimization
161+
and get their full select tree.
162+
163+
"Suitable" means:
164+
- "item" is a field or a field reference
165+
- "value" is NULL (e.g. WHERE field IS NULL), or
166+
"value" is an unexpensive item (e.g. WHERE field OP value)
167+
168+
@param item - the argument that is checked to be a field
169+
@param value - the other argument
170+
@returns - NULL if the arguments are not suitable for the range optimizer.
171+
@returns - the full select tree if the arguments are suitable.
172+
*/
173+
SEL_TREE *get_full_func_mm_tree_for_args(RANGE_OPT_PARAM *param,
174+
Item *item, Item *value)
175+
{
176+
DBUG_ENTER("Item_bool_func::get_full_func_mm_tree_for_args");
177+
Item *field= item->real_item();
178+
if (field->type() == Item::FIELD_ITEM && !field->const_item() &&
179+
(!value || !value->is_expensive()))
180+
DBUG_RETURN(get_full_func_mm_tree(param, (Item_field *) field, value));
181+
DBUG_RETURN(NULL);
182+
}
153183
SEL_TREE *get_mm_parts(RANGE_OPT_PARAM *param, Field *field,
154184
Item_func::Functype type, Item *value);
155185
SEL_TREE *get_ne_mm_tree(RANGE_OPT_PARAM *param,
@@ -324,33 +354,15 @@ class Item_in_optimizer: public Item_bool_func
324354
*/
325355
class Item_bool_func2 :public Item_bool_func
326356
{ /* Bool with 2 string args */
327-
bool have_rev_func() const { return rev_functype() != UNKNOWN_FUNC; }
328357
protected:
329358
void add_key_fields_optimize_op(JOIN *join, KEY_FIELD **key_fields,
330359
uint *and_level, table_map usable_tables,
331360
SARGABLE_PARAM **sargables, bool equal_func);
332-
SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param,
333-
Field *field, Item *value)
334-
{
335-
DBUG_ENTER("Item_bool_func2::get_func_mm_tree");
336-
/*
337-
Here the function for the following predicates are processed:
338-
<, <=, =, <=>, >=, >, LIKE, spatial relations
339-
If the predicate is of the form (value op field) it is handled
340-
as the equivalent predicate (field rev_op value), e.g.
341-
2 <= a is handled as a >= 2.
342-
*/
343-
Item_func::Functype func_type=
344-
(value != arguments()[0]) ? functype() : rev_functype();
345-
DBUG_RETURN(get_mm_parts(param, field, func_type, value));
346-
}
347361
public:
348362
Item_bool_func2(THD *thd, Item *a, Item *b):
349363
Item_bool_func(thd, a, b) { }
350-
virtual enum Functype rev_functype() const { return UNKNOWN_FUNC; }
351364

352365
bool is_null() { return MY_TEST(args[0]->is_null() || args[1]->is_null()); }
353-
SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
354366
COND *remove_eq_conds(THD *thd, Item::cond_result *cond_value,
355367
bool top_level);
356368
bool count_sargable_conds(uchar *arg);
@@ -368,15 +380,87 @@ class Item_bool_func2 :public Item_bool_func
368380
*/
369381
return STRING_RESULT;
370382
}
383+
SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
384+
{
385+
DBUG_ENTER("Item_bool_func2::get_mm_tree");
386+
DBUG_ASSERT(arg_count == 2);
387+
SEL_TREE *ftree= get_full_func_mm_tree_for_args(param, args[0], args[1]);
388+
if (!ftree)
389+
ftree= Item_func::get_mm_tree(param, cond_ptr);
390+
DBUG_RETURN(ftree);
391+
}
392+
};
393+
394+
395+
/**
396+
A class for functions and operators that can use the range optimizer and
397+
have a reverse function/operator that can also use the range optimizer,
398+
so this condition:
399+
WHERE value OP field
400+
can be optimized as equivalent to:
401+
WHERE field REV_OP value
402+
403+
This class covers:
404+
- scalar comparison predicates: <, <=, =, <=>, >=, >
405+
- MBR and precise spatial relation predicates (e.g. SP_TOUCHES(x,y))
406+
407+
For example:
408+
WHERE 10 > field
409+
can be optimized as:
410+
WHERE field < 10
411+
*/
412+
class Item_bool_func2_with_rev :public Item_bool_func2
413+
{
414+
protected:
415+
SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param,
416+
Field *field, Item *value)
417+
{
418+
DBUG_ENTER("Item_bool_func2_with_rev::get_func_mm_tree");
419+
Item_func::Functype func_type=
420+
(value != arguments()[0]) ? functype() : rev_functype();
421+
DBUG_RETURN(get_mm_parts(param, field, func_type, value));
422+
}
423+
public:
424+
Item_bool_func2_with_rev(THD *thd, Item *a, Item *b):
425+
Item_bool_func2(thd, a, b) { }
426+
virtual enum Functype rev_functype() const= 0;
427+
SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
428+
{
429+
DBUG_ENTER("Item_bool_func2_with_rev::get_mm_tree");
430+
DBUG_ASSERT(arg_count == 2);
431+
SEL_TREE *ftree;
432+
/*
433+
Even if get_full_func_mm_tree_for_args(param, args[0], args[1]) will not
434+
return a range predicate it may still be possible to create one
435+
by reversing the order of the operands. Note that this only
436+
applies to predicates where both operands are fields. Example: A
437+
query of the form
438+
439+
WHERE t1.a OP t2.b
440+
441+
In this case, args[0] == t1.a and args[1] == t2.b.
442+
When creating range predicates for t2,
443+
get_full_func_mm_tree_for_args(param, args[0], args[1])
444+
will return NULL because 'field' belongs to t1 and only
445+
predicates that applies to t2 are of interest. In this case a
446+
call to get_full_func_mm_tree_for_args() with reversed operands
447+
may succeed.
448+
*/
449+
if (!(ftree= get_full_func_mm_tree_for_args(param, args[0], args[1])) &&
450+
!(ftree= get_full_func_mm_tree_for_args(param, args[1], args[0])))
451+
ftree= Item_func::get_mm_tree(param, cond_ptr);
452+
DBUG_RETURN(ftree);
453+
}
371454
};
372455

373-
class Item_bool_rowready_func2 :public Item_bool_func2
456+
457+
class Item_bool_rowready_func2 :public Item_bool_func2_with_rev
374458
{
375459
protected:
376460
Arg_comparator cmp;
377461
public:
378462
Item_bool_rowready_func2(THD *thd, Item *a, Item *b):
379-
Item_bool_func2(thd, a, b), cmp(tmp_arg, tmp_arg + 1)
463+
Item_bool_func2_with_rev(thd, a, b), cmp(tmp_arg, tmp_arg + 1)
380464
{
381465
allowed_arg_cols= 0; // Fetch this value from first argument
382466
}
@@ -1495,7 +1579,14 @@ class Item_func_null_predicate :public Item_bool_func
14951579
Item_func_null_predicate(THD *thd, Item *a): Item_bool_func(thd, a) { }
14961580
void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
14971581
table_map usable_tables, SARGABLE_PARAM **sargables);
1498-
SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
1582+
SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
1583+
{
1584+
DBUG_ENTER("Item_func_null_predicate::get_mm_tree");
1585+
SEL_TREE *ftree= get_full_func_mm_tree_for_args(param, args[0], NULL);
1586+
if (!ftree)
1587+
ftree= Item_func::get_mm_tree(param, cond_ptr);
1588+
DBUG_RETURN(ftree);
1589+
}
14991590
CHARSET_INFO *compare_collation() const
15001591
{ return args[0]->collation.collation; }
15011592
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
16081699
String cmp_value1, cmp_value2;
16091700
bool with_sargable_pattern() const;
16101701
protected:
1702+
SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param,
1703+
Field *field, Item *value)
1704+
{
1705+
DBUG_ENTER("Item_func_like::get_func_mm_tree");
1706+
DBUG_RETURN(get_mm_parts(param, field, LIKE_FUNC, value));
1707+
}
16111708
SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, Field *field,
16121709
KEY_PART *key_part,
16131710
Item_func::Functype type, Item *value);

sql/item_func.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,11 @@ class Item_func :public Item_func_or_sum, public Used_tables_and_const_cache
130130
COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
131131
bool link_item_fields,
132132
COND_EQUAL **cond_equal_ref);
133-
SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
133+
SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
134+
{
135+
DBUG_ENTER("Item_func::get_mm_tree");
136+
DBUG_RETURN(const_item() ? get_mm_tree_for_const(param) : NULL);
137+
}
134138
bool eq(const Item *item, bool binary_cmp) const;
135139
virtual Item *key_item() const { return args[0]; }
136140
virtual bool const_item() const { return const_item_cache; }

sql/item_geofunc.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ class Item_func_spatial_collection: public Item_geometry_func
275275
Spatial relations
276276
*/
277277

278-
class Item_func_spatial_rel: public Item_bool_func2
278+
class Item_func_spatial_rel: public Item_bool_func2_with_rev
279279
{
280280
protected:
281281
enum Functype spatial_rel;
@@ -285,7 +285,7 @@ class Item_func_spatial_rel: public Item_bool_func2
285285
Item_func::Functype type, Item *value);
286286
public:
287287
Item_func_spatial_rel(THD *thd, Item *a, Item *b, enum Functype sp_rel):
288-
Item_bool_func2(thd, a, b), spatial_rel(sp_rel)
288+
Item_bool_func2_with_rev(thd, a, b), spatial_rel(sp_rel)
289289
{
290290
maybe_null= true;
291291
}

sql/opt_range.cc

Lines changed: 8 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -7423,10 +7423,10 @@ SEL_TREE *Item_cond::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
74237423
}
74247424

74257425

7426-
static SEL_TREE *get_mm_tree_for_const(RANGE_OPT_PARAM *param, Item *cond)
7426+
SEL_TREE *Item::get_mm_tree_for_const(RANGE_OPT_PARAM *param)
74277427
{
74287428
DBUG_ENTER("get_mm_tree_for_const");
7429-
if (cond->is_expensive())
7429+
if (is_expensive())
74307430
DBUG_RETURN(0);
74317431
/*
74327432
During the cond->val_int() evaluation we can come across a subselect
@@ -7437,8 +7437,8 @@ static SEL_TREE *get_mm_tree_for_const(RANGE_OPT_PARAM *param, Item *cond)
74377437
MEM_ROOT *tmp_root= param->mem_root;
74387438
param->thd->mem_root= param->old_root;
74397439
SEL_TREE *tree;
7440-
tree= cond->val_int() ? new(tmp_root) SEL_TREE(SEL_TREE::ALWAYS) :
7441-
new(tmp_root) SEL_TREE(SEL_TREE::IMPOSSIBLE);
7440+
tree= val_int() ? new(tmp_root) SEL_TREE(SEL_TREE::ALWAYS) :
7441+
new(tmp_root) SEL_TREE(SEL_TREE::IMPOSSIBLE);
74427442
param->thd->mem_root= tmp_root;
74437443
DBUG_RETURN(tree);
74447444
}
@@ -7448,7 +7448,7 @@ SEL_TREE *Item::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
74487448
{
74497449
DBUG_ENTER("Item::get_mm_tree");
74507450
if (const_item())
7451-
DBUG_RETURN(get_mm_tree_for_const(param, this));
7451+
DBUG_RETURN(get_mm_tree_for_const(param));
74527452

74537453
/*
74547454
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)
74747474
{
74757475
DBUG_ENTER("Item_func_between::get_mm_tree");
74767476
if (const_item())
7477-
DBUG_RETURN(get_mm_tree_for_const(param, this));
7477+
DBUG_RETURN(get_mm_tree_for_const(param));
74787478

74797479
SEL_TREE *tree= 0;
74807480
SEL_TREE *ftree= 0;
@@ -7521,7 +7521,7 @@ SEL_TREE *Item_func_in::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
75217521
{
75227522
DBUG_ENTER("Item_func_in::get_mm_tree");
75237523
if (const_item())
7524-
DBUG_RETURN(get_mm_tree_for_const(param, this));
7524+
DBUG_RETURN(get_mm_tree_for_const(param));
75257525

75267526
if (key_item()->real_item()->type() != Item::FIELD_ITEM)
75277527
DBUG_RETURN(0);
@@ -7535,7 +7535,7 @@ SEL_TREE *Item_equal::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
75357535
{
75367536
DBUG_ENTER("Item_equal::get_mm_tree");
75377537
if (const_item())
7538-
DBUG_RETURN(get_mm_tree_for_const(param, this));
7538+
DBUG_RETURN(get_mm_tree_for_const(param));
75397539

75407540
SEL_TREE *tree= 0;
75417541
SEL_TREE *ftree= 0;
@@ -7562,77 +7562,6 @@ SEL_TREE *Item_equal::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
75627562
}
75637563

75647564

7565-
SEL_TREE *Item_func::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
7566-
{
7567-
DBUG_ENTER("Item_func::get_mm_tree");
7568-
DBUG_RETURN(const_item() ? get_mm_tree_for_const(param, this) : NULL);
7569-
}
7570-
7571-
7572-
SEL_TREE *Item_func_null_predicate::get_mm_tree(RANGE_OPT_PARAM *param,
7573-
Item **cond_ptr)
7574-
{
7575-
DBUG_ENTER("Item_func_null_predicate::get_mm_tree");
7576-
if (const_item())
7577-
DBUG_RETURN(get_mm_tree_for_const(param, this));
7578-
if (args[0]->real_item()->type() == Item::FIELD_ITEM)
7579-
{
7580-
Item_field *field_item= (Item_field*) args[0]->real_item();
7581-
if (!field_item->const_item())
7582-
DBUG_RETURN(get_full_func_mm_tree(param, field_item, NULL));
7583-
}
7584-
DBUG_RETURN(NULL);
7585-
}
7586-
7587-
7588-
SEL_TREE *Item_bool_func2::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
7589-
{
7590-
DBUG_ENTER("Item_bool_func2::get_mm_tree");
7591-
if (const_item())
7592-
DBUG_RETURN(get_mm_tree_for_const(param, this));
7593-
7594-
SEL_TREE *ftree= 0;
7595-
DBUG_ASSERT(arg_count == 2);
7596-
if (arguments()[0]->real_item()->type() == Item::FIELD_ITEM)
7597-
{
7598-
Item_field *field_item= (Item_field*) (arguments()[0]->real_item());
7599-
Item *value= arguments()[1];
7600-
if (value && value->is_expensive())
7601-
DBUG_RETURN(0);
7602-
if (!arguments()[0]->real_item()->const_item())
7603-
ftree= get_full_func_mm_tree(param, field_item, value);
7604-
}
7605-
/*
7606-
Even if get_full_func_mm_tree() was executed above and did not
7607-
return a range predicate it may still be possible to create one
7608-
by reversing the order of the operands. Note that this only
7609-
applies to predicates where both operands are fields. Example: A
7610-
query of the form
7611-
7612-
WHERE t1.a OP t2.b
7613-
7614-
In this case, arguments()[0] == t1.a and arguments()[1] == t2.b.
7615-
When creating range predicates for t2, get_full_func_mm_tree()
7616-
above will return NULL because 'field' belongs to t1 and only
7617-
predicates that applies to t2 are of interest. In this case a
7618-
call to get_full_func_mm_tree() with reversed operands (see
7619-
below) may succeed.
7620-
*/
7621-
if (!ftree && have_rev_func() &&
7622-
arguments()[1]->real_item()->type() == Item::FIELD_ITEM)
7623-
{
7624-
Item_field *field_item= (Item_field*) (arguments()[1]->real_item());
7625-
Item *value= arguments()[0];
7626-
if (value && value->is_expensive())
7627-
DBUG_RETURN(0);
7628-
if (!arguments()[1]->real_item()->const_item())
7629-
ftree= get_full_func_mm_tree(param, field_item, value);
7630-
}
7631-
7632-
DBUG_RETURN(ftree);
7633-
}
7634-
7635-
76367565
SEL_TREE *
76377566
Item_bool_func::get_mm_parts(RANGE_OPT_PARAM *param, Field *field,
76387567
Item_func::Functype type, Item *value)

0 commit comments

Comments
 (0)