1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-27 18:02:13 +03:00

Fixing a few problems with data type and metadata for INT result functions (MDEV-12852, MDEV-12853, MDEV-12869)

This is a joint patch for:
MDEV-12852 Out-of-range errors when CAST(1-2 AS UNSIGNED
MDEV-12853 Out-of-range errors when CAST('-1' AS UNSIGNED
MDEV-12869 Wrong metadata for integer additive and multiplicative operators

1. Fixing all Item_func_numhybrid descendants to set the precise
   data type handler (type_handler_long or type_handler_longlong)
   at fix_fields() time. This fixes MDEV-12869.

2. Fixing Item_func_unsigned_typecast to set the precise data type handler
   at fix_fields() time. This fixes MDEV-12852 and MDEV-12853.
   This is done by:
   - fixing Type_handler::Item_func_unsigned_fix_length_and_dec()
     and Type_handler_string_result::Item_func_unsigned_fix_length_and_dec()
     to properly detect situations when a negative epxression is converted
     to UNSIGNED. In this case, length of the result is now always set to
     MAX_BIGINT_WIDTH without trying to use args[0]->max_length, as very
     short arguments can produce very long result in such conversion:
        CAST(-1 AS UNSIGNED) -> 18446744073709551614
   - adding a new virtual method "longlong Item::val_int_max() const",
     to preserve the old behavior for expressions like this:
        CAST(1 AS UNSIGNED)
     to stay under the INT data type (instead of BIGINT) for small
     positive integer literals. Using Item::unsigned_flag would not help,
     because Item_int does not set unsigned_flag to "true" for positive
     numbers.

3. Adding helper methods:
  * Item::type_handler_long_or_longlong()
  * Type_handler::type_handler_long_or_longlong()
  and reusing them in a few places, to reduce code duplication.

4. Making reorganation in create_tmp_field() and
   create_field_for_create_select() for Item_hybrid_func and descendants,
   to reduce duplicate code. They all now have a similar behavior in
   respect of creating fields. Only Item_func_user_var descendants have
   a different behavior. So moving the default behvior to Item_hybrid_func,
   and overriding behavior on Item_func_user_var level.
This commit is contained in:
Alexander Barkov
2017-05-23 12:45:47 +04:00
parent 9b79888df8
commit d9304914be
11 changed files with 451 additions and 39 deletions

View File

@ -528,6 +528,14 @@ Type_handler_hybrid_field_type::aggregate_for_result(const Type_handler *other)
}
const Type_handler *
Type_handler::type_handler_long_or_longlong(uint max_char_length)
{
if (max_char_length <= MY_INT32_NUM_DECIMAL_DIGITS - 2)
return &type_handler_long;
return &type_handler_longlong;
}
/*
This method is called for CASE (and its abbreviations) and LEAST/GREATEST
when data type aggregation returned LONGLONG and there were some BIT
@ -4168,6 +4176,16 @@ bool Type_handler::
bool Type_handler::
Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const
{
const Item *arg= item->arguments()[0];
if (!arg->unsigned_flag && arg->val_int_min() < 0)
{
/*
Negative arguments produce long results:
CAST(1-2 AS UNSIGNED) -> 18446744073709551615
*/
item->max_length= MAX_BIGINT_WIDTH;
return false;
}
item->fix_length_and_dec_generic();
return false;
}
@ -4184,6 +4202,14 @@ bool Type_handler_string_result::
bool Type_handler_string_result::
Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const
{
const Item *arg= item->arguments()[0];
if (!arg->unsigned_flag && // Not HEX hybrid
arg->max_char_length() > 1) // Can be negative
{
// String arguments can give long results: '-1' -> 18446744073709551614
item->max_length= MAX_BIGINT_WIDTH;
return false;
}
item->fix_length_and_dec_string();
return false;
}