1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

MDEV-12775 Reuse data type aggregation code for hybrid functions and UNION

Introducing a new class Type_holder (used internally in sql_union.cc),
to reuse exactly the same data type attribute aggregation Type_handler API
for hybrid functions and UNION.

This fixes a number of bugs in UNION:

- MDEV-9495 Wrong field type for a UNION of a signed and an unsigned INT expression
- MDEV-9497 UNION and COALESCE produce different field types for DECIMAL+INT
- MDEV-12594 UNION between fixed length double columns does not always preserve scale
- MDEV-12595 UNION converts INT to BIGINT
- MDEV-12599 UNION is not symmetric when mixing INT and CHAR

Details:

- sql_union.cc: Reusing attribute aggregation for UNION.
  Adding new methods:
  * st_select_lex_unit::join_union_type_handlers()
  * st_select_lex_unit::join_union_type_attributes()
  * st_select_lex_unit::join_union_item_types()
  Removing the old join_types()-based code.

- Changing Type_handler::Item_hybrid_func_fix_attributes()
  to accept "name", Type_handler_hybrid_field_type, Type_all_attributes
  as three separate parameters instead of a single Item_hybrid_func parameter,
  to make it possible to pass both Item_hybrid_func and Type_holder.

- Moving the former special GEOMETRY and ENUM/SET attribute aggregation code
  from Item_type_holder::join_types() to
  * Type_handler_typelib::Item_hybrid_func_fix_attributes().
  * Type_handler_geometry::Item_hybrid_func_fix_attrubutes().
  This makes GEOMETRY/ENUM/SET symmetric with all other data types
  (from the UNION point of view).
  Removing Item_type_holder::join_types() and Item_type_holder::get_full_info().

- Adding new methods into Type_all_attributes:
  * Type_all_attributes::set_geometry_type() and
    Item_hybrid_func::set_geometry_type().
  * Adding Type_all_attributes::get_typelib().
  * Adding Type_all_attributes::set_typelib().

- Adding Type_handler_typelib as a common parent for
  Type_handler_enum and Type_handler_set, to avoid code duplication: they have
  already had two common methods, and we're adding one more shared method.

- Adding Type_all_attributes::set_maybe_null(), as some type handlers
  may want to set maybe_null (e.g. Type_handler_geometry) during data type
  attribute aggregation.

- Changing Type_geometry_attributes() to accept Type_handler
  and Type_all_attributes as two separate parameters, instead
  of a single Item parameter, to make it possible to pass Type_holder.

- Adding Item_args::add_argument().

- Moving Item_args::alloc_arguments() from "protected" to "public".

- Moving Item_type_holder::Item_type_holder() from item.cc to item.h, as
  now it's very simple.
  Btw, this constructor should probably be eventually removed.
  It's now used only in sql_show.cc, which could be modified to use
  Item_return_decimal (for symmetry with Item_return_xxx created for all
  other data types). Or, another option: remove all Item_return_xxx and
  use Item_type_holder for all data types instead.

- storage/tokudb/mysql-test/tokudb/r/type_float.result
  Recording new results (MDEV-12594).

- mysql-test/r/cte_recursive.result
  Recording new results (MDEV-9497)

- mysql-test/r/subselect*.result
  Recording new results (MDEV-12595)

- mysql-test/r/metadata.result
  Recording new results (MDEV-9495)

- mysql-test/r/temp_table.result
  Recording new results (MDEV-12594)

- mysql-test/r/type_float.result
  Recording new results (MDEV-12594)
This commit is contained in:
Alexander Barkov
2017-05-10 15:29:48 +04:00
parent 7c44b8afb7
commit 705fc43eaa
21 changed files with 755 additions and 325 deletions

View File

