diff options
author | Alexander Barkov <bar@mariadb.com> | 2018-04-23 09:31:17 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.com> | 2018-04-23 09:31:17 +0400 |
commit | 6426b52ed43876ccc0142fc31f98dd6d42292388 (patch) | |
tree | e3e4d8ec47326db603c746e4d4eb975d9256c6a5 /sql/item.cc | |
parent | 9f84451d87ba1924539b7d2ab69619b71d0155b9 (diff) | |
download | mariadb-git-6426b52ed43876ccc0142fc31f98dd6d42292388.tar.gz |
MDEV-15957 Unexpected "Data too long" when doing CREATE..SELECT with stored func
Problems:
1. Unlike Item_field::fix_fields(),
Item_sum_sp::fix_length_and_dec() and Item_func_sp::fix_length_and_dec()
did not run the code which resided in adjust_max_effective_column_length(),
therefore they did not extend max_length for the integer return data types
from the user-specified length to the maximum length according to
the data type capacity.
2. The code in adjust_max_effective_column_length() was not correct
for TEXT data, because Field_blob::max_display_length()
multiplies to mbmaxlen. So TEXT variants were unintentionally
promoted to the next longer data type for multi-byte character
sets: TINYTEXT->TEXT, TEXT->MEDIUMTEXT, MEDIUMTEXT->LONGTEXT.
3. Item_sum_sp::create_table_field_from_handler()
Item_func_sp::create_table_field_from_handler()
erroneously called tmp_table_field_from_field_type(),
which converted VARCHAR(>512) to TEXT variants.
So "CREATE..SELECT spfunc()" erroneously converted
VARCHAR to TEXT. This was wrong, because stored
functions have explicitly declared data types,
which should be preserved.
Solution:
- Removing Type_std_attributes(const Field *)
and using instead Type_std_attributes::set() in combination
with field->type_str_attributes() all around the code, e.g.:
Type_std_attributes::set(field->type_std_attributes())
These two ways of copying attributes from a Field
to an Item duplicated each other, and were slightly
different in how to mix max_length and mbmaxlen.
- Removing adjust_max_effective_column_length() and
fixing Field::type_std_attributes() to do all necessary
type-specific calculations , so no further adjustments
is needed.
Field::type_std_attributes() is now called from all affected methods:
Item_field::fix_fields()
Item_sum_sp::fix_length_and_dec()
Item_func_sp::fix_length_and_dec()
This fixes the problem N1.
- Making Field::type_std_attributes() virtual, to make
sure that type-specific adjustments a properly done
by individual Field_xxx classes. Implementing
Field_blob::type_std_attributes() in the way that
no TEXT promotion is done.
This fixes the problem N2.
- Fixing Item_sum_sp::create_table_field_from_handler()
Item_func_sp::create_table_field_from_handler() to
call create_table_field_from_handler() instead of
tmp_table_field_from_field_type() to avoid
VARCHAR->TEXT conversion on "CREATE..SELECT spfunc()".
- Recording mysql-test/suite/compat/oracle/r/sp-param.result
as "CREATE..SELECT spfunc()" now correctly
preserve the data type as specified in the RETURNS clause.
- Adding new tests
Diffstat (limited to 'sql/item.cc')
-rw-r--r-- | sql/item.cc | 31 |
1 files changed, 1 insertions, 30 deletions
diff --git a/sql/item.cc b/sql/item.cc index 35c5ab8cc3d..1f2ebbd8be5 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3165,45 +3165,16 @@ Item_field::Item_field(THD *thd, Item_field *item) } -/** - Calculate the max column length not taking into account the - limitations over integer types. - - When storing data into fields the server currently just ignores the - limits specified on integer types, e.g. 1234 can safely be stored in - an int(2) and will not cause an error. - Thus when creating temporary tables and doing transformations - we must adjust the maximum field length to reflect this fact. - We take the un-restricted maximum length and adjust it similarly to - how the declared length is adjusted wrt unsignedness etc. - TODO: this all needs to go when we disable storing 1234 in int(2). - - @param field_par Original field the use to calculate the lengths - @param max_length Item's calculated explicit max length - @return The adjusted max length -*/ - -inline static uint32 -adjust_max_effective_column_length(Field *field_par, uint32 max_length) -{ - uint32 new_max_length= field_par->max_display_length(); - /* Adjust only if the actual precision based one is bigger than specified */ - return new_max_length > max_length ? new_max_length : max_length; -} - - void Item_field::set_field(Field *field_par) { field=result_field=field_par; // for easy coding with fields maybe_null=field->maybe_null(); - Type_std_attributes::set(field_par); + Type_std_attributes::set(field_par->type_std_attributes()); table_name= *field_par->table_name; field_name= field_par->field_name; db_name= field_par->table->s->db.str; alias_name_used= field_par->table->alias_name_used; - max_length= adjust_max_effective_column_length(field_par, max_length); - fixed= 1; if (field->table->s->tmp_table == SYSTEM_TMP_TABLE) any_privileges= 0; |