diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 9891d1179129b..381db9e4975b2 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -522,78 +522,6 @@ void Item_bool_rowready_func2::fix_length_and_dec() } -int Arg_comparator::set_compare_func(Item_func_or_sum *item, Item_result type) -{ - owner= item; - func= comparator_matrix[type] - [is_owner_equal_func()]; - - switch (type) { - case TIME_RESULT: - m_compare_collation= &my_charset_numeric; - break; - case ROW_RESULT: - { - uint n= (*a)->cols(); - if (n != (*b)->cols()) - { - my_error(ER_OPERAND_COLUMNS, MYF(0), n); - comparators= 0; - return 1; - } - if (!(comparators= new Arg_comparator[n])) - return 1; - for (uint i=0; i < n; i++) - { - if ((*a)->element_index(i)->cols() != (*b)->element_index(i)->cols()) - { - my_error(ER_OPERAND_COLUMNS, MYF(0), (*a)->element_index(i)->cols()); - return 1; - } - if (comparators[i].set_cmp_func(owner, (*a)->addr(i), - (*b)->addr(i), set_null)) - return 1; - } - break; - } - case INT_RESULT: - { - if (func == &Arg_comparator::compare_int_signed) - { - if ((*a)->unsigned_flag) - func= (((*b)->unsigned_flag)? - &Arg_comparator::compare_int_unsigned : - &Arg_comparator::compare_int_unsigned_signed); - else if ((*b)->unsigned_flag) - func= &Arg_comparator::compare_int_signed_unsigned; - } - else if (func== &Arg_comparator::compare_e_int) - { - if ((*a)->unsigned_flag ^ (*b)->unsigned_flag) - func= &Arg_comparator::compare_e_int_diff_signedness; - } - break; - } - case STRING_RESULT: - case DECIMAL_RESULT: - break; - case REAL_RESULT: - { - if ((*a)->decimals < NOT_FIXED_DEC && (*b)->decimals < NOT_FIXED_DEC) - { - precision= 5 / log_10[MY_MAX((*a)->decimals, (*b)->decimals) + 1]; - if (func == &Arg_comparator::compare_real) - func= &Arg_comparator::compare_real_fixed; - else if (func == &Arg_comparator::compare_e_real) - func= &Arg_comparator::compare_e_real_fixed; - } - break; - } - } - return 0; -} - - /** Prepare the comparator (set the comparison function) for comparing items *a1 and *a2 in the context of 'type'. @@ -615,9 +543,51 @@ int Arg_comparator::set_cmp_func(Item_func_or_sum *owner_arg, set_null= set_null && owner_arg; a= a1; b= a2; - m_compare_type= item_cmp_type(*a1, *a2); + m_compare_handler= Type_handler::get_handler_by_cmp_type(item_cmp_type(*a1, + *a2)); + return m_compare_handler->set_comparator_func(this); +} - if (m_compare_type == STRING_RESULT && + +bool Arg_comparator::set_cmp_func_for_row_arguments() +{ + uint n= (*a)->cols(); + if (n != (*b)->cols()) + { + my_error(ER_OPERAND_COLUMNS, MYF(0), n); + comparators= 0; + return true; + } + if (!(comparators= new Arg_comparator[n])) + return true; + for (uint i=0; i < n; i++) + { + if ((*a)->element_index(i)->cols() != (*b)->element_index(i)->cols()) + { + my_error(ER_OPERAND_COLUMNS, MYF(0), (*a)->element_index(i)->cols()); + return true; + } + if (comparators[i].set_cmp_func(owner, (*a)->addr(i), + (*b)->addr(i), set_null)) + return true; + } + return false; +} + + +bool Arg_comparator::set_cmp_func_row() +{ + func= is_owner_equal_func() ? &Arg_comparator::compare_e_row : + &Arg_comparator::compare_row; + return set_cmp_func_for_row_arguments(); +} + + +bool Arg_comparator::set_cmp_func_string() +{ + func= is_owner_equal_func() ? &Arg_comparator::compare_e_string : + &Arg_comparator::compare_string; + if (compare_type() == STRING_RESULT && (*a)->result_type() == STRING_RESULT && (*b)->result_type() == STRING_RESULT) { @@ -626,37 +596,87 @@ int Arg_comparator::set_cmp_func(Item_func_or_sum *owner_arg, generated item, like in natural join */ if (owner->agg_arg_charsets_for_comparison(&m_compare_collation, a, b)) - return 1; + return true; } + a= cache_converted_constant(thd, a, &a_cache, compare_type()); + b= cache_converted_constant(thd, b, &b_cache, compare_type()); + return false; +} + - if (m_compare_type == TIME_RESULT) +bool Arg_comparator::set_cmp_func_temporal() +{ + enum_field_types f_type= a[0]->field_type_for_temporal_comparison(b[0]); + m_compare_collation= &my_charset_numeric; + if (f_type == MYSQL_TYPE_TIME) { - enum_field_types f_type= a[0]->field_type_for_temporal_comparison(b[0]); - if (f_type == MYSQL_TYPE_TIME) - { - func= is_owner_equal_func() ? &Arg_comparator::compare_e_time : - &Arg_comparator::compare_time; - } - else - { - func= is_owner_equal_func() ? &Arg_comparator::compare_e_datetime : - &Arg_comparator::compare_datetime; - } - return 0; + func= is_owner_equal_func() ? &Arg_comparator::compare_e_time : + &Arg_comparator::compare_time; } + else + { + func= is_owner_equal_func() ? &Arg_comparator::compare_e_datetime : + &Arg_comparator::compare_datetime; + } + return false; +} + - if (m_compare_type == INT_RESULT && - (*a)->field_type() == MYSQL_TYPE_YEAR && +bool Arg_comparator::set_cmp_func_int() +{ + func= is_owner_equal_func() ? &Arg_comparator::compare_e_int : + &Arg_comparator::compare_int_signed; + if ((*a)->field_type() == MYSQL_TYPE_YEAR && (*b)->field_type() == MYSQL_TYPE_YEAR) { - m_compare_type= TIME_RESULT; func= is_owner_equal_func() ? &Arg_comparator::compare_e_datetime : &Arg_comparator::compare_datetime; } + else if (func == &Arg_comparator::compare_int_signed) + { + if ((*a)->unsigned_flag) + func= (((*b)->unsigned_flag)? + &Arg_comparator::compare_int_unsigned : + &Arg_comparator::compare_int_unsigned_signed); + else if ((*b)->unsigned_flag) + func= &Arg_comparator::compare_int_signed_unsigned; + } + else if (func== &Arg_comparator::compare_e_int) + { + if ((*a)->unsigned_flag ^ (*b)->unsigned_flag) + func= &Arg_comparator::compare_e_int_diff_signedness; + } + a= cache_converted_constant(thd, a, &a_cache, compare_type()); + b= cache_converted_constant(thd, b, &b_cache, compare_type()); + return false; +} + - a= cache_converted_constant(thd, a, &a_cache, m_compare_type); - b= cache_converted_constant(thd, b, &b_cache, m_compare_type); - return set_compare_func(owner_arg, m_compare_type); +bool Arg_comparator::set_cmp_func_real() +{ + func= is_owner_equal_func() ? &Arg_comparator::compare_e_real : + &Arg_comparator::compare_real; + if ((*a)->decimals < NOT_FIXED_DEC && (*b)->decimals < NOT_FIXED_DEC) + { + precision= 5 / log_10[MY_MAX((*a)->decimals, (*b)->decimals) + 1]; + if (func == &Arg_comparator::compare_real) + func= &Arg_comparator::compare_real_fixed; + else if (func == &Arg_comparator::compare_e_real) + func= &Arg_comparator::compare_e_real_fixed; + } + a= cache_converted_constant(thd, a, &a_cache, compare_type()); + b= cache_converted_constant(thd, b, &b_cache, compare_type()); + return false; +} + + +bool Arg_comparator::set_cmp_func_decimal() +{ + func= is_owner_equal_func() ? &Arg_comparator::compare_e_decimal : + &Arg_comparator::compare_decimal; + a= cache_converted_constant(thd, a, &a_cache, compare_type()); + b= cache_converted_constant(thd, b, &b_cache, compare_type()); + return false; } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 69b95c669a31e..49d26ce6f0abd 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -47,7 +47,7 @@ typedef int (*Item_field_cmpfunc)(Item *f1, Item *f2, void *arg); class Arg_comparator: public Sql_alloc { Item **a, **b; - Item_result m_compare_type; + const Type_handler *m_compare_handler; CHARSET_INFO *m_compare_collation; arg_cmp_func func; Item_func_or_sum *owner; @@ -58,7 +58,7 @@ 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_func_or_sum *owner, Item_result type); + int set_cmp_func(Item_func_or_sum *owner_arg, Item **a1, Item **a2); int compare_temporal(enum_field_types type); @@ -68,17 +68,26 @@ class Arg_comparator: public Sql_alloc /* Allow owner function to use string buffers. */ String value1, value2; - Arg_comparator(): m_compare_type(STRING_RESULT), + Arg_comparator(): + m_compare_handler(&type_handler_null), m_compare_collation(&my_charset_bin), set_null(TRUE), comparators(0), thd(0), a_cache(0), b_cache(0) {}; Arg_comparator(Item **a1, Item **a2): a(a1), b(a2), - m_compare_type(STRING_RESULT), + m_compare_handler(&type_handler_null), m_compare_collation(&my_charset_bin), set_null(TRUE), comparators(0), thd(0), a_cache(0), b_cache(0) {}; public: + bool set_cmp_func_for_row_arguments(); + bool set_cmp_func_row(); + bool set_cmp_func_string(); + bool set_cmp_func_temporal(); + bool set_cmp_func_int(); + bool set_cmp_func_real(); + bool set_cmp_func_decimal(); + inline int set_cmp_func(Item_func_or_sum *owner_arg, Item **a1, Item **a2, bool set_null_arg) { @@ -110,13 +119,13 @@ class Arg_comparator: public Sql_alloc Item** cache_converted_constant(THD *thd, Item **value, Item **cache, Item_result type); - static arg_cmp_func comparator_matrix [6][2]; inline bool is_owner_equal_func() { return (owner->type() == Item::FUNC_ITEM && ((Item_func*)owner)->functype() == Item_func::EQUAL_FUNC); } - Item_result compare_type() const { return m_compare_type; } + const Type_handler *compare_type_handler() const { return m_compare_handler; } + Item_result compare_type() const { return m_compare_handler->cmp_type(); } CHARSET_INFO *compare_collation() const { return m_compare_collation; } Arg_comparator *subcomparators() const { return comparators; } void cleanup() diff --git a/sql/item_row.h b/sql/item_row.h index bbfebb56010a8..f8858738b7829 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -56,6 +56,7 @@ class Item_row: public Item, {} enum Type type() const { return ROW_ITEM; }; + const Type_handler *type_handler() const { return &type_handler_row; } void illegal_method_call(const char *); bool is_null() { return null_value; } void make_field(THD *thd, Send_field *) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index e7fb7b7e0c9b2..845d2b6d1ad7e 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -309,14 +309,6 @@ static my_bool opt_autocommit; ///< for --autocommit command-line option */ static my_bool opt_verbose= 0; -arg_cmp_func Arg_comparator::comparator_matrix[6][2] = -{{&Arg_comparator::compare_string, &Arg_comparator::compare_e_string}, - {&Arg_comparator::compare_real, &Arg_comparator::compare_e_real}, - {&Arg_comparator::compare_int_signed, &Arg_comparator::compare_e_int}, - {&Arg_comparator::compare_row, &Arg_comparator::compare_e_row}, - {&Arg_comparator::compare_decimal, &Arg_comparator::compare_e_decimal}, - {&Arg_comparator::compare_datetime, &Arg_comparator::compare_e_datetime}}; - /* Timer info to be used by the SQL layer */ MY_TIMER_INFO sys_timer_info; diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 42aa37a19a7b3..e78a3a60f5127 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -39,7 +39,6 @@ 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_null type_handler_null; static Type_handler_string type_handler_string; static Type_handler_varchar type_handler_varchar; static Type_handler_tiny_blob type_handler_tiny_blob; @@ -53,6 +52,10 @@ static Type_handler_enum type_handler_enum; static Type_handler_set type_handler_set; +Type_handler_null type_handler_null; +Type_handler_row type_handler_row; + + /** This method is used by: - Item_user_var_as_out_param::field_type() @@ -99,18 +102,17 @@ Type_handler_string_result::type_handler_adjusted_to_max_octet_length( const Type_handler * -Type_handler_hybrid_field_type::get_handler_by_result_type(Item_result type) - const +Type_handler::get_handler_by_cmp_type(Item_result type) { switch (type) { case REAL_RESULT: return &type_handler_double; case INT_RESULT: return &type_handler_longlong; case DECIMAL_RESULT: return &type_handler_newdecimal; case STRING_RESULT: return &type_handler_long_blob; - case TIME_RESULT: - case ROW_RESULT: - DBUG_ASSERT(0); + case TIME_RESULT: return &type_handler_datetime; + case ROW_RESULT: return &type_handler_row; } + DBUG_ASSERT(0); return &type_handler_string; } @@ -684,3 +686,39 @@ int Type_handler_int_result::Item_save_in_field(Item *item, Field *field, { return item->save_int_in_field(field, no_conversions); } + + +/***********************************************************************/ + +bool Type_handler_row::set_comparator_func(Arg_comparator *cmp) const +{ + return cmp->set_cmp_func_row(); +} + +bool Type_handler_int_result::set_comparator_func(Arg_comparator *cmp) const +{ + return cmp->set_cmp_func_int(); +} + +bool Type_handler_real_result::set_comparator_func(Arg_comparator *cmp) const +{ + return cmp->set_cmp_func_real(); +} + +bool Type_handler_decimal_result::set_comparator_func(Arg_comparator *cmp) const +{ + return cmp->set_cmp_func_decimal(); +} + +bool Type_handler_string_result::set_comparator_func(Arg_comparator *cmp) const +{ + return cmp->set_cmp_func_string(); +} + +bool Type_handler_temporal_result::set_comparator_func(Arg_comparator *cmp) const +{ + return cmp->set_cmp_func_temporal(); +} + + +/*************************************************************************/ diff --git a/sql/sql_type.h b/sql/sql_type.h index 0147ee5639b7b..f34be07bde02a 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -27,6 +27,7 @@ class Field; class Item; class Type_std_attributes; class Sort_param; +class Arg_comparator; struct TABLE; struct SORT_FIELD_ATTR; @@ -221,6 +222,16 @@ class Type_handler static const Type_handler *string_type_handler(uint max_octet_length); static const Type_handler *get_handler_by_field_type(enum_field_types type); static const Type_handler *get_handler_by_real_type(enum_field_types type); + static const Type_handler *get_handler_by_cmp_type(Item_result type); + static const Type_handler *get_handler_by_result_type(Item_result type) + { + /* + As result_type() returns STRING_RESULT for temporal Items, + type should never be equal to TIME_RESULT here. + */ + DBUG_ASSERT(type != TIME_RESULT); + return get_handler_by_cmp_type(type); + } virtual enum_field_types field_type() const= 0; virtual enum_field_types real_field_type() const { return field_type(); } virtual Item_result result_type() const= 0; @@ -275,6 +286,59 @@ class Type_handler virtual int Item_save_in_field(Item *item, Field *field, bool no_conversions) const= 0; + virtual bool set_comparator_func(Arg_comparator *cmp) const= 0; +}; + + +/* + Special handler for ROW +*/ +class Type_handler_row: public Type_handler +{ +public: + virtual ~Type_handler_row() {} + enum_field_types field_type() const + { + DBUG_ASSERT(0); + return MYSQL_TYPE_NULL; + }; + Item_result result_type() const + { + return ROW_RESULT; + } + Item_result cmp_type() const + { + return ROW_RESULT; + } + Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const + { + DBUG_ASSERT(0); + return NULL; + } + Field *make_conversion_table_field(TABLE *TABLE, + uint metadata, + const Field *target) const + { + DBUG_ASSERT(0); + return NULL; + } + void make_sort_key(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const + { + DBUG_ASSERT(0); + } + void sortlength(THD *thd, const Type_std_attributes *item, + SORT_FIELD_ATTR *attr) const + { + DBUG_ASSERT(0); + } + int Item_save_in_field(Item *item, Field *field, bool no_conversions) const + { + DBUG_ASSERT(0); + return 1; + } + bool set_comparator_func(Arg_comparator *cmp) const; }; @@ -292,6 +356,7 @@ class Type_handler_real_result: public Type_handler const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; + bool set_comparator_func(Arg_comparator *cmp) const; }; @@ -308,6 +373,7 @@ class Type_handler_decimal_result: public Type_handler const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; + bool set_comparator_func(Arg_comparator *cmp) const; }; @@ -324,6 +390,7 @@ class Type_handler_int_result: public Type_handler const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; + bool set_comparator_func(Arg_comparator *cmp) const; }; @@ -338,6 +405,7 @@ class Type_handler_temporal_result: public Type_handler void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; + bool set_comparator_func(Arg_comparator *cmp) const; }; @@ -356,6 +424,7 @@ class Type_handler_string_result: public Type_handler const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; + bool set_comparator_func(Arg_comparator *cmp) const; }; @@ -704,7 +773,6 @@ class Type_handler_set: public Type_handler_string_result class Type_handler_hybrid_field_type { const Type_handler *m_type_handler; - const Type_handler *get_handler_by_result_type(Item_result type) const; public: Type_handler_hybrid_field_type(); Type_handler_hybrid_field_type(const Type_handler *handler) @@ -730,13 +798,13 @@ class Type_handler_hybrid_field_type } const Type_handler *set_handler_by_result_type(Item_result type) { - return (m_type_handler= get_handler_by_result_type(type)); + return (m_type_handler= Type_handler::get_handler_by_result_type(type)); } const Type_handler *set_handler_by_result_type(Item_result type, uint max_octet_length, CHARSET_INFO *cs) { - m_type_handler= get_handler_by_result_type(type); + m_type_handler= Type_handler::get_handler_by_result_type(type); return m_type_handler= m_type_handler->type_handler_adjusted_to_max_octet_length(max_octet_length, cs); @@ -766,4 +834,7 @@ class Type_handler_hybrid_real_field_type: }; +extern Type_handler_row type_handler_row; +extern Type_handler_null type_handler_null; + #endif /* SQL_TYPE_H_INCLUDED */