Commit 2dac1235 authored by Alexander Barkov's avatar Alexander Barkov

A cleanup for `MDEV-20273 Add class Item_sum_min_max` - removing duplicate code

Reusing the MIN()/MAX() fix_length_and_dec() related code for window functions
- FIRST_VALUE()
- LAST_VALUE()
- NTH_VALUE()
- LEAD()
- LAG
parent c3d67c17
......@@ -1184,11 +1184,73 @@ Item_sum_min_max::fix_fields(THD *thd, Item **ref)
}
bool Item_sum_hybrid::fix_length_and_dec_generic()
{
Item *item= arguments()[0];
Type_std_attributes::set(item);
set_handler(item->type_handler());
return false;
}
/**
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 Item_sum_hybrid::fix_length_and_dec_numeric(const Type_handler *handler)
{
Item *item= arguments()[0];
Item *item2= item->real_item();
Type_std_attributes::set(item);
if (item2->type() == Item::FIELD_ITEM)
set_handler(item2->type_handler());
else
set_handler(handler);
return false;
}
/**
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 Item_sum_hybrid::fix_length_and_dec_string()
{
Item *item= arguments()[0];
Item *item2= item->real_item();
Type_std_attributes::set(item);
if (item2->type() == Item::FIELD_ITEM)
{
// Fields: convert ENUM/SET to CHAR, preserve the type otherwise.
set_handler(item->type_handler());
}
else
{
// Items: choose VARCHAR/BLOB/MEDIUMBLOB/LONGBLOB, depending on length.
set_handler(type_handler_varchar.
type_handler_adjusted_to_max_octet_length(max_length,
collation.collation));
}
return false;
}
bool Item_sum_min_max::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());
return args[0]->type_handler()->Item_sum_min_max_fix_length_and_dec(this);
/* MIN/MAX can return NULL for empty set indepedent of the used column */
maybe_null= null_value= true;
return args[0]->type_handler()->Item_sum_hybrid_fix_length_and_dec(this);
}
......
......@@ -1044,6 +1044,9 @@ class Item_sum_hybrid: public Item_sum,
{ }
const Type_handler *type_handler() const
{ return Type_handler_hybrid_field_type::type_handler(); }
bool fix_length_and_dec_generic();
bool fix_length_and_dec_numeric(const Type_handler *h);
bool fix_length_and_dec_string();
};
......
......@@ -353,39 +353,15 @@ bool Item_sum_hybrid_simple::fix_fields(THD *thd, Item **ref)
if (args[i]->fix_fields_if_needed_for_scalar(thd, &args[i]))
return TRUE;
}
Type_std_attributes::set(args[0]);
for (uint i= 0; i < arg_count && !m_with_subquery; i++)
m_with_subquery|= args[i]->with_subquery();
Item *item2= args[0]->real_item();
if (item2->type() == Item::FIELD_ITEM)
set_handler(item2->type_handler());
else if (args[0]->cmp_type() == TIME_RESULT)
set_handler(item2->type_handler());
else
set_handler_by_result_type(item2->result_type(),
max_length, collation.collation);
if (fix_length_and_dec())
return true;
switch (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); // XXX(cvicentiu) Should this never happen?
return TRUE;
};
setup_hybrid(thd, args[0]);
/* MIN/MAX can return NULL for empty set indepedent of the used column */
maybe_null= 1;
result_field=0;
null_value=1;
if (fix_length_and_dec())
return TRUE;
if (check_sum_func(thd, ref))
return TRUE;
......@@ -397,6 +373,14 @@ bool Item_sum_hybrid_simple::fix_fields(THD *thd, Item **ref)
return FALSE;
}
bool Item_sum_hybrid_simple::fix_length_and_dec()
{
maybe_null= null_value= true;
return args[0]->type_handler()->Item_sum_hybrid_fix_length_and_dec(this);
}
bool Item_sum_hybrid_simple::add()
{
value->store(args[0]);
......
......@@ -307,6 +307,7 @@ class Item_sum_hybrid_simple : public Item_sum_hybrid
bool add();
bool fix_fields(THD *, Item **);
bool fix_length_and_dec();
void setup_hybrid(THD *thd, Item *item);
double val_real();
longlong val_int();
......
......@@ -365,7 +365,7 @@ Type_handler::blob_type_handler(const Item *item)
/**
This method is used by:
- Item_sum_min_max, e.g. MAX(item), MIN(item).
- Item_sum_hybrid, e.g. MAX(item), MIN(item).
- Item_func_set_user_var
*/
const Type_handler *
......@@ -3076,87 +3076,33 @@ bool Type_handler_real_result::
/*************************************************************************/
/**
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_min_max_fix_length_and_dec_numeric(Item_sum_min_max *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(item2->type_handler());
else
func->set_handler(handler);
return false;
}
bool Type_handler_int_result::
Item_sum_min_max_fix_length_and_dec(Item_sum_min_max *func) const
Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
{
return Item_sum_min_max_fix_length_and_dec_numeric(func,
&type_handler_longlong);
return func->fix_length_and_dec_numeric(&type_handler_longlong);
}
bool Type_handler_real_result::
Item_sum_min_max_fix_length_and_dec(Item_sum_min_max *func) const
Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
{
(void) Item_sum_min_max_fix_length_and_dec_numeric(func,
&type_handler_double);
(void) func->fix_length_and_dec_numeric(&type_handler_double);
func->max_length= func->float_length(func->decimals);
return false;
}
bool Type_handler_decimal_result::
Item_sum_min_max_fix_length_and_dec(Item_sum_min_max *func) const
Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
{
return Item_sum_min_max_fix_length_and_dec_numeric(func,
&type_handler_newdecimal);
return func->fix_length_and_dec_numeric(&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_min_max_fix_length_and_dec(Item_sum_min_max *func) const
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(item->type_handler());
}
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;
return func->fix_length_and_dec_string();
}
......@@ -3164,13 +3110,9 @@ bool Type_handler_string_result::
Traditional temporal types always preserve the type of the argument.
*/
bool Type_handler_temporal_result::
Item_sum_min_max_fix_length_and_dec(Item_sum_min_max *func) const
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;
return func->fix_length_and_dec_generic();
}
......
......@@ -33,7 +33,7 @@ class Item;
class Item_param;
class Item_cache;
class Item_func_or_sum;
class Item_sum_min_max;
class Item_sum_hybrid;
class Item_sum_sum;
class Item_sum_avg;
class Item_sum_variance;
......@@ -1314,7 +1314,7 @@ class Type_handler
Item_func_min_max *func,
Item **items,
uint nitems) const;
virtual bool Item_sum_min_max_fix_length_and_dec(Item_sum_min_max *) const= 0;
virtual bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *) const= 0;
virtual bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const= 0;
virtual bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const= 0;
virtual
......@@ -1563,7 +1563,7 @@ class Type_handler_row: public Type_handler
DBUG_ASSERT(0);
return true;
}
bool Item_sum_min_max_fix_length_and_dec(Item_sum_min_max *func) const
bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
{
DBUG_ASSERT(0);
return true;
......@@ -1742,10 +1742,6 @@ class Type_handler_row: public Type_handler
*/
class Type_handler_numeric: public Type_handler
{
protected:
bool Item_sum_min_max_fix_length_and_dec_numeric(Item_sum_min_max *func,
const Type_handler *handler)
const;
public:
String *print_item_value(THD *thd, Item *item, String *str) const;
double Item_func_min_max_val_real(Item_func_min_max *) const;
......@@ -1796,7 +1792,7 @@ class Type_handler_real_result: public Type_handler_numeric
Item **items, uint nitems) const;
bool Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
Item **items, uint nitems) const;
bool Item_sum_min_max_fix_length_and_dec(Item_sum_min_max *func) const;
bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const;
bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const;
bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const;
bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const;
......@@ -1874,7 +1870,7 @@ class Type_handler_decimal_result: public Type_handler_numeric
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
Item **items, uint nitems) const;
bool Item_sum_min_max_fix_length_and_dec(Item_sum_min_max *func) const;
bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const;
bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const;
bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const;
bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const;
......@@ -2068,7 +2064,7 @@ class Type_handler_int_result: public Type_handler_numeric
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
Item **items, uint nitems) const;
bool Item_sum_min_max_fix_length_and_dec(Item_sum_min_max *func) const;
bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const;
bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const;
bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const;
bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const;
......@@ -2145,7 +2141,7 @@ class Type_handler_temporal_result: public Type_handler
const Item *outer) const;
bool Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
Item **items, uint nitems) const;
bool Item_sum_min_max_fix_length_and_dec(Item_sum_min_max *func) const;
bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const;
bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const;
bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const;
bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const;
......@@ -2258,7 +2254,7 @@ class Type_handler_string_result: public Type_handler
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
Item **items, uint nitems) const;
bool Item_sum_min_max_fix_length_and_dec(Item_sum_min_max *func) const;
bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const;
bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const;
bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const;
bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const;
......
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