mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
MDEV-17460 Move the code from Item_extract::val_int() to a new class Extract_source
This commit is contained in:
@ -2119,66 +2119,42 @@ bool Item_extract::fix_length_and_dec()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint Extract_source::week(THD *thd) const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(is_valid_extract_source());
|
||||||
|
uint year;
|
||||||
|
ulong week_format= current_thd->variables.default_week_format;
|
||||||
|
return calc_week(this, week_mode(week_format), &year);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
longlong Item_extract::val_int()
|
longlong Item_extract::val_int()
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed == 1);
|
DBUG_ASSERT(fixed == 1);
|
||||||
MYSQL_TIME ltime;
|
Extract_source dt(current_thd, args[0], m_date_mode);
|
||||||
uint year;
|
if ((null_value= !dt.is_valid_extract_source()))
|
||||||
ulong week_format;
|
|
||||||
long neg;
|
|
||||||
date_mode_t is_time_flag = date_value ? date_mode_t(0) : TIME_TIME_ONLY;
|
|
||||||
|
|
||||||
// Not using get_arg0_date to avoid automatic TIME to DATETIME conversion
|
|
||||||
if ((null_value= args[0]->get_date(current_thd, <ime, is_time_flag)))
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
neg= ltime.neg ? -1 : 1;
|
|
||||||
|
|
||||||
DBUG_ASSERT(ltime.time_type != MYSQL_TIMESTAMP_TIME || ltime.day == 0);
|
|
||||||
if (ltime.time_type == MYSQL_TIMESTAMP_TIME)
|
|
||||||
time_to_daytime_interval(<ime);
|
|
||||||
|
|
||||||
switch (int_type) {
|
switch (int_type) {
|
||||||
case INTERVAL_YEAR: return ltime.year;
|
case INTERVAL_YEAR: return dt.year();
|
||||||
case INTERVAL_YEAR_MONTH: return ltime.year*100L+ltime.month;
|
case INTERVAL_YEAR_MONTH: return dt.year_month();
|
||||||
case INTERVAL_QUARTER: return (ltime.month+2)/3;
|
case INTERVAL_QUARTER: return dt.quarter();
|
||||||
case INTERVAL_MONTH: return ltime.month;
|
case INTERVAL_MONTH: return dt.month();
|
||||||
case INTERVAL_WEEK:
|
case INTERVAL_WEEK: return dt.week(current_thd);
|
||||||
{
|
case INTERVAL_DAY: return dt.day();
|
||||||
week_format= current_thd->variables.default_week_format;
|
case INTERVAL_DAY_HOUR: return dt.day_hour();
|
||||||
return calc_week(<ime, week_mode(week_format), &year);
|
case INTERVAL_DAY_MINUTE: return dt.day_minute();
|
||||||
}
|
case INTERVAL_DAY_SECOND: return dt.day_second();
|
||||||
case INTERVAL_DAY: return (long) ltime.day * neg;
|
case INTERVAL_HOUR: return dt.hour();
|
||||||
case INTERVAL_DAY_HOUR: return (long) (ltime.day*100L+ltime.hour)*neg;
|
case INTERVAL_HOUR_MINUTE: return dt.hour_minute();
|
||||||
case INTERVAL_DAY_MINUTE: return (long) (ltime.day*10000L+
|
case INTERVAL_HOUR_SECOND: return dt.hour_second();
|
||||||
ltime.hour*100L+
|
case INTERVAL_MINUTE: return dt.minute();
|
||||||
ltime.minute)*neg;
|
case INTERVAL_MINUTE_SECOND: return dt.minute_second();
|
||||||
case INTERVAL_DAY_SECOND: return ((longlong) ltime.day*1000000L+
|
case INTERVAL_SECOND: return dt.second();
|
||||||
(longlong) (ltime.hour*10000L+
|
case INTERVAL_MICROSECOND: return dt.microsecond();
|
||||||
ltime.minute*100+
|
case INTERVAL_DAY_MICROSECOND: return dt.day_microsecond();
|
||||||
ltime.second))*neg;
|
case INTERVAL_HOUR_MICROSECOND: return dt.hour_microsecond();
|
||||||
case INTERVAL_HOUR: return (long) ltime.hour*neg;
|
case INTERVAL_MINUTE_MICROSECOND: return dt.minute_microsecond();
|
||||||
case INTERVAL_HOUR_MINUTE: return (long) (ltime.hour*100+ltime.minute)*neg;
|
case INTERVAL_SECOND_MICROSECOND: return dt.second_microsecond();
|
||||||
case INTERVAL_HOUR_SECOND: return (long) (ltime.hour*10000+ltime.minute*100+
|
|
||||||
ltime.second)*neg;
|
|
||||||
case INTERVAL_MINUTE: return (long) ltime.minute*neg;
|
|
||||||
case INTERVAL_MINUTE_SECOND: return (long) (ltime.minute*100+ltime.second)*neg;
|
|
||||||
case INTERVAL_SECOND: return (long) ltime.second*neg;
|
|
||||||
case INTERVAL_MICROSECOND: return (long) ltime.second_part*neg;
|
|
||||||
case INTERVAL_DAY_MICROSECOND: return (((longlong)ltime.day*1000000L +
|
|
||||||
(longlong)ltime.hour*10000L +
|
|
||||||
ltime.minute*100 +
|
|
||||||
ltime.second)*1000000L +
|
|
||||||
ltime.second_part)*neg;
|
|
||||||
case INTERVAL_HOUR_MICROSECOND: return (((longlong)ltime.hour*10000L +
|
|
||||||
ltime.minute*100 +
|
|
||||||
ltime.second)*1000000L +
|
|
||||||
ltime.second_part)*neg;
|
|
||||||
case INTERVAL_MINUTE_MICROSECOND: return (((longlong)(ltime.minute*100+
|
|
||||||
ltime.second))*1000000L+
|
|
||||||
ltime.second_part)*neg;
|
|
||||||
case INTERVAL_SECOND_MICROSECOND: return ((longlong)ltime.second*1000000L+
|
|
||||||
ltime.second_part)*neg;
|
|
||||||
case INTERVAL_LAST: DBUG_ASSERT(0); break; /* purecov: deadcode */
|
case INTERVAL_LAST: DBUG_ASSERT(0); break; /* purecov: deadcode */
|
||||||
}
|
}
|
||||||
return 0; // Impossible
|
return 0; // Impossible
|
||||||
|
@ -964,9 +964,17 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Item_extract :public Item_int_func
|
class Item_extract :public Item_int_func,
|
||||||
|
public Type_handler_hybrid_field_type
|
||||||
{
|
{
|
||||||
bool date_value;
|
date_mode_t m_date_mode;
|
||||||
|
const Type_handler_int_result *handler_by_length(uint32 length,
|
||||||
|
uint32 threashold)
|
||||||
|
{
|
||||||
|
if (length >= threashold)
|
||||||
|
return &type_handler_longlong;
|
||||||
|
return &type_handler_long;
|
||||||
|
}
|
||||||
void set_date_length(uint32 length)
|
void set_date_length(uint32 length)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -975,53 +983,34 @@ class Item_extract :public Item_int_func
|
|||||||
because all around the code we assume that max_length is sign inclusive.
|
because all around the code we assume that max_length is sign inclusive.
|
||||||
Another options is to set unsigned_flag to "true".
|
Another options is to set unsigned_flag to "true".
|
||||||
*/
|
*/
|
||||||
max_length= length; //QQ: see above
|
set_handler(handler_by_length(max_length= length, 10)); // QQ: see above
|
||||||
date_value= true;
|
m_date_mode= date_mode_t(0);
|
||||||
}
|
}
|
||||||
void set_day_length(uint32 length)
|
void set_day_length(uint32 length)
|
||||||
{
|
{
|
||||||
max_length= length + 1/*sign*/; // e.g. '-24:00:00' -> -1
|
/*
|
||||||
date_value= true;
|
Units starting with DAY can be negative:
|
||||||
|
EXTRACT(DAY FROM '-24:00:00') -> -1
|
||||||
|
*/
|
||||||
|
set_handler(handler_by_length(max_length= length + 1/*sign*/, 11));
|
||||||
|
m_date_mode= date_mode_t(0);
|
||||||
}
|
}
|
||||||
void set_time_length(uint32 length)
|
void set_time_length(uint32 length)
|
||||||
{
|
{
|
||||||
max_length= length + 1/*sign*/;
|
set_handler(handler_by_length(max_length= length + 1/*sign*/, 11));
|
||||||
date_value= false;
|
m_date_mode= TIME_TIME_ONLY;
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
const interval_type int_type; // keep it public
|
const interval_type int_type; // keep it public
|
||||||
Item_extract(THD *thd, interval_type type_arg, Item *a):
|
Item_extract(THD *thd, interval_type type_arg, Item *a):
|
||||||
Item_int_func(thd, a), int_type(type_arg) {}
|
Item_int_func(thd, a),
|
||||||
|
Type_handler_hybrid_field_type(&type_handler_longlong),
|
||||||
|
m_date_mode(date_mode_t(0)),
|
||||||
|
int_type(type_arg)
|
||||||
|
{ }
|
||||||
const Type_handler *type_handler() const
|
const Type_handler *type_handler() const
|
||||||
{
|
{
|
||||||
switch (int_type) {
|
return Type_handler_hybrid_field_type::type_handler();
|
||||||
case INTERVAL_YEAR:
|
|
||||||
case INTERVAL_YEAR_MONTH:
|
|
||||||
case INTERVAL_QUARTER:
|
|
||||||
case INTERVAL_MONTH:
|
|
||||||
case INTERVAL_WEEK:
|
|
||||||
case INTERVAL_DAY:
|
|
||||||
case INTERVAL_DAY_HOUR:
|
|
||||||
case INTERVAL_DAY_MINUTE:
|
|
||||||
case INTERVAL_DAY_SECOND:
|
|
||||||
case INTERVAL_HOUR:
|
|
||||||
case INTERVAL_HOUR_MINUTE:
|
|
||||||
case INTERVAL_HOUR_SECOND:
|
|
||||||
case INTERVAL_MINUTE:
|
|
||||||
case INTERVAL_MINUTE_SECOND:
|
|
||||||
case INTERVAL_SECOND:
|
|
||||||
case INTERVAL_MICROSECOND:
|
|
||||||
case INTERVAL_SECOND_MICROSECOND:
|
|
||||||
return &type_handler_long;
|
|
||||||
case INTERVAL_DAY_MICROSECOND:
|
|
||||||
case INTERVAL_HOUR_MICROSECOND:
|
|
||||||
case INTERVAL_MINUTE_MICROSECOND:
|
|
||||||
return &type_handler_longlong;
|
|
||||||
case INTERVAL_LAST:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
DBUG_ASSERT(0);
|
|
||||||
return &type_handler_longlong;
|
|
||||||
}
|
}
|
||||||
longlong val_int();
|
longlong val_int();
|
||||||
enum Functype functype() const { return EXTRACT_FUNC; }
|
enum Functype functype() const { return EXTRACT_FUNC; }
|
||||||
|
@ -1218,26 +1218,6 @@ bool time_to_datetime(MYSQL_TIME *ltime)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Convert a TIME value to DAY-TIME interval, e.g. for extraction:
|
|
||||||
EXTRACT(DAY FROM x), EXTRACT(HOUR FROM x), etc.
|
|
||||||
Moves full days from ltime->hour to ltime->day.
|
|
||||||
Note, time_type is set to MYSQL_TIMESTAMP_NONE, to make sure that
|
|
||||||
the structure is not used for anything else other than extraction:
|
|
||||||
non-extraction TIME functions expect zero day value!
|
|
||||||
*/
|
|
||||||
void time_to_daytime_interval(MYSQL_TIME *ltime)
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(ltime->time_type == MYSQL_TIMESTAMP_TIME);
|
|
||||||
DBUG_ASSERT(ltime->year == 0);
|
|
||||||
DBUG_ASSERT(ltime->month == 0);
|
|
||||||
DBUG_ASSERT(ltime->day == 0);
|
|
||||||
ltime->day= ltime->hour / 24;
|
|
||||||
ltime->hour%= 24;
|
|
||||||
ltime->time_type= MYSQL_TIMESTAMP_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*** Conversion from TIME to DATETIME ***/
|
/*** Conversion from TIME to DATETIME ***/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -36,7 +36,6 @@ ulong convert_period_to_month(ulong period);
|
|||||||
ulong convert_month_to_period(ulong month);
|
ulong convert_month_to_period(ulong month);
|
||||||
void set_current_date(THD *thd, MYSQL_TIME *to);
|
void set_current_date(THD *thd, MYSQL_TIME *to);
|
||||||
bool time_to_datetime(MYSQL_TIME *ltime);
|
bool time_to_datetime(MYSQL_TIME *ltime);
|
||||||
void time_to_daytime_interval(MYSQL_TIME *l_time);
|
|
||||||
bool get_date_from_daynr(long daynr,uint *year, uint *month, uint *day);
|
bool get_date_from_daynr(long daynr,uint *year, uint *month, uint *day);
|
||||||
my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, uint *error_code);
|
my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, uint *error_code);
|
||||||
bool str_to_datetime_with_warn(THD *thd,
|
bool str_to_datetime_with_warn(THD *thd,
|
||||||
|
118
sql/sql_type.h
118
sql/sql_type.h
@ -478,6 +478,10 @@ protected:
|
|||||||
second <= TIME_MAX_SECOND &&
|
second <= TIME_MAX_SECOND &&
|
||||||
second_part <= TIME_MAX_SECOND_PART;
|
second_part <= TIME_MAX_SECOND_PART;
|
||||||
}
|
}
|
||||||
|
bool has_zero_YYYYMM() const
|
||||||
|
{
|
||||||
|
return year == 0 && month == 0;
|
||||||
|
}
|
||||||
bool has_zero_YYYYMMDD() const
|
bool has_zero_YYYYMMDD() const
|
||||||
{
|
{
|
||||||
return year == 0 && month == 0 && day == 0;
|
return year == 0 && month == 0 && day == 0;
|
||||||
@ -556,6 +560,120 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
This class resembles the SQL standard <extract source>,
|
||||||
|
used in extract expressions, e.g: EXTRACT(DAY FROM dt)
|
||||||
|
<extract expression> ::=
|
||||||
|
EXTRACT <left paren> <extract field> FROM <extract source> <right paren>
|
||||||
|
<extract source> ::= <datetime value expression> | <interval value expression>
|
||||||
|
*/
|
||||||
|
class Extract_source: public Temporal_hybrid
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Convert a TIME value to DAY-TIME interval, e.g. for extraction:
|
||||||
|
EXTRACT(DAY FROM x), EXTRACT(HOUR FROM x), etc.
|
||||||
|
Moves full days from ltime->hour to ltime->day.
|
||||||
|
*/
|
||||||
|
void time_to_daytime_interval()
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(time_type == MYSQL_TIMESTAMP_TIME);
|
||||||
|
DBUG_ASSERT(has_zero_YYYYMMDD());
|
||||||
|
MYSQL_TIME::day= MYSQL_TIME::hour / 24;
|
||||||
|
MYSQL_TIME::hour%= 24;
|
||||||
|
}
|
||||||
|
bool is_valid_extract_source_slow() const
|
||||||
|
{
|
||||||
|
return is_valid_temporal() && MYSQL_TIME::hour < 24 &&
|
||||||
|
(has_zero_YYYYMM() || time_type != MYSQL_TIMESTAMP_TIME);
|
||||||
|
}
|
||||||
|
bool is_valid_value_slow() const
|
||||||
|
{
|
||||||
|
return time_type == MYSQL_TIMESTAMP_NONE || is_valid_extract_source_slow();
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
Extract_source(THD *thd, Item *item, date_mode_t mode)
|
||||||
|
:Temporal_hybrid(thd, item, mode)
|
||||||
|
{
|
||||||
|
if (MYSQL_TIME::time_type == MYSQL_TIMESTAMP_TIME)
|
||||||
|
time_to_daytime_interval();
|
||||||
|
DBUG_ASSERT(is_valid_value_slow());
|
||||||
|
}
|
||||||
|
inline const MYSQL_TIME *get_mysql_time() const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(is_valid_extract_source_slow());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
bool is_valid_extract_source() const { return is_valid_temporal(); }
|
||||||
|
int sign() const { return get_mysql_time()->neg ? -1 : 1; }
|
||||||
|
uint year() const { return get_mysql_time()->year; }
|
||||||
|
uint month() const { return get_mysql_time()->month; }
|
||||||
|
int day() const { return (int) get_mysql_time()->day * sign(); }
|
||||||
|
int hour() const { return (int) get_mysql_time()->hour * sign(); }
|
||||||
|
int minute() const { return (int) get_mysql_time()->minute * sign(); }
|
||||||
|
int second() const { return (int) get_mysql_time()->second * sign(); }
|
||||||
|
int microsecond() const { return (int) get_mysql_time()->second_part * sign(); }
|
||||||
|
|
||||||
|
uint year_month() const { return year() * 100 + month(); }
|
||||||
|
uint quarter() const { return (month() + 2)/3; }
|
||||||
|
uint week(THD *thd) const;
|
||||||
|
|
||||||
|
longlong second_microsecond() const
|
||||||
|
{
|
||||||
|
return (second() * 1000000LL + microsecond());
|
||||||
|
}
|
||||||
|
|
||||||
|
// DAY TO XXX
|
||||||
|
longlong day_hour() const
|
||||||
|
{
|
||||||
|
return (longlong) day() * 100LL + hour();
|
||||||
|
}
|
||||||
|
longlong day_minute() const
|
||||||
|
{
|
||||||
|
return day_hour() * 100LL + minute();
|
||||||
|
}
|
||||||
|
longlong day_second() const
|
||||||
|
{
|
||||||
|
return day_minute() * 100LL + second();
|
||||||
|
}
|
||||||
|
longlong day_microsecond() const
|
||||||
|
{
|
||||||
|
return day_second() * 1000000LL + microsecond();
|
||||||
|
}
|
||||||
|
|
||||||
|
// HOUR TO XXX
|
||||||
|
int hour_minute() const
|
||||||
|
{
|
||||||
|
return hour() * 100 + minute();
|
||||||
|
}
|
||||||
|
int hour_second() const
|
||||||
|
{
|
||||||
|
return hour_minute() * 100 + second();
|
||||||
|
}
|
||||||
|
longlong hour_microsecond() const
|
||||||
|
{
|
||||||
|
return hour_second() * 1000000LL + microsecond();
|
||||||
|
}
|
||||||
|
|
||||||
|
// MINUTE TO XXX
|
||||||
|
int minute_second() const
|
||||||
|
{
|
||||||
|
return minute() * 100 + second();
|
||||||
|
}
|
||||||
|
longlong minute_microsecond() const
|
||||||
|
{
|
||||||
|
return minute_second() * 1000000LL + microsecond();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
This class is used for the "time_interval" argument of these SQL functions:
|
||||||
|
TIMESTAMP(tm,time_interval)
|
||||||
|
ADDTIME(tm,time_interval)
|
||||||
|
Features:
|
||||||
|
- DATE and DATETIME formats are treated as errors
|
||||||
|
- Preserves hours for TIME format as is, without limiting to TIME_MAX_HOUR
|
||||||
|
*/
|
||||||
class Interval_DDhhmmssff: public Temporal
|
class Interval_DDhhmmssff: public Temporal
|
||||||
{
|
{
|
||||||
static const LEX_CSTRING m_type_name;
|
static const LEX_CSTRING m_type_name;
|
||||||
|
Reference in New Issue
Block a user