diff options
author | Alexander Barkov <bar@mariadb.com> | 2018-06-09 13:38:22 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.com> | 2018-06-09 13:38:22 +0400 |
commit | d60fdb58141f4ae607b9595acd0ac5655fc71970 (patch) | |
tree | 9dad388dbd313fe30e16aef480582df2f2ba4b49 | |
parent | 9043dd7a2d380b26349bc23e904d44e9ce634cef (diff) | |
download | mariadb-git-d60fdb58141f4ae607b9595acd0ac5655fc71970.tar.gz |
MDEV-16451 Split Item_equal::add_const() into a virtual method in type_handler()
MDEV-16452 Split TIME and DATETIME handling in Item_func_between, in_temporal, cmp_item_internal
-rw-r--r-- | mysql-test/main/type_year.result | 41 | ||||
-rw-r--r-- | mysql-test/main/type_year.test | 27 | ||||
-rw-r--r-- | sql/item.h | 6 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 180 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 23 | ||||
-rw-r--r-- | sql/sql_type.cc | 85 | ||||
-rw-r--r-- | sql/sql_type.h | 27 |
7 files changed, 271 insertions, 118 deletions
diff --git a/mysql-test/main/type_year.result b/mysql-test/main/type_year.result index 8d58659769e..2d04853a0b2 100644 --- a/mysql-test/main/type_year.result +++ b/mysql-test/main/type_year.result @@ -486,3 +486,44 @@ DROP TABLE t1; # # End of 10.2 tests # +# +# Start of 10.4 tests +# +# +# MDEV-16451 Split Item_equal::add_const() into a virtual method in type_handler() +# +CREATE TABLE t1 (a YEAR(4)); +INSERT INTO t1 VALUES (93),(94); +SELECT * FROM t1; +a +1993 +1994 +SELECT * FROM t1 WHERE a=1993 and a=93; +a +1993 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=1993 and a=93; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 1993 +DROP TABLE t1; +CREATE TABLE t1 (a YEAR(2)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +INSERT INTO t1 VALUES (93),(94); +SELECT * FROM t1; +a +93 +94 +SELECT * FROM t1 WHERE a=1993 and a=93; +a +93 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=1993 and a=93; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 93 +DROP TABLE t1; +# +# End of 10.4 tests +# diff --git a/mysql-test/main/type_year.test b/mysql-test/main/type_year.test index 117906fd889..f7354ebf7c6 100644 --- a/mysql-test/main/type_year.test +++ b/mysql-test/main/type_year.test @@ -254,3 +254,30 @@ DROP TABLE t1; --echo # --echo # End of 10.2 tests --echo # + + +--echo # +--echo # Start of 10.4 tests +--echo # + +--echo # +--echo # MDEV-16451 Split Item_equal::add_const() into a virtual method in type_handler() +--echo # + +CREATE TABLE t1 (a YEAR(4)); +INSERT INTO t1 VALUES (93),(94); +SELECT * FROM t1; +SELECT * FROM t1 WHERE a=1993 and a=93; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=1993 and a=93; +DROP TABLE t1; + +CREATE TABLE t1 (a YEAR(2)); +INSERT INTO t1 VALUES (93),(94); +SELECT * FROM t1; +SELECT * FROM t1 WHERE a=1993 and a=93; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=1993 and a=93; +DROP TABLE t1; + +--echo # +--echo # End of 10.4 tests +--echo # diff --git a/sql/item.h b/sql/item.h index bf94896a61c..3beea6a85e8 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1676,12 +1676,6 @@ public: return get_date_result(<ime, fuzzydate) ? 0 : pack_time(<ime); } - // Get a temporal value in packed DATE/DATETIME or TIME format - longlong val_temporal_packed(enum_field_types f_type) - { - return f_type == MYSQL_TYPE_TIME ? val_time_packed() : - val_datetime_packed(); - } bool get_seconds(ulonglong *sec, ulong *sec_part); virtual bool get_date_result(MYSQL_TIME *ltime, ulonglong fuzzydate) { return get_date(ltime,fuzzydate); } diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 152f5ba89be..bddbd905bda 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2117,23 +2117,25 @@ bool Item_func_between::fix_length_and_dec_temporal(THD *thd) } -longlong Item_func_between::val_int_cmp_temporal() +longlong Item_func_between::val_int_cmp_datetime() { - enum_field_types f_type= m_comparator.type_handler()->field_type(); - longlong value= args[0]->val_temporal_packed(f_type), a, b; + longlong value= args[0]->val_datetime_packed(), a, b; if ((null_value= args[0]->null_value)) return 0; - a= args[1]->val_temporal_packed(f_type); - b= args[2]->val_temporal_packed(f_type); - if (!args[1]->null_value && !args[2]->null_value) - return (longlong) ((value >= a && value <= b) != negated); - if (args[1]->null_value && args[2]->null_value) - null_value= true; - else if (args[1]->null_value) - null_value= value <= b; // not null if false range. - else - null_value= value >= a; - return (longlong) (!null_value && negated); + a= args[1]->val_datetime_packed(); + b= args[2]->val_datetime_packed(); + return val_int_cmp_int_finalize(value, a, b); +} + + +longlong Item_func_between::val_int_cmp_time() +{ + longlong value= args[0]->val_time_packed(), a, b; + if ((null_value= args[0]->null_value)) + return 0; + a= args[1]->val_time_packed(); + b= args[2]->val_time_packed(); + return val_int_cmp_int_finalize(value, a, b); } @@ -2172,18 +2174,22 @@ longlong Item_func_between::val_int_cmp_int() return 0; /* purecov: inspected */ a= args[1]->val_int(); b= args[2]->val_int(); + return val_int_cmp_int_finalize(value, a, b); +} + + +bool Item_func_between::val_int_cmp_int_finalize(longlong value, + longlong a, + longlong b) +{ if (!args[1]->null_value && !args[2]->null_value) return (longlong) ((value >= a && value <= b) != negated); if (args[1]->null_value && args[2]->null_value) null_value= true; else if (args[1]->null_value) - { null_value= value <= b; // not null if false range. - } else - { null_value= value >= a; - } return (longlong) (!null_value && negated); } @@ -3653,9 +3659,18 @@ void in_time::set(uint pos,Item *item) buff->unsigned_flag= 1L; } -uchar *in_temporal::get_value_internal(Item *item, enum_field_types f_type) +uchar *in_datetime::get_value(Item *item) +{ + tmp.val= item->val_datetime_packed(); + if (item->null_value) + return 0; + tmp.unsigned_flag= 1L; + return (uchar*) &tmp; +} + +uchar *in_time::get_value(Item *item) { - tmp.val= item->val_temporal_packed(f_type); + tmp.val= item->val_time_packed(); if (item->null_value) return 0; tmp.unsigned_flag= 1L; @@ -4011,14 +4026,6 @@ cmp_item* cmp_item_decimal::make_same() } -void cmp_item_temporal::store_value_internal(Item *item, - enum_field_types f_type) -{ - value= item->val_temporal_packed(f_type); - m_null_value= item->null_value; -} - - int cmp_item_datetime::cmp_not_null(const Value *val) { DBUG_ASSERT(!val->is_null()); @@ -6262,76 +6269,53 @@ void Item_equal::add_const(THD *thd, Item *c) equal_items.push_front(c, thd->mem_root); return; } - Item *const_item= get_const(); - switch (Item_equal::compare_type_handler()->cmp_type()) { - case TIME_RESULT: - { - enum_field_types f_type= context_field->field_type(); - longlong value0= c->val_temporal_packed(f_type); - longlong value1= const_item->val_temporal_packed(f_type); - cond_false= c->null_value || const_item->null_value || value0 != value1; - break; - } - case STRING_RESULT: - { - String *str1, *str2; - /* - Suppose we have an expression (with a string type field) like this: - WHERE field=const1 AND field=const2 ... - - For all pairs field=constXXX we know that: - - - Item_func_eq::fix_length_and_dec() performed collation and character - set aggregation and added character set converters when needed. - Note, the case like: - WHERE field=const1 COLLATE latin1_bin AND field=const2 - is not handled here, because the field would be replaced to - Item_func_set_collation, which cannot get into Item_equal. - So all constXXX that are handled by Item_equal - already have compatible character sets with "field". - - - Also, Field_str::test_if_equality_guarantees_uniqueness() guarantees - that the comparison collation of all equalities handled by Item_equal - match the the collation of the field. - - Therefore, at Item_equal::add_const() time all constants constXXX - should be directly comparable to each other without an additional - character set conversion. - It's safe to do val_str() for "const_item" and "c" and compare - them according to the collation of the *field*. - - So in a script like this: - CREATE TABLE t1 (a VARCHAR(10) COLLATE xxx); - INSERT INTO t1 VALUES ('a'),('A'); - SELECT * FROM t1 WHERE a='a' AND a='A'; - Item_equal::add_const() effectively rewrites the condition to: - SELECT * FROM t1 WHERE a='a' AND 'a' COLLATE xxx='A'; - and then to: - SELECT * FROM t1 WHERE a='a'; // if the two constants were equal - // e.g. in case of latin1_swedish_ci - or to: - SELECT * FROM t1 WHERE FALSE; // if the two constants were not equal - // e.g. in case of latin1_bin - - Note, both "const_item" and "c" can return NULL, e.g.: - SELECT * FROM t1 WHERE a=NULL AND a='const'; - SELECT * FROM t1 WHERE a='const' AND a=NULL; - SELECT * FROM t1 WHERE a='const' AND a=(SELECT MAX(a) FROM t2) - */ - cond_false= !(str1= const_item->val_str(&cmp_value1)) || - !(str2= c->val_str(&cmp_value2)) || - !str1->eq(str2, compare_collation()); - break; - } - default: - { - Item_func_eq *func= new (thd->mem_root) Item_func_eq(thd, c, const_item); - if (func->set_cmp_func()) - return; - func->quick_fix_field(); - cond_false= !func->val_int(); - } - } + + /* + Suppose we have an expression (with a string type field) like this: + WHERE field=const1 AND field=const2 ... + + For all pairs field=constXXX we know that: + + - Item_func_eq::fix_length_and_dec() performed collation and character + set aggregation and added character set converters when needed. + Note, the case like: + WHERE field=const1 COLLATE latin1_bin AND field=const2 + is not handled here, because the field would be replaced to + Item_func_set_collation, which cannot get into Item_equal. + So all constXXX that are handled by Item_equal + already have compatible character sets with "field". + + - Also, Field_str::test_if_equality_guarantees_uniqueness() guarantees + that the comparison collation of all equalities handled by Item_equal + match the the collation of the field. + + Therefore, at Item_equal::add_const() time all constants constXXX + should be directly comparable to each other without an additional + character set conversion. + It's safe to do val_str() for "const_item" and "c" and compare + them according to the collation of the *field*. + + So in a script like this: + CREATE TABLE t1 (a VARCHAR(10) COLLATE xxx); + INSERT INTO t1 VALUES ('a'),('A'); + SELECT * FROM t1 WHERE a='a' AND a='A'; + Item_equal::add_const() effectively rewrites the condition to: + SELECT * FROM t1 WHERE a='a' AND 'a' COLLATE xxx='A'; + and then to: + SELECT * FROM t1 WHERE a='a'; // if the two constants were equal + // e.g. in case of latin1_swedish_ci + or to: + SELECT * FROM t1 WHERE FALSE; // if the two constants were not equal + // e.g. in case of latin1_bin + + Note, both "const_item" and "c" can return NULL, e.g.: + SELECT * FROM t1 WHERE a=NULL AND a='const'; + SELECT * FROM t1 WHERE a='const' AND a=NULL; + SELECT * FROM t1 WHERE a='const' AND a=(SELECT MAX(a) FROM t2) + */ + + cond_false= !Item_equal::compare_type_handler()->Item_eq_value(thd, this, c, + get_const()); if (with_const && equal_items.elements == 1) cond_true= TRUE; if (cond_false || cond_true) diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 1cdc48c8962..64500009bb7 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -152,7 +152,8 @@ public: class SEL_ARG; struct KEY_PART; -class Item_bool_func :public Item_int_func +class Item_bool_func :public Item_int_func, + public Type_cmp_attributes { protected: /* @@ -217,7 +218,7 @@ public: Item_bool_func(THD *thd, Item_bool_func *item) :Item_int_func(thd, item) {} const Type_handler *type_handler() const { return &type_handler_bool; } const Type_handler *fixed_type_handler() const { return &type_handler_bool; } - virtual CHARSET_INFO *compare_collation() const { return NULL; } + CHARSET_INFO *compare_collation() const { return NULL; } void fix_length_and_dec() { decimals=0; max_length=1; } uint decimal_precision() const { return 1; } bool need_parentheses_in_default() { return true; } @@ -891,6 +892,7 @@ class Item_func_between :public Item_func_opt_neg protected: SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Field *field, Item *value); + bool val_int_cmp_int_finalize(longlong value, longlong a, longlong b); public: String value0,value1,value2; Item_func_between(THD *thd, Item *a, Item *b, Item *c): @@ -931,7 +933,8 @@ public: { return get_item_copy<Item_func_between>(thd, this); } longlong val_int_cmp_string(); - longlong val_int_cmp_temporal(); + longlong val_int_cmp_datetime(); + longlong val_int_cmp_time(); longlong val_int_cmp_int(); longlong val_int_cmp_real(); longlong val_int_cmp_decimal(); @@ -1404,8 +1407,6 @@ public: */ class in_temporal :public in_longlong { -protected: - uchar *get_value_internal(Item *item, enum_field_types f_type); public: /* Cache for the left item. */ @@ -1418,8 +1419,6 @@ public: Item_datetime *dt= static_cast<Item_datetime*>(item); dt->set(val->val, type_handler()->mysql_timestamp_type()); } - uchar *get_value(Item *item) - { return get_value_internal(item, type_handler()->field_type()); } friend int cmp_longlong(void *cmp_arg, packed_longlong *a,packed_longlong *b); }; @@ -1431,6 +1430,7 @@ public: :in_temporal(thd, elements) {} void set(uint pos,Item *item); + uchar *get_value(Item *item); const Type_handler *type_handler() const { return &type_handler_datetime2; } }; @@ -1442,6 +1442,7 @@ public: :in_temporal(thd, elements) {} void set(uint pos,Item *item); + uchar *get_value(Item *item); const Type_handler *type_handler() const { return &type_handler_time2; } }; @@ -1616,7 +1617,6 @@ class cmp_item_temporal: public cmp_item_scalar { protected: longlong value; - void store_value_internal(Item *item, enum_field_types type); public: cmp_item_temporal() {} int compare(cmp_item *ci); @@ -1631,7 +1631,8 @@ public: { } void store_value(Item *item) { - store_value_internal(item, MYSQL_TYPE_DATETIME); + value= item->val_datetime_packed(); + m_null_value= item->null_value; } int cmp_not_null(const Value *val); int cmp(Item *arg); @@ -1647,7 +1648,8 @@ public: { } void store_value(Item *item) { - store_value_internal(item, MYSQL_TYPE_TIME); + value= item->val_time_packed(); + m_null_value= item->null_value; } int cmp_not_null(const Value *val); int cmp(Item *arg); @@ -3081,7 +3083,6 @@ class Item_equal: public Item_bool_func const Type_handler *m_compare_handler; CHARSET_INFO *m_compare_collation; - String cmp_value1, cmp_value2; public: COND_EQUAL *upper_levels; /* multiple equalities of upper and levels */ diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 66e1d2d79eb..3607e6d329b 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -3739,10 +3739,16 @@ longlong Type_handler_string_result:: return func->val_int_cmp_string(); } -longlong Type_handler_temporal_result:: +longlong Type_handler_temporal_with_date:: + Item_func_between_val_int(Item_func_between *func) const +{ + return func->val_int_cmp_datetime(); +} + +longlong Type_handler_time_common:: Item_func_between_val_int(Item_func_between *func) const { - return func->val_int_cmp_temporal(); + return func->val_int_cmp_time(); } longlong Type_handler_int_result:: @@ -6451,3 +6457,78 @@ Type_handler_hex_hybrid::type_handler_for_system_time() const /***************************************************************************/ + +bool Type_handler_row::Item_eq_value(THD *thd, const Type_cmp_attributes *attr, + Item *a, Item *b) const +{ + DBUG_ASSERT(0); + return false; +} + + +bool Type_handler_int_result::Item_eq_value(THD *thd, + const Type_cmp_attributes *attr, + Item *a, Item *b) const +{ + longlong value0= a->val_int(); + longlong value1= b->val_int(); + return !a->null_value && !b->null_value && value0 == value1 && + (value0 >= 0 || a->unsigned_flag == b->unsigned_flag); +} + + +bool Type_handler_real_result::Item_eq_value(THD *thd, + const Type_cmp_attributes *attr, + Item *a, Item *b) const +{ + double value0= a->val_real(); + double value1= b->val_real(); + return !a->null_value && !b->null_value && value0 == value1; +} + + +bool Type_handler_time_common::Item_eq_value(THD *thd, + const Type_cmp_attributes *attr, + Item *a, Item *b) const +{ + longlong value0= a->val_time_packed(); + longlong value1= b->val_time_packed(); + return !a->null_value && !b->null_value && value0 == value1; +} + + +bool Type_handler_temporal_with_date::Item_eq_value(THD *thd, + const Type_cmp_attributes *attr, + Item *a, Item *b) const +{ + longlong value0= a->val_datetime_packed(); + longlong value1= b->val_datetime_packed(); + return !a->null_value && !b->null_value && value0 == value1; +} + + +bool Type_handler_string_result::Item_eq_value(THD *thd, + const Type_cmp_attributes *attr, + Item *a, Item *b) const +{ + String *va, *vb; + StringBuffer<128> cmp_value1, cmp_value2; + return (va= a->val_str(&cmp_value1)) && + (vb= b->val_str(&cmp_value2)) && + va->eq(vb, attr->compare_collation()); +} + + +bool Type_handler_decimal_result::Item_eq_value(THD *thd, + const Type_cmp_attributes *attr, + Item *a, Item *b) const +{ + my_decimal *va, *vb; + my_decimal cmp_value1, cmp_value2; + return (va= a->val_decimal(&cmp_value1)) && + (vb= b->val_decimal(&cmp_value2)) && + !my_decimal_cmp(va, vb); + +} + +/***************************************************************************/ diff --git a/sql/sql_type.h b/sql/sql_type.h index f9ba99e775f..f0ec0ba4e94 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -836,6 +836,14 @@ public: }; +class Type_cmp_attributes +{ +public: + virtual ~Type_cmp_attributes() { } + virtual CHARSET_INFO *compare_collation() const= 0; +}; + + class Type_cast_attributes { CHARSET_INFO *m_charset; @@ -1400,6 +1408,8 @@ public: { return false; } + virtual bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, + Item *a, Item *b) const= 0; virtual bool Item_hybrid_func_fix_attributes(THD *thd, const char *name, Type_handler_hybrid_field_type *, @@ -1623,6 +1633,8 @@ public: DBUG_ASSERT(0); return 0; } + bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, + Item *a, Item *b) const; uint Item_decimal_precision(const Item *item) const { DBUG_ASSERT(0); @@ -1878,6 +1890,8 @@ public: SORT_FIELD_ATTR *attr) const; bool Item_const_eq(const Item_const *a, const Item_const *b, bool binary_cmp) const; + bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, + Item *a, Item *b) const; uint Item_decimal_precision(const Item *item) const; bool Item_save_in_value(Item *item, st_value *value) const; bool Item_param_set_from_value(THD *thd, @@ -1957,6 +1971,8 @@ public: const Type_cast_attributes &attr) const; bool Item_const_eq(const Item_const *a, const Item_const *b, bool binary_cmp) const; + bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, + Item *a, Item *b) const; uint Item_decimal_precision(const Item *item) const; bool Item_save_in_value(Item *item, st_value *value) const; void Item_param_set_param_func(Item_param *param, @@ -2161,6 +2177,8 @@ public: SORT_FIELD_ATTR *attr) const; bool Item_const_eq(const Item_const *a, const Item_const *b, bool binary_cmp) const; + bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, + Item *a, Item *b) const; uint Item_decimal_precision(const Item *item) const; bool Item_save_in_value(Item *item, st_value *value) const; bool Item_param_set_from_value(THD *thd, @@ -2282,7 +2300,6 @@ public: bool Item_func_min_max_get_date(Item_func_min_max*, MYSQL_TIME *, ulonglong fuzzydate) const; bool Item_func_between_fix_length_and_dec(Item_func_between *func) const; - longlong Item_func_between_val_int(Item_func_between *func) const; bool Item_func_in_fix_comparator_compatible_types(THD *thd, Item_func_in *) const; bool Item_func_round_fix_length_and_dec(Item_func_round *) const; @@ -2328,6 +2345,8 @@ public: uint32 max_display_length(const Item *item) const; bool Item_const_eq(const Item_const *a, const Item_const *b, bool binary_cmp) const; + bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, + Item *a, Item *b) const; uint Item_time_precision(Item *item) const { return Item_temporal_precision(item, true); @@ -2847,6 +2866,8 @@ public: } Item *create_typecast_item(THD *thd, Item *item, const Type_cast_attributes &attr) const; + bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, + Item *a, Item *b) const; uint Item_decimal_scale(const Item *item) const { return Item_decimal_scale_with_seconds(item); @@ -2885,6 +2906,7 @@ public: ulonglong fuzzydate) const; bool Item_func_min_max_get_date(Item_func_min_max*, MYSQL_TIME *, ulonglong fuzzydate) const; + longlong Item_func_between_val_int(Item_func_between *func) const; Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const; bool set_comparator_func(Arg_comparator *cmp) const; cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const; @@ -2952,6 +2974,8 @@ class Type_handler_temporal_with_date: public Type_handler_temporal_result { public: virtual ~Type_handler_temporal_with_date() {} + bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, + Item *a, Item *b) const; bool Item_save_in_value(Item *item, st_value *value) const; bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { @@ -2962,6 +2986,7 @@ public: bool set_comparator_func(Arg_comparator *cmp) const; cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const; in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const; + longlong Item_func_between_val_int(Item_func_between *func) const; }; |