mirror of
https://github.com/MariaDB/server.git
synced 2025-12-24 11:21:21 +03:00
MDEV-14032 SEC_TO_TIME executes side effect two times
- Adding a helper class Sec6 to store (neg,seconds,microseconds)
- Adding a helper class VSec6 (Sec6 with a flag for "IS NULL")
- Wrapping related functions as methods of Sec6;
* number_to_datetime()
* number_to_time()
* my_decimal2seconds()
* Item::get_seconds()
* A big piece of code in Item_func_sec_to_time::get_date()
- Using the new classes in places where second-to-temporal
conversion takes place:
* Field_timestamp::store(double)
* Field_timestamp::store(longlong)
* Field_timestamp_with_dec::store_decimal(my_decimal)
* Field_temporal_with_date::store(double)
* Field_temporal_with_date::store(longlong)
* Field_time::store(double)
* Field_time::store(longlong)
* Field_time::store_decimal(my_decimal)
* Field_temporal_with_date::store_decimal(my_decimal)
* get_interval_value()
* Item_func_sec_to_time::get_date()
* Item_func_from_unixtime::get_date()
* Item_func_maketime::get_date()
This change simplifies these methods and functions a lot.
- Warnings are now sent at VSec6 initialization time, when the source
data is available in its original data type representation.
If Sec6::to_time() or Sec6::to_datetime() truncate data again during
conversion to MYSQL_TIME, they send warnings, but only if no warnings
were sent during VSec6 initialization. This helps prevents double warnings.
The call for val_str() in Item_func_sec_to_time::get_date() is not
needed any more, so it's removed. This change actually fixes the problem.
As a good effect, FROM_UNIXTIME() and MAKETIME() now also send warnings
in case if the seconds arguments is out of range. Previously these
functions returned NULL silently.
- Splitting the code in the global function make_truncated_value_warning()
into a number of methods THD::raise_warning_xxxx().
This was needed to reuse the logic that chooses between:
* ER_TRUNCATED_WRONG_VALUE
* ER_WRONG_VALUE
* ER_TRUNCATED_WRONG_VALUE_FOR_FIELD
for non-temporal data types (Sec6).
- Removing:
* Item::get_seconds()
* number_to_time_with_warn()
as this code now resides inside methods of Sec6.
- Cleanup (changes that are not directly related to the fix):
* Removing calls for field_name_or_null() and passing NULL instead
in Item_func_hybrid_field_type::get_date_from_{int|real}_op,
because Item_func_hybrid_field_type::field_name_or_null()
always returns NULL
* Replacing a number of calls for make_truncated_value_warning()
to calls for THD::raise_warning_xxx(). In these places
we know that the execution went through a certain
branch of make_truncated_value_warning(),
(e.g. the exact error code is known, or field name is always NULL,
or field name is always not-NULL). So calls for the entire
make_truncated_value_warning() after splitting are not necessary.
This commit is contained in:
@@ -4372,6 +4372,69 @@ private:
|
||||
return raised;
|
||||
}
|
||||
|
||||
private:
|
||||
void push_warning_truncated_priv(Sql_condition::enum_warning_level level,
|
||||
uint sql_errno,
|
||||
const char *type_str, const char *val)
|
||||
{
|
||||
DBUG_ASSERT(sql_errno == ER_TRUNCATED_WRONG_VALUE ||
|
||||
sql_errno == ER_WRONG_VALUE);
|
||||
char buff[MYSQL_ERRMSG_SIZE];
|
||||
CHARSET_INFO *cs= &my_charset_latin1;
|
||||
cs->cset->snprintf(cs, buff, sizeof(buff),
|
||||
ER_THD(this, sql_errno), type_str, val);
|
||||
/*
|
||||
Note: the format string can vary between ER_TRUNCATED_WRONG_VALUE
|
||||
and ER_WRONG_VALUE, but the code passed to push_warning() is
|
||||
always ER_TRUNCATED_WRONG_VALUE. This is intentional.
|
||||
*/
|
||||
push_warning(this, level, ER_TRUNCATED_WRONG_VALUE, buff);
|
||||
}
|
||||
public:
|
||||
void push_warning_truncated_wrong_value(Sql_condition::enum_warning_level level,
|
||||
const char *type_str, const char *val)
|
||||
{
|
||||
return push_warning_truncated_priv(level, ER_TRUNCATED_WRONG_VALUE,
|
||||
type_str, val);
|
||||
}
|
||||
void push_warning_wrong_value(Sql_condition::enum_warning_level level,
|
||||
const char *type_str, const char *val)
|
||||
{
|
||||
return push_warning_truncated_priv(level, ER_WRONG_VALUE, type_str, val);
|
||||
}
|
||||
void push_warning_truncated_wrong_value(const char *type_str, const char *val)
|
||||
{
|
||||
return push_warning_truncated_wrong_value(Sql_condition::WARN_LEVEL_WARN,
|
||||
type_str, val);
|
||||
}
|
||||
void push_warning_truncated_value_for_field(Sql_condition::enum_warning_level
|
||||
level, const char *type_str,
|
||||
const char *val, const char *name)
|
||||
{
|
||||
DBUG_ASSERT(name);
|
||||
char buff[MYSQL_ERRMSG_SIZE];
|
||||
CHARSET_INFO *cs= &my_charset_latin1;
|
||||
cs->cset->snprintf(cs, buff, sizeof(buff),
|
||||
ER_THD(this, ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
|
||||
type_str, val, name,
|
||||
(ulong) get_stmt_da()->current_row_for_warning());
|
||||
push_warning(this, level, ER_TRUNCATED_WRONG_VALUE, buff);
|
||||
|
||||
}
|
||||
void push_warning_wrong_or_truncated_value(Sql_condition::enum_warning_level level,
|
||||
bool totally_useless_value,
|
||||
const char *type_str,
|
||||
const char *val,
|
||||
const char *field_name)
|
||||
{
|
||||
if (field_name)
|
||||
push_warning_truncated_value_for_field(level, type_str, val, field_name);
|
||||
else if (totally_useless_value)
|
||||
push_warning_wrong_value(level, type_str, val);
|
||||
else
|
||||
push_warning_truncated_wrong_value(level, type_str, val);
|
||||
}
|
||||
|
||||
public:
|
||||
/** Overloaded to guard query/query_length fields */
|
||||
virtual void set_statement(Statement *stmt);
|
||||
|
||||
Reference in New Issue
Block a user