diff options
Diffstat (limited to 'sql/item_timefunc.cc')
-rw-r--r-- | sql/item_timefunc.cc | 359 |
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(<ime, 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(<ime, 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(<ime); - return (double) TIME_to_ulonglong_datetime(<ime); + return ulonglong2double(TIME_to_ulonglong_datetime(<ime)); } @@ -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, <ime->year, <ime->month, - <ime->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,<ime->year,<ime->month,<ime->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]; |