summaryrefslogtreecommitdiff
path: root/sql/item_cmpfunc.h
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item_cmpfunc.h')
-rw-r--r--sql/item_cmpfunc.h71
1 files changed, 52 insertions, 19 deletions
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index d4a1c6b1384..5d11057228c 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -48,6 +48,14 @@ class Arg_comparator: public Sql_alloc
THD *thd;
Item *a_cache, *b_cache; // Cached values of a and b items
// when one of arguments is NULL.
+ int set_compare_func(Item_result_field *owner, Item_result type);
+ inline int set_compare_func(Item_result_field *owner_arg)
+ {
+ return set_compare_func(owner_arg, item_cmp_type((*a)->result_type(),
+ (*b)->result_type()));
+ }
+ bool agg_arg_charsets_for_comparison();
+
public:
DTCollation cmp_collation;
/* Allow owner function to use string buffers. */
@@ -58,12 +66,6 @@ public:
Arg_comparator(Item **a1, Item **a2): a(a1), b(a2), set_null(TRUE),
comparators(0), thd(0), a_cache(0), b_cache(0) {};
- int set_compare_func(Item_result_field *owner, Item_result type);
- inline int set_compare_func(Item_result_field *owner_arg)
- {
- return set_compare_func(owner_arg, item_cmp_type((*a)->result_type(),
- (*b)->result_type()));
- }
int set_cmp_func(Item_result_field *owner_arg,
Item **a1, Item **a2,
Item_result type);
@@ -122,6 +124,8 @@ public:
Item_bool_func() :Item_int_func() {}
Item_bool_func(Item *a) :Item_int_func(a) {}
Item_bool_func(Item *a,Item *b) :Item_int_func(a,b) {}
+ Item_bool_func(Item *a, Item *b, Item *c) :Item_int_func(a, b, c) {}
+ Item_bool_func(List<Item> &list) :Item_int_func(list) { }
Item_bool_func(THD *thd, Item_bool_func *item) :Item_int_func(thd, item) {}
bool is_bool_func() { return 1; }
void fix_length_and_dec() { decimals=0; max_length=1; }
@@ -364,7 +368,7 @@ public:
virtual bool l_op() const { return 1; }
};
-class Item_bool_func2 :public Item_int_func
+class Item_bool_func2 :public Item_bool_func
{ /* Bool with 2 string args */
protected:
Arg_comparator cmp;
@@ -372,7 +376,7 @@ protected:
public:
Item_bool_func2(Item *a,Item *b)
- :Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1),
+ :Item_bool_func(a,b), cmp(tmp_arg, tmp_arg+1),
abort_on_null(FALSE) { sargable= TRUE; }
void fix_length_and_dec();
int set_cmp_func()
@@ -389,14 +393,12 @@ public:
}
bool is_null() { return MY_TEST(args[0]->is_null() || args[1]->is_null()); }
- bool is_bool_func() { return 1; }
CHARSET_INFO *compare_collation() { return cmp.cmp_collation.collation; }
- uint decimal_precision() const { return 1; }
void top_level_item() { abort_on_null= TRUE; }
Arg_comparator *get_comparator() { return &cmp; }
void cleanup()
{
- Item_int_func::cleanup();
+ Item_bool_func::cleanup();
cmp.cleanup();
}
@@ -646,16 +648,16 @@ public:
*/
-class Item_func_opt_neg :public Item_int_func
+class Item_func_opt_neg :public Item_bool_func
{
public:
bool negated; /* <=> the item represents NOT <func> */
bool pred_level; /* <=> [NOT] <func> is used on a predicate level */
public:
Item_func_opt_neg(Item *a, Item *b, Item *c)
- :Item_int_func(a, b, c), negated(0), pred_level(0) {}
+ :Item_bool_func(a, b, c), negated(0), pred_level(0) {}
Item_func_opt_neg(List<Item> &list)
- :Item_int_func(list), negated(0), pred_level(0) {}
+ :Item_bool_func(list), negated(0), pred_level(0) {}
public:
inline void negate() { negated= !negated; }
inline void top_level_item() { pred_level= 1; }
@@ -686,9 +688,7 @@ public:
bool fix_fields(THD *, Item **);
void fix_length_and_dec();
virtual void print(String *str, enum_query_type query_type);
- bool is_bool_func() { return 1; }
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
- uint decimal_precision() const { return 1; }
bool eval_not_null_tables(uchar *opt_arg);
void fix_after_pullout(st_select_lex *new_parent, Item **ref);
bool count_sargable_conds(uchar *arg);
@@ -1316,7 +1316,6 @@ public:
longlong val_int();
bool fix_fields(THD *, Item **);
void fix_length_and_dec();
- uint decimal_precision() const { return 1; }
void cleanup()
{
uint i;
@@ -1337,7 +1336,6 @@ public:
enum Functype functype() const { return IN_FUNC; }
const char *func_name() const { return " IN "; }
bool nulls_in_row();
- bool is_bool_func() { return 1; }
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
bool eval_not_null_tables(uchar *opt_arg);
void fix_after_pullout(st_select_lex *new_parent, Item **ref);
@@ -1490,7 +1488,42 @@ public:
longlong val_int();
enum Functype functype() const { return LIKE_FUNC; }
optimize_type select_optimize() const;
- cond_result eq_cmp_result() const { return COND_TRUE; }
+ cond_result eq_cmp_result() const
+ {
+ /**
+ We cannot always rewrite conditions as follows:
+ from: WHERE expr1=const AND expr1 LIKE expr2
+ to: WHERE expr1=const AND const LIKE expr2
+ or
+ from: WHERE expr1=const AND expr2 LIKE expr1
+ to: WHERE expr1=const AND expr2 LIKE const
+
+ because LIKE works differently comparing to the regular "=" operator:
+
+ 1. LIKE performs a stricter one-character-to-one-character comparison
+ and does not recognize contractions and expansions.
+ Replacing "expr1" to "const in LIKE would make the condition
+ stricter in case of a complex collation.
+
+ 2. LIKE does not ignore trailing spaces and thus works differently
+ from the "=" operator in case of "PAD SPACE" collations
+ (which are the majority in MariaDB). So, for "PAD SPACE" collations:
+
+ - expr1=const - ignores trailing spaces
+ - const LIKE expr2 - does not ignore trailing spaces
+ - expr2 LIKE const - does not ignore trailing spaces
+
+ Allow only "binary" for now.
+ It neither ignores trailing spaces nor has contractions/expansions.
+
+ TODO:
+ We could still replace "expr1" to "const" in "expr1 LIKE expr2"
+ in case of a "PAD SPACE" collation, but only if "expr2" has '%'
+ at the end.
+ */
+ return ((Item_func_like *)this)->compare_collation() == &my_charset_bin ?
+ COND_TRUE : COND_OK;
+ }
const char *func_name() const { return "like"; }
bool fix_fields(THD *thd, Item **ref);
void cleanup();