MDEV-11365 Split the data type and attribute related code in Item_sum_hybrid::fix_fields into Type_handler::Item_sum_hybrid_fix_length_and_dec()
This patch: - Implements the task according to the description - Adds a new class Type_handler_numeric as a common parent for Type_handler_real_result, Type_handler_int_result, Type_handler_decimal_result, to share the common code between numeric data type handlers. - Removes the dedundant call for collation.set(item->collation) in Item_sum_hybrid::setup_hybrid(), because setup_hybrid() is called either after fix_length_and_dec() or afte ther constructor Item_sum_hybrid(THD *thd, Item_sum_hybrid *item), so the collation is already properly set in all cases.
This commit is contained in:
parent
749bbb3d7b
commit
9185f8d4a7
@ -1126,36 +1126,11 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
|
||||
if ((!item->fixed && item->fix_fields(thd, args)) ||
|
||||
(item= args[0])->check_cols(1))
|
||||
return TRUE;
|
||||
Type_std_attributes::set(args[0]);
|
||||
with_subselect= args[0]->with_subselect;
|
||||
|
||||
Item *item2= item->real_item();
|
||||
if (item2->type() == Item::FIELD_ITEM)
|
||||
set_handler_by_field_type(((Item_field*) item2)->field->type());
|
||||
else if (item->cmp_type() == TIME_RESULT)
|
||||
set_handler_by_field_type(item2->field_type());
|
||||
else
|
||||
set_handler_by_result_type(item2->result_type(),
|
||||
max_length, collation.collation);
|
||||
|
||||
switch (Item_sum_hybrid::result_type()) {
|
||||
case INT_RESULT:
|
||||
case DECIMAL_RESULT:
|
||||
case STRING_RESULT:
|
||||
break;
|
||||
case REAL_RESULT:
|
||||
max_length= float_length(decimals);
|
||||
break;
|
||||
case ROW_RESULT:
|
||||
case TIME_RESULT:
|
||||
DBUG_ASSERT(0);
|
||||
};
|
||||
setup_hybrid(thd, args[0], NULL);
|
||||
/* MIN/MAX can return NULL for empty set indepedent of the used column */
|
||||
maybe_null= 1;
|
||||
result_field=0;
|
||||
null_value=1;
|
||||
fix_length_and_dec();
|
||||
setup_hybrid(thd, args[0], NULL);
|
||||
result_field=0;
|
||||
|
||||
if (check_sum_func(thd, ref))
|
||||
return TRUE;
|
||||
@ -1166,6 +1141,14 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
|
||||
}
|
||||
|
||||
|
||||
void Item_sum_hybrid::fix_length_and_dec()
|
||||
{
|
||||
DBUG_ASSERT(args[0]->field_type() == args[0]->real_item()->field_type());
|
||||
DBUG_ASSERT(args[0]->result_type() == args[0]->real_item()->result_type());
|
||||
(void) args[0]->type_handler()->Item_sum_hybrid_fix_length_and_dec(this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
MIN/MAX function setup.
|
||||
|
||||
@ -1201,7 +1184,6 @@ void Item_sum_hybrid::setup_hybrid(THD *thd, Item *item, Item *value_arg)
|
||||
cmp= new Arg_comparator();
|
||||
if (cmp)
|
||||
cmp->set_cmp_func(this, (Item**)&arg_cache, (Item**)&value, FALSE);
|
||||
collation.set(item->collation);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1006,6 +1006,7 @@ protected:
|
||||
cmp_sign(item->cmp_sign), was_values(item->was_values)
|
||||
{ }
|
||||
bool fix_fields(THD *, Item **);
|
||||
void fix_length_and_dec();
|
||||
void setup_hybrid(THD *thd, Item *item, Item *value_arg);
|
||||
void clear();
|
||||
double val_real();
|
||||
|
@ -761,3 +761,101 @@ Type_handler_temporal_result::Item_get_cache(THD *thd, const Item *item) const
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/**
|
||||
MAX/MIN for the traditional numeric types preserve the exact data type
|
||||
from Fields, but do not preserve the exact type from Items:
|
||||
MAX(float_field) -> FLOAT
|
||||
MAX(smallint_field) -> LONGLONG
|
||||
MAX(COALESCE(float_field)) -> DOUBLE
|
||||
MAX(COALESCE(smallint_field)) -> LONGLONG
|
||||
QQ: Items should probably be fixed to preserve the exact type.
|
||||
*/
|
||||
bool Type_handler_numeric::
|
||||
Item_sum_hybrid_fix_length_and_dec_numeric(Item_sum_hybrid *func,
|
||||
const Type_handler *handler)
|
||||
const
|
||||
{
|
||||
Item *item= func->arguments()[0];
|
||||
Item *item2= item->real_item();
|
||||
func->Type_std_attributes::set(item);
|
||||
/* MIN/MAX can return NULL for empty set indepedent of the used column */
|
||||
func->maybe_null= func->null_value= true;
|
||||
if (item2->type() == Item::FIELD_ITEM)
|
||||
func->set_handler_by_field_type(item2->field_type());
|
||||
else
|
||||
func->set_handler(handler);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Type_handler_int_result::
|
||||
Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
|
||||
{
|
||||
return Item_sum_hybrid_fix_length_and_dec_numeric(func,
|
||||
&type_handler_longlong);
|
||||
}
|
||||
|
||||
|
||||
bool Type_handler_real_result::
|
||||
Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
|
||||
{
|
||||
(void) Item_sum_hybrid_fix_length_and_dec_numeric(func,
|
||||
&type_handler_double);
|
||||
func->max_length= func->float_length(func->decimals);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Type_handler_decimal_result::
|
||||
Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
|
||||
{
|
||||
return Item_sum_hybrid_fix_length_and_dec_numeric(func,
|
||||
&type_handler_newdecimal);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
MAX(str_field) converts ENUM/SET to CHAR, and preserve all other types
|
||||
for Fields.
|
||||
QQ: This works differently from UNION, which preserve the exact data
|
||||
type for ENUM/SET if the joined ENUM/SET fields are equally defined.
|
||||
Perhaps should be fixed.
|
||||
MAX(str_item) chooses the best suitable string type.
|
||||
*/
|
||||
bool Type_handler_string_result::
|
||||
Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
|
||||
{
|
||||
Item *item= func->arguments()[0];
|
||||
Item *item2= item->real_item();
|
||||
func->Type_std_attributes::set(item);
|
||||
func->maybe_null= func->null_value= true;
|
||||
if (item2->type() == Item::FIELD_ITEM)
|
||||
{
|
||||
// Fields: convert ENUM/SET to CHAR, preserve the type otherwise.
|
||||
func->set_handler_by_field_type(item->field_type());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Items: choose VARCHAR/BLOB/MEDIUMBLOB/LONGBLOB, depending on length.
|
||||
func->set_handler(type_handler_varchar.
|
||||
type_handler_adjusted_to_max_octet_length(func->max_length,
|
||||
func->collation.collation));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Traditional temporal types always preserve the type of the argument.
|
||||
*/
|
||||
bool Type_handler_temporal_result::
|
||||
Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
|
||||
{
|
||||
Item *item= func->arguments()[0];
|
||||
func->Type_std_attributes::set(item);
|
||||
func->maybe_null= func->null_value= true;
|
||||
func->set_handler(item->type_handler());
|
||||
return false;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
@ -26,6 +26,7 @@
|
||||
class Field;
|
||||
class Item;
|
||||
class Item_cache;
|
||||
class Item_sum_hybrid;
|
||||
class Type_std_attributes;
|
||||
class Sort_param;
|
||||
class Arg_comparator;
|
||||
@ -289,6 +290,7 @@ public:
|
||||
bool no_conversions) const= 0;
|
||||
virtual Item_cache *Item_get_cache(THD *thd, const Item *item) const= 0;
|
||||
virtual bool set_comparator_func(Arg_comparator *cmp) const= 0;
|
||||
virtual bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *) const= 0;
|
||||
};
|
||||
|
||||
|
||||
@ -342,12 +344,31 @@ public:
|
||||
}
|
||||
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
|
||||
bool set_comparator_func(Arg_comparator *cmp) const;
|
||||
bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
|
||||
{
|
||||
DBUG_ASSERT(0);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
A common parent class for numeric data type handlers
|
||||
*/
|
||||
class Type_handler_numeric: public Type_handler
|
||||
{
|
||||
protected:
|
||||
bool Item_sum_hybrid_fix_length_and_dec_numeric(Item_sum_hybrid *func,
|
||||
const Type_handler *handler)
|
||||
const;
|
||||
public:
|
||||
virtual ~Type_handler_numeric() { }
|
||||
};
|
||||
|
||||
|
||||
/*** Abstract classes for every XXX_RESULT */
|
||||
|
||||
class Type_handler_real_result: public Type_handler
|
||||
class Type_handler_real_result: public Type_handler_numeric
|
||||
{
|
||||
public:
|
||||
Item_result result_type() const { return REAL_RESULT; }
|
||||
@ -361,10 +382,11 @@ public:
|
||||
int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
|
||||
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
|
||||
bool set_comparator_func(Arg_comparator *cmp) const;
|
||||
bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const;
|
||||
};
|
||||
|
||||
|
||||
class Type_handler_decimal_result: public Type_handler
|
||||
class Type_handler_decimal_result: public Type_handler_numeric
|
||||
{
|
||||
public:
|
||||
Item_result result_type() const { return DECIMAL_RESULT; }
|
||||
@ -379,10 +401,11 @@ public:
|
||||
int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
|
||||
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
|
||||
bool set_comparator_func(Arg_comparator *cmp) const;
|
||||
bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const;
|
||||
};
|
||||
|
||||
|
||||
class Type_handler_int_result: public Type_handler
|
||||
class Type_handler_int_result: public Type_handler_numeric
|
||||
{
|
||||
public:
|
||||
Item_result result_type() const { return INT_RESULT; }
|
||||
@ -397,6 +420,7 @@ public:
|
||||
int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
|
||||
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
|
||||
bool set_comparator_func(Arg_comparator *cmp) const;
|
||||
bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const;
|
||||
};
|
||||
|
||||
|
||||
@ -413,6 +437,7 @@ public:
|
||||
SORT_FIELD_ATTR *attr) const;
|
||||
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
|
||||
bool set_comparator_func(Arg_comparator *cmp) const;
|
||||
bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const;
|
||||
};
|
||||
|
||||
|
||||
@ -433,6 +458,7 @@ public:
|
||||
int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
|
||||
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
|
||||
bool set_comparator_func(Arg_comparator *cmp) const;
|
||||
bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const;
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user