@ -482,29 +482,18 @@ const Type_handler *Type_handler_row::type_handler_for_comparison() const
/***************************************************************************/
const Type_handler *Type_handler_enum::type_handler_for_item_field() const
const Type_handler *Type_handler_typelib::type_handler_for_item_field() const
{
return &type_handler_string;
}
const Type_handler *Type_handler_enum::cast_to_int_type_handler() const
const Type_handler *Type_handler_typelib::cast_to_int_type_handler() const
{
return &type_handler_longlong;
}
const Type_handler *Type_handler_set::type_handler_for_item_field() const
{
return &type_handler_string;
}
const Type_handler *Type_handler_set::cast_to_int_type_handler() const
{
return &type_handler_longlong;
}
/***************************************************************************/
bool
@ -2080,7 +2069,10 @@ Type_handler_temporal_result::Item_get_cache(THD *thd, const Item *item) const
/*************************************************************************/
bool Type_handler_int_result::
Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
Item_hybrid_func_fix_attributes(THD *thd,
const char *func_name,
Type_handler_hybrid_field_type *handler,
Type_all_attributes *func,
Item **items, uint nitems) const
{
uint unsigned_flag= items[0]->unsigned_flag;
@ -2089,7 +2081,7 @@ bool Type_handler_int_result::
if (unsigned_flag != items[i]->unsigned_flag)
{
// Convert a mixture of signed and unsigned int to decimal
func->set_handler(&type_handler_newdecimal);
handler->set_handler(&type_handler_newdecimal);
func->aggregate_attributes_decimal(items, nitems);
return false;
}
@ -2100,7 +2092,10 @@ bool Type_handler_int_result::
bool Type_handler_real_result::
Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
Item_hybrid_func_fix_attributes(THD *thd,
const char *func_name,
Type_handler_hybrid_field_type *handler,
Type_all_attributes *func,
Item **items, uint nitems) const
{
func->aggregate_attributes_real(items, nitems);
@ -2109,7 +2104,10 @@ bool Type_handler_real_result::
bool Type_handler_decimal_result::
Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
Item_hybrid_func_fix_attributes(THD *thd,
const char *func_name,
Type_handler_hybrid_field_type *handler,
Type_all_attributes *func,
Item **items, uint nitems) const
{
func->aggregate_attributes_decimal(items, nitems);
@ -2118,26 +2116,59 @@ bool Type_handler_decimal_result::
bool Type_handler_string_result::
Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
Item_hybrid_func_fix_attributes(THD *thd,
const char *func_name,
Type_handler_hybrid_field_type *handler,
Type_all_attributes *func,
Item **items, uint nitems) const
{
return func->aggregate_attributes_string(func->func_name(), items, nitems);
return func->aggregate_attributes_string(func_name, items, nitems);
}
/*
We can have enum/set type after merging only if we have one enum|set
field (or MIN|MAX(enum|set field)) and number of NULL fields
*/
bool Type_handler_typelib::
Item_hybrid_func_fix_attributes(THD *thd,
const char *func_name,
Type_handler_hybrid_field_type *handler,
Type_all_attributes *func,
Item **items, uint nitems) const
{
TYPELIB *typelib= NULL;
for (uint i= 0; i < nitems; i++)
{
if ((typelib= items[i]->get_typelib()))
break;
}
DBUG_ASSERT(typelib); // There must be at least one typelib
func->set_typelib(typelib);
return func->aggregate_attributes_string(func_name, items, nitems);
}
bool Type_handler_blob_common::
Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
Item_hybrid_func_fix_attributes(THD *thd,
const char *func_name,
Type_handler_hybrid_field_type *handler,
Type_all_attributes *func,
Item **items, uint nitems) const
{
if (func->aggregate_attributes_string(func->func_name(), items, nitems))
if (func->aggregate_attributes_string(func_name, items, nitems))
return true;
func->set_handler(blob_type_handler(func->max_length));
handler->set_handler(blob_type_handler(func->max_length));
return false;
}
bool Type_handler_date_common::
Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
Item_hybrid_func_fix_attributes(THD *thd,
const char *func_name,
Type_handler_hybrid_field_type *handler,
Type_all_attributes *func,
Item **items, uint nitems) const
{
func->fix_attributes_date();
@ -2146,7 +2177,10 @@ bool Type_handler_date_common::
bool Type_handler_time_common::
Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
Item_hybrid_func_fix_attributes(THD *thd,
const char *func_name,
Type_handler_hybrid_field_type *handler,
Type_all_attributes *func,
Item **items, uint nitems) const
{
func->aggregate_attributes_temporal(MIN_TIME_WIDTH, items, nitems);
@ -2155,7 +2189,10 @@ bool Type_handler_time_common::
bool Type_handler_datetime_common::
Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
Item_hybrid_func_fix_attributes(THD *thd,
const char *func_name,
Type_handler_hybrid_field_type *handler,
Type_all_attributes *func,
Item **items, uint nitems) const
{
func->aggregate_attributes_temporal(MAX_DATETIME_WIDTH, items, nitems);
@ -2164,7 +2201,10 @@ bool Type_handler_datetime_common::
bool Type_handler_timestamp_common::
Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
Item_hybrid_func_fix_attributes(THD *thd,
const char *func_name,
Type_handler_hybrid_field_type *handler,
Type_all_attributes *func,
Item **items, uint nitems) const
{
func->aggregate_attributes_temporal(MAX_DATETIME_WIDTH, items, nitems);
@ -2173,11 +2213,14 @@ bool Type_handler_timestamp_common::
#ifdef HAVE_SPATIAL
bool Type_handler_geometry::
Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
Item_hybrid_func_fix_attributes(THD *thd,
const char *func_name,
Type_handler_hybrid_field_type *handler,
Type_all_attributes *func,
Item **items, uint nitems) const
{
DBUG_ASSERT(nitems > 0);
Type_geometry_attributes gattr(items[0]);
Type_geometry_attributes gattr(items[0]->type_handler(), items[0]);
for (uint i= 1; i < nitems; i++)
gattr.join(items[i]);
func->set_geometry_type(gattr.get_geometry_type());
@ -2185,7 +2228,7 @@ bool Type_handler_geometry::
func->unsigned_flag= false;
func->decimals= 0;
func->max_length= (uint32) UINT_MAX32;
func->maybe_null= true;
func->set_maybe_null(true);
return false;
}
#endif
@ -2202,7 +2245,8 @@ bool Type_handler::
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);
return Item_hybrid_func_fix_attributes(thd, func->func_name(),
func, func, items, nitems);
}