diff --git a/mysql-test/main/func_debug.result b/mysql-test/main/func_debug.result index 7fcf522abba..a394bf3c334 100644 --- a/mysql-test/main/func_debug.result +++ b/mysql-test/main/func_debug.result @@ -1655,3 +1655,104 @@ Note 1105 DBUG: [1] arg=2 handler=0 (time) Note 1105 DBUG: [2] arg=3 handler=2 (datetime) SET SESSION debug_dbug="-d,Predicant_to_list_comparator"; SET SESSION debug_dbug="-d,Item_func_in"; +# +# MDEV-16408 Remove tests for Item::type() in Item_basic_value::eq() +# +SET SESSION debug_dbug="+d,Item_basic_value"; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2),(3); +SELECT * FROM t1 WHERE a BETWEEN 1 AND 1.0; +a +1 +Warnings: +Note 1105 bin_eq=0 a=int'1' b=decimal'1.0' +SELECT * FROM t1 WHERE a BETWEEN 1 AND 1; +a +1 +Warnings: +Note 1105 bin_eq=1 a=int'1' b=int'1' +SELECT * FROM t1 WHERE a BETWEEN 0 AND 1; +a +1 +Warnings: +Note 1105 bin_eq=0 a=int'0' b=int'1' +SELECT * FROM t1 WHERE a BETWEEN 0 AND -1; +a +Warnings: +Note 1105 bin_eq=0 a=int'0' b=int'' +SELECT * FROM t1 WHERE a BETWEEN -1 AND -1; +a +Warnings: +Note 1105 bin_eq=1 a=int'' b=int'' +SELECT * FROM t1 WHERE a BETWEEN -0000000000000001 AND -1; +a +Warnings: +Note 1105 bin_eq=1 a=bigint'' b=int'' +SELECT * FROM t1 WHERE a BETWEEN -1 AND 18446744073709551615; +a +1 +2 +3 +Warnings: +Note 1105 bin_eq=0 a=int'' b=bigint'18446744073709551615' +SELECT * FROM t1 WHERE a BETWEEN -1 AND 18446744073709551616; +a +1 +2 +3 +Warnings: +Note 1105 bin_eq=0 a=int'' b=decimal'18446744073709551616' +SELECT * FROM t1 WHERE a BETWEEN 1e2 AND 100e0; +a +Warnings: +Note 1105 bin_eq=1 a=double'1e2' b=double'100e0' +EXECUTE IMMEDIATE 'SELECT * FROM t1 WHERE a BETWEEN 1 AND ?' USING 1; +a +1 +Warnings: +Note 1105 bin_eq=1 a=int'1' b=int'?' +EXECUTE IMMEDIATE 'SELECT * FROM t1 WHERE a BETWEEN -1 AND ?' USING 18446744073709551615; +a +1 +2 +3 +Warnings: +Note 1105 bin_eq=0 a=int'' b=bigint'?' +EXECUTE IMMEDIATE 'SELECT * FROM t1 WHERE a BETWEEN -1 AND ?' USING 18446744073709551616; +a +1 +2 +3 +Warnings: +Note 1105 bin_eq=0 a=int'' b=decimal'?' +DROP TABLE t1; +CREATE TABLE t1 (a DECIMAL(10,3)); +INSERT INTO t1 VALUES (1),(2),(3); +SELECT * FROM t1 WHERE a BETWEEN 1.0 AND 1.0; +a +1.000 +DROP TABLE t1; +CREATE TABLE t1 (a TIME); +INSERT INTO t1 VALUES ('00:00:00'),('00:00:01'); +SELECT * FROM t1 WHERE a BETWEEN TIME'00:00:00' AND TIME'00:00:00'; +a +00:00:00 +DROP TABLE t1; +CREATE TABLE t1 (a VARCHAR(10)); +INSERT INTO t1 VALUES ('0'),('1'),('2'); +SELECT * FROM t1 WHERE a BETWEEN '0' AND '0'; +a +0 +Warnings: +Note 1105 eq=1 a=varchar'0' b=varchar'0' +SELECT * FROM t1 WHERE a BETWEEN '0' AND ' 0'; +a +Warnings: +Note 1105 eq=0 a=varchar'0' b=varchar'0' +SELECT * FROM t1 WHERE a BETWEEN '0' AND '0 '; +a +0 +Warnings: +Note 1105 eq=1 a=varchar'0' b=varchar'0 ' +DROP TABLE t1; +SET SESSION debug_dbug="-d,Item_basic_value"; diff --git a/mysql-test/main/func_debug.test b/mysql-test/main/func_debug.test index e0960f736cb..f9b6daab3a2 100644 --- a/mysql-test/main/func_debug.test +++ b/mysql-test/main/func_debug.test @@ -475,3 +475,48 @@ SELECT SET SESSION debug_dbug="-d,Predicant_to_list_comparator"; SET SESSION debug_dbug="-d,Item_func_in"; + + +--echo # +--echo # MDEV-16408 Remove tests for Item::type() in Item_basic_value::eq() +--echo # + +SET SESSION debug_dbug="+d,Item_basic_value"; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2),(3); +SELECT * FROM t1 WHERE a BETWEEN 1 AND 1.0; +SELECT * FROM t1 WHERE a BETWEEN 1 AND 1; +SELECT * FROM t1 WHERE a BETWEEN 0 AND 1; +SELECT * FROM t1 WHERE a BETWEEN 0 AND -1; +SELECT * FROM t1 WHERE a BETWEEN -1 AND -1; +SELECT * FROM t1 WHERE a BETWEEN -0000000000000001 AND -1; +SELECT * FROM t1 WHERE a BETWEEN -1 AND 18446744073709551615; +SELECT * FROM t1 WHERE a BETWEEN -1 AND 18446744073709551616; +SELECT * FROM t1 WHERE a BETWEEN 1e2 AND 100e0; + +EXECUTE IMMEDIATE 'SELECT * FROM t1 WHERE a BETWEEN 1 AND ?' USING 1; +EXECUTE IMMEDIATE 'SELECT * FROM t1 WHERE a BETWEEN -1 AND ?' USING 18446744073709551615; +EXECUTE IMMEDIATE 'SELECT * FROM t1 WHERE a BETWEEN -1 AND ?' USING 18446744073709551616; +DROP TABLE t1; + + +# DECIMAL does not work yet +CREATE TABLE t1 (a DECIMAL(10,3)); +INSERT INTO t1 VALUES (1),(2),(3); +SELECT * FROM t1 WHERE a BETWEEN 1.0 AND 1.0; +DROP TABLE t1; + +# Temporal types do not work yet +CREATE TABLE t1 (a TIME); +INSERT INTO t1 VALUES ('00:00:00'),('00:00:01'); +SELECT * FROM t1 WHERE a BETWEEN TIME'00:00:00' AND TIME'00:00:00'; +DROP TABLE t1; + +CREATE TABLE t1 (a VARCHAR(10)); +INSERT INTO t1 VALUES ('0'),('1'),('2'); +SELECT * FROM t1 WHERE a BETWEEN '0' AND '0'; +SELECT * FROM t1 WHERE a BETWEEN '0' AND ' 0'; +SELECT * FROM t1 WHERE a BETWEEN '0' AND '0 '; +DROP TABLE t1; + +SET SESSION debug_dbug="-d,Item_basic_value"; diff --git a/sql/item.cc b/sql/item.cc index 9852053f925..a4a72a8d2f8 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3631,6 +3631,35 @@ longlong Item_field::val_int_endpoint(bool left_endp, bool *incl_endp) return null_value? LONGLONG_MIN : res; } + +bool Item_basic_value::eq(const Item *item, bool binary_cmp) const +{ + const Item_basic_value *other= item->get_item_basic_value(); + Type other_type; + // Exclude CACHE_OTEM and VARBIN_ITEM + if (!other || + (other_type= other->type()) == CACHE_ITEM || + other_type == VARBIN_ITEM) + return false; + const Type_handler *h= type_handler()->type_handler_for_comparison(); + bool res= (h == other->type_handler()->type_handler_for_comparison()) && + (binary_cmp ? h->Item_basic_value_bin_eq(this, other) : + h->Item_basic_value_eq(this, other)); + DBUG_EXECUTE_IF("Item_basic_value", + push_warning_printf(current_thd, + Sql_condition::WARN_LEVEL_NOTE, + ER_UNKNOWN_ERROR, "%seq=%d a=%s'%.*s' b=%s'%.*s'", + binary_cmp ? "bin_" : "", + (int) res, + type_handler()->name().ptr(), + (int) name.length, name.str, + other->type_handler()->name().ptr(), + (int) other->name.length, other->name.str + );); + return res; +} + + /** Create an item from a string we KNOW points to a valid longlong end \\0 terminated number string. @@ -4697,10 +4726,20 @@ bool Item_param::convert_str_value(THD *thd) bool Item_param::basic_const_item() const { DBUG_ASSERT(has_valid_state()); - if (state == NO_VALUE || - (state == SHORT_DATA_VALUE && type_handler()->cmp_type() == TIME_RESULT)) - return FALSE; - return TRUE; + switch (state) { + case LONG_DATA_VALUE: + case NULL_VALUE: + return true; + case SHORT_DATA_VALUE: + return type_handler()->cmp_type() != TIME_RESULT; + case DEFAULT_VALUE: + case IGNORE_VALUE: + invalid_default_param(); + return false; + case NO_VALUE: + break; + } + return false; } @@ -4761,48 +4800,6 @@ Item_param::clone_item(THD *thd) } -bool Item_param::value_eq(const Item *item, bool binary_cmp) const -{ - switch (value.type_handler()->cmp_type()) { - case INT_RESULT: - return int_eq(value.integer, item); - case REAL_RESULT: - return real_eq(value.real, item); - case STRING_RESULT: - return str_eq(&value.m_string, item, binary_cmp); - case DECIMAL_RESULT: - case TIME_RESULT: - case ROW_RESULT: - break; - } - return false; -} - - -bool -Item_param::eq(const Item *item, bool binary_cmp) const -{ - if (!basic_const_item()) - return FALSE; - - // There's no "default". See comments in Item_param::save_in_field(). - switch (state) { - case IGNORE_VALUE: - case DEFAULT_VALUE: - invalid_default_param(); - return false; - case NULL_VALUE: - return null_eq(item); - case SHORT_DATA_VALUE: - case LONG_DATA_VALUE: - return value_eq(item, binary_cmp); - case NO_VALUE: - return false; - } - DBUG_ASSERT(0); // Garbage - return FALSE; -} - /* End of Item_param related */ void Item_param::print(String *str, enum_query_type query_type) diff --git a/sql/item.h b/sql/item.h index ee3dc7edd70..811a0fac0ba 100644 --- a/sql/item.h +++ b/sql/item.h @@ -99,6 +99,7 @@ class sp_head; class Protocol; struct TABLE_LIST; void item_init(void); /* Init item functions */ +class Item_basic_value; class Item_result_field; class Item_field; class Item_ref; @@ -2077,6 +2078,7 @@ public: delete this; } + virtual const Item_basic_value *get_item_basic_value() const { return NULL; } virtual Item_splocal *get_item_splocal() { return 0; } virtual Rewritable_query_parameter *get_rewritable_query_parameter() { return 0; } @@ -2503,22 +2505,6 @@ public: */ class Item_basic_value :public Item { - bool is_basic_value(const Item *item, Type type_arg) const - { - return item->basic_const_item() && item->type() == type_arg; - } - bool is_basic_value(Type type_arg) const - { - return basic_const_item() && type() == type_arg; - } - bool str_eq(const String *value, - const String *other, CHARSET_INFO *cs, bool binary_cmp) const - { - return binary_cmp ? - value->bin_eq(other) : - collation.collation == cs && value->eq(other, collation.collation); - } - protected: // Value metadata, e.g. to make string processing easier class Metadata: private MY_STRING_METADATA @@ -2555,37 +2541,11 @@ protected: fix_charset_and_length(str.charset(), dv, Metadata(&str)); } Item_basic_value(THD *thd): Item(thd) {} - /* - In the xxx_eq() methods below we need to cast off "const" to - call val_xxx(). This is OK for Item_basic_constant and Item_param. - */ - bool null_eq(const Item *item) const - { - DBUG_ASSERT(is_basic_value(NULL_ITEM)); - return item->type() == NULL_ITEM; - } - bool str_eq(const String *value, const Item *item, bool binary_cmp) const - { - DBUG_ASSERT(is_basic_value(STRING_ITEM)); - return is_basic_value(item, STRING_ITEM) && - str_eq(value, ((Item_basic_value*)item)->val_str(NULL), - item->collation.collation, binary_cmp); - } - bool real_eq(double value, const Item *item) const - { - DBUG_ASSERT(is_basic_value(REAL_ITEM)); - return is_basic_value(item, REAL_ITEM) && - value == ((Item_basic_value*)item)->val_real(); - } - bool int_eq(longlong value, const Item *item) const - { - DBUG_ASSERT(is_basic_value(INT_ITEM)); - return is_basic_value(item, INT_ITEM) && - value == ((Item_basic_value*)item)->val_int() && - (value >= 0 || item->unsigned_flag == unsigned_flag); - } +public: Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src, const Tmp_field_param *param); + const Item_basic_value *get_item_basic_value() const { return this; } + bool eq(const Item *item, bool binary_cmp) const; }; @@ -2983,6 +2943,7 @@ public: bool check_partition_func_processor(void *int_arg) { return false;} bool const_item() const { return true; } bool basic_const_item() const { return true; } + const Item_basic_value *get_item_basic_value() const { return this; } }; @@ -3448,7 +3409,6 @@ public: collation.set(cs, DERIVATION_IGNORABLE, MY_REPERTOIRE_ASCII); } enum Type type() const { return NULL_ITEM; } - bool eq(const Item *item, bool binary_cmp) const { return null_eq(item); } double val_real(); longlong val_int(); String *val_str(String *str); @@ -3694,7 +3654,6 @@ class Item_param :public Item_basic_value, PValue value; const String *value_query_val_str(THD *thd, String* str) const; - bool value_eq(const Item *item, bool binary_cmp) const; Item *value_clone_item(THD *thd); bool can_return_value() const; @@ -3861,12 +3820,6 @@ public: */ Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs); Item *clone_item(THD *thd); - /* - Implement by-value equality evaluation if parameter value - is set and is a basic constant (integer, real or string). - Otherwise return FALSE. - */ - bool eq(const Item *item, bool binary_cmp) const; void set_param_type_and_swap_value(Item_param *from); Rewritable_query_parameter *get_rewritable_query_parameter() @@ -3942,8 +3895,6 @@ public: Item *neg(THD *thd); uint decimal_precision() const { return (uint) (max_length - MY_TEST(value < 0)); } - bool eq(const Item *item, bool binary_cmp) const - { return int_eq(value, item); } Item *get_copy(THD *thd) { return get_item_copy(thd, this); } }; @@ -4084,8 +4035,6 @@ public: Item *clone_item(THD *thd); Item *neg(THD *thd); virtual void print(String *str, enum_query_type query_type); - bool eq(const Item *item, bool binary_cmp) const - { return real_eq(value, item); } Item *get_copy(THD *thd) { return get_item_copy(thd, this); } }; @@ -4204,10 +4153,6 @@ public: } int save_in_field(Field *field, bool no_conversions); const Type_handler *type_handler() const { return &type_handler_varchar; } - bool eq(const Item *item, bool binary_cmp) const - { - return str_eq(&str_value, item, binary_cmp); - } Item *clone_item(THD *thd); Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) { diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 8eca6593e4e..dce74d92859 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -6356,3 +6356,65 @@ bool Type_handler_general_purpose_string:: } /***************************************************************************/ + +bool Type_handler_null::Item_basic_value_eq(const Item_basic_value *a, + const Item_basic_value *b) + const +{ + return a->basic_const_item() && + b->basic_const_item(); +} + + +bool Type_handler_real_result::Item_basic_value_eq(const Item_basic_value *a, + const Item_basic_value *b) + const +{ + return a->basic_const_item() && + b->basic_const_item() && + const_cast(a)->val_real() == + const_cast(b)->val_real(); +} + + +bool Type_handler_int_result::Item_basic_value_eq(const Item_basic_value *a, + const Item_basic_value *b) + const +{ + longlong value; + return a->basic_const_item() && + b->basic_const_item() && + (value= const_cast(a)->val_int()) == + const_cast(b)->val_int() && + (value >= 0 || a->unsigned_flag == b->unsigned_flag); +} + + +bool Type_handler_string_result::Item_basic_value_eq(const Item_basic_value *a, + const Item_basic_value *b) + const +{ + if (!a->basic_const_item() || + !b->basic_const_item() || + a->collation.collation != b->collation.collation) + return false; + String *sa= const_cast(a)->val_str(NULL); + String *sb= const_cast(b)->val_str(NULL); + return sa->eq(sb, a->collation.collation); +} + + +bool +Type_handler_string_result::Item_basic_value_bin_eq(const Item_basic_value *a, + const Item_basic_value *b) + const +{ + if (!a->basic_const_item() || + !b->basic_const_item()) + return false; + String *sa= const_cast(a)->val_str(NULL); + String *sb= const_cast(b)->val_str(NULL); + return sa->bin_eq(sb); +} + +/***************************************************************************/ diff --git a/sql/sql_type.h b/sql/sql_type.h index ad554a91024..656c5e06e81 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -30,6 +30,7 @@ class Field; class Column_definition; class Column_definition_attributes; class Item; +class Item_basic_value; class Item_param; class Item_cache; class Item_func_or_sum; @@ -1390,6 +1391,16 @@ public: return NULL; } virtual bool set_comparator_func(Arg_comparator *cmp) const= 0; + virtual bool Item_basic_value_eq(const Item_basic_value *a, + const Item_basic_value *b) const + { + return false; + } + virtual bool Item_basic_value_bin_eq(const Item_basic_value *a, + const Item_basic_value *b) const + { + return Item_basic_value_eq(a, b); + } virtual bool Item_hybrid_func_fix_attributes(THD *thd, const char *name, Type_handler_hybrid_field_type *, @@ -1866,6 +1877,8 @@ public: void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; + bool Item_basic_value_eq(const Item_basic_value *a, + const Item_basic_value *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, @@ -2145,6 +2158,8 @@ public: void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; + bool Item_basic_value_eq(const Item_basic_value *a, + const Item_basic_value *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, @@ -2308,6 +2323,10 @@ public: const Schema_specification_st *schema) const; uint32 max_display_length(const Item *item) const; + bool Item_basic_value_eq(const Item_basic_value *a, + const Item_basic_value *b) const; + bool Item_basic_value_bin_eq(const Item_basic_value *a, + const Item_basic_value *b) const; uint Item_time_precision(Item *item) const { return Item_temporal_precision(item, true); @@ -3296,6 +3315,13 @@ public: const Type_handler *type_handler_for_union(const Item *) const; uint32 max_display_length(const Item *item) const { return 0; } uint32 calc_pack_length(uint32 length) const { return 0; } + bool Item_basic_value_eq(const Item_basic_value *a, + const Item_basic_value *b) const; + bool Item_basic_value_bin_eq(const Item_basic_value *a, + const Item_basic_value *b) const + { + return Type_handler_null::Item_basic_value_eq(a, b); + } bool Item_save_in_value(Item *item, st_value *value) const; bool Item_send(Item *item, Protocol *protocol, st_value *buf) const; Field *make_conversion_table_field(TABLE *, uint metadata,