summaryrefslogtreecommitdiff
path: root/sql/item_timefunc.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item_timefunc.cc')
-rw-r--r--sql/item_timefunc.cc359
1 files changed, 144 insertions, 215 deletions
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index b7c9086c127..59e1777f542 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -597,7 +597,7 @@ err:
strmake(buff, val_begin, min(length, sizeof(buff)-1));
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_WRONG_VALUE_FOR_TYPE, ER(ER_WRONG_VALUE_FOR_TYPE),
- date_time_type, buff, "str_to_time");
+ date_time_type, buff, "str_to_date");
}
DBUG_RETURN(1);
}
@@ -886,9 +886,9 @@ static bool get_interval_info(const char *str,uint length,CHARSET_INFO *cs,
{
i++;
/* Change values[0...i-1] -> values[0...count-1] */
- bmove_upp((char*) (values+count), (char*) (values+i),
+ bmove_upp((uchar*) (values+count), (uchar*) (values+i),
sizeof(*values)*i);
- bzero((char*) values, sizeof(*values)*(count-i));
+ bzero((uchar*) values, sizeof(*values)*(count-i));
break;
}
}
@@ -896,81 +896,6 @@ static bool get_interval_info(const char *str,uint length,CHARSET_INFO *cs,
}
-/*
- Calculate difference between two datetime values as seconds + microseconds.
-
- SYNOPSIS
- calc_time_diff()
- l_time1 - TIME/DATE/DATETIME value
- l_time2 - TIME/DATE/DATETIME value
- l_sign - 1 absolute values are substracted,
- -1 absolute values are added.
- seconds_out - Out parameter where difference between
- l_time1 and l_time2 in seconds is stored.
- microseconds_out- Out parameter where microsecond part of difference
- between l_time1 and l_time2 is stored.
-
- NOTE
- This function calculates difference between l_time1 and l_time2 absolute
- values. So one should set l_sign and correct result if he want to take
- signs into account (i.e. for TIME values).
-
- RETURN VALUES
- Returns sign of difference.
- 1 means negative result
- 0 means positive result
-
-*/
-
-bool calc_time_diff(MYSQL_TIME *l_time1, MYSQL_TIME *l_time2, int l_sign,
- longlong *seconds_out, long *microseconds_out)
-{
- long days;
- bool neg;
- longlong microseconds;
-
- /*
- We suppose that if first argument is MYSQL_TIMESTAMP_TIME
- the second argument should be TIMESTAMP_TIME also.
- We should check it before calc_time_diff call.
- */
- if (l_time1->time_type == MYSQL_TIMESTAMP_TIME) // Time value
- days= (long)l_time1->day - l_sign * (long)l_time2->day;
- else
- {
- days= calc_daynr((uint) l_time1->year,
- (uint) l_time1->month,
- (uint) l_time1->day);
- if (l_time2->time_type == MYSQL_TIMESTAMP_TIME)
- days-= l_sign * (long)l_time2->day;
- else
- days-= l_sign*calc_daynr((uint) l_time2->year,
- (uint) l_time2->month,
- (uint) l_time2->day);
- }
-
- microseconds= ((longlong)days*LL(86400) +
- (longlong)(l_time1->hour*3600L +
- l_time1->minute*60L +
- l_time1->second) -
- l_sign*(longlong)(l_time2->hour*3600L +
- l_time2->minute*60L +
- l_time2->second)) * LL(1000000) +
- (longlong)l_time1->second_part -
- l_sign*(longlong)l_time2->second_part;
-
- neg= 0;
- if (microseconds < 0)
- {
- microseconds= -microseconds;
- neg= 1;
- }
- *seconds_out= microseconds/1000000L;
- *microseconds_out= (long) (microseconds%1000000L);
- return neg;
-}
-
-
longlong Item_func_period_add::val_int()
{
DBUG_ASSERT(fixed == 1);
@@ -1009,6 +934,72 @@ longlong Item_func_to_days::val_int()
return (longlong) calc_daynr(ltime.year,ltime.month,ltime.day);
}
+
+/*
+ Get information about this Item tree monotonicity
+
+ SYNOPSIS
+ Item_func_to_days::get_monotonicity_info()
+
+ DESCRIPTION
+ Get information about monotonicity of the function represented by this item
+ tree.
+
+ RETURN
+ See enum_monotonicity_info.
+*/
+
+enum_monotonicity_info Item_func_to_days::get_monotonicity_info() const
+{
+ if (args[0]->type() == Item::FIELD_ITEM)
+ {
+ if (args[0]->field_type() == MYSQL_TYPE_DATE)
+ return MONOTONIC_STRICT_INCREASING;
+ if (args[0]->field_type() == MYSQL_TYPE_DATETIME)
+ return MONOTONIC_INCREASING;
+ }
+ return NON_MONOTONIC;
+}
+
+
+longlong Item_func_to_days::val_int_endpoint(bool left_endp, bool *incl_endp)
+{
+ DBUG_ASSERT(fixed == 1);
+ MYSQL_TIME ltime;
+ longlong res;
+ if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE))
+ {
+ /* got NULL, leave the incl_endp intact */
+ return LONGLONG_MIN;
+ }
+ res=(longlong) calc_daynr(ltime.year,ltime.month,ltime.day);
+
+ if (args[0]->field_type() == MYSQL_TYPE_DATE)
+ {
+ // TO_DAYS() is strictly monotonic for dates, leave incl_endp intact
+ return res;
+ }
+
+ /*
+ Handle the special but practically useful case of datetime values that
+ point to day bound ("strictly less" comparison stays intact):
+
+ col < '2007-09-15 00:00:00' -> TO_DAYS(col) < TO_DAYS('2007-09-15')
+
+ which is different from the general case ("strictly less" changes to
+ "less or equal"):
+
+ col < '2007-09-15 12:34:56' -> TO_DAYS(col) <= TO_DAYS('2007-09-15')
+ */
+ if (!left_endp && !(ltime.hour || ltime.minute || ltime.second ||
+ ltime.second_part))
+ ; /* do nothing */
+ else
+ *incl_endp= TRUE;
+ return res;
+}
+
+
longlong Item_func_dayofyear::val_int()
{
DBUG_ASSERT(fixed == 1);
@@ -1195,6 +1186,60 @@ longlong Item_func_year::val_int()
}
+/*
+ Get information about this Item tree monotonicity
+
+ SYNOPSIS
+ Item_func_year::get_monotonicity_info()
+
+ DESCRIPTION
+ Get information about monotonicity of the function represented by this item
+ tree.
+
+ RETURN
+ See enum_monotonicity_info.
+*/
+
+enum_monotonicity_info Item_func_year::get_monotonicity_info() const
+{
+ if (args[0]->type() == Item::FIELD_ITEM &&
+ (args[0]->field_type() == MYSQL_TYPE_DATE ||
+ args[0]->field_type() == MYSQL_TYPE_DATETIME))
+ return MONOTONIC_INCREASING;
+ return NON_MONOTONIC;
+}
+
+
+longlong Item_func_year::val_int_endpoint(bool left_endp, bool *incl_endp)
+{
+ DBUG_ASSERT(fixed == 1);
+ MYSQL_TIME ltime;
+ if (get_arg0_date(&ltime, TIME_FUZZY_DATE))
+ {
+ /* got NULL, leave the incl_endp intact */
+ return LONGLONG_MIN;
+ }
+
+ /*
+ Handle the special but practically useful case of datetime values that
+ point to year bound ("strictly less" comparison stays intact) :
+
+ col < '2007-01-01 00:00:00' -> YEAR(col) < 2007
+
+ which is different from the general case ("strictly less" changes to
+ "less or equal"):
+
+ col < '2007-09-15 23:00:00' -> YEAR(col) <= 2007
+ */
+ if (!left_endp && ltime.day == 1 && ltime.month == 1 &&
+ !(ltime.hour || ltime.minute || ltime.second || ltime.second_part))
+ ; /* do nothing */
+ else
+ *incl_endp= TRUE;
+ return ltime.year;
+}
+
+
longlong Item_func_unix_timestamp::val_int()
{
MYSQL_TIME ltime;
@@ -1206,7 +1251,7 @@ longlong Item_func_unix_timestamp::val_int()
if (args[0]->type() == FIELD_ITEM)
{ // Optimize timestamp field
Field *field=((Item_field*) args[0])->field;
- if (field->type() == FIELD_TYPE_TIMESTAMP)
+ if (field->type() == MYSQL_TYPE_TIMESTAMP)
return ((Field_timestamp*) field)->get_timestamp(&null_value);
}
@@ -1241,13 +1286,13 @@ longlong Item_func_time_to_sec::val_int()
To make code easy, allow interval objects without separators.
*/
-static bool get_interval_value(Item *args,interval_type int_type,
+bool get_interval_value(Item *args,interval_type int_type,
String *str_value, INTERVAL *interval)
{
ulonglong array[5];
longlong value;
const char *str;
- uint32 length;
+ size_t length;
CHARSET_INFO *cs=str_value->charset();
LINT_INIT(value);
@@ -1282,7 +1327,7 @@ static bool get_interval_value(Item *args,interval_type int_type,
interval->neg=1;
str++;
}
- length=(uint32) (end-str); // Set up pointers to new str
+ length= (size_t) (end-str); // Set up pointers to new str
}
switch (int_type) {
@@ -1389,6 +1434,9 @@ static bool get_interval_value(Item *args,interval_type int_type,
interval->second= array[0];
interval->second_part= array[1];
break;
+ case INTERVAL_LAST: /* purecov: begin deadcode */
+ DBUG_ASSERT(0);
+ break; /* purecov: end */
}
return 0;
}
@@ -1615,7 +1663,7 @@ int Item_func_now::save_in_field(Field *to, bool no_conversions)
void Item_func_sysdate_local::store_now_in_TIME(MYSQL_TIME *now_time)
{
THD *thd= current_thd;
- thd->variables.time_zone->gmt_sec_to_TIME(now_time, (my_time_t) time(NULL));
+ thd->variables.time_zone->gmt_sec_to_TIME(now_time, (my_time_t) my_time(0));
thd->time_zone_used= 1;
}
@@ -1642,7 +1690,7 @@ double Item_func_sysdate_local::val_real()
{
DBUG_ASSERT(fixed == 1);
store_now_in_TIME(&ltime);
- return (double) TIME_to_ulonglong_datetime(&ltime);
+ return ulonglong2double(TIME_to_ulonglong_datetime(&ltime));
}
@@ -1965,19 +2013,6 @@ void Item_func_convert_tz::fix_length_and_dec()
}
-bool
-Item_func_convert_tz::fix_fields(THD *thd_arg, Item **ref)
-{
- String str;
- if (Item_date_func::fix_fields(thd_arg, ref))
- return TRUE;
-
- tz_tables= thd_arg->lex->time_zone_tables_used;
-
- return FALSE;
-}
-
-
String *Item_func_convert_tz::val_str(String *str)
{
MYSQL_TIME time_tmp;
@@ -2013,16 +2048,17 @@ bool Item_func_convert_tz::get_date(MYSQL_TIME *ltime,
{
my_time_t my_time_tmp;
String str;
+ THD *thd= current_thd;
if (!from_tz_cached)
{
- from_tz= my_tz_find(args[1]->val_str(&str), tz_tables);
+ from_tz= my_tz_find(thd, args[1]->val_str(&str));
from_tz_cached= args[1]->const_item();
}
if (!to_tz_cached)
{
- to_tz= my_tz_find(args[2]->val_str(&str), tz_tables);
+ to_tz= my_tz_find(thd, args[2]->val_str(&str));
to_tz_cached= args[2]->const_item();
}
@@ -2091,115 +2127,18 @@ void Item_date_add_interval::fix_length_and_dec()
bool Item_date_add_interval::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
- long period,sign;
INTERVAL interval;
- ltime->neg= 0;
if (args[0]->get_date(ltime, TIME_NO_ZERO_DATE) ||
- get_interval_value(args[1],int_type,&value,&interval))
- goto null_date;
- sign= (interval.neg ? -1 : 1);
- if (date_sub_interval)
- sign = -sign;
+ get_interval_value(args[1], int_type, &value, &interval))
+ return (null_value=1);
- null_value=0;
- switch (int_type) {
- case INTERVAL_SECOND:
- case INTERVAL_SECOND_MICROSECOND:
- case INTERVAL_MICROSECOND:
- case INTERVAL_MINUTE:
- case INTERVAL_HOUR:
- case INTERVAL_MINUTE_MICROSECOND:
- case INTERVAL_MINUTE_SECOND:
- case INTERVAL_HOUR_MICROSECOND:
- case INTERVAL_HOUR_SECOND:
- case INTERVAL_HOUR_MINUTE:
- case INTERVAL_DAY_MICROSECOND:
- case INTERVAL_DAY_SECOND:
- case INTERVAL_DAY_MINUTE:
- case INTERVAL_DAY_HOUR:
- {
- longlong sec, days, daynr, microseconds, extra_sec;
- ltime->time_type= MYSQL_TIMESTAMP_DATETIME; // Return full date
- microseconds= ltime->second_part + sign*interval.second_part;
- extra_sec= microseconds/1000000L;
- microseconds= microseconds%1000000L;
-
- sec=((ltime->day-1)*3600*24L+ltime->hour*3600+ltime->minute*60+
- ltime->second +
- sign* (longlong) (interval.day*3600*24L +
- interval.hour*LL(3600)+interval.minute*LL(60)+
- interval.second))+ extra_sec;
- if (microseconds < 0)
- {
- microseconds+= LL(1000000);
- sec--;
- }
- days= sec/(3600*LL(24));
- sec-= days*3600*LL(24);
- if (sec < 0)
- {
- days--;
- sec+= 3600*LL(24);
- }
- ltime->second_part= (uint) microseconds;
- ltime->second= (uint) (sec % 60);
- ltime->minute= (uint) (sec/60 % 60);
- ltime->hour= (uint) (sec/3600);
- daynr= calc_daynr(ltime->year,ltime->month,1) + days;
- /* Day number from year 0 to 9999-12-31 */
- if ((ulonglong) daynr > MAX_DAY_NUMBER)
- goto invalid_date;
- get_date_from_daynr((long) daynr, &ltime->year, &ltime->month,
- &ltime->day);
- break;
- }
- case INTERVAL_DAY:
- case INTERVAL_WEEK:
- period= (calc_daynr(ltime->year,ltime->month,ltime->day) +
- sign * (long) interval.day);
- /* Daynumber from year 0 to 9999-12-31 */
- if ((ulong) period > MAX_DAY_NUMBER)
- goto invalid_date;
- get_date_from_daynr((long) period,&ltime->year,&ltime->month,&ltime->day);
- break;
- case INTERVAL_YEAR:
- ltime->year+= sign * (long) interval.year;
- if ((ulong) ltime->year >= 10000L)
- goto invalid_date;
- if (ltime->month == 2 && ltime->day == 29 &&
- calc_days_in_year(ltime->year) != 366)
- ltime->day=28; // Was leap-year
- break;
- case INTERVAL_YEAR_MONTH:
- case INTERVAL_QUARTER:
- case INTERVAL_MONTH:
- period= (ltime->year*12 + sign * (long) interval.year*12 +
- ltime->month-1 + sign * (long) interval.month);
- if ((ulong) period >= 120000L)
- goto invalid_date;
- ltime->year= (uint) (period / 12);
- ltime->month= (uint) (period % 12L)+1;
- /* Adjust day if the new month doesn't have enough days */
- if (ltime->day > days_in_month[ltime->month-1])
- {
- ltime->day = days_in_month[ltime->month-1];
- if (ltime->month == 2 && calc_days_in_year(ltime->year) == 366)
- ltime->day++; // Leap-year
- }
- break;
- default:
- goto null_date;
- }
- return 0; // Ok
+ if (date_sub_interval)
+ interval.neg = !interval.neg;
-invalid_date:
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_DATETIME_FUNCTION_OVERFLOW,
- ER(ER_DATETIME_FUNCTION_OVERFLOW),
- "datetime");
- null_date:
- return (null_value=1);
+ if ((null_value= date_add_interval(ltime, int_type, interval)))
+ return 1;
+ return 0;
}
@@ -2312,6 +2251,7 @@ void Item_extract::fix_length_and_dec()
case INTERVAL_HOUR_MICROSECOND: max_length=13; date_value=0; break;
case INTERVAL_MINUTE_MICROSECOND: max_length=11; date_value=0; break;
case INTERVAL_SECOND_MICROSECOND: max_length=9; date_value=0; break;
+ case INTERVAL_LAST: DBUG_ASSERT(0); break; /* purecov: deadcode */
}
}
@@ -2381,6 +2321,7 @@ longlong Item_extract::val_int()
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 */
}
return 0; // Impossible
}
@@ -3292,18 +3233,6 @@ get_date_time_result_type(const char *format, uint length)
}
-Field *Item_func_str_to_date::tmp_table_field(TABLE *t_arg)
-{
- if (cached_field_type == MYSQL_TYPE_TIME)
- return (new Field_time(maybe_null, name, t_arg, &my_charset_bin));
- if (cached_field_type == MYSQL_TYPE_DATE)
- return (new Field_date(maybe_null, name, t_arg, &my_charset_bin));
- if (cached_field_type == MYSQL_TYPE_DATETIME)
- return (new Field_datetime(maybe_null, name, t_arg, &my_charset_bin));
- return (new Field_string(max_length, maybe_null, name, t_arg, &my_charset_bin));
-}
-
-
void Item_func_str_to_date::fix_length_and_dec()
{
char format_buff[64];