Commit 2fe51a6f authored by Alexander Barkov's avatar Alexander Barkov

MDEV-17175 Change Time/Datetime constructors to return warnings in MYSQL_TIME_STATUS

parent 5567a8c9
...@@ -5093,9 +5093,9 @@ int Field_timestamp::store(const char *from,size_t len,CHARSET_INFO *cs) ...@@ -5093,9 +5093,9 @@ int Field_timestamp::store(const char *from,size_t len,CHARSET_INFO *cs)
{ {
ErrConvString str(from, len, cs); ErrConvString str(from, len, cs);
THD *thd= get_thd(); THD *thd= get_thd();
int error; MYSQL_TIME_STATUS st;
Datetime dt(&error, from, len, cs, sql_mode_for_timestamp(thd)); Datetime dt(&st, from, len, cs, sql_mode_for_timestamp(thd));
return store_TIME_with_warning(thd, &dt, &str, error); return store_TIME_with_warning(thd, &dt, &str, st.warnings);
} }
...@@ -5577,10 +5577,10 @@ int Field_temporal_with_date::store_TIME_with_warning(const Datetime *dt, ...@@ -5577,10 +5577,10 @@ int Field_temporal_with_date::store_TIME_with_warning(const Datetime *dt,
int Field_temporal_with_date::store(const char *from, size_t len, CHARSET_INFO *cs) int Field_temporal_with_date::store(const char *from, size_t len, CHARSET_INFO *cs)
{ {
int error; MYSQL_TIME_STATUS st;
ErrConvString str(from, len, cs); ErrConvString str(from, len, cs);
Datetime dt(&error, from, len, cs, sql_mode_for_dates(get_thd())); Datetime dt(&st, from, len, cs, sql_mode_for_dates(get_thd()));
return store_TIME_with_warning(&dt, &str, error); return store_TIME_with_warning(&dt, &str, st.warnings);
} }
int Field_temporal_with_date::store(double nr) int Field_temporal_with_date::store(double nr)
...@@ -5731,9 +5731,9 @@ void Field_time::store_TIME(const MYSQL_TIME *ltime) ...@@ -5731,9 +5731,9 @@ void Field_time::store_TIME(const MYSQL_TIME *ltime)
int Field_time::store(const char *from,size_t len,CHARSET_INFO *cs) int Field_time::store(const char *from,size_t len,CHARSET_INFO *cs)
{ {
ErrConvString str(from, len, cs); ErrConvString str(from, len, cs);
int error; MYSQL_TIME_STATUS st;
Time tm(&error, from, len, cs, sql_mode_for_dates(get_thd())); Time tm(&st, from, len, cs, sql_mode_for_dates(get_thd()));
return store_TIME_with_warning(&tm, &str, error); return store_TIME_with_warning(&tm, &str, st.warnings);
} }
......
...@@ -351,33 +351,43 @@ to_ascii(CHARSET_INFO *cs, ...@@ -351,33 +351,43 @@ to_ascii(CHARSET_INFO *cs,
} }
/* Character set-aware version of str_to_time() */ class TemporalAsciiBuffer: public LEX_CSTRING
bool
str_to_time(CHARSET_INFO *cs, const char *str, size_t length,
MYSQL_TIME *l_time, ulonglong fuzzydate, MYSQL_TIME_STATUS *status)
{ {
char cnv[32]; char cnv[32];
if ((cs->state & MY_CS_NONASCII) != 0) public:
TemporalAsciiBuffer(const char *str, size_t length, CHARSET_INFO *cs)
{ {
length= to_ascii(cs, str, length, cnv, sizeof(cnv)); if ((cs->state & MY_CS_NONASCII) != 0)
str= cnv; {
LEX_CSTRING::str= cnv;
LEX_CSTRING::length= to_ascii(cs, str, length, cnv, sizeof(cnv));
}
else
{
LEX_CSTRING::str= str;
LEX_CSTRING::length= length;
}
} }
return str_to_time(str, length, l_time, fuzzydate, status); };
/* Character set-aware version of str_to_time() */
bool Temporal::str_to_time(MYSQL_TIME_STATUS *status,
const char *str, size_t length, CHARSET_INFO *cs,
sql_mode_t fuzzydate)
{
TemporalAsciiBuffer tmp(str, length, cs);
return ::str_to_time(tmp.str, tmp.length, this, fuzzydate, status);
} }
/* Character set-aware version of str_to_datetime() */ /* Character set-aware version of str_to_datetime() */
bool str_to_datetime(CHARSET_INFO *cs, const char *str, size_t length, bool Temporal::str_to_datetime(MYSQL_TIME_STATUS *status,
MYSQL_TIME *l_time, ulonglong flags, const char *str, size_t length, CHARSET_INFO *cs,
MYSQL_TIME_STATUS *status) sql_mode_t flags)
{ {
char cnv[32]; TemporalAsciiBuffer tmp(str, length, cs);
if ((cs->state & MY_CS_NONASCII) != 0) return ::str_to_datetime(tmp.str, tmp.length, this, flags, status);
{
length= to_ascii(cs, str, length, cnv, sizeof(cnv));
str= cnv;
}
return str_to_datetime(str, length, l_time, flags, status);
} }
...@@ -396,7 +406,8 @@ str_to_datetime_with_warn(CHARSET_INFO *cs, ...@@ -396,7 +406,8 @@ str_to_datetime_with_warn(CHARSET_INFO *cs,
{ {
MYSQL_TIME_STATUS status; MYSQL_TIME_STATUS status;
THD *thd= current_thd; THD *thd= current_thd;
bool ret_val= str_to_datetime(cs, str, length, l_time, flags, &status); TemporalAsciiBuffer tmp(str, length, cs);
bool ret_val= str_to_datetime(tmp.str, tmp.length, l_time, flags, &status);
if (ret_val || status.warnings) if (ret_val || status.warnings)
{ {
const ErrConvString err(str, length, &my_charset_bin); const ErrConvString err(str, length, &my_charset_bin);
......
...@@ -126,15 +126,6 @@ int calc_weekday(long daynr,bool sunday_first_day_of_week); ...@@ -126,15 +126,6 @@ int calc_weekday(long daynr,bool sunday_first_day_of_week);
bool parse_date_time_format(timestamp_type format_type, bool parse_date_time_format(timestamp_type format_type,
const char *format, uint format_length, const char *format, uint format_length,
DATE_TIME_FORMAT *date_time_format); DATE_TIME_FORMAT *date_time_format);
/* Character set-aware version of str_to_time() */
bool str_to_time(CHARSET_INFO *cs, const char *str,size_t length,
MYSQL_TIME *l_time, ulonglong fuzzydate,
MYSQL_TIME_STATUS *status);
/* Character set-aware version of str_to_datetime() */
bool str_to_datetime(CHARSET_INFO *cs,
const char *str, size_t length,
MYSQL_TIME *l_time, ulonglong flags,
MYSQL_TIME_STATUS *status);
/* convenience wrapper */ /* convenience wrapper */
inline bool parse_date_time_format(timestamp_type format_type, inline bool parse_date_time_format(timestamp_type format_type,
......
...@@ -5489,17 +5489,19 @@ uint Type_handler::Item_datetime_precision(Item *item) const ...@@ -5489,17 +5489,19 @@ uint Type_handler::Item_datetime_precision(Item *item) const
uint Type_handler_string_result::Item_temporal_precision(Item *item, uint Type_handler_string_result::Item_temporal_precision(Item *item,
bool is_time) const bool is_time) const
{ {
MYSQL_TIME ltime;
StringBuffer<64> buf; StringBuffer<64> buf;
String *tmp; String *tmp;
MYSQL_TIME_STATUS status; MYSQL_TIME_STATUS status;
DBUG_ASSERT(item->is_fixed()); DBUG_ASSERT(item->is_fixed());
if ((tmp= item->val_str(&buf)) && if ((tmp= item->val_str(&buf)) &&
!(is_time ? (is_time ?
str_to_time(tmp->charset(), tmp->ptr(), tmp->length(), Time(&status, tmp->ptr(), tmp->length(), tmp->charset(),
&ltime, TIME_TIME_ONLY, &status) : Time::Options(TIME_TIME_ONLY,
str_to_datetime(tmp->charset(), tmp->ptr(), tmp->length(), Time::DATETIME_TO_TIME_YYYYMMDD_TRUNCATE)).
&ltime, TIME_FUZZY_DATES, &status))) is_valid_time() :
Datetime(&status, tmp->ptr(), tmp->length(), tmp->charset(),
TIME_FUZZY_DATES).
is_valid_datetime()))
return MY_MIN(status.precision, TIME_SECOND_PART_DIGITS); return MY_MIN(status.precision, TIME_SECOND_PART_DIGITS);
return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS); return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
} }
...@@ -7208,7 +7210,7 @@ static bool have_important_literal_warnings(const MYSQL_TIME_STATUS *status) ...@@ -7208,7 +7210,7 @@ static bool have_important_literal_warnings(const MYSQL_TIME_STATUS *status)
static void literal_warn(THD *thd, const Item *item, static void literal_warn(THD *thd, const Item *item,
const char *str, size_t length, CHARSET_INFO *cs, const char *str, size_t length, CHARSET_INFO *cs,
const MYSQL_TIME *ltime, timestamp_type time_type,
const MYSQL_TIME_STATUS *st, const MYSQL_TIME_STATUS *st,
const char *typestr, bool send_error) const char *typestr, bool send_error)
{ {
...@@ -7219,7 +7221,7 @@ static void literal_warn(THD *thd, const Item *item, ...@@ -7219,7 +7221,7 @@ static void literal_warn(THD *thd, const Item *item,
ErrConvString err(str, length, cs); ErrConvString err(str, length, cs);
make_truncated_value_warning(thd, make_truncated_value_warning(thd,
Sql_condition::time_warn_level(st->warnings), Sql_condition::time_warn_level(st->warnings),
&err, ltime->time_type, 0); &err, time_type, 0);
} }
} }
else if (send_error) else if (send_error)
...@@ -7238,13 +7240,14 @@ Type_handler_date_common::create_literal_item(THD *thd, ...@@ -7238,13 +7240,14 @@ Type_handler_date_common::create_literal_item(THD *thd,
bool send_error) const bool send_error) const
{ {
MYSQL_TIME_STATUS st; MYSQL_TIME_STATUS st;
MYSQL_TIME ltime;
Item_literal *item= NULL; Item_literal *item= NULL;
sql_mode_t flags= sql_mode_for_dates(thd); Temporal_hybrid tmp(&st, str, length, cs, sql_mode_for_dates(thd));
if (!str_to_datetime(cs, str, length, &ltime, flags, &st) && if (tmp.is_valid_temporal() &&
ltime.time_type == MYSQL_TIMESTAMP_DATE && !st.warnings) tmp.get_mysql_time()->time_type == MYSQL_TIMESTAMP_DATE &&
item= new (thd->mem_root) Item_date_literal(thd, &ltime); !have_important_literal_warnings(&st))
literal_warn(thd, item, str, length, cs, &ltime, &st, "DATE", send_error); item= new (thd->mem_root) Item_date_literal(thd, tmp.get_mysql_time());
literal_warn(thd, item, str, length, cs, MYSQL_TIMESTAMP_DATE,
&st, "DATE", send_error);
return item; return item;
} }
...@@ -7257,14 +7260,15 @@ Type_handler_temporal_with_date::create_literal_item(THD *thd, ...@@ -7257,14 +7260,15 @@ Type_handler_temporal_with_date::create_literal_item(THD *thd,
bool send_error) const bool send_error) const
{ {
MYSQL_TIME_STATUS st; MYSQL_TIME_STATUS st;
MYSQL_TIME ltime;
Item_literal *item= NULL; Item_literal *item= NULL;
sql_mode_t flags= sql_mode_for_dates(thd); Temporal_hybrid tmp(&st, str, length, cs, sql_mode_for_dates(thd));
if (!str_to_datetime(cs, str, length, &ltime, flags, &st) && if (tmp.is_valid_temporal() &&
ltime.time_type == MYSQL_TIMESTAMP_DATETIME && tmp.get_mysql_time()->time_type == MYSQL_TIMESTAMP_DATETIME &&
!have_important_literal_warnings(&st)) !have_important_literal_warnings(&st))
item= new (thd->mem_root) Item_datetime_literal(thd, &ltime, st.precision); item= new (thd->mem_root) Item_datetime_literal(thd, tmp.get_mysql_time(),
literal_warn(thd, item, str, length, cs, &ltime, &st, "DATETIME", send_error); st.precision);
literal_warn(thd, item, str, length, cs, MYSQL_TIMESTAMP_DATETIME,
&st, "DATETIME", send_error);
return item; return item;
} }
...@@ -7277,12 +7281,14 @@ Type_handler_time_common::create_literal_item(THD *thd, ...@@ -7277,12 +7281,14 @@ Type_handler_time_common::create_literal_item(THD *thd,
bool send_error) const bool send_error) const
{ {
MYSQL_TIME_STATUS st; MYSQL_TIME_STATUS st;
MYSQL_TIME ltime;
Item_literal *item= NULL; Item_literal *item= NULL;
if (!str_to_time(cs, str, length, &ltime, 0, &st) && Time::Options opt(TIME_TIME_ONLY, Time::DATETIME_TO_TIME_DISALLOW);
ltime.time_type == MYSQL_TIMESTAMP_TIME && Time tmp(&st, str, length, cs, opt);
if (tmp.is_valid_time() &&
!have_important_literal_warnings(&st)) !have_important_literal_warnings(&st))
item= new (thd->mem_root) Item_time_literal(thd, &ltime, st.precision); item= new (thd->mem_root) Item_time_literal(thd, tmp.get_mysql_time(),
literal_warn(thd, item, str, length, cs, &ltime, &st, "TIME", send_error); st.precision);
literal_warn(thd, item, str, length, cs, MYSQL_TIMESTAMP_TIME,
&st, "TIME", send_error);
return item; return item;
} }
...@@ -446,12 +446,13 @@ class VYear_op: public Year_null ...@@ -446,12 +446,13 @@ class VYear_op: public Year_null
class Temporal: protected MYSQL_TIME class Temporal: protected MYSQL_TIME
{ {
protected: public:
bool is_valid_temporal() const bool is_valid_temporal() const
{ {
DBUG_ASSERT(time_type != MYSQL_TIMESTAMP_ERROR); DBUG_ASSERT(time_type != MYSQL_TIMESTAMP_ERROR);
return time_type != MYSQL_TIMESTAMP_NONE; return time_type != MYSQL_TIMESTAMP_NONE;
} }
protected:
my_decimal *bad_to_decimal(my_decimal *to) const; my_decimal *bad_to_decimal(my_decimal *to) const;
my_decimal *to_decimal(my_decimal *to) const; my_decimal *to_decimal(my_decimal *to) const;
static double to_double(bool negate, ulonglong num, ulong frac) static double to_double(bool negate, ulonglong num, ulong frac)
...@@ -465,6 +466,10 @@ class Temporal: protected MYSQL_TIME ...@@ -465,6 +466,10 @@ class Temporal: protected MYSQL_TIME
*warn= MYSQL_TIME_WARN_OUT_OF_RANGE; *warn= MYSQL_TIME_WARN_OUT_OF_RANGE;
time_type= MYSQL_TIMESTAMP_NONE; time_type= MYSQL_TIMESTAMP_NONE;
} }
bool str_to_time(MYSQL_TIME_STATUS *st, const char *str, size_t length,
CHARSET_INFO *cs, sql_mode_t fuzzydate);
bool str_to_datetime(MYSQL_TIME_STATUS *st, const char *str, size_t length,
CHARSET_INFO *cs, sql_mode_t fuzzydate);
public: public:
long fraction_remainder(uint dec) const long fraction_remainder(uint dec) const
{ {
...@@ -483,6 +488,12 @@ class Temporal_hybrid: public Temporal ...@@ -483,6 +488,12 @@ class Temporal_hybrid: public Temporal
public: public:
Temporal_hybrid(THD *thd, Item *item); Temporal_hybrid(THD *thd, Item *item);
Temporal_hybrid(Item *item) { *this= Temporal_hybrid(current_thd, item); } Temporal_hybrid(Item *item) { *this= Temporal_hybrid(current_thd, item); }
Temporal_hybrid(MYSQL_TIME_STATUS *st, const char *str, size_t length,
CHARSET_INFO *cs, sql_mode_t fuzzydate)
{
if (str_to_datetime(st, str, length, cs, fuzzydate))
time_type= MYSQL_TIMESTAMP_NONE;
}
longlong to_longlong() const longlong to_longlong() const
{ {
if (!is_valid_temporal()) if (!is_valid_temporal())
...@@ -507,6 +518,11 @@ class Temporal_hybrid: public Temporal ...@@ -507,6 +518,11 @@ class Temporal_hybrid: public Temporal
str->length(my_TIME_to_str(this, const_cast<char*>(str->ptr()), dec)); str->length(my_TIME_to_str(this, const_cast<char*>(str->ptr()), dec));
return str; return str;
} }
const MYSQL_TIME *get_mysql_time() const
{
DBUG_ASSERT(is_valid_temporal());
return this;
}
}; };
...@@ -533,6 +549,7 @@ class Time: public Temporal ...@@ -533,6 +549,7 @@ class Time: public Temporal
public: public:
enum datetime_to_time_mode_t enum datetime_to_time_mode_t
{ {
DATETIME_TO_TIME_DISALLOW,
DATETIME_TO_TIME_YYYYMMDD_000000DD_MIX_TO_HOURS, DATETIME_TO_TIME_YYYYMMDD_000000DD_MIX_TO_HOURS,
DATETIME_TO_TIME_YYYYMMDD_TRUNCATE, DATETIME_TO_TIME_YYYYMMDD_TRUNCATE,
DATETIME_TO_TIME_YYYYMMDD_00000000_ONLY, DATETIME_TO_TIME_YYYYMMDD_00000000_ONLY,
...@@ -674,6 +691,8 @@ class Time: public Temporal ...@@ -674,6 +691,8 @@ class Time: public Temporal
DATETIME_TO_TIME_YYYYMMDD_00000000_ONLY && DATETIME_TO_TIME_YYYYMMDD_00000000_ONLY &&
(year || month || day)) (year || month || day))
make_from_out_of_range(warn); make_from_out_of_range(warn);
else if (opt.datetime_to_time_mode() == DATETIME_TO_TIME_DISALLOW)
make_from_out_of_range(warn);
else else
valid_datetime_to_valid_time(warn, opt); valid_datetime_to_valid_time(warn, opt);
break; break;
...@@ -729,15 +748,13 @@ class Time: public Temporal ...@@ -729,15 +748,13 @@ class Time: public Temporal
make_from_item(&warn, item, opt); make_from_item(&warn, item, opt);
} }
Time(int *warn, const MYSQL_TIME *from, long curdays); Time(int *warn, const MYSQL_TIME *from, long curdays);
Time(int *warn, const char *str, size_t len, CHARSET_INFO *cs, Time(MYSQL_TIME_STATUS *status, const char *str, size_t len, CHARSET_INFO *cs,
const Options opt) const Options opt)
{ {
MYSQL_TIME_STATUS status; if (str_to_time(status, str, len, cs, opt.get_date_flags()))
if (str_to_time(cs, str, len, this, opt.get_date_flags(), &status))
time_type= MYSQL_TIMESTAMP_NONE; time_type= MYSQL_TIMESTAMP_NONE;
// The below call will optionally add notes to already collected warnings: // The below call will optionally add notes to already collected warnings:
xxx_to_time_result_to_valid_value(&status.warnings, opt); xxx_to_time_result_to_valid_value(&status->warnings, opt);
*warn= status.warnings;
} }
Time(int *warn, const Sec6 &nr, const Options opt) Time(int *warn, const Sec6 &nr, const Options opt)
{ {
...@@ -885,14 +902,13 @@ class Temporal_with_date: public Temporal ...@@ -885,14 +902,13 @@ class Temporal_with_date: public Temporal
if (nr.to_datetime(this, flags, warn)) if (nr.to_datetime(this, flags, warn))
time_type= MYSQL_TIMESTAMP_NONE; time_type= MYSQL_TIMESTAMP_NONE;
} }
Temporal_with_date(int *warn, const char *str, size_t len, CHARSET_INFO *cs, Temporal_with_date(MYSQL_TIME_STATUS *status,
const char *str, size_t len, CHARSET_INFO *cs,
sql_mode_t flags) sql_mode_t flags)
{ {
DBUG_ASSERT((flags & TIME_TIME_ONLY) == 0); DBUG_ASSERT((flags & TIME_TIME_ONLY) == 0);
MYSQL_TIME_STATUS status; if (str_to_datetime(status, str, len, cs, flags))
if (str_to_datetime(cs, str, len, this, flags, &status))
time_type= MYSQL_TIMESTAMP_NONE; time_type= MYSQL_TIMESTAMP_NONE;
*warn= status.warnings;
} }
public: public:
bool check_date_with_warn(ulonglong flags) bool check_date_with_warn(ulonglong flags)
...@@ -1051,9 +1067,10 @@ class Datetime: public Temporal_with_date ...@@ -1051,9 +1067,10 @@ class Datetime: public Temporal_with_date
{ {
set_zero_time(this, MYSQL_TIMESTAMP_DATETIME); set_zero_time(this, MYSQL_TIMESTAMP_DATETIME);
} }
Datetime(int *warn, const char *str, size_t len, CHARSET_INFO *cs, Datetime(MYSQL_TIME_STATUS *status,
const char *str, size_t len, CHARSET_INFO *cs,
sql_mode_t flags) sql_mode_t flags)
:Temporal_with_date(warn, str, len, cs, flags) :Temporal_with_date(status, str, len, cs, flags)
{ {
date_to_datetime_if_needed(); date_to_datetime_if_needed();
DBUG_ASSERT(is_valid_value_slow()); DBUG_ASSERT(is_valid_value_slow());
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment