summaryrefslogtreecommitdiffstats
path: root/sql/field.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 13:22:53 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 13:22:53 +0000
commit347c164c35eddab388009470e6848cb361ac93f8 (patch)
tree2c0c44eac690f510bb0a35b2a13b36d606b77b6b /sql/field.cc
parentReleasing progress-linux version 1:10.11.7-4~progress7.99u1. (diff)
downloadmariadb-347c164c35eddab388009470e6848cb361ac93f8.tar.xz
mariadb-347c164c35eddab388009470e6848cb361ac93f8.zip
Merging upstream version 1:10.11.8.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sql/field.cc')
-rw-r--r--sql/field.cc62
1 files changed, 56 insertions, 6 deletions
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;