Commit 59c58f6e authored by Alexander Barkov's avatar Alexander Barkov

MDEV-9522 Split sql_select.cc:can_change_cond_ref_to_const into virtual methods in Type_handler

parent 306ce497
...@@ -392,7 +392,7 @@ class Item_bool_func2 :public Item_bool_func ...@@ -392,7 +392,7 @@ class Item_bool_func2 :public Item_bool_func
Specifies which result type the function uses to compare its arguments. Specifies which result type the function uses to compare its arguments.
This method is used in equal field propagation. This method is used in equal field propagation.
*/ */
virtual Item_result compare_type() const virtual const Type_handler *compare_type_handler() const
{ {
/* /*
Have STRING_RESULT by default, which means the function compares Have STRING_RESULT by default, which means the function compares
...@@ -400,7 +400,7 @@ class Item_bool_func2 :public Item_bool_func ...@@ -400,7 +400,7 @@ class Item_bool_func2 :public Item_bool_func
and for Item_func_spatial_rel. and for Item_func_spatial_rel.
Note, Item_bool_rowready_func2 overrides this default behaviour. Note, Item_bool_rowready_func2 overrides this default behaviour.
*/ */
return STRING_RESULT; return &type_handler_varchar;
} }
SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr) SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
{ {
...@@ -508,7 +508,10 @@ class Item_bool_rowready_func2 :public Item_bool_func2_with_rev ...@@ -508,7 +508,10 @@ class Item_bool_rowready_func2 :public Item_bool_func2_with_rev
return cmp.set_cmp_func(this, tmp_arg, tmp_arg + 1, true); return cmp.set_cmp_func(this, tmp_arg, tmp_arg + 1, true);
} }
CHARSET_INFO *compare_collation() const { return cmp.compare_collation(); } CHARSET_INFO *compare_collation() const { return cmp.compare_collation(); }
Item_result compare_type() const { return cmp.compare_type(); } const Type_handler *compare_type_handler() const
{
return cmp.compare_type_handler();
}
Arg_comparator *get_comparator() { return &cmp; } Arg_comparator *get_comparator() { return &cmp; }
void cleanup() void cleanup()
{ {
......
...@@ -12927,7 +12927,7 @@ bool Item_func_eq::check_equality(THD *thd, COND_EQUAL *cond_equal, ...@@ -12927,7 +12927,7 @@ bool Item_func_eq::check_equality(THD *thd, COND_EQUAL *cond_equal,
} }
return check_simple_equality(thd, return check_simple_equality(thd,
Context(ANY_SUBST, Context(ANY_SUBST,
compare_type(), compare_type_handler()->cmp_type(),
compare_collation()), compare_collation()),
left_item, right_item, cond_equal); left_item, right_item, cond_equal);
} }
...@@ -13995,71 +13995,11 @@ can_change_cond_ref_to_const(Item_bool_func2 *target, ...@@ -13995,71 +13995,11 @@ can_change_cond_ref_to_const(Item_bool_func2 *target,
Item_bool_func2 *source, Item_bool_func2 *source,
Item *source_expr, Item *source_const) Item *source_expr, Item *source_const)
{ {
if (!target_expr->eq(source_expr,0) || return target_expr->eq(source_expr,0) &&
target_value == source_const || target_value != source_const &&
target->compare_type() != source->compare_type()) target->compare_type_handler()->
return false; can_change_cond_ref_to_const(target, target_expr, target_value,
if (target->compare_type() == STRING_RESULT) source, source_expr, source_const);
{
/*
In this example:
SET NAMES utf8 COLLATE utf8_german2_ci;
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (a CHAR(10) CHARACTER SET utf8);
INSERT INTO t1 VALUES ('o-umlaut'),('oe');
SELECT * FROM t1 WHERE a='oe' COLLATE utf8_german2_ci AND a='oe';
the query should return only the row with 'oe'.
It should not return 'o-umlaut', because 'o-umlaut' does not match
the right part of the condition: a='oe'
('o-umlaut' is not equal to 'oe' in utf8_general_ci,
which is the collation of the field "a").
If we change the right part from:
... AND a='oe'
to
... AND 'oe' COLLATE utf8_german2_ci='oe'
it will be evalulated to TRUE and removed from the condition,
so the overall query will be simplified to:
SELECT * FROM t1 WHERE a='oe' COLLATE utf8_german2_ci;
which will erroneously start to return both 'oe' and 'o-umlaut'.
So changing "expr" to "const" is not possible if the effective
collations of "target" and "source" are not exactly the same.
Note, the code before the fix for MDEV-7152 only checked that
collations of "source_const" and "target_value" are the same.
This was not enough, as the bug report demonstrated.
*/
return
target->compare_collation() == source->compare_collation() &&
target_value->collation.collation == source_const->collation.collation;
}
if (target->compare_type() == TIME_RESULT)
{
if (target_value->cmp_type() != TIME_RESULT)
{
/*
Can't rewrite:
WHERE COALESCE(time_column)='00:00:00'
AND COALESCE(time_column)=DATE'2015-09-11'
to
WHERE DATE'2015-09-11'='00:00:00'
AND COALESCE(time_column)=DATE'2015-09-11'
because the left part will erroneously try to parse '00:00:00'
as DATE, not as TIME.
TODO: It could still be rewritten to:
WHERE DATE'2015-09-11'=TIME'00:00:00'
AND COALESCE(time_column)=DATE'2015-09-11'
i.e. we need to replace both target_expr and target_value
at the same time. This is not supported yet.
*/
return false;
}
}
return true; // Non-string comparison
} }
......
...@@ -1057,6 +1057,99 @@ bool Type_handler_temporal_result::set_comparator_func(Arg_comparator *cmp) cons ...@@ -1057,6 +1057,99 @@ bool Type_handler_temporal_result::set_comparator_func(Arg_comparator *cmp) cons
} }
/*************************************************************************/
bool Type_handler_temporal_result::
can_change_cond_ref_to_const(Item_bool_func2 *target,
Item *target_expr, Item *target_value,
Item_bool_func2 *source,
Item *source_expr, Item *source_const)
const
{
if (source->compare_type_handler()->cmp_type() != TIME_RESULT)
return false;
/*
Can't rewrite:
WHERE COALESCE(time_column)='00:00:00'
AND COALESCE(time_column)=DATE'2015-09-11'
to
WHERE DATE'2015-09-11'='00:00:00'
AND COALESCE(time_column)=DATE'2015-09-11'
because the left part will erroneously try to parse '00:00:00'
as DATE, not as TIME.
TODO: It could still be rewritten to:
WHERE DATE'2015-09-11'=TIME'00:00:00'
AND COALESCE(time_column)=DATE'2015-09-11'
i.e. we need to replace both target_expr and target_value
at the same time. This is not supported yet.
*/
return target_value->cmp_type() == TIME_RESULT;
}
bool Type_handler_string_result::
can_change_cond_ref_to_const(Item_bool_func2 *target,
Item *target_expr, Item *target_value,
Item_bool_func2 *source,
Item *source_expr, Item *source_const)
const
{
if (source->compare_type_handler()->cmp_type() != STRING_RESULT)
return false;
/*
In this example:
SET NAMES utf8 COLLATE utf8_german2_ci;
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (a CHAR(10) CHARACTER SET utf8);
INSERT INTO t1 VALUES ('o-umlaut'),('oe');
SELECT * FROM t1 WHERE a='oe' COLLATE utf8_german2_ci AND a='oe';
the query should return only the row with 'oe'.
It should not return 'o-umlaut', because 'o-umlaut' does not match
the right part of the condition: a='oe'
('o-umlaut' is not equal to 'oe' in utf8_general_ci,
which is the collation of the field "a").
If we change the right part from:
... AND a='oe'
to
... AND 'oe' COLLATE utf8_german2_ci='oe'
it will be evalulated to TRUE and removed from the condition,
so the overall query will be simplified to:
SELECT * FROM t1 WHERE a='oe' COLLATE utf8_german2_ci;
which will erroneously start to return both 'oe' and 'o-umlaut'.
So changing "expr" to "const" is not possible if the effective
collations of "target" and "source" are not exactly the same.
Note, the code before the fix for MDEV-7152 only checked that
collations of "source_const" and "target_value" are the same.
This was not enough, as the bug report demonstrated.
*/
return
target->compare_collation() == source->compare_collation() &&
target_value->collation.collation == source_const->collation.collation;
}
bool Type_handler_numeric::
can_change_cond_ref_to_const(Item_bool_func2 *target,
Item *target_expr, Item *target_value,
Item_bool_func2 *source,
Item *source_expr, Item *source_const)
const
{
/*
The collations of "target" and "source" do not make sense for numeric
data types.
*/
return target->compare_type_handler() == source->compare_type_handler();
}
/*************************************************************************/ /*************************************************************************/
Item_cache * Item_cache *
......
...@@ -32,6 +32,7 @@ class Item_func_hex; ...@@ -32,6 +32,7 @@ class Item_func_hex;
class Item_hybrid_func; class Item_hybrid_func;
class Item_func_min_max; class Item_func_min_max;
class Item_func_hybrid_field_type; class Item_func_hybrid_field_type;
class Item_bool_func2;
class Item_func_between; class Item_func_between;
class Item_func_in; class Item_func_in;
class cmp_item; class cmp_item;
...@@ -346,6 +347,31 @@ class Type_handler ...@@ -346,6 +347,31 @@ class Type_handler
virtual uint32 max_display_length(const Item *item) const= 0; virtual uint32 max_display_length(const Item *item) const= 0;
virtual int Item_save_in_field(Item *item, Field *field, virtual int Item_save_in_field(Item *item, Field *field,
bool no_conversions) const= 0; bool no_conversions) const= 0;
/**
Check if
WHERE expr=value AND expr=const
can be rewritten as:
WHERE const=value AND expr=const
"this" is the comparison handler that is used by "target".
@param target - the predicate expr=value,
whose "expr" argument will be replaced to "const".
@param target_expr - the target's "expr" which will be replaced to "const".
@param target_value - the target's second argument, it will remain unchanged.
@param source - the equality predicate expr=const (or expr<=>const)
that can be used to rewrite the "target" part
(under certain conditions, see the code).
@param source_expr - the source's "expr". It should be exactly equal to
the target's "expr" to make condition rewrite possible.
@param source_const - the source's "const" argument, it will be inserted
into "target" instead of "expr".
*/
virtual bool
can_change_cond_ref_to_const(Item_bool_func2 *target,
Item *target_expr, Item *target_value,
Item_bool_func2 *source,
Item *source_expr, Item *source_const) const= 0;
virtual Item_cache *Item_get_cache(THD *thd, const Item *item) const= 0; virtual Item_cache *Item_get_cache(THD *thd, const Item *item) const= 0;
virtual bool set_comparator_func(Arg_comparator *cmp) const= 0; virtual bool set_comparator_func(Arg_comparator *cmp) const= 0;
virtual bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, virtual bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
...@@ -455,6 +481,14 @@ class Type_handler_row: public Type_handler ...@@ -455,6 +481,14 @@ class Type_handler_row: public Type_handler
DBUG_ASSERT(0); DBUG_ASSERT(0);
return 1; return 1;
} }
bool can_change_cond_ref_to_const(Item_bool_func2 *target,
Item *target_expr, Item *target_value,
Item_bool_func2 *source,
Item *source_expr, Item *source_const) const
{
DBUG_ASSERT(0);
return false;
}
Item_cache *Item_get_cache(THD *thd, const Item *item) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const;
bool set_comparator_func(Arg_comparator *cmp) const; bool set_comparator_func(Arg_comparator *cmp) const;
bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
...@@ -558,6 +592,10 @@ class Type_handler_numeric: public Type_handler ...@@ -558,6 +592,10 @@ class Type_handler_numeric: public Type_handler
bool Item_func_min_max_get_date(Item_func_min_max*, bool Item_func_min_max_get_date(Item_func_min_max*,
MYSQL_TIME *, ulonglong fuzzydate) const; MYSQL_TIME *, ulonglong fuzzydate) const;
virtual ~Type_handler_numeric() { } virtual ~Type_handler_numeric() { }
bool can_change_cond_ref_to_const(Item_bool_func2 *target,
Item *target_expr, Item *target_value,
Item_bool_func2 *source,
Item *source_expr, Item *source_const) const;
}; };
...@@ -699,6 +737,10 @@ class Type_handler_temporal_result: public Type_handler ...@@ -699,6 +737,10 @@ class Type_handler_temporal_result: public Type_handler
const Type_std_attributes *item, const Type_std_attributes *item,
SORT_FIELD_ATTR *attr) const; SORT_FIELD_ATTR *attr) const;
uint32 max_display_length(const Item *item) const; uint32 max_display_length(const Item *item) const;
bool can_change_cond_ref_to_const(Item_bool_func2 *target,
Item *target_expr, Item *target_value,
Item_bool_func2 *source,
Item *source_expr, Item *source_const) const;
Item_cache *Item_get_cache(THD *thd, const Item *item) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const;
bool set_comparator_func(Arg_comparator *cmp) const; bool set_comparator_func(Arg_comparator *cmp) const;
bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const; bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const;
...@@ -746,6 +788,10 @@ class Type_handler_string_result: public Type_handler ...@@ -746,6 +788,10 @@ class Type_handler_string_result: public Type_handler
SORT_FIELD_ATTR *attr) const; SORT_FIELD_ATTR *attr) const;
uint32 max_display_length(const Item *item) const; uint32 max_display_length(const Item *item) const;
int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
bool can_change_cond_ref_to_const(Item_bool_func2 *target,
Item *target_expr, Item *target_value,
Item_bool_func2 *source,
Item *source_expr, Item *source_const) const;
Item_cache *Item_get_cache(THD *thd, const Item *item) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const;
bool set_comparator_func(Arg_comparator *cmp) const; bool set_comparator_func(Arg_comparator *cmp) const;
bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
......
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