1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

MDEV-12506 Split Item_func_min_max::fix_length_and_dec() into methods in Type_handler + MDEV-12497 + MDEV-12504

This patch does the following:

1. Adds a new method Type_handler_hybrid_field_type::aggregate_for_min_max()

   - For non-traditional data types it uses
     type_handler_data->m_type_aggregator_for_result.find_handler()
     This allows pluggable data types to define in the future their
     own behavior of the result data type detection for LEAST/GREATEST.
     Also, this disallows expressions of the GEOMETRY data type
     (and its variants such as POINT) to be mixed in with
     numeric and temporal data types in LEAST/GREATEST.

   - For traditional data types it reproduces the old behavior of
     the result data type detection (but not attributes, see below).

2. Adds a new virtual method Type_handler::Item_func_min_max_fix_attributes()
   and reuses as much as possible the code that calculates data type attributes
   for CASE-alike functions (e.g. CASE..THEN, COALESCE, IF).

   As the old code responsible for attributes calculation in the old
   implementation of Item_func_min_max::fix_length_and_dec()
   was not fully correct, this automatically fixes the following bugs:

   - MDEV-12497 Wrong data type for LEAST(latin1_expr, utf8_expr)
     The old fix_length_and_dec() calculated max_length before
     character set aggregation. Now max_length is calculated after, in
     Item_func::count_string_length() called from
     Item_func::aggregate_attributes_string() called from
     Type_handler_string_result::Item_hybrid_func_fix_attributes() called from
     Type_handler::Item_func_min_max_fix_attributes() called from
     Item_func_min_max::fix_length_and_dec().

   - MDEV-12504 Wrong data type for LEAST(date_expr,time_expr)
     The old fix_length_and_dec() simply used the maximum of max_length
     among all arguments to set its own max_length and did not take
     into account that a mixture of DATE and TIME becomes DATETIME.
     Now this is correctly handled by:
     Type_handler_datetime_common::Item_hybrid_func_fix_attributes() called from
     Type_handler::Item_func_min_max_fix_attributes() called from
     Item_func_min_max::fix_length_and_dec().

3. Removes the old implementation of Item_func_min_max::fix_length_and_dec()
   and replaces it to calls of the new methods.

4. Cleanup: moves the code related to unsigned_flag processing
   from Type_handler_hybrid_field_type::aggregate_for_result()
   to   Type_handler_int_result::Item_hybrid_func_fix_attributes().
   This is done:
   - to avoid code duplication in
     Type_handler_hybrid_field_type::aggregate_for_min_max()
   - to get rid of one more call for field_type(), which is unfriendly
     to the conceipt of pluggable data types.
This commit is contained in:
Alexander Barkov
2017-04-22 23:47:27 +04:00
parent ba670edfa3
commit 658082551f
14 changed files with 575 additions and 157 deletions

View File

