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)) ||
|
if ((!item->fixed && item->fix_fields(thd, args)) ||
|
||||||
(item= args[0])->check_cols(1))
|
(item= args[0])->check_cols(1))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
Type_std_attributes::set(args[0]);
|
|
||||||
with_subselect= args[0]->with_subselect;
|
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();
|
fix_length_and_dec();
|
||||||
|
setup_hybrid(thd, args[0], NULL);
|
||||||
|
result_field=0;
|
||||||
|
|
||||||
if (check_sum_func(thd, ref))
|
if (check_sum_func(thd, ref))
|
||||||
return TRUE;
|
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.
|
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();
|
cmp= new Arg_comparator();
|
||||||
if (cmp)
|
if (cmp)
|
||||||
cmp->set_cmp_func(this, (Item**)&arg_cache, (Item**)&value, FALSE);
|
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)
|
cmp_sign(item->cmp_sign), was_values(item->was_values)
|
||||||
{ }
|
{ }
|
||||||
bool fix_fields(THD *, Item **);
|
bool fix_fields(THD *, Item **);
|
||||||
|
void fix_length_and_dec();
|
||||||
void setup_hybrid(THD *thd, Item *item, Item *value_arg);
|
void setup_hybrid(THD *thd, Item *item, Item *value_arg);
|
||||||
void clear();
|
void clear();
|
||||||
double val_real();
|
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 Field;
|
||||||
class Item;
|
class Item;
|
||||||
class Item_cache;
|
class Item_cache;
|
||||||
|
class Item_sum_hybrid;
|
||||||
class Type_std_attributes;
|
class Type_std_attributes;
|
||||||
class Sort_param;
|
class Sort_param;
|
||||||
class Arg_comparator;
|
class Arg_comparator;
|
||||||
@ -289,6 +290,7 @@ public:
|
|||||||
bool no_conversions) const= 0;
|
bool no_conversions) const= 0;
|
||||||
virtual Item_cache *Item_get_cache(THD *thd, const Item *item) 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 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;
|
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
|
||||||
bool set_comparator_func(Arg_comparator *cmp) 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 */
|
/*** Abstract classes for every XXX_RESULT */
|
||||||
|
|
||||||
class Type_handler_real_result: public Type_handler
|
class Type_handler_real_result: public Type_handler_numeric
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Item_result result_type() const { return REAL_RESULT; }
|
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;
|
int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
|
||||||
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
|
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
|
||||||
bool set_comparator_func(Arg_comparator *cmp) 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:
|
public:
|
||||||
Item_result result_type() const { return DECIMAL_RESULT; }
|
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;
|
int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
|
||||||
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
|
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
|
||||||
bool set_comparator_func(Arg_comparator *cmp) 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:
|
public:
|
||||||
Item_result result_type() const { return INT_RESULT; }
|
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;
|
int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
|
||||||
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
|
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
|
||||||
bool set_comparator_func(Arg_comparator *cmp) 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;
|
SORT_FIELD_ATTR *attr) const;
|
||||||
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
|
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
|
||||||
bool set_comparator_func(Arg_comparator *cmp) 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;
|
int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
|
||||||
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
|
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
|
||||||
bool set_comparator_func(Arg_comparator *cmp) 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