diff --git a/mysql-test/r/type_timestamp.result b/mysql-test/r/type_timestamp.result index c5e41a237fc..881b57ac1d7 100644 --- a/mysql-test/r/type_timestamp.result +++ b/mysql-test/r/type_timestamp.result @@ -980,5 +980,17 @@ Warnings: Warning 1441 Datetime function: datetime field overflow DROP TABLE t1; # +# MDEV-11482 Incorrect result for (time_expr BETWEEN timestamp_exp1 AND timestamp_expr2) +# +SET @@sql_mode=DEFAULT; +SET @@timestamp=UNIX_TIMESTAMP('2001-01-01 10:20:30'); +CREATE TABLE t1 (a TIMESTAMP,b TIMESTAMP); +INSERT INTO t1 VALUES ('2001-01-01 00:00:00','2001-01-01 23:59:59'); +SELECT * FROM t1 WHERE TIME'10:20:30' BETWEEN a and b; +a b +2001-01-01 00:00:00 2001-01-01 23:59:59 +DROP TABLE t1; +SET @@timestamp=DEFAULT; +# # End of 10.3 tests # diff --git a/mysql-test/t/type_timestamp.test b/mysql-test/t/type_timestamp.test index 2dad92b6b90..7f32f7a1d65 100644 --- a/mysql-test/t/type_timestamp.test +++ b/mysql-test/t/type_timestamp.test @@ -576,6 +576,17 @@ EXPLAIN SELECT * FROM t1 WHERE a >= DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTE EXPLAIN SELECT * FROM t1 WHERE a >= COALESCE(DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTERVAL 1000 YEAR)); DROP TABLE t1; +--echo # +--echo # MDEV-11482 Incorrect result for (time_expr BETWEEN timestamp_exp1 AND timestamp_expr2) +--echo # +SET @@sql_mode=DEFAULT; +SET @@timestamp=UNIX_TIMESTAMP('2001-01-01 10:20:30'); +CREATE TABLE t1 (a TIMESTAMP,b TIMESTAMP); +INSERT INTO t1 VALUES ('2001-01-01 00:00:00','2001-01-01 23:59:59'); +SELECT * FROM t1 WHERE TIME'10:20:30' BETWEEN a and b; +DROP TABLE t1; +SET @@timestamp=DEFAULT; + --echo # --echo # End of 10.3 tests --echo # diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 57c8220381f..0b392213f3e 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -118,14 +118,15 @@ static int cmp_row_type(Item* item1, Item* item2) 0 otherwise */ -static int agg_cmp_type(Item_result *type, Item **items, uint nitems) +bool Type_handler_hybrid_field_type::aggregate_for_comparison(Item **items, + uint nitems) { uint unsigned_count= items[0]->unsigned_flag; - type[0]= items[0]->cmp_type(); + set_handler(items[0]->type_handler()); for (uint i= 1 ; i < nitems ; i++) { unsigned_count+= items[i]->unsigned_flag; - type[0]= item_cmp_type(type[0], items[i]); + aggregate_for_comparison(items[i]->type_handler()); /* When aggregating types of two row expressions we have to check that they have the same cardinality and that each component @@ -133,15 +134,16 @@ static int agg_cmp_type(Item_result *type, Item **items, uint nitems) the signature of the corresponding component of the second row expression. */ - if (type[0] == ROW_RESULT && cmp_row_type(items[0], items[i])) - return 1; // error found: invalid usage of rows + if (cmp_type() == ROW_RESULT && cmp_row_type(items[0], items[i])) + return true; // error found: invalid usage of rows } /** If all arguments are of INT type but have different unsigned_flag values, switch to DECIMAL_RESULT. */ - if (type[0] == INT_RESULT && unsigned_count != nitems && unsigned_count != 0) - type[0]= DECIMAL_RESULT; + if (cmp_type() == INT_RESULT && + unsigned_count != nitems && unsigned_count != 0) + set_handler(&type_handler_newdecimal); return 0; } @@ -2069,7 +2071,6 @@ void Item_func_between::fix_length_and_dec() { THD *thd= current_thd; max_length= 1; - compare_as_dates= 0; /* As some compare functions are generated after sql_yacc, @@ -2077,24 +2078,13 @@ void Item_func_between::fix_length_and_dec() */ if (!args[0] || !args[1] || !args[2]) return; - if (agg_cmp_type(&m_compare_type, args, 3)) + if (m_comparator.aggregate_for_comparison(args, 3)) return; - if (m_compare_type == STRING_RESULT && + if (m_comparator.cmp_type() == STRING_RESULT && agg_arg_charsets_for_comparison(cmp_collation, args, 3)) return; - /* - When comparing as date/time, we need to convert non-temporal values - (e.g. strings) to MYSQL_TIME. get_datetime_value() does it - automatically when one of the operands is a date/time. But here we - may need to compare two strings as dates (str1 BETWEEN str2 AND date). - For this to work, we need to know what date/time type we compare - strings as. - */ - if (m_compare_type == TIME_RESULT) - compare_as_dates= find_date_time_item(args, 3, 0); - /* See the comment about the similar block in Item_bool_func2 */ if (args[0]->real_item()->type() == FIELD_ITEM && !thd->lex->is_ps_or_view_context_analysis()) @@ -2106,145 +2096,143 @@ void Item_func_between::fix_length_and_dec() const bool cvt_arg1= convert_const_to_int(thd, field_item, &args[1]); const bool cvt_arg2= convert_const_to_int(thd, field_item, &args[2]); if (cvt_arg1 && cvt_arg2) - m_compare_type= INT_RESULT; // Works for all types. + { + // Works for all types + m_comparator.set_handler(&type_handler_longlong); + } } } } -longlong Item_func_between::val_int() +longlong Item_func_between::val_int_cmp_temporal() { - DBUG_ASSERT(fixed == 1); + THD *thd= current_thd; + longlong value, a, b; + Item *cache, **ptr; + bool value_is_null, a_is_null, b_is_null; - switch (m_compare_type) { - case TIME_RESULT: - { - THD *thd= current_thd; - longlong value, a, b; - Item *cache, **ptr; - bool value_is_null, a_is_null, b_is_null; + ptr= &args[0]; + enum_field_types f_type= m_comparator.field_type(); + value= get_datetime_value(thd, &ptr, &cache, f_type, &value_is_null); + if (ptr != &args[0]) + thd->change_item_tree(&args[0], *ptr); - ptr= &args[0]; - enum_field_types f_type= field_type_for_temporal_comparison(compare_as_dates); - value= get_datetime_value(thd, &ptr, &cache, f_type, &value_is_null); - if (ptr != &args[0]) - thd->change_item_tree(&args[0], *ptr); - - if ((null_value= value_is_null)) - return 0; - - ptr= &args[1]; - a= get_datetime_value(thd, &ptr, &cache, f_type, &a_is_null); - if (ptr != &args[1]) - thd->change_item_tree(&args[1], *ptr); - - ptr= &args[2]; - b= get_datetime_value(thd, &ptr, &cache, f_type, &b_is_null); - if (ptr != &args[2]) - thd->change_item_tree(&args[2], *ptr); - - if (!a_is_null && !b_is_null) - return (longlong) ((value >= a && value <= b) != negated); - if (a_is_null && b_is_null) - null_value=1; - else if (a_is_null) - null_value= value <= b; // not null if false range. - else - null_value= value >= a; - break; - } - - case STRING_RESULT: - { - String *value,*a,*b; - value=args[0]->val_str(&value0); - if ((null_value=args[0]->null_value)) - return 0; - a=args[1]->val_str(&value1); - b=args[2]->val_str(&value2); - if (!args[1]->null_value && !args[2]->null_value) - return (longlong) ((sortcmp(value,a,cmp_collation.collation) >= 0 && - sortcmp(value,b,cmp_collation.collation) <= 0) != - negated); - if (args[1]->null_value && args[2]->null_value) - null_value=1; - else if (args[1]->null_value) - { - // Set to not null if false range. - null_value= sortcmp(value,b,cmp_collation.collation) <= 0; - } - else - { - // Set to not null if false range. - null_value= sortcmp(value,a,cmp_collation.collation) >= 0; - } - break; - } - case INT_RESULT: - { - longlong value=args[0]->val_int(), a, b; - if ((null_value=args[0]->null_value)) - return 0; /* purecov: inspected */ - a=args[1]->val_int(); - b=args[2]->val_int(); - 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=1; - else if (args[1]->null_value) - { - null_value= value <= b; // not null if false range. - } - else - { - null_value= value >= a; - } - break; - } - case DECIMAL_RESULT: - { - my_decimal dec_buf, *dec= args[0]->val_decimal(&dec_buf), - a_buf, *a_dec, b_buf, *b_dec; - if ((null_value=args[0]->null_value)) - return 0; /* purecov: inspected */ - a_dec= args[1]->val_decimal(&a_buf); - b_dec= args[2]->val_decimal(&b_buf); - if (!args[1]->null_value && !args[2]->null_value) - return (longlong) ((my_decimal_cmp(dec, a_dec) >= 0 && - my_decimal_cmp(dec, b_dec) <= 0) != negated); - if (args[1]->null_value && args[2]->null_value) - null_value=1; - else if (args[1]->null_value) - null_value= (my_decimal_cmp(dec, b_dec) <= 0); - else - null_value= (my_decimal_cmp(dec, a_dec) >= 0); - break; - } - case REAL_RESULT: - { - double value= args[0]->val_real(),a,b; - if ((null_value=args[0]->null_value)) - return 0; /* purecov: inspected */ - a= args[1]->val_real(); - b= args[2]->val_real(); - 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=1; - else if (args[1]->null_value) - { - null_value= value <= b; // not null if false range. - } - else - { - null_value= value >= a; - } - break; - } - case ROW_RESULT: - DBUG_ASSERT(0); - null_value= 1; + if ((null_value= value_is_null)) return 0; + + ptr= &args[1]; + a= get_datetime_value(thd, &ptr, &cache, f_type, &a_is_null); + if (ptr != &args[1]) + thd->change_item_tree(&args[1], *ptr); + + ptr= &args[2]; + b= get_datetime_value(thd, &ptr, &cache, f_type, &b_is_null); + if (ptr != &args[2]) + thd->change_item_tree(&args[2], *ptr); + + if (!a_is_null && !b_is_null) + return (longlong) ((value >= a && value <= b) != negated); + if (a_is_null && b_is_null) + null_value= true; + else if (a_is_null) + null_value= value <= b; // not null if false range. + else + null_value= value >= a; + return (longlong) (!null_value && negated); +} + + +longlong Item_func_between::val_int_cmp_string() +{ + String *value,*a,*b; + value=args[0]->val_str(&value0); + if ((null_value=args[0]->null_value)) + return 0; + a= args[1]->val_str(&value1); + b= args[2]->val_str(&value2); + if (!args[1]->null_value && !args[2]->null_value) + return (longlong) ((sortcmp(value,a,cmp_collation.collation) >= 0 && + sortcmp(value,b,cmp_collation.collation) <= 0) != + negated); + if (args[1]->null_value && args[2]->null_value) + null_value= true; + else if (args[1]->null_value) + { + // Set to not null if false range. + null_value= sortcmp(value,b,cmp_collation.collation) <= 0; + } + else + { + // Set to not null if false range. + null_value= sortcmp(value,a,cmp_collation.collation) >= 0; + } + return (longlong) (!null_value && negated); +} + + +longlong Item_func_between::val_int_cmp_int() +{ + longlong value= args[0]->val_int(), a, b; + if ((null_value= args[0]->null_value)) + return 0; /* purecov: inspected */ + a= args[1]->val_int(); + b= args[2]->val_int(); + 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); +} + + +longlong Item_func_between::val_int_cmp_decimal() +{ + my_decimal dec_buf, *dec= args[0]->val_decimal(&dec_buf), + a_buf, *a_dec, b_buf, *b_dec; + if ((null_value=args[0]->null_value)) + return 0; /* purecov: inspected */ + a_dec= args[1]->val_decimal(&a_buf); + b_dec= args[2]->val_decimal(&b_buf); + if (!args[1]->null_value && !args[2]->null_value) + return (longlong) ((my_decimal_cmp(dec, a_dec) >= 0 && + my_decimal_cmp(dec, b_dec) <= 0) != negated); + if (args[1]->null_value && args[2]->null_value) + null_value= true; + else if (args[1]->null_value) + null_value= (my_decimal_cmp(dec, b_dec) <= 0); + else + null_value= (my_decimal_cmp(dec, a_dec) >= 0); + return (longlong) (!null_value && negated); +} + + +longlong Item_func_between::val_int_cmp_real() +{ + double value= args[0]->val_real(),a,b; + if ((null_value=args[0]->null_value)) + return 0; /* purecov: inspected */ + a= args[1]->val_real(); + b= args[2]->val_real(); + 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); } @@ -4119,7 +4107,7 @@ void Item_func_in::fix_length_and_dec() Item *date_arg= 0; uint found_types= 0; uint type_cnt= 0, i; - m_compare_type= STRING_RESULT; + m_comparator.set_handler(&type_handler_varchar); left_cmp_type= args[0]->cmp_type(); if (!(found_types= collect_cmp_types(args, arg_count, true))) return; @@ -4137,7 +4125,7 @@ void Item_func_in::fix_length_and_dec() if (found_types & (1U << i)) { (type_cnt)++; - m_compare_type= (Item_result) i; + m_comparator.set_handler_by_cmp_type((Item_result) i); } } @@ -4161,7 +4149,7 @@ void Item_func_in::fix_length_and_dec() 4. Neither left expression nor contain any NULL value */ - if (m_compare_type == ROW_RESULT && + if (m_comparator.cmp_type() == ROW_RESULT && ((!is_top_level_item() || negated) && // 3 (list_contains_null() || args[0]->maybe_null))) // 4 bisection_possible= false; @@ -4169,12 +4157,12 @@ void Item_func_in::fix_length_and_dec() if (type_cnt == 1) { - if (m_compare_type == STRING_RESULT && + if (m_comparator.cmp_type() == STRING_RESULT && agg_arg_charsets_for_comparison(cmp_collation, args, arg_count)) return; arg_types_compatible= TRUE; - if (m_compare_type == ROW_RESULT) + if (m_comparator.cmp_type() == ROW_RESULT) { uint cols= args[0]->cols(); cmp_item_row *cmp= 0; @@ -4221,7 +4209,8 @@ void Item_func_in::fix_length_and_dec() See the comment about the similar block in Item_bool_func2 */ if (args[0]->real_item()->type() == FIELD_ITEM && - !thd->lex->is_view_context_analysis() && m_compare_type != INT_RESULT) + !thd->lex->is_view_context_analysis() && + m_comparator.cmp_type() != INT_RESULT) { Item_field *field_item= (Item_field*) (args[0]->real_item()); if (field_item->field_type() == MYSQL_TYPE_LONGLONG || @@ -4234,10 +4223,10 @@ void Item_func_in::fix_length_and_dec() all_converted= FALSE; } if (all_converted) - m_compare_type= INT_RESULT; + m_comparator.set_handler(&type_handler_longlong); } } - switch (m_compare_type) { + switch (m_comparator.cmp_type()) { case STRING_RESULT: array=new (thd->mem_root) in_string(thd, arg_count - 1, (qsort2_cmp) srtcmp_in, diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index ae685459a7f..316b9336ac6 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -834,10 +834,10 @@ class Item_func_opt_neg :public Item_bool_func { protected: /* - The result type that will be used for comparison. - cmp_type() of all arguments are collected to here. + The data type handler that will be used for comparison. + Data type handlers of all arguments are mixed to here. */ - Item_result m_compare_type; + Type_handler_hybrid_field_type m_comparator; /* The collation that will be used for comparison in case when m_compare_type is STRING_RESULT. @@ -872,11 +872,13 @@ protected: Field *field, Item *value); public: String value0,value1,value2; - /* TRUE <=> arguments will be compared as dates. */ - Item *compare_as_dates; Item_func_between(THD *thd, Item *a, Item *b, Item *c): - Item_func_opt_neg(thd, a, b, c), compare_as_dates(FALSE) { } - longlong val_int(); + Item_func_opt_neg(thd, a, b, c) { } + longlong val_int() + { + DBUG_ASSERT(fixed); + return m_comparator.type_handler()->Item_func_between_val_int(this); + } enum Functype functype() const { return BETWEEN; } const char *func_name() const { return "between"; } enum precedence precedence() const { return BETWEEN_PRECEDENCE; } @@ -893,13 +895,19 @@ public: { Item_args::propagate_equal_fields(thd, Context(ANY_SUBST, - m_compare_type, + m_comparator.cmp_type(), compare_collation()), cond); return this; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy(thd, mem_root, this); } + + longlong val_int_cmp_string(); + longlong val_int_cmp_temporal(); + longlong val_int_cmp_int(); + longlong val_int_cmp_real(); + longlong val_int_cmp_decimal(); }; @@ -1664,7 +1672,7 @@ public: will be replaced to a zero-filled Item_string. Such a change would require rebuilding of cmp_items. */ - Context cmpctx(ANY_SUBST, m_compare_type, + Context cmpctx(ANY_SUBST, m_comparator.cmp_type(), Item_func_in::compare_collation()); for (uint i= 0; i < arg_count; i++) { diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 00d4da5b268..9538f020a19 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -23,7 +23,6 @@ static Type_handler_tiny type_handler_tiny; static Type_handler_short type_handler_short; static Type_handler_long type_handler_long; -static Type_handler_longlong type_handler_longlong; static Type_handler_int24 type_handler_int24; static Type_handler_year type_handler_year; static Type_handler_bit type_handler_bit; @@ -38,7 +37,6 @@ static Type_handler_datetime2 type_handler_datetime2; static Type_handler_timestamp type_handler_timestamp; static Type_handler_timestamp2 type_handler_timestamp2; static Type_handler_olddecimal type_handler_olddecimal; -static Type_handler_newdecimal type_handler_newdecimal; static Type_handler_string type_handler_string; static Type_handler_tiny_blob type_handler_tiny_blob; static Type_handler_medium_blob type_handler_medium_blob; @@ -54,6 +52,8 @@ static Type_handler_set type_handler_set; Type_handler_null type_handler_null; Type_handler_row type_handler_row; Type_handler_varchar type_handler_varchar; +Type_handler_longlong type_handler_longlong; +Type_handler_newdecimal type_handler_newdecimal; /** @@ -123,6 +123,55 @@ Type_handler_hybrid_field_type::Type_handler_hybrid_field_type() } +/* + Collect built-in data type handlers for comparison. + This method is very similar to item_cmp_type() defined in item.cc. + Now they coexist. Later item_cmp_type() will be removed. + In addition to item_cmp_type(), this method correctly aggregates + TIME with DATETIME/TIMESTAMP/DATE, so no additional find_date_time_item() + is needed after this call. +*/ +void +Type_handler_hybrid_field_type::aggregate_for_comparison(const Type_handler *h) +{ + Item_result a= cmp_type(); + Item_result b= h->cmp_type(); + if (a == STRING_RESULT && b == STRING_RESULT) + m_type_handler= &type_handler_long_blob; + else if (a == INT_RESULT && b == INT_RESULT) + m_type_handler= &type_handler_longlong; + else if (a == ROW_RESULT || b == ROW_RESULT) + m_type_handler= &type_handler_row; + else if (a == TIME_RESULT || b == TIME_RESULT) + { + if ((a == TIME_RESULT) + (b == TIME_RESULT) == 1) + { + /* + We're here if there's only one temporal data type: + either m_type_handler or h. + */ + if (b == TIME_RESULT) + m_type_handler= h; // Temporal types bit non-temporal types + } + else + { + /* + We're here if both m_type_handler and h are temporal data types. + */ + if (field_type() != MYSQL_TYPE_TIME || h->field_type() != MYSQL_TYPE_TIME) + m_type_handler= &type_handler_datetime; // DATETIME bits TIME + } + } + else if ((a == INT_RESULT || a == DECIMAL_RESULT) && + (b == INT_RESULT || b == DECIMAL_RESULT)) + { + m_type_handler= &type_handler_newdecimal; + } + else + m_type_handler= &type_handler_double; +} + + const Type_handler * Type_handler::get_handler_by_field_type(enum_field_types type) { @@ -1141,3 +1190,43 @@ Type_handler_string_result::Item_func_hybrid_field_type_get_date( } /***************************************************************************/ + +longlong Type_handler_row:: + Item_func_between_val_int(Item_func_between *func) const +{ + DBUG_ASSERT(0); + func->null_value= true; + return 0; +} + +longlong Type_handler_string_result:: + Item_func_between_val_int(Item_func_between *func) const +{ + return func->val_int_cmp_string(); +} + +longlong Type_handler_temporal_result:: + Item_func_between_val_int(Item_func_between *func) const +{ + return func->val_int_cmp_temporal(); +} + +longlong Type_handler_int_result:: + Item_func_between_val_int(Item_func_between *func) const +{ + return func->val_int_cmp_int(); +} + +longlong Type_handler_real_result:: + Item_func_between_val_int(Item_func_between *func) const +{ + return func->val_int_cmp_real(); +} + +longlong Type_handler_decimal_result:: + Item_func_between_val_int(Item_func_between *func) const +{ + return func->val_int_cmp_decimal(); +} + +/***************************************************************************/ diff --git a/sql/sql_type.h b/sql/sql_type.h index ab04a4dd211..9086e60dc0f 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -29,6 +29,7 @@ class Item_cache; class Item_sum_hybrid; class Item_func_hex; class Item_func_hybrid_field_type; +class Item_func_between; class Type_std_attributes; class Sort_param; class Arg_comparator; @@ -314,6 +315,8 @@ public: MYSQL_TIME *, ulonglong fuzzydate) const= 0; + virtual longlong + Item_func_between_val_int(Item_func_between *func) const= 0; }; @@ -410,6 +413,7 @@ public: return true; } + longlong Item_func_between_val_int(Item_func_between *func) const; }; @@ -457,6 +461,7 @@ public: bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *, MYSQL_TIME *, ulonglong fuzzydate) const; + longlong Item_func_between_val_int(Item_func_between *func) const; }; @@ -489,6 +494,7 @@ public: bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *, MYSQL_TIME *, ulonglong fuzzydate) const; + longlong Item_func_between_val_int(Item_func_between *func) const; }; @@ -521,6 +527,7 @@ public: bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *, MYSQL_TIME *, ulonglong fuzzydate) const; + longlong Item_func_between_val_int(Item_func_between *func) const; }; @@ -551,6 +558,7 @@ public: bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *, MYSQL_TIME *, ulonglong fuzzydate) const; + longlong Item_func_between_val_int(Item_func_between *func) const; }; @@ -585,6 +593,7 @@ public: bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *, MYSQL_TIME *, ulonglong fuzzydate) const; + longlong Item_func_between_val_int(Item_func_between *func) const; }; @@ -960,6 +969,10 @@ public: { return (m_type_handler= Type_handler::get_handler_by_result_type(type)); } + const Type_handler *set_handler_by_cmp_type(Item_result type) + { + return (m_type_handler= Type_handler::get_handler_by_cmp_type(type)); + } const Type_handler *set_handler_by_result_type(Item_result type, uint max_octet_length, CHARSET_INFO *cs) @@ -977,6 +990,8 @@ public: { return (m_type_handler= Type_handler::get_handler_by_real_type(type)); } + void aggregate_for_comparison(const Type_handler *other); + bool aggregate_for_comparison(Item **items, uint nitems); }; @@ -997,5 +1012,7 @@ public: extern Type_handler_row type_handler_row; extern Type_handler_null type_handler_null; extern Type_handler_varchar type_handler_varchar; +extern Type_handler_longlong type_handler_longlong; +extern Type_handler_newdecimal type_handler_newdecimal; #endif /* SQL_TYPE_H_INCLUDED */