Skip to content

Commit

Permalink
MDEV-11365 Split the data type and attribute related code in Item_sum…
Browse files Browse the repository at this point in the history
…_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.
  • Loading branch information
Alexander Barkov committed Dec 6, 2016
1 parent 81f448c commit 587d387
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 30 deletions.
36 changes: 9 additions & 27 deletions sql/item_sum.cc
Expand Up @@ -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);
};
fix_length_and_dec();
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();

if (check_sum_func(thd, ref))
return TRUE;
Expand All @@ -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.
Expand Down Expand Up @@ -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);
}


Expand Down
1 change: 1 addition & 0 deletions sql/item_sum.h
Expand Up @@ -1006,6 +1006,7 @@ class Item_sum_hybrid :public Item_sum, public Type_handler_hybrid_field_type
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();
Expand Down
98 changes: 98 additions & 0 deletions sql/sql_type.cc
Expand Up @@ -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;
}

/*************************************************************************/
32 changes: 29 additions & 3 deletions sql/sql_type.h
Expand Up @@ -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;
Expand Down Expand Up @@ -289,6 +290,7 @@ class Type_handler
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;
};


Expand Down Expand Up @@ -342,12 +344,31 @@ class Type_handler_row: public Type_handler
}
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; }
Expand All @@ -361,10 +382,11 @@ class Type_handler_real_result: public Type_handler
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; }
Expand All @@ -379,10 +401,11 @@ class Type_handler_decimal_result: public Type_handler
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; }
Expand All @@ -397,6 +420,7 @@ class Type_handler_int_result: public Type_handler
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;
};


Expand All @@ -413,6 +437,7 @@ class Type_handler_temporal_result: public Type_handler
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;
};


Expand All @@ -433,6 +458,7 @@ class Type_handler_string_result: public Type_handler
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;
};


Expand Down

0 comments on commit 587d387

Please sign in to comment.