diff options
Diffstat (limited to 'sql/field.cc')
-rw-r--r-- | sql/field.cc | 108 |
1 files changed, 85 insertions, 23 deletions
diff --git a/sql/field.cc b/sql/field.cc index f413d77be87..c49d4d6f4a7 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -964,6 +964,51 @@ Type_handler::aggregate_for_result_traditional(const Type_handler *a, } +bool Field::check_assignability_from(const Type_handler *from, + bool ignore) const +{ + /* + Using type_handler_for_item_field() here to get the data type handler + on both sides. This is needed to make sure aggregation for Field + works the same way with how Item_field aggregates for UNION or CASE, + so these statements: + SELECT a FROM t1 UNION SELECT b FROM t1; // Item_field vs Item_field + UPDATE t1 SET a=b; // Field vs Item_field + either both return "Illegal parameter data types" or both pass + the data type compatibility test. + For MariaDB standard data types, using type_handler_for_item_field() + turns ENUM/SET into just CHAR. + */ + Type_handler_hybrid_field_type th(type_handler()-> + type_handler_for_item_field()); + if (th.aggregate_for_result(from->type_handler_for_item_field())) + { + bool error= (!ignore && get_thd()->is_strict_mode()) || + (type_handler()->is_scalar_type() != from->is_scalar_type()); + /* + Display fully qualified column name for table columns. + Display non-qualified names for other things, + e.g. SP variables, SP return values, SP and CURSOR parameters. + */ + if (table->s->db.str && table->s->table_name.str) + my_printf_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, + "Cannot cast '%s' as '%s' in assignment of %`s.%`s.%`s", + MYF(error ? 0 : ME_WARNING), + from->name().ptr(), type_handler()->name().ptr(), + table->s->db.str, table->s->table_name.str, + field_name.str); + else + my_printf_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, + "Cannot cast '%s' as '%s' in assignment of %`s", + MYF(error ? 0 : ME_WARNING), + from->name().ptr(), type_handler()->name().ptr(), + field_name.str); + return error; + } + return false; +} + + /* Test if the given string contains important data: not spaces for character string, @@ -1108,19 +1153,27 @@ Field_longstr::pack_sort_string(uchar *to, const SORT_FIELD_ATTR *sort_field) relative position of the field value in the numeric interval [min,max] */ -double Field::pos_in_interval_val_real(Field *min, Field *max) +double pos_in_interval_for_double(double midp_val, double min_val, + double max_val) { double n, d; - n= val_real() - min->val_real(); + n= midp_val - min_val; if (n < 0) return 0.0; - d= max->val_real() - min->val_real(); + d= max_val - min_val; if (d <= 0) return 1.0; return MY_MIN(n/d, 1.0); } +double Field::pos_in_interval_val_real(Field *min, Field *max) +{ + return pos_in_interval_for_double(val_real(), min->val_real(), + max->val_real()); +} + + static inline ulonglong char_prefix_to_ulonglong(uchar *src) { @@ -1178,22 +1231,32 @@ static inline double safe_substract(ulonglong a, ulonglong b) double Field::pos_in_interval_val_str(Field *min, Field *max, uint data_offset) { + return pos_in_interval_for_string(charset(), + ptr + data_offset, data_length(), + min->ptr + data_offset, min->data_length(), + max->ptr + data_offset, max->data_length() + ); +} + + +double pos_in_interval_for_string(CHARSET_INFO *cset, + const uchar *midp_val, uint32 midp_len, + const uchar *min_val, uint32 min_len, + const uchar *max_val, uint32 max_len) +{ uchar mp_prefix[sizeof(ulonglong)]; uchar minp_prefix[sizeof(ulonglong)]; uchar maxp_prefix[sizeof(ulonglong)]; ulonglong mp, minp, maxp; - charset()->strnxfrm(mp_prefix, sizeof(mp), - ptr + data_offset, - data_length()); - charset()->strnxfrm(minp_prefix, sizeof(minp), - min->ptr + data_offset, - min->data_length()); - charset()->strnxfrm(maxp_prefix, sizeof(maxp), - max->ptr + data_offset, - max->data_length()); - mp= char_prefix_to_ulonglong(mp_prefix); + + cset->strnxfrm(mp_prefix, sizeof(mp), midp_val, midp_len); + cset->strnxfrm(minp_prefix, sizeof(minp), min_val, min_len); + cset->strnxfrm(maxp_prefix, sizeof(maxp), max_val, max_len); + + mp= char_prefix_to_ulonglong(mp_prefix); minp= char_prefix_to_ulonglong(minp_prefix); maxp= char_prefix_to_ulonglong(maxp_prefix); + double n, d; n= safe_substract(mp, minp); if (n < 0) @@ -1427,18 +1490,9 @@ bool Field::sp_prepare_and_store_item(THD *thd, Item **value) Item *expr_item; - if (!(expr_item= thd->sp_prepare_func_item(value, 1))) + if (!(expr_item= thd->sp_fix_func_item_for_assignment(this, value))) goto error; - /* - expr_item is now fixed, it's safe to call cmp_type() - */ - if (expr_item->cmp_type() == ROW_RESULT) - { - my_error(ER_OPERAND_COLUMNS, MYF(0), 1); - goto error; - } - /* Save the value in the field. Convert the value if needed. */ expr_item->save_in_field(this, 0); @@ -11127,6 +11181,14 @@ Field::set_warning(Sql_condition::enum_warning_level level, uint code, will have table == NULL. */ THD *thd= get_thd(); + + /* + In INPLACE ALTER, server can't know which row has generated + the warning, so the value of current row is supplied by the engine. + */ + if (current_row) + thd->get_stmt_da()->reset_current_row_for_warning(current_row); + if (thd->count_cuted_fields > CHECK_FIELD_EXPRESSION) { thd->cuted_fields+= cut_increment; |