@@ -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*/
325355class Item_bool_func2 :public Item_bool_func
326356{ /* Bool with 2 string args */
327- bool have_rev_func () const { return rev_functype () != UNKNOWN_FUNC; }
328357protected:
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- }
347361public:
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{
375459protected:
376460 Arg_comparator cmp;
377461public:
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 ;
16101701protected:
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);
0 commit comments