Commit de1a48e7 authored by Alexander Barkov's avatar Alexander Barkov

A clean-up for a few recent result set metadata related bug fixes:

- MDEV-8875 Wrong metadata for MAX(CAST(time_column AS DATETIME))
- MDEV-8873 Wrong field type or metadata for LEAST(int_column,string_column)
- MDEV-8912 Wrong metadata or type for @c:=string_or_blob_field

Adding Item_hybrid_func as a common parent for Item_func_hybrid_field_type,
Item_func_min_max, Item_func_user_var. This removes some duplicate code.
parent 87777249
...@@ -383,33 +383,65 @@ public: ...@@ -383,33 +383,65 @@ public:
}; };
class Item_func_hybrid_field_type: public Item_func, /**
public Type_handler_hybrid_field_type Functions whose returned field type is determined at fix_fields() time.
*/
class Item_hybrid_func: public Item_func,
public Type_handler_hybrid_field_type
{
public:
Item_hybrid_func(THD *thd): Item_func(thd) { }
Item_hybrid_func(THD *thd, Item *a): Item_func(thd, a) { }
Item_hybrid_func(THD *thd, Item *a, Item *b): Item_func(thd, a, b) { }
Item_hybrid_func(THD *thd, Item *a, Item *b, Item *c):
Item_func(thd, a, b, c) { }
Item_hybrid_func(THD *thd, List<Item> &list): Item_func(thd, list) { }
Item_hybrid_func(THD *thd, Item_hybrid_func *item)
:Item_func(thd, item), Type_handler_hybrid_field_type(item) { }
enum_field_types field_type() const
{ return Type_handler_hybrid_field_type::field_type(); }
enum Item_result result_type () const
{ return Type_handler_hybrid_field_type::result_type(); }
enum Item_result cmp_type () const
{ return Type_handler_hybrid_field_type::cmp_type(); }
};
/**
Functions that at fix_fields() time determine the returned field type,
trying to preserve the exact data type of the arguments.
The descendants have to implement "native" value methods,
i.e. str_op(), date_op(), int_op(), real_op(), decimal_op().
fix_fields() chooses which of the above value methods will be
used during execution time, according to the returned field type.
For example, if fix_fields() determines that the returned value type
is MYSQL_TYPE_LONG, then:
- int_op() is chosen as the execution time native method.
- val_int() returns the result of int_op() as is.
- all other methods, i.e. val_real(), val_decimal(), val_str(), get_date(),
call int_op() first, then convert the result to the requested data type.
*/
class Item_func_hybrid_field_type: public Item_hybrid_func
{ {
public: public:
Item_func_hybrid_field_type(THD *thd): Item_func_hybrid_field_type(THD *thd):
Item_func(thd) Item_hybrid_func(thd)
{ collation.set_numeric(); } { collation.set_numeric(); }
Item_func_hybrid_field_type(THD *thd, Item *a): Item_func_hybrid_field_type(THD *thd, Item *a):
Item_func(thd, a) Item_hybrid_func(thd, a)
{ collation.set_numeric(); } { collation.set_numeric(); }
Item_func_hybrid_field_type(THD *thd, Item *a, Item *b): Item_func_hybrid_field_type(THD *thd, Item *a, Item *b):
Item_func(thd, a, b) Item_hybrid_func(thd, a, b)
{ collation.set_numeric(); } { collation.set_numeric(); }
Item_func_hybrid_field_type(THD *thd, Item *a, Item *b, Item *c): Item_func_hybrid_field_type(THD *thd, Item *a, Item *b, Item *c):
Item_func(thd, a, b, c) Item_hybrid_func(thd, a, b, c)
{ collation.set_numeric(); } { collation.set_numeric(); }
Item_func_hybrid_field_type(THD *thd, List<Item> &list): Item_func_hybrid_field_type(THD *thd, List<Item> &list):
Item_func(thd, list) Item_hybrid_func(thd, list)
{ collation.set_numeric(); } { collation.set_numeric(); }
enum_field_types field_type() const
{ return Type_handler_hybrid_field_type::field_type(); }
enum Item_result result_type () const
{ return Type_handler_hybrid_field_type::result_type(); }
enum Item_result cmp_type () const
{ return Type_handler_hybrid_field_type::cmp_type(); }
double val_real(); double val_real();
longlong val_int(); longlong val_int();
my_decimal *val_decimal(my_decimal *); my_decimal *val_decimal(my_decimal *);
...@@ -1007,15 +1039,14 @@ public: ...@@ -1007,15 +1039,14 @@ public:
than strings. than strings.
Perhaps this should be changed eventually (see MDEV-5893). Perhaps this should be changed eventually (see MDEV-5893).
*/ */
class Item_func_min_max :public Item_func, class Item_func_min_max :public Item_hybrid_func
public Type_handler_hybrid_field_type
{ {
String tmp_value; String tmp_value;
int cmp_sign; int cmp_sign;
THD *thd; THD *thd;
public: public:
Item_func_min_max(THD *thd, List<Item> &list, int cmp_sign_arg): Item_func_min_max(THD *thd, List<Item> &list, int cmp_sign_arg):
Item_func(thd, list), cmp_sign(cmp_sign_arg) Item_hybrid_func(thd, list), cmp_sign(cmp_sign_arg)
{} {}
double val_real(); double val_real();
longlong val_int(); longlong val_int();
...@@ -1023,12 +1054,6 @@ public: ...@@ -1023,12 +1054,6 @@ public:
my_decimal *val_decimal(my_decimal *); my_decimal *val_decimal(my_decimal *);
bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
void fix_length_and_dec(); void fix_length_and_dec();
enum Item_result cmp_type() const
{ return Type_handler_hybrid_field_type::cmp_type(); }
enum Item_result result_type() const
{ return Type_handler_hybrid_field_type::result_type(); }
enum_field_types field_type() const
{ return Type_handler_hybrid_field_type::field_type(); }
}; };
class Item_func_min :public Item_func_min_max class Item_func_min :public Item_func_min_max
...@@ -1628,29 +1653,19 @@ class user_var_entry; ...@@ -1628,29 +1653,19 @@ class user_var_entry;
/** /**
A class to set and get user variables A class to set and get user variables
*/ */
class Item_func_user_var :public Item_func, class Item_func_user_var :public Item_hybrid_func
public Type_handler_hybrid_field_type
{ {
protected: protected:
user_var_entry *m_var_entry; user_var_entry *m_var_entry;
public: public:
LEX_STRING name; // keep it public LEX_STRING name; // keep it public
Item_func_user_var(THD *thd, LEX_STRING a) Item_func_user_var(THD *thd, LEX_STRING a)
:Item_func(thd), m_var_entry(NULL), name(a) { } :Item_hybrid_func(thd), m_var_entry(NULL), name(a) { }
Item_func_user_var(THD *thd, LEX_STRING a, Item *b) Item_func_user_var(THD *thd, LEX_STRING a, Item *b)
:Item_func(thd, b), m_var_entry(NULL), name(a) { } :Item_hybrid_func(thd, b), m_var_entry(NULL), name(a) { }
Item_func_user_var(THD *thd, Item_func_user_var *item) Item_func_user_var(THD *thd, Item_func_user_var *item)
:Item_func(thd, item), :Item_hybrid_func(thd, item),
m_var_entry(item->m_var_entry), name(item->name) m_var_entry(item->m_var_entry), name(item->name) { }
{
set_handler_by_result_type(item->result_type());
}
enum Item_result cmp_type() const
{ return Type_handler_hybrid_field_type::cmp_type(); }
enum Item_result result_type() const
{ return Type_handler_hybrid_field_type::result_type(); }
enum_field_types field_type() const
{ return Type_handler_hybrid_field_type::field_type(); }
bool check_vcol_func_processor(uchar *int_arg) { return true; } bool check_vcol_func_processor(uchar *int_arg) { return true; }
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment