From 347c164c35eddab388009470e6848cb361ac93f8 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 18 May 2024 15:22:53 +0200 Subject: Merging upstream version 1:10.11.8. Signed-off-by: Daniel Baumann --- sql/field.cc | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 6 deletions(-) (limited to 'sql/field.cc') diff --git a/sql/field.cc b/sql/field.cc index 76b7ff61..4fbcc181 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1502,6 +1502,9 @@ bool Field::sp_prepare_and_store_item(THD *thd, Item **value) if (!(expr_item= thd->sp_fix_func_item_for_assignment(this, value))) goto error; + if (expr_item->check_is_evaluable_expression_or_error()) + goto error; + /* Save the value in the field. Convert the value if needed. */ expr_item->save_in_field(this, 0); @@ -5277,6 +5280,8 @@ int Field_timestamp::save_in_field(Field *to) { ulong sec_part; my_time_t ts= get_timestamp(&sec_part); + if (!ts && !sec_part) + return to->store_time_dec(Datetime::zero().get_mysql_time(), decimals()); return to->store_timestamp_dec(Timeval(ts, sec_part), decimals()); } @@ -5398,11 +5403,33 @@ int Field_timestamp::store(longlong nr, bool unsigned_val) } -int Field_timestamp::store_timestamp_dec(const timeval &ts, uint dec) +int Field_timestamp::store_timestamp_dec(const timeval &tv, uint dec) { int warn= 0; time_round_mode_t mode= Datetime::default_round_mode(get_thd()); - store_TIMESTAMP(Timestamp(ts).round(decimals(), mode, &warn)); + const Timestamp ts= Timestamp(tv).round(decimals(), mode, &warn); + store_TIMESTAMP(ts); + if (ts.tv().tv_sec == 0 && ts.tv().tv_usec == 0) + { + /* + The value {tv_sec==0, tv_usec==0} here means '1970-01-01 00:00:00 +00'. + It does not mean zero datetime! because store_timestamp_dec() knows + nothing about zero dates. It inserts only real timeval values. + Zero ts={0,0} here is possible in two scenarios: + - the passed tv was already {0,0} meaning '1970-01-01 00:00:00 +00' + - the passed tv had some microseconds but they were rounded/truncated + to zero: '1970-01-01 00:00:00.1 +00' -> '1970-01-01 00:00:00 +00'. + It does not matter whether rounding/truncation really happened. + In both cases the call for store_TIMESTAMP(ts) above re-interpreted + '1970-01-01 00:00:00 +00:00' to zero date. Return 1 no matter what + sql_mode is. Even if sql_mode allows zero dates, there is still a problem + here: '1970-01-01 00:00:00 +00' could not be stored as-is! + */ + ErrConvString str(STRING_WITH_LEN("1970-01-01 00:00:00 +00:00"), + system_charset_info); + set_datetime_warning(ER_WARN_DATA_OUT_OF_RANGE, &str, "datetime", 1); + return 1; // '1970-01-01 00:00:00 +00' was converted to a zero date + } if (warn) { /* @@ -5416,9 +5443,6 @@ int Field_timestamp::store_timestamp_dec(const timeval &ts, uint dec) */ set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); } - if (ts.tv_sec == 0 && ts.tv_usec == 0 && - get_thd()->variables.sql_mode & (ulonglong) TIME_NO_ZERO_DATE) - return zero_time_stored_return_code_with_warning(); return 0; } @@ -5789,8 +5813,10 @@ my_time_t Field_timestampf::get_timestamp(const uchar *pos, bool Field_timestampf::val_native(Native *to) { DBUG_ASSERT(marked_for_read()); + char zero[8]= "\0\0\0\0\0\0\0"; + DBUG_ASSERT(pack_length () <= sizeof(zero)); // Check if it's '0000-00-00 00:00:00' rather than a real timestamp - if (ptr[0] == 0 && ptr[1] == 0 && ptr[2] == 0 && ptr[3] == 0) + if (!memcmp(ptr, zero, pack_length())) { to->length(0); return false; @@ -11481,6 +11507,30 @@ bool Field::validate_value_in_record_with_warn(THD *thd, const uchar *record) } +/** + Find which reaction should be for IGNORE value. +*/ + +ignore_value_reaction find_ignore_reaction(THD *thd) +{ + enum_sql_command com= thd->lex->sql_command; + + // All insert-like commands + if (com == SQLCOM_INSERT || com == SQLCOM_REPLACE || + com == SQLCOM_INSERT_SELECT || com == SQLCOM_REPLACE_SELECT || + com == SQLCOM_LOAD) + { + return IGNORE_MEANS_DEFAULT; + } + // Update commands + if (com == SQLCOM_UPDATE || com == SQLCOM_UPDATE_MULTI) + { + return IGNORE_MEANS_FIELD_VALUE; + } + return IGNORE_MEANS_ERROR; +} + + bool Field::save_in_field_default_value(bool view_error_processing) { THD *thd= table->in_use; -- cgit v1.2.3