summaryrefslogtreecommitdiff
path: root/sql/item.cc
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.com>2018-04-23 09:31:17 +0400
committerAlexander Barkov <bar@mariadb.com>2018-04-23 09:31:17 +0400
commit6426b52ed43876ccc0142fc31f98dd6d42292388 (patch)
treee3e4d8ec47326db603c746e4d4eb975d9256c6a5 /sql/item.cc
parent9f84451d87ba1924539b7d2ab69619b71d0155b9 (diff)
downloadmariadb-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.cc31
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;