@ -370,7 +370,6 @@ Type_handler_hybrid_field_type::aggregate_for_result(const char *funcname,
return true;
}
set_handler(items[0]->type_handler());
uint unsigned_count= items[0]->unsigned_flag;
for (uint i= 1 ; i < nitems ; i++)
{
const Type_handler *cur= items[i]->type_handler();
@ -388,26 +387,6 @@ Type_handler_hybrid_field_type::aggregate_for_result(const char *funcname,
type_handler()->name().ptr(), cur->name().ptr(), funcname);
return true;
}
unsigned_count+= items[i]->unsigned_flag;
}
switch (field_type()) {
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_LONG:
case MYSQL_TYPE_LONGLONG:
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_YEAR:
case MYSQL_TYPE_BIT:
if (unsigned_count != 0 && unsigned_count != nitems)
{
/*
If all arguments are of INT-alike type but have different
unsigned_flag, then convert to DECIMAL.
*/
set_handler(&type_handler_newdecimal);
}
default:
break;
}
return false;
}
@ -479,6 +458,114 @@ Type_handler_hybrid_field_type::aggregate_for_comparison(const Type_handler *h)
}
/**
Aggregate data type handler for LEAST/GRATEST.
aggregate_for_min_max() is close to aggregate_for_comparison(),
but tries to preserve the exact type handler for string, int and temporal
data types (instead of converting to super-types).
FLOAT is not preserved and is converted to its super-type (DOUBLE).
This should probably fixed eventually, for symmetry.
*/
bool
Type_handler_hybrid_field_type::aggregate_for_min_max(const Type_handler *h)
{
if (!m_type_handler->is_traditional_type() ||
!h->is_traditional_type())
{
/*
If at least one data type is non-traditional,
do aggregation for result immediately.
For now we suppose that these two expressions:
- LEAST(type1, type2)
- COALESCE(type1, type2)
return the same data type (or both expressions return error)
if type1 and/or type2 are non-traditional.
This may change in the future.
*/
h= type_handler_data->
m_type_aggregator_for_result.find_handler(m_type_handler, h);
if (!h)
return true;
m_type_handler= h;
return false;
}
Item_result a= cmp_type();
Item_result b= h->cmp_type();
DBUG_ASSERT(a != ROW_RESULT); // Disallowed by check_cols() in fix_fields()
DBUG_ASSERT(b != ROW_RESULT); // Disallowed by check_cols() in fix_fields()
if (a == STRING_RESULT && b == STRING_RESULT)
m_type_handler=
Type_handler::aggregate_for_result_traditional(m_type_handler, h);
else if (a == INT_RESULT && b == INT_RESULT)
{
// BIT aggregates with non-BIT as BIGINT
if (m_type_handler != h)
{
if (m_type_handler == &type_handler_bit)
m_type_handler= &type_handler_longlong;
else if (h == &type_handler_bit)
h= &type_handler_longlong;
}
m_type_handler=
Type_handler::aggregate_for_result_traditional(m_type_handler, h);
}
else if (a == TIME_RESULT || b == TIME_RESULT)
{
if ((a == TIME_RESULT) + (b == TIME_RESULT) == 1)
{
/*
We're here if there's only one temporal data type:
either m_type_handler or h.
*/
if (b == TIME_RESULT)
m_type_handler= h; // Temporal types bit non-temporal types
}
else
{
/*
We're here if both m_type_handler and h are temporal data types.
*/
m_type_handler=
Type_handler::aggregate_for_result_traditional(m_type_handler, h);
}
}
else if ((a == INT_RESULT || a == DECIMAL_RESULT) &&
(b == INT_RESULT || b == DECIMAL_RESULT))
{
m_type_handler= &type_handler_newdecimal;
}
else
{
m_type_handler= &type_handler_double;
}
return false;
}
bool
Type_handler_hybrid_field_type::aggregate_for_min_max(const char *funcname,
Item **items, uint nitems)
{
// LEAST/GREATEST require at least two arguments
DBUG_ASSERT(nitems > 1);
set_handler(items[0]->type_handler());
for (uint i= 1; i < nitems; i++)
{
const Type_handler *cur= items[i]->type_handler();
if (aggregate_for_min_max(cur))
{
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0),
type_handler()->name().ptr(), cur->name().ptr(), funcname);
return true;
}
}
return false;
}
const Type_handler *
Type_handler::aggregate_for_num_op_traditional(const Type_handler *h0,
const Type_handler *h1)
@ -1313,6 +1400,17 @@ bool Type_handler_int_result::
Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
Item **items, uint nitems) const
{
uint unsigned_flag= items[0]->unsigned_flag;
for (uint i= 1; i < nitems; i++)
{
if (unsigned_flag != items[i]->unsigned_flag)
{
// Convert a mixture of signed and unsigned int to decimal
func->set_handler(&type_handler_newdecimal);
func->aggregate_attributes_decimal(items, nitems);
return false;
}
}
func->aggregate_attributes_int(items, nitems);
return false;
}
@ -1379,6 +1477,33 @@ bool Type_handler_timestamp_common::
return false;
}
/*************************************************************************/
bool Type_handler::
Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
Item **items, uint nitems) const
{
/*
Aggregating attributes for LEAST/GREATES is exactly the same
with aggregating for CASE-alike functions (e.g. COALESCE)
for the majority of data type handlers.
*/
return Item_hybrid_func_fix_attributes(thd, func, items, nitems);
}
bool Type_handler_real_result::
Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
Item **items, uint nitems) const
{
/*
DOUBLE is an exception and aggregates attributes differently
for LEAST/GREATEST vs CASE-alike functions. See the comment in
Item_func_min_max::aggregate_attributes_real().
*/
func->aggregate_attributes_real(items, nitems);
return false;
}
/*************************************************************************/