mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / sql / item_timefunc.cc
blob7d62956d84ceecb174483b1f474c12b2e725e501
1 /*
2 Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 /**
20 @file
22 @brief
23 This file defines all time functions
25 @todo
26 Move month and days to language files
29 #ifdef USE_PRAGMA_IMPLEMENTATION
30 #pragma implementation // gcc: Class implementation
31 #endif
33 #include "mysql_priv.h"
34 #include <m_ctype.h>
35 #include <time.h>
37 /** Day number for Dec 31st, 9999. */
38 #define MAX_DAY_NUMBER 3652424L
40 /**
41 @todo
42 OPTIMIZATION
43 - Replace the switch with a function that should be called for each
44 date type.
45 - Remove sprintf and opencode the conversion, like we do in
46 Field_datetime.
48 The reason for this functions existence is that as we don't have a
49 way to know if a datetime/time value has microseconds in them
50 we are now only adding microseconds to the output if the
51 value has microseconds.
53 We can't use a standard make_date_time() for this as we don't know
54 if someone will use %f in the format specifier in which case we would get
55 the microseconds twice.
58 static bool make_datetime(date_time_format_types format, MYSQL_TIME *ltime,
59 String *str)
61 char *buff;
62 CHARSET_INFO *cs= &my_charset_bin;
63 uint length= MAX_DATE_STRING_REP_LENGTH;
65 if (str->alloc(length))
66 return 1;
67 buff= (char*) str->ptr();
69 switch (format) {
70 case TIME_ONLY:
71 length= cs->cset->snprintf(cs, buff, length, "%s%02d:%02d:%02d",
72 ltime->neg ? "-" : "",
73 ltime->hour, ltime->minute, ltime->second);
74 break;
75 case TIME_MICROSECOND:
76 length= cs->cset->snprintf(cs, buff, length, "%s%02d:%02d:%02d.%06ld",
77 ltime->neg ? "-" : "",
78 ltime->hour, ltime->minute, ltime->second,
79 ltime->second_part);
80 break;
81 case DATE_ONLY:
82 length= cs->cset->snprintf(cs, buff, length, "%04d-%02d-%02d",
83 ltime->year, ltime->month, ltime->day);
84 break;
85 case DATE_TIME:
86 length= cs->cset->snprintf(cs, buff, length,
87 "%04d-%02d-%02d %02d:%02d:%02d",
88 ltime->year, ltime->month, ltime->day,
89 ltime->hour, ltime->minute, ltime->second);
90 break;
91 case DATE_TIME_MICROSECOND:
92 length= cs->cset->snprintf(cs, buff, length,
93 "%04d-%02d-%02d %02d:%02d:%02d.%06ld",
94 ltime->year, ltime->month, ltime->day,
95 ltime->hour, ltime->minute, ltime->second,
96 ltime->second_part);
97 break;
100 str->length(length);
101 str->set_charset(cs);
102 return 0;
107 Wrapper over make_datetime() with validation of the input MYSQL_TIME value
109 NOTE
110 see make_datetime() for more information
112 RETURN
113 1 if there was an error during converion
114 0 otherwise
117 static bool make_datetime_with_warn(date_time_format_types format, MYSQL_TIME *ltime,
118 String *str)
120 int warning= 0;
122 if (make_datetime(format, ltime, str))
123 return 1;
124 if (check_time_range(ltime, &warning))
125 return 1;
126 if (!warning)
127 return 0;
129 make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
130 str->ptr(), str->length(),
131 MYSQL_TIMESTAMP_TIME, NullS);
132 return make_datetime(format, ltime, str);
137 Wrapper over make_time() with validation of the input MYSQL_TIME value
139 NOTE
140 see make_time() for more info
142 RETURN
143 1 if there was an error during conversion
144 0 otherwise
147 static bool make_time_with_warn(const DATE_TIME_FORMAT *format,
148 MYSQL_TIME *l_time, String *str)
150 int warning= 0;
151 make_time(format, l_time, str);
152 if (check_time_range(l_time, &warning))
153 return 1;
154 if (warning)
156 make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
157 str->ptr(), str->length(),
158 MYSQL_TIMESTAMP_TIME, NullS);
159 make_time(format, l_time, str);
162 return 0;
167 Convert seconds to MYSQL_TIME value with overflow checking
169 SYNOPSIS:
170 sec_to_time()
171 seconds number of seconds
172 unsigned_flag 1, if 'seconds' is unsigned, 0, otherwise
173 ltime output MYSQL_TIME value
175 DESCRIPTION
176 If the 'seconds' argument is inside MYSQL_TIME data range, convert it to a
177 corresponding value.
178 Otherwise, truncate the resulting value to the nearest endpoint, and
179 produce a warning message.
181 RETURN
182 1 if the value was truncated during conversion
183 0 otherwise
186 static bool sec_to_time(longlong seconds, bool unsigned_flag, MYSQL_TIME *ltime)
188 uint sec;
190 bzero((char *)ltime, sizeof(*ltime));
192 if (seconds < 0)
194 if (unsigned_flag)
195 goto overflow;
196 ltime->neg= 1;
197 if (seconds < -3020399)
198 goto overflow;
199 seconds= -seconds;
201 else if (seconds > 3020399)
202 goto overflow;
204 sec= (uint) ((ulonglong) seconds % 3600);
205 ltime->hour= (uint) (seconds/3600);
206 ltime->minute= sec/60;
207 ltime->second= sec % 60;
209 return 0;
211 overflow:
212 ltime->hour= TIME_MAX_HOUR;
213 ltime->minute= TIME_MAX_MINUTE;
214 ltime->second= TIME_MAX_SECOND;
216 char buf[22];
217 int len= (int)(longlong10_to_str(seconds, buf, unsigned_flag ? 10 : -10)
218 - buf);
219 make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
220 buf, len, MYSQL_TIMESTAMP_TIME,
221 NullS);
223 return 1;
228 Date formats corresponding to compound %r and %T conversion specifiers
230 Note: We should init at least first element of "positions" array
231 (first member) or hpux11 compiler will die horribly.
233 static DATE_TIME_FORMAT time_ampm_format= {{0}, '\0', 0,
234 {(char *)"%I:%i:%S %p", 11}};
235 static DATE_TIME_FORMAT time_24hrs_format= {{0}, '\0', 0,
236 {(char *)"%H:%i:%S", 8}};
239 Extract datetime value to MYSQL_TIME struct from string value
240 according to format string.
242 @param format date/time format specification
243 @param val String to decode
244 @param length Length of string
245 @param l_time Store result here
246 @param cached_timestamp_type It uses to get an appropriate warning
247 in the case when the value is truncated.
248 @param sub_pattern_end if non-zero then we are parsing string which
249 should correspond compound specifier (like %T or
250 %r) and this parameter is pointer to place where
251 pointer to end of string matching this specifier
252 should be stored.
254 @note
255 Possibility to parse strings matching to patterns equivalent to compound
256 specifiers is mainly intended for use from inside of this function in
257 order to understand %T and %r conversion specifiers, so number of
258 conversion specifiers that can be used in such sub-patterns is limited.
259 Also most of checks are skipped in this case.
261 @note
262 If one adds new format specifiers to this function he should also
263 consider adding them to get_date_time_result_type() function.
265 @retval
266 0 ok
267 @retval
268 1 error
271 static bool extract_date_time(DATE_TIME_FORMAT *format,
272 const char *val, uint length, MYSQL_TIME *l_time,
273 timestamp_type cached_timestamp_type,
274 const char **sub_pattern_end,
275 const char *date_time_type)
277 int weekday= 0, yearday= 0, daypart= 0;
278 int week_number= -1;
279 int error= 0;
280 int strict_week_number_year= -1;
281 int frac_part;
282 bool usa_time= 0;
283 bool UNINIT_VAR(sunday_first_n_first_week_non_iso);
284 bool UNINIT_VAR(strict_week_number);
285 bool UNINIT_VAR(strict_week_number_year_type);
286 const char *val_begin= val;
287 const char *val_end= val + length;
288 const char *ptr= format->format.str;
289 const char *end= ptr + format->format.length;
290 CHARSET_INFO *cs= &my_charset_bin;
291 DBUG_ENTER("extract_date_time");
293 if (!sub_pattern_end)
294 bzero((char*) l_time, sizeof(*l_time));
296 for (; ptr != end && val != val_end; ptr++)
298 /* Skip pre-space between each argument */
299 if ((val+= cs->cset->scan(cs, val, val_end, MY_SEQ_SPACES)) >= val_end)
300 break;
302 if (*ptr == '%' && ptr+1 != end)
304 int val_len;
305 char *tmp;
307 error= 0;
309 val_len= (uint) (val_end - val);
310 switch (*++ptr) {
311 /* Year */
312 case 'Y':
313 tmp= (char*) val + min(4, val_len);
314 l_time->year= (int) my_strtoll10(val, &tmp, &error);
315 if ((int) (tmp-val) <= 2)
316 l_time->year= year_2000_handling(l_time->year);
317 val= tmp;
318 break;
319 case 'y':
320 tmp= (char*) val + min(2, val_len);
321 l_time->year= (int) my_strtoll10(val, &tmp, &error);
322 val= tmp;
323 l_time->year= year_2000_handling(l_time->year);
324 break;
326 /* Month */
327 case 'm':
328 case 'c':
329 tmp= (char*) val + min(2, val_len);
330 l_time->month= (int) my_strtoll10(val, &tmp, &error);
331 val= tmp;
332 break;
333 case 'M':
334 if ((l_time->month= check_word(my_locale_en_US.month_names,
335 val, val_end, &val)) <= 0)
336 goto err;
337 break;
338 case 'b':
339 if ((l_time->month= check_word(my_locale_en_US.ab_month_names,
340 val, val_end, &val)) <= 0)
341 goto err;
342 break;
343 /* Day */
344 case 'd':
345 case 'e':
346 tmp= (char*) val + min(2, val_len);
347 l_time->day= (int) my_strtoll10(val, &tmp, &error);
348 val= tmp;
349 break;
350 case 'D':
351 tmp= (char*) val + min(2, val_len);
352 l_time->day= (int) my_strtoll10(val, &tmp, &error);
353 /* Skip 'st, 'nd, 'th .. */
354 val= tmp + min((int) (val_end-tmp), 2);
355 break;
357 /* Hour */
358 case 'h':
359 case 'I':
360 case 'l':
361 usa_time= 1;
362 /* fall through */
363 case 'k':
364 case 'H':
365 tmp= (char*) val + min(2, val_len);
366 l_time->hour= (int) my_strtoll10(val, &tmp, &error);
367 val= tmp;
368 break;
370 /* Minute */
371 case 'i':
372 tmp= (char*) val + min(2, val_len);
373 l_time->minute= (int) my_strtoll10(val, &tmp, &error);
374 val= tmp;
375 break;
377 /* Second */
378 case 's':
379 case 'S':
380 tmp= (char*) val + min(2, val_len);
381 l_time->second= (int) my_strtoll10(val, &tmp, &error);
382 val= tmp;
383 break;
385 /* Second part */
386 case 'f':
387 tmp= (char*) val_end;
388 if (tmp - val > 6)
389 tmp= (char*) val + 6;
390 l_time->second_part= (int) my_strtoll10(val, &tmp, &error);
391 frac_part= 6 - (int) (tmp - val);
392 if (frac_part > 0)
393 l_time->second_part*= (ulong) log_10_int[frac_part];
394 val= tmp;
395 break;
397 /* AM / PM */
398 case 'p':
399 if (val_len < 2 || ! usa_time)
400 goto err;
401 if (!my_strnncoll(&my_charset_latin1,
402 (const uchar *) val, 2,
403 (const uchar *) "PM", 2))
404 daypart= 12;
405 else if (my_strnncoll(&my_charset_latin1,
406 (const uchar *) val, 2,
407 (const uchar *) "AM", 2))
408 goto err;
409 val+= 2;
410 break;
412 /* Exotic things */
413 case 'W':
414 if ((weekday= check_word(my_locale_en_US.day_names, val, val_end, &val)) <= 0)
415 goto err;
416 break;
417 case 'a':
418 if ((weekday= check_word(my_locale_en_US.ab_day_names, val, val_end, &val)) <= 0)
419 goto err;
420 break;
421 case 'w':
422 tmp= (char*) val + 1;
423 if ((weekday= (int) my_strtoll10(val, &tmp, &error)) < 0 ||
424 weekday >= 7)
425 goto err;
426 /* We should use the same 1 - 7 scale for %w as for %W */
427 if (!weekday)
428 weekday= 7;
429 val= tmp;
430 break;
431 case 'j':
432 tmp= (char*) val + min(val_len, 3);
433 yearday= (int) my_strtoll10(val, &tmp, &error);
434 val= tmp;
435 break;
437 /* Week numbers */
438 case 'V':
439 case 'U':
440 case 'v':
441 case 'u':
442 sunday_first_n_first_week_non_iso= (*ptr=='U' || *ptr== 'V');
443 strict_week_number= (*ptr=='V' || *ptr=='v');
444 tmp= (char*) val + min(val_len, 2);
445 if ((week_number= (int) my_strtoll10(val, &tmp, &error)) < 0 ||
446 (strict_week_number && !week_number) ||
447 week_number > 53)
448 goto err;
449 val= tmp;
450 break;
452 /* Year used with 'strict' %V and %v week numbers */
453 case 'X':
454 case 'x':
455 strict_week_number_year_type= (*ptr=='X');
456 tmp= (char*) val + min(4, val_len);
457 strict_week_number_year= (int) my_strtoll10(val, &tmp, &error);
458 val= tmp;
459 break;
461 /* Time in AM/PM notation */
462 case 'r':
464 We can't just set error here, as we don't want to generate two
465 warnings in case of errors
467 if (extract_date_time(&time_ampm_format, val,
468 (uint)(val_end - val), l_time,
469 cached_timestamp_type, &val, "time"))
470 DBUG_RETURN(1);
471 break;
473 /* Time in 24-hour notation */
474 case 'T':
475 if (extract_date_time(&time_24hrs_format, val,
476 (uint)(val_end - val), l_time,
477 cached_timestamp_type, &val, "time"))
478 DBUG_RETURN(1);
479 break;
481 /* Conversion specifiers that match classes of characters */
482 case '.':
483 while (my_ispunct(cs, *val) && val != val_end)
484 val++;
485 break;
486 case '@':
487 while (my_isalpha(cs, *val) && val != val_end)
488 val++;
489 break;
490 case '#':
491 while (my_isdigit(cs, *val) && val != val_end)
492 val++;
493 break;
494 default:
495 goto err;
497 if (error) // Error from my_strtoll10
498 goto err;
500 else if (!my_isspace(cs, *ptr))
502 if (*val != *ptr)
503 goto err;
504 val++;
507 if (usa_time)
509 if (l_time->hour > 12 || l_time->hour < 1)
510 goto err;
511 l_time->hour= l_time->hour%12+daypart;
515 If we are recursively called for parsing string matching compound
516 specifiers we are already done.
518 if (sub_pattern_end)
520 *sub_pattern_end= val;
521 DBUG_RETURN(0);
524 if (yearday > 0)
526 uint days;
527 days= calc_daynr(l_time->year,1,1) + yearday - 1;
528 if (days <= 0 || days > MAX_DAY_NUMBER)
529 goto err;
530 get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day);
533 if (week_number >= 0 && weekday)
535 int days;
536 uint weekday_b;
539 %V,%v require %X,%x resprectively,
540 %U,%u should be used with %Y and not %X or %x
542 if ((strict_week_number &&
543 (strict_week_number_year < 0 ||
544 strict_week_number_year_type != sunday_first_n_first_week_non_iso)) ||
545 (!strict_week_number && strict_week_number_year >= 0))
546 goto err;
548 /* Number of days since year 0 till 1st Jan of this year */
549 days= calc_daynr((strict_week_number ? strict_week_number_year :
550 l_time->year),
551 1, 1);
552 /* Which day of week is 1st Jan of this year */
553 weekday_b= calc_weekday(days, sunday_first_n_first_week_non_iso);
556 Below we are going to sum:
557 1) number of days since year 0 till 1st day of 1st week of this year
558 2) number of days between 1st week and our week
559 3) and position of our day in the week
561 if (sunday_first_n_first_week_non_iso)
563 days+= ((weekday_b == 0) ? 0 : 7) - weekday_b +
564 (week_number - 1) * 7 +
565 weekday % 7;
567 else
569 days+= ((weekday_b <= 3) ? 0 : 7) - weekday_b +
570 (week_number - 1) * 7 +
571 (weekday - 1);
574 if (days <= 0 || days > MAX_DAY_NUMBER)
575 goto err;
576 get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day);
579 if (l_time->month > 12 || l_time->day > 31 || l_time->hour > 23 ||
580 l_time->minute > 59 || l_time->second > 59)
581 goto err;
583 if (val != val_end)
587 if (!my_isspace(&my_charset_latin1,*val))
589 make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
590 val_begin, length,
591 cached_timestamp_type, NullS);
592 break;
594 } while (++val != val_end);
596 DBUG_RETURN(0);
598 err:
600 char buff[128];
601 strmake(buff, val_begin, min(length, sizeof(buff)-1));
602 push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
603 ER_WRONG_VALUE_FOR_TYPE, ER(ER_WRONG_VALUE_FOR_TYPE),
604 date_time_type, buff, "str_to_date");
606 DBUG_RETURN(1);
611 Create a formated date/time value in a string.
614 bool make_date_time(DATE_TIME_FORMAT *format, MYSQL_TIME *l_time,
615 timestamp_type type, String *str)
617 char intbuff[15];
618 uint hours_i;
619 uint weekday;
620 ulong length;
621 const char *ptr, *end;
622 THD *thd= current_thd;
623 MY_LOCALE *locale= thd->variables.lc_time_names;
625 str->length(0);
627 if (l_time->neg)
628 str->append('-');
630 end= (ptr= format->format.str) + format->format.length;
631 for (; ptr != end ; ptr++)
633 if (*ptr != '%' || ptr+1 == end)
634 str->append(*ptr);
635 else
637 switch (*++ptr) {
638 case 'M':
639 if (!l_time->month)
640 return 1;
641 str->append(locale->month_names->type_names[l_time->month-1],
642 (uint) strlen(locale->month_names->type_names[l_time->month-1]),
643 system_charset_info);
644 break;
645 case 'b':
646 if (!l_time->month)
647 return 1;
648 str->append(locale->ab_month_names->type_names[l_time->month-1],
649 (uint) strlen(locale->ab_month_names->type_names[l_time->month-1]),
650 system_charset_info);
651 break;
652 case 'W':
653 if (type == MYSQL_TIMESTAMP_TIME || !(l_time->month || l_time->year))
654 return 1;
655 weekday= calc_weekday(calc_daynr(l_time->year,l_time->month,
656 l_time->day),0);
657 str->append(locale->day_names->type_names[weekday],
658 (uint) strlen(locale->day_names->type_names[weekday]),
659 system_charset_info);
660 break;
661 case 'a':
662 if (type == MYSQL_TIMESTAMP_TIME || !(l_time->month || l_time->year))
663 return 1;
664 weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,
665 l_time->day),0);
666 str->append(locale->ab_day_names->type_names[weekday],
667 (uint) strlen(locale->ab_day_names->type_names[weekday]),
668 system_charset_info);
669 break;
670 case 'D':
671 if (type == MYSQL_TIMESTAMP_TIME)
672 return 1;
673 length= (uint) (int10_to_str(l_time->day, intbuff, 10) - intbuff);
674 str->append_with_prefill(intbuff, length, 1, '0');
675 if (l_time->day >= 10 && l_time->day <= 19)
676 str->append(STRING_WITH_LEN("th"));
677 else
679 switch (l_time->day %10) {
680 case 1:
681 str->append(STRING_WITH_LEN("st"));
682 break;
683 case 2:
684 str->append(STRING_WITH_LEN("nd"));
685 break;
686 case 3:
687 str->append(STRING_WITH_LEN("rd"));
688 break;
689 default:
690 str->append(STRING_WITH_LEN("th"));
691 break;
694 break;
695 case 'Y':
696 length= (uint) (int10_to_str(l_time->year, intbuff, 10) - intbuff);
697 str->append_with_prefill(intbuff, length, 4, '0');
698 break;
699 case 'y':
700 length= (uint) (int10_to_str(l_time->year%100, intbuff, 10) - intbuff);
701 str->append_with_prefill(intbuff, length, 2, '0');
702 break;
703 case 'm':
704 length= (uint) (int10_to_str(l_time->month, intbuff, 10) - intbuff);
705 str->append_with_prefill(intbuff, length, 2, '0');
706 break;
707 case 'c':
708 length= (uint) (int10_to_str(l_time->month, intbuff, 10) - intbuff);
709 str->append_with_prefill(intbuff, length, 1, '0');
710 break;
711 case 'd':
712 length= (uint) (int10_to_str(l_time->day, intbuff, 10) - intbuff);
713 str->append_with_prefill(intbuff, length, 2, '0');
714 break;
715 case 'e':
716 length= (uint) (int10_to_str(l_time->day, intbuff, 10) - intbuff);
717 str->append_with_prefill(intbuff, length, 1, '0');
718 break;
719 case 'f':
720 length= (uint) (int10_to_str(l_time->second_part, intbuff, 10) - intbuff);
721 str->append_with_prefill(intbuff, length, 6, '0');
722 break;
723 case 'H':
724 length= (uint) (int10_to_str(l_time->hour, intbuff, 10) - intbuff);
725 str->append_with_prefill(intbuff, length, 2, '0');
726 break;
727 case 'h':
728 case 'I':
729 hours_i= (l_time->hour%24 + 11)%12+1;
730 length= (uint) (int10_to_str(hours_i, intbuff, 10) - intbuff);
731 str->append_with_prefill(intbuff, length, 2, '0');
732 break;
733 case 'i': /* minutes */
734 length= (uint) (int10_to_str(l_time->minute, intbuff, 10) - intbuff);
735 str->append_with_prefill(intbuff, length, 2, '0');
736 break;
737 case 'j':
738 if (type == MYSQL_TIMESTAMP_TIME)
739 return 1;
740 length= (uint) (int10_to_str(calc_daynr(l_time->year,l_time->month,
741 l_time->day) -
742 calc_daynr(l_time->year,1,1) + 1, intbuff, 10) - intbuff);
743 str->append_with_prefill(intbuff, length, 3, '0');
744 break;
745 case 'k':
746 length= (uint) (int10_to_str(l_time->hour, intbuff, 10) - intbuff);
747 str->append_with_prefill(intbuff, length, 1, '0');
748 break;
749 case 'l':
750 hours_i= (l_time->hour%24 + 11)%12+1;
751 length= (uint) (int10_to_str(hours_i, intbuff, 10) - intbuff);
752 str->append_with_prefill(intbuff, length, 1, '0');
753 break;
754 case 'p':
755 hours_i= l_time->hour%24;
756 str->append(hours_i < 12 ? "AM" : "PM",2);
757 break;
758 case 'r':
759 length= sprintf(intbuff, ((l_time->hour % 24) < 12) ?
760 "%02d:%02d:%02d AM" : "%02d:%02d:%02d PM",
761 (l_time->hour+11)%12+1,
762 l_time->minute,
763 l_time->second);
764 str->append(intbuff, length);
765 break;
766 case 'S':
767 case 's':
768 length= (uint) (int10_to_str(l_time->second, intbuff, 10) - intbuff);
769 str->append_with_prefill(intbuff, length, 2, '0');
770 break;
771 case 'T':
772 length= sprintf(intbuff, "%02d:%02d:%02d",
773 l_time->hour, l_time->minute, l_time->second);
774 str->append(intbuff, length);
775 break;
776 case 'U':
777 case 'u':
779 uint year;
780 if (type == MYSQL_TIMESTAMP_TIME)
781 return 1;
782 length= (uint) (int10_to_str(calc_week(l_time,
783 (*ptr) == 'U' ?
784 WEEK_FIRST_WEEKDAY : WEEK_MONDAY_FIRST,
785 &year),
786 intbuff, 10) - intbuff);
787 str->append_with_prefill(intbuff, length, 2, '0');
789 break;
790 case 'v':
791 case 'V':
793 uint year;
794 if (type == MYSQL_TIMESTAMP_TIME)
795 return 1;
796 length= (uint) (int10_to_str(calc_week(l_time,
797 ((*ptr) == 'V' ?
798 (WEEK_YEAR | WEEK_FIRST_WEEKDAY) :
799 (WEEK_YEAR | WEEK_MONDAY_FIRST)),
800 &year),
801 intbuff, 10) - intbuff);
802 str->append_with_prefill(intbuff, length, 2, '0');
804 break;
805 case 'x':
806 case 'X':
808 uint year;
809 if (type == MYSQL_TIMESTAMP_TIME)
810 return 1;
811 (void) calc_week(l_time,
812 ((*ptr) == 'X' ?
813 WEEK_YEAR | WEEK_FIRST_WEEKDAY :
814 WEEK_YEAR | WEEK_MONDAY_FIRST),
815 &year);
816 length= (uint) (int10_to_str(year, intbuff, 10) - intbuff);
817 str->append_with_prefill(intbuff, length, 4, '0');
819 break;
820 case 'w':
821 if (type == MYSQL_TIMESTAMP_TIME || !(l_time->month || l_time->year))
822 return 1;
823 weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,
824 l_time->day),1);
825 length= (uint) (int10_to_str(weekday, intbuff, 10) - intbuff);
826 str->append_with_prefill(intbuff, length, 1, '0');
827 break;
829 default:
830 str->append(*ptr);
831 break;
835 return 0;
840 @details
841 Get a array of positive numbers from a string object.
842 Each number is separated by 1 non digit character
843 Return error if there is too many numbers.
844 If there is too few numbers, assume that the numbers are left out
845 from the high end. This allows one to give:
846 DAY_TO_SECOND as "D MM:HH:SS", "MM:HH:SS" "HH:SS" or as seconds.
848 @param length: length of str
849 @param cs: charset of str
850 @param values: array of results
851 @param count: count of elements in result array
852 @param transform_msec: if value is true we suppose
853 that the last part of string value is microseconds
854 and we should transform value to six digit value.
855 For example, '1.1' -> '1.100000'
858 static bool get_interval_info(const char *str,uint length,CHARSET_INFO *cs,
859 uint count, ulonglong *values,
860 bool transform_msec)
862 const char *end=str+length;
863 uint i;
864 while (str != end && !my_isdigit(cs,*str))
865 str++;
867 for (i=0 ; i < count ; i++)
869 longlong value;
870 const char *start= str;
871 for (value=0; str != end && my_isdigit(cs,*str) ; str++)
872 value= value*LL(10) + (longlong) (*str - '0');
873 if (transform_msec && i == count - 1) // microseconds always last
875 int msec_length= 6 - (int) (str - start);
876 if (msec_length > 0)
877 value*= (long)log_10_int[msec_length];
879 values[i]= value;
880 while (str != end && !my_isdigit(cs,*str))
881 str++;
882 if (str == end && i != count-1)
884 i++;
885 /* Change values[0...i-1] -> values[0...count-1] */
886 bmove_upp((uchar*) (values+count), (uchar*) (values+i),
887 sizeof(*values)*i);
888 bzero((uchar*) values, sizeof(*values)*(count-i));
889 break;
892 return (str != end);
896 longlong Item_func_period_add::val_int()
898 DBUG_ASSERT(fixed == 1);
899 ulong period=(ulong) args[0]->val_int();
900 int months=(int) args[1]->val_int();
902 if ((null_value=args[0]->null_value || args[1]->null_value) ||
903 period == 0L)
904 return 0; /* purecov: inspected */
905 return (longlong)
906 convert_month_to_period((uint) ((int) convert_period_to_month(period)+
907 months));
911 longlong Item_func_period_diff::val_int()
913 DBUG_ASSERT(fixed == 1);
914 ulong period1=(ulong) args[0]->val_int();
915 ulong period2=(ulong) args[1]->val_int();
917 if ((null_value=args[0]->null_value || args[1]->null_value))
918 return 0; /* purecov: inspected */
919 return (longlong) ((long) convert_period_to_month(period1)-
920 (long) convert_period_to_month(period2));
925 longlong Item_func_to_days::val_int()
927 DBUG_ASSERT(fixed == 1);
928 MYSQL_TIME ltime;
929 if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE))
930 return 0;
931 return (longlong) calc_daynr(ltime.year,ltime.month,ltime.day);
936 Get information about this Item tree monotonicity
938 SYNOPSIS
939 Item_func_to_days::get_monotonicity_info()
941 DESCRIPTION
942 Get information about monotonicity of the function represented by this item
943 tree.
945 RETURN
946 See enum_monotonicity_info.
949 enum_monotonicity_info Item_func_to_days::get_monotonicity_info() const
951 if (args[0]->type() == Item::FIELD_ITEM)
953 if (args[0]->field_type() == MYSQL_TYPE_DATE)
954 return MONOTONIC_STRICT_INCREASING_NOT_NULL;
955 if (args[0]->field_type() == MYSQL_TYPE_DATETIME)
956 return MONOTONIC_INCREASING_NOT_NULL;
958 return NON_MONOTONIC;
962 longlong Item_func_to_days::val_int_endpoint(bool left_endp, bool *incl_endp)
964 DBUG_ASSERT(fixed == 1);
965 MYSQL_TIME ltime;
966 longlong res;
967 int dummy; /* unused */
968 if (get_arg0_date(&ltime, TIME_FUZZY_DATE))
970 /* got NULL, leave the incl_endp intact */
971 return LONGLONG_MIN;
973 res=(longlong) calc_daynr(ltime.year,ltime.month,ltime.day);
974 /* Set to NULL if invalid date, but keep the value */
975 null_value= check_date(&ltime,
976 (ltime.year || ltime.month || ltime.day),
977 (TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE),
978 &dummy);
979 if (null_value)
982 Even if the evaluation return NULL, the calc_daynr is useful for pruning
984 if (args[0]->field_type() != MYSQL_TYPE_DATE)
985 *incl_endp= TRUE;
986 return res;
989 if (args[0]->field_type() == MYSQL_TYPE_DATE)
991 // TO_DAYS() is strictly monotonic for dates, leave incl_endp intact
992 return res;
996 Handle the special but practically useful case of datetime values that
997 point to day bound ("strictly less" comparison stays intact):
999 col < '2007-09-15 00:00:00' -> TO_DAYS(col) < TO_DAYS('2007-09-15')
1000 col > '2007-09-15 23:59:59' -> TO_DAYS(col) > TO_DAYS('2007-09-15')
1002 which is different from the general case ("strictly less" changes to
1003 "less or equal"):
1005 col < '2007-09-15 12:34:56' -> TO_DAYS(col) <= TO_DAYS('2007-09-15')
1007 if ((!left_endp && !(ltime.hour || ltime.minute || ltime.second ||
1008 ltime.second_part)) ||
1009 (left_endp && ltime.hour == 23 && ltime.minute == 59 &&
1010 ltime.second == 59))
1011 /* do nothing */
1013 else
1014 *incl_endp= TRUE;
1015 return res;
1019 longlong Item_func_dayofyear::val_int()
1021 DBUG_ASSERT(fixed == 1);
1022 MYSQL_TIME ltime;
1023 if (get_arg0_date(&ltime,TIME_NO_ZERO_DATE))
1024 return 0;
1025 return (longlong) calc_daynr(ltime.year,ltime.month,ltime.day) -
1026 calc_daynr(ltime.year,1,1) + 1;
1029 longlong Item_func_dayofmonth::val_int()
1031 DBUG_ASSERT(fixed == 1);
1032 MYSQL_TIME ltime;
1033 (void) get_arg0_date(&ltime, TIME_FUZZY_DATE);
1034 return (longlong) ltime.day;
1037 longlong Item_func_month::val_int()
1039 DBUG_ASSERT(fixed == 1);
1040 MYSQL_TIME ltime;
1041 (void) get_arg0_date(&ltime, TIME_FUZZY_DATE);
1042 return (longlong) ltime.month;
1046 void Item_func_monthname::fix_length_and_dec()
1048 THD* thd= current_thd;
1049 CHARSET_INFO *cs= thd->variables.collation_connection;
1050 uint32 repertoire= my_charset_repertoire(cs);
1051 locale= thd->variables.lc_time_names;
1052 collation.set(cs, DERIVATION_COERCIBLE, repertoire);
1053 decimals=0;
1054 max_length= locale->max_month_name_length * collation.collation->mbmaxlen;
1055 maybe_null=1;
1059 String* Item_func_monthname::val_str(String* str)
1061 DBUG_ASSERT(fixed == 1);
1062 const char *month_name;
1063 uint month= (uint) val_int();
1064 uint err;
1066 if (null_value || !month)
1068 null_value=1;
1069 return (String*) 0;
1071 null_value=0;
1072 month_name= locale->month_names->type_names[month-1];
1073 str->copy(month_name, (uint) strlen(month_name), &my_charset_utf8_bin,
1074 collation.collation, &err);
1075 return str;
1080 Returns the quarter of the year.
1083 longlong Item_func_quarter::val_int()
1085 DBUG_ASSERT(fixed == 1);
1086 MYSQL_TIME ltime;
1087 if (get_arg0_date(&ltime, TIME_FUZZY_DATE))
1088 return 0;
1089 return (longlong) ((ltime.month+2)/3);
1092 longlong Item_func_hour::val_int()
1094 DBUG_ASSERT(fixed == 1);
1095 MYSQL_TIME ltime;
1096 (void) get_arg0_time(&ltime);
1097 return ltime.hour;
1100 longlong Item_func_minute::val_int()
1102 DBUG_ASSERT(fixed == 1);
1103 MYSQL_TIME ltime;
1104 (void) get_arg0_time(&ltime);
1105 return ltime.minute;
1109 Returns the second in time_exp in the range of 0 - 59.
1111 longlong Item_func_second::val_int()
1113 DBUG_ASSERT(fixed == 1);
1114 MYSQL_TIME ltime;
1115 (void) get_arg0_time(&ltime);
1116 return ltime.second;
1120 uint week_mode(uint mode)
1122 uint week_format= (mode & 7);
1123 if (!(week_format & WEEK_MONDAY_FIRST))
1124 week_format^= WEEK_FIRST_WEEKDAY;
1125 return week_format;
1129 @verbatim
1130 The bits in week_format(for calc_week() function) has the following meaning:
1131 WEEK_MONDAY_FIRST (0) If not set Sunday is first day of week
1132 If set Monday is first day of week
1133 WEEK_YEAR (1) If not set Week is in range 0-53
1135 Week 0 is returned for the the last week of the previous year (for
1136 a date at start of january) In this case one can get 53 for the
1137 first week of next year. This flag ensures that the week is
1138 relevant for the given year. Note that this flag is only
1139 releveant if WEEK_JANUARY is not set.
1141 If set Week is in range 1-53.
1143 In this case one may get week 53 for a date in January (when
1144 the week is that last week of previous year) and week 1 for a
1145 date in December.
1147 WEEK_FIRST_WEEKDAY (2) If not set Weeks are numbered according
1148 to ISO 8601:1988
1149 If set The week that contains the first
1150 'first-day-of-week' is week 1.
1152 ISO 8601:1988 means that if the week containing January 1 has
1153 four or more days in the new year, then it is week 1;
1154 Otherwise it is the last week of the previous year, and the
1155 next week is week 1.
1156 @endverbatim
1159 longlong Item_func_week::val_int()
1161 DBUG_ASSERT(fixed == 1);
1162 uint year;
1163 MYSQL_TIME ltime;
1164 if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE))
1165 return 0;
1166 return (longlong) calc_week(&ltime,
1167 week_mode((uint) args[1]->val_int()),
1168 &year);
1172 longlong Item_func_yearweek::val_int()
1174 DBUG_ASSERT(fixed == 1);
1175 uint year,week;
1176 MYSQL_TIME ltime;
1177 if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE))
1178 return 0;
1179 week= calc_week(&ltime,
1180 (week_mode((uint) args[1]->val_int()) | WEEK_YEAR),
1181 &year);
1182 return week+year*100;
1186 longlong Item_func_weekday::val_int()
1188 DBUG_ASSERT(fixed == 1);
1189 MYSQL_TIME ltime;
1191 if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE))
1192 return 0;
1194 return (longlong) calc_weekday(calc_daynr(ltime.year, ltime.month,
1195 ltime.day),
1196 odbc_type) + test(odbc_type);
1199 void Item_func_dayname::fix_length_and_dec()
1201 THD* thd= current_thd;
1202 CHARSET_INFO *cs= thd->variables.collation_connection;
1203 uint32 repertoire= my_charset_repertoire(cs);
1204 locale= thd->variables.lc_time_names;
1205 collation.set(cs, DERIVATION_COERCIBLE, repertoire);
1206 decimals=0;
1207 max_length= locale->max_day_name_length * collation.collation->mbmaxlen;
1208 maybe_null=1;
1212 String* Item_func_dayname::val_str(String* str)
1214 DBUG_ASSERT(fixed == 1);
1215 uint weekday=(uint) val_int(); // Always Item_func_daynr()
1216 const char *day_name;
1217 uint err;
1219 if (null_value)
1220 return (String*) 0;
1222 day_name= locale->day_names->type_names[weekday];
1223 str->copy(day_name, (uint) strlen(day_name), &my_charset_utf8_bin,
1224 collation.collation, &err);
1225 return str;
1229 longlong Item_func_year::val_int()
1231 DBUG_ASSERT(fixed == 1);
1232 MYSQL_TIME ltime;
1233 (void) get_arg0_date(&ltime, TIME_FUZZY_DATE);
1234 return (longlong) ltime.year;
1239 Get information about this Item tree monotonicity
1241 SYNOPSIS
1242 Item_func_year::get_monotonicity_info()
1244 DESCRIPTION
1245 Get information about monotonicity of the function represented by this item
1246 tree.
1248 RETURN
1249 See enum_monotonicity_info.
1252 enum_monotonicity_info Item_func_year::get_monotonicity_info() const
1254 if (args[0]->type() == Item::FIELD_ITEM &&
1255 (args[0]->field_type() == MYSQL_TYPE_DATE ||
1256 args[0]->field_type() == MYSQL_TYPE_DATETIME))
1257 return MONOTONIC_INCREASING;
1258 return NON_MONOTONIC;
1262 longlong Item_func_year::val_int_endpoint(bool left_endp, bool *incl_endp)
1264 DBUG_ASSERT(fixed == 1);
1265 MYSQL_TIME ltime;
1266 if (get_arg0_date(&ltime, TIME_FUZZY_DATE))
1268 /* got NULL, leave the incl_endp intact */
1269 return LONGLONG_MIN;
1273 Handle the special but practically useful case of datetime values that
1274 point to year bound ("strictly less" comparison stays intact) :
1276 col < '2007-01-01 00:00:00' -> YEAR(col) < 2007
1278 which is different from the general case ("strictly less" changes to
1279 "less or equal"):
1281 col < '2007-09-15 23:00:00' -> YEAR(col) <= 2007
1283 if (!left_endp && ltime.day == 1 && ltime.month == 1 &&
1284 !(ltime.hour || ltime.minute || ltime.second || ltime.second_part))
1285 ; /* do nothing */
1286 else
1287 *incl_endp= TRUE;
1288 return ltime.year;
1292 longlong Item_func_unix_timestamp::val_int()
1294 MYSQL_TIME ltime;
1295 my_bool not_used;
1297 DBUG_ASSERT(fixed == 1);
1298 if (arg_count == 0)
1299 return (longlong) current_thd->query_start();
1300 if (args[0]->type() == FIELD_ITEM)
1301 { // Optimize timestamp field
1302 Field *field=((Item_field*) args[0])->field;
1303 if (field->type() == MYSQL_TYPE_TIMESTAMP)
1304 return ((Field_timestamp*) field)->get_timestamp(&null_value);
1307 if (get_arg0_date(&ltime, 0))
1310 We have to set null_value again because get_arg0_date will also set it
1311 to true if we have wrong datetime parameter (and we should return 0 in
1312 this case).
1314 null_value= args[0]->null_value;
1315 return 0;
1318 return (longlong) TIME_to_timestamp(current_thd, &ltime, &not_used);
1322 longlong Item_func_time_to_sec::val_int()
1324 DBUG_ASSERT(fixed == 1);
1325 MYSQL_TIME ltime;
1326 longlong seconds;
1327 (void) get_arg0_time(&ltime);
1328 seconds=ltime.hour*3600L+ltime.minute*60+ltime.second;
1329 return ltime.neg ? -seconds : seconds;
1334 Convert a string to a interval value.
1336 To make code easy, allow interval objects without separators.
1339 bool get_interval_value(Item *args,interval_type int_type,
1340 String *str_value, INTERVAL *interval)
1342 ulonglong array[5];
1343 longlong UNINIT_VAR(value);
1344 const char *UNINIT_VAR(str);
1345 size_t UNINIT_VAR(length);
1346 CHARSET_INFO *cs=str_value->charset();
1348 bzero((char*) interval,sizeof(*interval));
1349 if ((int) int_type <= INTERVAL_MICROSECOND)
1351 value= args->val_int();
1352 if (args->null_value)
1353 return 1;
1354 if (value < 0)
1356 interval->neg=1;
1357 value= -value;
1360 else
1362 String *res;
1363 if (!(res=args->val_str(str_value)))
1364 return (1);
1366 /* record negative intervalls in interval->neg */
1367 str=res->ptr();
1368 const char *end=str+res->length();
1369 while (str != end && my_isspace(cs,*str))
1370 str++;
1371 if (str != end && *str == '-')
1373 interval->neg=1;
1374 str++;
1376 length= (size_t) (end-str); // Set up pointers to new str
1379 switch (int_type) {
1380 case INTERVAL_YEAR:
1381 interval->year= (ulong) value;
1382 break;
1383 case INTERVAL_QUARTER:
1384 interval->month= (ulong)(value*3);
1385 break;
1386 case INTERVAL_MONTH:
1387 interval->month= (ulong) value;
1388 break;
1389 case INTERVAL_WEEK:
1390 interval->day= (ulong)(value*7);
1391 break;
1392 case INTERVAL_DAY:
1393 interval->day= (ulong) value;
1394 break;
1395 case INTERVAL_HOUR:
1396 interval->hour= (ulong) value;
1397 break;
1398 case INTERVAL_MICROSECOND:
1399 interval->second_part=value;
1400 break;
1401 case INTERVAL_MINUTE:
1402 interval->minute=value;
1403 break;
1404 case INTERVAL_SECOND:
1405 interval->second=value;
1406 break;
1407 case INTERVAL_YEAR_MONTH: // Allow YEAR-MONTH YYYYYMM
1408 if (get_interval_info(str,length,cs,2,array,0))
1409 return (1);
1410 interval->year= (ulong) array[0];
1411 interval->month= (ulong) array[1];
1412 break;
1413 case INTERVAL_DAY_HOUR:
1414 if (get_interval_info(str,length,cs,2,array,0))
1415 return (1);
1416 interval->day= (ulong) array[0];
1417 interval->hour= (ulong) array[1];
1418 break;
1419 case INTERVAL_DAY_MICROSECOND:
1420 if (get_interval_info(str,length,cs,5,array,1))
1421 return (1);
1422 interval->day= (ulong) array[0];
1423 interval->hour= (ulong) array[1];
1424 interval->minute= array[2];
1425 interval->second= array[3];
1426 interval->second_part= array[4];
1427 break;
1428 case INTERVAL_DAY_MINUTE:
1429 if (get_interval_info(str,length,cs,3,array,0))
1430 return (1);
1431 interval->day= (ulong) array[0];
1432 interval->hour= (ulong) array[1];
1433 interval->minute= array[2];
1434 break;
1435 case INTERVAL_DAY_SECOND:
1436 if (get_interval_info(str,length,cs,4,array,0))
1437 return (1);
1438 interval->day= (ulong) array[0];
1439 interval->hour= (ulong) array[1];
1440 interval->minute= array[2];
1441 interval->second= array[3];
1442 break;
1443 case INTERVAL_HOUR_MICROSECOND:
1444 if (get_interval_info(str,length,cs,4,array,1))
1445 return (1);
1446 interval->hour= (ulong) array[0];
1447 interval->minute= array[1];
1448 interval->second= array[2];
1449 interval->second_part= array[3];
1450 break;
1451 case INTERVAL_HOUR_MINUTE:
1452 if (get_interval_info(str,length,cs,2,array,0))
1453 return (1);
1454 interval->hour= (ulong) array[0];
1455 interval->minute= array[1];
1456 break;
1457 case INTERVAL_HOUR_SECOND:
1458 if (get_interval_info(str,length,cs,3,array,0))
1459 return (1);
1460 interval->hour= (ulong) array[0];
1461 interval->minute= array[1];
1462 interval->second= array[2];
1463 break;
1464 case INTERVAL_MINUTE_MICROSECOND:
1465 if (get_interval_info(str,length,cs,3,array,1))
1466 return (1);
1467 interval->minute= array[0];
1468 interval->second= array[1];
1469 interval->second_part= array[2];
1470 break;
1471 case INTERVAL_MINUTE_SECOND:
1472 if (get_interval_info(str,length,cs,2,array,0))
1473 return (1);
1474 interval->minute= array[0];
1475 interval->second= array[1];
1476 break;
1477 case INTERVAL_SECOND_MICROSECOND:
1478 if (get_interval_info(str,length,cs,2,array,1))
1479 return (1);
1480 interval->second= array[0];
1481 interval->second_part= array[1];
1482 break;
1483 case INTERVAL_LAST: /* purecov: begin deadcode */
1484 DBUG_ASSERT(0);
1485 break; /* purecov: end */
1487 return 0;
1491 String *Item_date::val_str(String *str)
1493 DBUG_ASSERT(fixed == 1);
1494 MYSQL_TIME ltime;
1495 if (get_date(&ltime, TIME_FUZZY_DATE))
1496 return (String *) 0;
1497 if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
1499 null_value= 1;
1500 return (String *) 0;
1502 make_date((DATE_TIME_FORMAT *) 0, &ltime, str);
1503 return str;
1507 longlong Item_date::val_int()
1509 DBUG_ASSERT(fixed == 1);
1510 MYSQL_TIME ltime;
1511 if (get_date(&ltime, TIME_FUZZY_DATE))
1512 return 0;
1513 return (longlong) (ltime.year*10000L+ltime.month*100+ltime.day);
1517 bool Item_func_from_days::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
1519 longlong value=args[0]->val_int();
1520 if ((null_value=args[0]->null_value))
1521 return 1;
1522 bzero(ltime, sizeof(MYSQL_TIME));
1523 get_date_from_daynr((long) value, &ltime->year, &ltime->month, &ltime->day);
1525 if ((null_value= (fuzzy_date & TIME_NO_ZERO_DATE) &&
1526 (ltime->year == 0 || ltime->month == 0 || ltime->day == 0)))
1527 return TRUE;
1529 ltime->time_type= MYSQL_TIMESTAMP_DATE;
1530 return 0;
1534 void Item_func_curdate::fix_length_and_dec()
1536 collation.set(&my_charset_bin);
1537 decimals=0;
1538 max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
1540 store_now_in_TIME(&ltime);
1542 /* We don't need to set second_part and neg because they already 0 */
1543 ltime.hour= ltime.minute= ltime.second= 0;
1544 ltime.time_type= MYSQL_TIMESTAMP_DATE;
1545 value= (longlong) TIME_to_ulonglong_date(&ltime);
1548 String *Item_func_curdate::val_str(String *str)
1550 DBUG_ASSERT(fixed == 1);
1551 if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
1553 null_value= 1;
1554 return (String *) 0;
1556 make_date((DATE_TIME_FORMAT *) 0, &ltime, str);
1557 return str;
1561 Converts current time in my_time_t to MYSQL_TIME represenatation for local
1562 time zone. Defines time zone (local) used for whole CURDATE function.
1564 void Item_func_curdate_local::store_now_in_TIME(MYSQL_TIME *now_time)
1566 THD *thd= current_thd;
1567 thd->variables.time_zone->gmt_sec_to_TIME(now_time,
1568 (my_time_t)thd->query_start());
1569 thd->time_zone_used= 1;
1574 Converts current time in my_time_t to MYSQL_TIME represenatation for UTC
1575 time zone. Defines time zone (UTC) used for whole UTC_DATE function.
1577 void Item_func_curdate_utc::store_now_in_TIME(MYSQL_TIME *now_time)
1579 my_tz_UTC->gmt_sec_to_TIME(now_time,
1580 (my_time_t)(current_thd->query_start()));
1582 We are not flagging this query as using time zone, since it uses fixed
1583 UTC-SYSTEM time-zone.
1588 bool Item_func_curdate::get_date(MYSQL_TIME *res,
1589 uint fuzzy_date __attribute__((unused)))
1591 *res=ltime;
1592 return 0;
1596 String *Item_func_curtime::val_str(String *str)
1598 DBUG_ASSERT(fixed == 1);
1599 str_value.set(buff, buff_length, &my_charset_bin);
1600 return &str_value;
1604 void Item_func_curtime::fix_length_and_dec()
1606 MYSQL_TIME ltime;
1608 decimals= DATETIME_DEC;
1609 collation.set(&my_charset_bin);
1610 store_now_in_TIME(&ltime);
1611 value= TIME_to_ulonglong_time(&ltime);
1612 buff_length= (uint) my_time_to_str(&ltime, buff);
1613 max_length= buff_length;
1618 Converts current time in my_time_t to MYSQL_TIME represenatation for local
1619 time zone. Defines time zone (local) used for whole CURTIME function.
1621 void Item_func_curtime_local::store_now_in_TIME(MYSQL_TIME *now_time)
1623 THD *thd= current_thd;
1624 thd->variables.time_zone->gmt_sec_to_TIME(now_time,
1625 (my_time_t)thd->query_start());
1626 thd->time_zone_used= 1;
1631 Converts current time in my_time_t to MYSQL_TIME represenatation for UTC
1632 time zone. Defines time zone (UTC) used for whole UTC_TIME function.
1634 void Item_func_curtime_utc::store_now_in_TIME(MYSQL_TIME *now_time)
1636 my_tz_UTC->gmt_sec_to_TIME(now_time,
1637 (my_time_t)(current_thd->query_start()));
1639 We are not flagging this query as using time zone, since it uses fixed
1640 UTC-SYSTEM time-zone.
1645 String *Item_func_now::val_str(String *str)
1647 DBUG_ASSERT(fixed == 1);
1648 str_value.set(buff,buff_length, &my_charset_bin);
1649 return &str_value;
1653 void Item_func_now::fix_length_and_dec()
1655 decimals= DATETIME_DEC;
1656 collation.set(&my_charset_bin);
1658 store_now_in_TIME(&ltime);
1659 value= (longlong) TIME_to_ulonglong_datetime(&ltime);
1661 buff_length= (uint) my_datetime_to_str(&ltime, buff);
1662 max_length= buff_length;
1667 Converts current time in my_time_t to MYSQL_TIME represenatation for local
1668 time zone. Defines time zone (local) used for whole NOW function.
1670 void Item_func_now_local::store_now_in_TIME(MYSQL_TIME *now_time)
1672 THD *thd= current_thd;
1673 thd->variables.time_zone->gmt_sec_to_TIME(now_time,
1674 (my_time_t)thd->query_start());
1675 thd->time_zone_used= 1;
1680 Converts current time in my_time_t to MYSQL_TIME represenatation for UTC
1681 time zone. Defines time zone (UTC) used for whole UTC_TIMESTAMP function.
1683 void Item_func_now_utc::store_now_in_TIME(MYSQL_TIME *now_time)
1685 my_tz_UTC->gmt_sec_to_TIME(now_time,
1686 (my_time_t)(current_thd->query_start()));
1688 We are not flagging this query as using time zone, since it uses fixed
1689 UTC-SYSTEM time-zone.
1694 bool Item_func_now::get_date(MYSQL_TIME *res,
1695 uint fuzzy_date __attribute__((unused)))
1697 *res= ltime;
1698 return 0;
1702 int Item_func_now::save_in_field(Field *to, bool no_conversions)
1704 to->set_notnull();
1705 return to->store_time(&ltime, MYSQL_TIMESTAMP_DATETIME);
1710 Converts current time in my_time_t to MYSQL_TIME represenatation for local
1711 time zone. Defines time zone (local) used for whole SYSDATE function.
1713 void Item_func_sysdate_local::store_now_in_TIME(MYSQL_TIME *now_time)
1715 THD *thd= current_thd;
1716 thd->variables.time_zone->gmt_sec_to_TIME(now_time, (my_time_t) my_time(0));
1717 thd->time_zone_used= 1;
1721 String *Item_func_sysdate_local::val_str(String *str)
1723 DBUG_ASSERT(fixed == 1);
1724 store_now_in_TIME(&ltime);
1725 buff_length= (uint) my_datetime_to_str(&ltime, buff);
1726 str_value.set(buff, buff_length, &my_charset_bin);
1727 return &str_value;
1731 longlong Item_func_sysdate_local::val_int()
1733 DBUG_ASSERT(fixed == 1);
1734 store_now_in_TIME(&ltime);
1735 return (longlong) TIME_to_ulonglong_datetime(&ltime);
1739 double Item_func_sysdate_local::val_real()
1741 DBUG_ASSERT(fixed == 1);
1742 store_now_in_TIME(&ltime);
1743 return ulonglong2double(TIME_to_ulonglong_datetime(&ltime));
1747 void Item_func_sysdate_local::fix_length_and_dec()
1749 decimals= 0;
1750 collation.set(&my_charset_bin);
1751 max_length= MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
1755 bool Item_func_sysdate_local::get_date(MYSQL_TIME *res,
1756 uint fuzzy_date __attribute__((unused)))
1758 store_now_in_TIME(&ltime);
1759 *res= ltime;
1760 return 0;
1764 int Item_func_sysdate_local::save_in_field(Field *to, bool no_conversions)
1766 store_now_in_TIME(&ltime);
1767 to->set_notnull();
1768 to->store_time(&ltime, MYSQL_TIMESTAMP_DATETIME);
1769 return 0;
1773 String *Item_func_sec_to_time::val_str(String *str)
1775 DBUG_ASSERT(fixed == 1);
1776 MYSQL_TIME ltime;
1777 longlong arg_val= args[0]->val_int();
1779 if ((null_value=args[0]->null_value) ||
1780 str->alloc(MAX_DATE_STRING_REP_LENGTH))
1782 null_value= 1;
1783 return (String*) 0;
1786 sec_to_time(arg_val, args[0]->unsigned_flag, &ltime);
1788 make_time((DATE_TIME_FORMAT *) 0, &ltime, str);
1789 return str;
1793 longlong Item_func_sec_to_time::val_int()
1795 DBUG_ASSERT(fixed == 1);
1796 MYSQL_TIME ltime;
1797 longlong arg_val= args[0]->val_int();
1799 if ((null_value=args[0]->null_value))
1800 return 0;
1802 sec_to_time(arg_val, args[0]->unsigned_flag, &ltime);
1804 return (ltime.neg ? -1 : 1) *
1805 ((ltime.hour)*10000 + ltime.minute*100 + ltime.second);
1809 void Item_func_date_format::fix_length_and_dec()
1811 THD* thd= current_thd;
1813 Must use this_item() in case it's a local SP variable
1814 (for ->max_length and ->str_value)
1816 Item *arg1= args[1]->this_item();
1818 decimals=0;
1819 CHARSET_INFO *cs= thd->variables.collation_connection;
1820 uint32 repertoire= arg1->collation.repertoire;
1821 if (!thd->variables.lc_time_names->is_ascii)
1822 repertoire|= MY_REPERTOIRE_EXTENDED;
1823 collation.set(cs, arg1->collation.derivation, repertoire);
1824 if (arg1->type() == STRING_ITEM)
1825 { // Optimize the normal case
1826 fixed_length=1;
1827 max_length= format_length(&arg1->str_value) *
1828 collation.collation->mbmaxlen;
1830 else
1832 fixed_length=0;
1833 max_length=min(arg1->max_length, MAX_BLOB_WIDTH) * 10 *
1834 collation.collation->mbmaxlen;
1835 set_if_smaller(max_length,MAX_BLOB_WIDTH);
1837 maybe_null=1; // If wrong date
1841 bool Item_func_date_format::eq(const Item *item, bool binary_cmp) const
1843 Item_func_date_format *item_func;
1845 if (item->type() != FUNC_ITEM)
1846 return 0;
1847 if (func_name() != ((Item_func*) item)->func_name())
1848 return 0;
1849 if (this == item)
1850 return 1;
1851 item_func= (Item_func_date_format*) item;
1852 if (!args[0]->eq(item_func->args[0], binary_cmp))
1853 return 0;
1855 We must compare format string case sensitive.
1856 This needed because format modifiers with different case,
1857 for example %m and %M, have different meaning.
1859 if (!args[1]->eq(item_func->args[1], 1))
1860 return 0;
1861 return 1;
1866 uint Item_func_date_format::format_length(const String *format)
1868 uint size=0;
1869 const char *ptr=format->ptr();
1870 const char *end=ptr+format->length();
1872 for (; ptr != end ; ptr++)
1874 if (*ptr != '%' || ptr == end-1)
1875 size++;
1876 else
1878 switch(*++ptr) {
1879 case 'M': /* month, textual */
1880 case 'W': /* day (of the week), textual */
1881 size += 64; /* large for UTF8 locale data */
1882 break;
1883 case 'D': /* day (of the month), numeric plus english suffix */
1884 case 'Y': /* year, numeric, 4 digits */
1885 case 'x': /* Year, used with 'v' */
1886 case 'X': /* Year, used with 'v, where week starts with Monday' */
1887 size += 4;
1888 break;
1889 case 'a': /* locale's abbreviated weekday name (Sun..Sat) */
1890 case 'b': /* locale's abbreviated month name (Jan.Dec) */
1891 size += 32; /* large for UTF8 locale data */
1892 break;
1893 case 'j': /* day of year (001..366) */
1894 size += 3;
1895 break;
1896 case 'U': /* week (00..52) */
1897 case 'u': /* week (00..52), where week starts with Monday */
1898 case 'V': /* week 1..53 used with 'x' */
1899 case 'v': /* week 1..53 used with 'x', where week starts with Monday */
1900 case 'y': /* year, numeric, 2 digits */
1901 case 'm': /* month, numeric */
1902 case 'd': /* day (of the month), numeric */
1903 case 'h': /* hour (01..12) */
1904 case 'I': /* --||-- */
1905 case 'i': /* minutes, numeric */
1906 case 'l': /* hour ( 1..12) */
1907 case 'p': /* locale's AM or PM */
1908 case 'S': /* second (00..61) */
1909 case 's': /* seconds, numeric */
1910 case 'c': /* month (0..12) */
1911 case 'e': /* day (0..31) */
1912 size += 2;
1913 break;
1914 case 'k': /* hour ( 0..23) */
1915 case 'H': /* hour (00..23; value > 23 OK, padding always 2-digit) */
1916 size += 7; /* docs allow > 23, range depends on sizeof(unsigned int) */
1917 break;
1918 case 'r': /* time, 12-hour (hh:mm:ss [AP]M) */
1919 size += 11;
1920 break;
1921 case 'T': /* time, 24-hour (hh:mm:ss) */
1922 size += 8;
1923 break;
1924 case 'f': /* microseconds */
1925 size += 6;
1926 break;
1927 case 'w': /* day (of the week), numeric */
1928 case '%':
1929 default:
1930 size++;
1931 break;
1935 return size;
1939 String *Item_func_date_format::val_str(String *str)
1941 String *format;
1942 MYSQL_TIME l_time;
1943 uint size;
1944 DBUG_ASSERT(fixed == 1);
1946 if (!is_time_format)
1948 if (get_arg0_date(&l_time, TIME_FUZZY_DATE))
1949 return 0;
1951 else
1953 String *res;
1954 if (!(res=args[0]->val_str(str)) ||
1955 (str_to_time_with_warn(res->ptr(), res->length(), &l_time)))
1956 goto null_date;
1958 l_time.year=l_time.month=l_time.day=0;
1959 null_value=0;
1962 if (!(format = args[1]->val_str(str)) || !format->length())
1963 goto null_date;
1965 if (fixed_length)
1966 size=max_length;
1967 else
1968 size=format_length(format);
1970 if (size < MAX_DATE_STRING_REP_LENGTH)
1971 size= MAX_DATE_STRING_REP_LENGTH;
1973 if (format == str)
1974 str= &value; // Save result here
1975 if (str->alloc(size))
1976 goto null_date;
1978 DATE_TIME_FORMAT date_time_format;
1979 date_time_format.format.str= (char*) format->ptr();
1980 date_time_format.format.length= format->length();
1982 /* Create the result string */
1983 str->set_charset(collation.collation);
1984 if (!make_date_time(&date_time_format, &l_time,
1985 is_time_format ? MYSQL_TIMESTAMP_TIME :
1986 MYSQL_TIMESTAMP_DATE,
1987 str))
1988 return str;
1990 null_date:
1991 null_value=1;
1992 return 0;
1996 void Item_func_from_unixtime::fix_length_and_dec()
1998 thd= current_thd;
1999 collation.set(&my_charset_bin);
2000 decimals= DATETIME_DEC;
2001 max_length=MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
2002 maybe_null= 1;
2003 thd->time_zone_used= 1;
2007 String *Item_func_from_unixtime::val_str(String *str)
2009 MYSQL_TIME time_tmp;
2011 DBUG_ASSERT(fixed == 1);
2013 if (get_date(&time_tmp, 0))
2014 return 0;
2016 if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
2018 null_value= 1;
2019 return 0;
2022 make_datetime((DATE_TIME_FORMAT *) 0, &time_tmp, str);
2024 return str;
2028 longlong Item_func_from_unixtime::val_int()
2030 MYSQL_TIME time_tmp;
2032 DBUG_ASSERT(fixed == 1);
2034 if (get_date(&time_tmp, 0))
2035 return 0;
2037 return (longlong) TIME_to_ulonglong_datetime(&time_tmp);
2040 bool Item_func_from_unixtime::get_date(MYSQL_TIME *ltime,
2041 uint fuzzy_date __attribute__((unused)))
2043 ulonglong tmp= (ulonglong)(args[0]->val_int());
2045 "tmp > TIMESTAMP_MAX_VALUE" check also covers case of negative
2046 from_unixtime() argument since tmp is unsigned.
2048 if ((null_value= (args[0]->null_value || tmp > TIMESTAMP_MAX_VALUE)))
2049 return 1;
2051 thd->variables.time_zone->gmt_sec_to_TIME(ltime, (my_time_t)tmp);
2053 return 0;
2057 void Item_func_convert_tz::fix_length_and_dec()
2059 collation.set(&my_charset_bin);
2060 decimals= 0;
2061 max_length= MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
2062 maybe_null= 1;
2066 String *Item_func_convert_tz::val_str(String *str)
2068 MYSQL_TIME time_tmp;
2070 if (get_date(&time_tmp, 0))
2071 return 0;
2073 if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
2075 null_value= 1;
2076 return 0;
2079 make_datetime((DATE_TIME_FORMAT *) 0, &time_tmp, str);
2081 return str;
2085 longlong Item_func_convert_tz::val_int()
2087 MYSQL_TIME time_tmp;
2089 if (get_date(&time_tmp, 0))
2090 return 0;
2092 return (longlong)TIME_to_ulonglong_datetime(&time_tmp);
2096 bool Item_func_convert_tz::get_date(MYSQL_TIME *ltime,
2097 uint fuzzy_date __attribute__((unused)))
2099 my_time_t my_time_tmp;
2100 String str;
2101 THD *thd= current_thd;
2103 if (!from_tz_cached)
2105 from_tz= my_tz_find(thd, args[1]->val_str(&str));
2106 from_tz_cached= args[1]->const_item();
2109 if (!to_tz_cached)
2111 to_tz= my_tz_find(thd, args[2]->val_str(&str));
2112 to_tz_cached= args[2]->const_item();
2115 if (from_tz==0 || to_tz==0 || get_arg0_date(ltime, TIME_NO_ZERO_DATE))
2117 null_value= 1;
2118 return 1;
2122 my_bool not_used;
2123 my_time_tmp= from_tz->TIME_to_gmt_sec(ltime, &not_used);
2124 /* my_time_tmp is guranteed to be in the allowed range */
2125 if (my_time_tmp)
2126 to_tz->gmt_sec_to_TIME(ltime, my_time_tmp);
2129 null_value= 0;
2130 return 0;
2134 void Item_func_convert_tz::cleanup()
2136 from_tz_cached= to_tz_cached= 0;
2137 Item_date_func::cleanup();
2141 void Item_date_add_interval::fix_length_and_dec()
2143 enum_field_types arg0_field_type;
2145 collation.set(&my_charset_bin);
2146 maybe_null=1;
2147 max_length=MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
2148 value.alloc(max_length);
2151 The field type for the result of an Item_date function is defined as
2152 follows:
2154 - If first arg is a MYSQL_TYPE_DATETIME result is MYSQL_TYPE_DATETIME
2155 - If first arg is a MYSQL_TYPE_DATE and the interval type uses hours,
2156 minutes or seconds then type is MYSQL_TYPE_DATETIME.
2157 - Otherwise the result is MYSQL_TYPE_STRING
2158 (This is because you can't know if the string contains a DATE, MYSQL_TIME or
2159 DATETIME argument)
2161 cached_field_type= MYSQL_TYPE_STRING;
2162 arg0_field_type= args[0]->field_type();
2163 if (arg0_field_type == MYSQL_TYPE_DATETIME ||
2164 arg0_field_type == MYSQL_TYPE_TIMESTAMP)
2165 cached_field_type= MYSQL_TYPE_DATETIME;
2166 else if (arg0_field_type == MYSQL_TYPE_DATE)
2168 if (int_type <= INTERVAL_DAY || int_type == INTERVAL_YEAR_MONTH)
2169 cached_field_type= arg0_field_type;
2170 else
2171 cached_field_type= MYSQL_TYPE_DATETIME;
2176 /* Here arg[1] is a Item_interval object */
2178 bool Item_date_add_interval::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
2180 INTERVAL interval;
2182 if (args[0]->get_date(ltime, TIME_NO_ZERO_DATE) ||
2183 get_interval_value(args[1], int_type, &value, &interval))
2184 return (null_value=1);
2186 if (date_sub_interval)
2187 interval.neg = !interval.neg;
2189 if ((null_value= date_add_interval(ltime, int_type, interval)))
2190 return 1;
2191 return 0;
2195 String *Item_date_add_interval::val_str(String *str)
2197 DBUG_ASSERT(fixed == 1);
2198 MYSQL_TIME ltime;
2199 enum date_time_format_types format;
2201 if (Item_date_add_interval::get_date(&ltime, TIME_NO_ZERO_DATE))
2202 return 0;
2204 if (ltime.time_type == MYSQL_TIMESTAMP_DATE)
2205 format= DATE_ONLY;
2206 else if (ltime.second_part)
2207 format= DATE_TIME_MICROSECOND;
2208 else
2209 format= DATE_TIME;
2211 if (!make_datetime(format, &ltime, str))
2212 return str;
2214 null_value=1;
2215 return 0;
2219 longlong Item_date_add_interval::val_int()
2221 DBUG_ASSERT(fixed == 1);
2222 MYSQL_TIME ltime;
2223 longlong date;
2224 if (Item_date_add_interval::get_date(&ltime, TIME_NO_ZERO_DATE))
2225 return (longlong) 0;
2226 date = (ltime.year*100L + ltime.month)*100L + ltime.day;
2227 return ltime.time_type == MYSQL_TIMESTAMP_DATE ? date :
2228 ((date*100L + ltime.hour)*100L+ ltime.minute)*100L + ltime.second;
2233 bool Item_date_add_interval::eq(const Item *item, bool binary_cmp) const
2235 Item_date_add_interval *other= (Item_date_add_interval*) item;
2236 if (!Item_func::eq(item, binary_cmp))
2237 return 0;
2238 return ((int_type == other->int_type) &&
2239 (date_sub_interval == other->date_sub_interval));
2243 'interval_names' reflects the order of the enumeration interval_type.
2244 See item_timefunc.h
2247 static const char *interval_names[]=
2249 "year", "quarter", "month", "week", "day",
2250 "hour", "minute", "second", "microsecond",
2251 "year_month", "day_hour", "day_minute",
2252 "day_second", "hour_minute", "hour_second",
2253 "minute_second", "day_microsecond",
2254 "hour_microsecond", "minute_microsecond",
2255 "second_microsecond"
2258 void Item_date_add_interval::print(String *str, enum_query_type query_type)
2260 str->append('(');
2261 args[0]->print(str, query_type);
2262 str->append(date_sub_interval?" - interval ":" + interval ");
2263 args[1]->print(str, query_type);
2264 str->append(' ');
2265 str->append(interval_names[int_type]);
2266 str->append(')');
2269 void Item_extract::print(String *str, enum_query_type query_type)
2271 str->append(STRING_WITH_LEN("extract("));
2272 str->append(interval_names[int_type]);
2273 str->append(STRING_WITH_LEN(" from "));
2274 args[0]->print(str, query_type);
2275 str->append(')');
2278 void Item_extract::fix_length_and_dec()
2280 maybe_null=1; // If wrong date
2281 switch (int_type) {
2282 case INTERVAL_YEAR: max_length=4; date_value=1; break;
2283 case INTERVAL_YEAR_MONTH: max_length=6; date_value=1; break;
2284 case INTERVAL_QUARTER: max_length=2; date_value=1; break;
2285 case INTERVAL_MONTH: max_length=2; date_value=1; break;
2286 case INTERVAL_WEEK: max_length=2; date_value=1; break;
2287 case INTERVAL_DAY: max_length=2; date_value=1; break;
2288 case INTERVAL_DAY_HOUR: max_length=9; date_value=0; break;
2289 case INTERVAL_DAY_MINUTE: max_length=11; date_value=0; break;
2290 case INTERVAL_DAY_SECOND: max_length=13; date_value=0; break;
2291 case INTERVAL_HOUR: max_length=2; date_value=0; break;
2292 case INTERVAL_HOUR_MINUTE: max_length=4; date_value=0; break;
2293 case INTERVAL_HOUR_SECOND: max_length=6; date_value=0; break;
2294 case INTERVAL_MINUTE: max_length=2; date_value=0; break;
2295 case INTERVAL_MINUTE_SECOND: max_length=4; date_value=0; break;
2296 case INTERVAL_SECOND: max_length=2; date_value=0; break;
2297 case INTERVAL_MICROSECOND: max_length=2; date_value=0; break;
2298 case INTERVAL_DAY_MICROSECOND: max_length=20; date_value=0; break;
2299 case INTERVAL_HOUR_MICROSECOND: max_length=13; date_value=0; break;
2300 case INTERVAL_MINUTE_MICROSECOND: max_length=11; date_value=0; break;
2301 case INTERVAL_SECOND_MICROSECOND: max_length=9; date_value=0; break;
2302 case INTERVAL_LAST: DBUG_ASSERT(0); break; /* purecov: deadcode */
2307 longlong Item_extract::val_int()
2309 DBUG_ASSERT(fixed == 1);
2310 MYSQL_TIME ltime;
2311 uint year;
2312 ulong week_format;
2313 long neg;
2314 if (date_value)
2316 if (get_arg0_date(&ltime, TIME_FUZZY_DATE))
2317 return 0;
2318 neg=1;
2320 else
2322 char buf[40];
2323 String value(buf, sizeof(buf), &my_charset_bin);;
2324 String *res= args[0]->val_str(&value);
2325 if (!res || str_to_time_with_warn(res->ptr(), res->length(), &ltime))
2327 null_value=1;
2328 return 0;
2330 neg= ltime.neg ? -1 : 1;
2331 null_value=0;
2333 switch (int_type) {
2334 case INTERVAL_YEAR: return ltime.year;
2335 case INTERVAL_YEAR_MONTH: return ltime.year*100L+ltime.month;
2336 case INTERVAL_QUARTER: return (ltime.month+2)/3;
2337 case INTERVAL_MONTH: return ltime.month;
2338 case INTERVAL_WEEK:
2340 week_format= current_thd->variables.default_week_format;
2341 return calc_week(&ltime, week_mode(week_format), &year);
2343 case INTERVAL_DAY: return ltime.day;
2344 case INTERVAL_DAY_HOUR: return (long) (ltime.day*100L+ltime.hour)*neg;
2345 case INTERVAL_DAY_MINUTE: return (long) (ltime.day*10000L+
2346 ltime.hour*100L+
2347 ltime.minute)*neg;
2348 case INTERVAL_DAY_SECOND: return ((longlong) ltime.day*1000000L+
2349 (longlong) (ltime.hour*10000L+
2350 ltime.minute*100+
2351 ltime.second))*neg;
2352 case INTERVAL_HOUR: return (long) ltime.hour*neg;
2353 case INTERVAL_HOUR_MINUTE: return (long) (ltime.hour*100+ltime.minute)*neg;
2354 case INTERVAL_HOUR_SECOND: return (long) (ltime.hour*10000+ltime.minute*100+
2355 ltime.second)*neg;
2356 case INTERVAL_MINUTE: return (long) ltime.minute*neg;
2357 case INTERVAL_MINUTE_SECOND: return (long) (ltime.minute*100+ltime.second)*neg;
2358 case INTERVAL_SECOND: return (long) ltime.second*neg;
2359 case INTERVAL_MICROSECOND: return (long) ltime.second_part*neg;
2360 case INTERVAL_DAY_MICROSECOND: return (((longlong)ltime.day*1000000L +
2361 (longlong)ltime.hour*10000L +
2362 ltime.minute*100 +
2363 ltime.second)*1000000L +
2364 ltime.second_part)*neg;
2365 case INTERVAL_HOUR_MICROSECOND: return (((longlong)ltime.hour*10000L +
2366 ltime.minute*100 +
2367 ltime.second)*1000000L +
2368 ltime.second_part)*neg;
2369 case INTERVAL_MINUTE_MICROSECOND: return (((longlong)(ltime.minute*100+
2370 ltime.second))*1000000L+
2371 ltime.second_part)*neg;
2372 case INTERVAL_SECOND_MICROSECOND: return ((longlong)ltime.second*1000000L+
2373 ltime.second_part)*neg;
2374 case INTERVAL_LAST: DBUG_ASSERT(0); break; /* purecov: deadcode */
2376 return 0; // Impossible
2379 bool Item_extract::eq(const Item *item, bool binary_cmp) const
2381 if (this == item)
2382 return 1;
2383 if (item->type() != FUNC_ITEM ||
2384 functype() != ((Item_func*)item)->functype())
2385 return 0;
2387 Item_extract* ie= (Item_extract*)item;
2388 if (ie->int_type != int_type)
2389 return 0;
2391 if (!args[0]->eq(ie->args[0], binary_cmp))
2392 return 0;
2393 return 1;
2397 bool Item_char_typecast::eq(const Item *item, bool binary_cmp) const
2399 if (this == item)
2400 return 1;
2401 if (item->type() != FUNC_ITEM ||
2402 functype() != ((Item_func*)item)->functype())
2403 return 0;
2405 Item_char_typecast *cast= (Item_char_typecast*)item;
2406 if (cast_length != cast->cast_length ||
2407 cast_cs != cast->cast_cs)
2408 return 0;
2410 if (!args[0]->eq(cast->args[0], binary_cmp))
2411 return 0;
2412 return 1;
2415 void Item_typecast::print(String *str, enum_query_type query_type)
2417 str->append(STRING_WITH_LEN("cast("));
2418 args[0]->print(str, query_type);
2419 str->append(STRING_WITH_LEN(" as "));
2420 str->append(cast_type());
2421 str->append(')');
2425 void Item_char_typecast::print(String *str, enum_query_type query_type)
2427 str->append(STRING_WITH_LEN("cast("));
2428 args[0]->print(str, query_type);
2429 str->append(STRING_WITH_LEN(" as char"));
2430 if (cast_length >= 0)
2432 str->append('(');
2433 char buffer[20];
2434 // my_charset_bin is good enough for numbers
2435 String st(buffer, sizeof(buffer), &my_charset_bin);
2436 st.set((ulonglong)cast_length, &my_charset_bin);
2437 str->append(st);
2438 str->append(')');
2440 if (cast_cs)
2442 str->append(STRING_WITH_LEN(" charset "));
2443 str->append(cast_cs->csname);
2445 str->append(')');
2448 String *Item_char_typecast::val_str(String *str)
2450 DBUG_ASSERT(fixed == 1);
2451 String *res;
2452 uint32 length;
2454 if (cast_length >= 0 &&
2455 ((unsigned) cast_length) > current_thd->variables.max_allowed_packet)
2457 push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
2458 ER_WARN_ALLOWED_PACKET_OVERFLOWED,
2459 ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED),
2460 cast_cs == &my_charset_bin ?
2461 "cast_as_binary" : func_name(),
2462 current_thd->variables.max_allowed_packet);
2463 null_value= 1;
2464 return 0;
2467 if (!charset_conversion)
2469 if (!(res= args[0]->val_str(str)))
2471 null_value= 1;
2472 return 0;
2475 else
2477 // Convert character set if differ
2478 uint dummy_errors;
2479 if (!(res= args[0]->val_str(str)) ||
2480 tmp_value.copy(res->ptr(), res->length(), from_cs,
2481 cast_cs, &dummy_errors))
2483 null_value= 1;
2484 return 0;
2486 res= &tmp_value;
2489 res->set_charset(cast_cs);
2492 Cut the tail if cast with length
2493 and the result is longer than cast length, e.g.
2494 CAST('string' AS CHAR(1))
2496 if (cast_length >= 0)
2498 if (res->length() > (length= (uint32) res->charpos(cast_length)))
2499 { // Safe even if const arg
2500 char char_type[40];
2501 my_snprintf(char_type, sizeof(char_type), "%s(%lu)",
2502 cast_cs == &my_charset_bin ? "BINARY" : "CHAR",
2503 (ulong) length);
2505 if (!res->alloced_length())
2506 { // Don't change const str
2507 str_value= *res; // Not malloced string
2508 res= &str_value;
2510 push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
2511 ER_TRUNCATED_WRONG_VALUE,
2512 ER(ER_TRUNCATED_WRONG_VALUE), char_type,
2513 res->c_ptr_safe());
2514 res->length((uint) length);
2516 else if (cast_cs == &my_charset_bin && res->length() < (uint) cast_length)
2518 if (res->alloced_length() < (uint) cast_length)
2520 str_value.alloc(cast_length);
2521 str_value.copy(*res);
2522 res= &str_value;
2524 bzero((char*) res->ptr() + res->length(),
2525 (uint) cast_length - res->length());
2526 res->length(cast_length);
2529 null_value= 0;
2530 return res;
2534 void Item_char_typecast::fix_length_and_dec()
2536 uint32 char_length;
2538 We always force character set conversion if cast_cs
2539 is a multi-byte character set. It garantees that the
2540 result of CAST is a well-formed string.
2541 For single-byte character sets we allow just to copy
2542 from the argument. A single-byte character sets string
2543 is always well-formed.
2545 There is a special trick to convert form a number to ucs2.
2546 As numbers have my_charset_bin as their character set,
2547 it wouldn't do conversion to ucs2 without an additional action.
2548 To force conversion, we should pretend to be non-binary.
2549 Let's choose from_cs this way:
2550 - If the argument in a number and cast_cs is ucs2 (i.e. mbminlen > 1),
2551 then from_cs is set to latin1, to perform latin1 -> ucs2 conversion.
2552 - If the argument is a number and cast_cs is ASCII-compatible
2553 (i.e. mbminlen == 1), then from_cs is set to cast_cs,
2554 which allows just to take over the args[0]->val_str() result
2555 and thus avoid unnecessary character set conversion.
2556 - If the argument is not a number, then from_cs is set to
2557 the argument's charset.
2559 Note (TODO): we could use repertoire technique here.
2561 from_cs= (args[0]->result_type() == INT_RESULT ||
2562 args[0]->result_type() == DECIMAL_RESULT ||
2563 args[0]->result_type() == REAL_RESULT) ?
2564 (cast_cs->mbminlen == 1 ? cast_cs : &my_charset_latin1) :
2565 args[0]->collation.collation;
2566 charset_conversion= (cast_cs->mbmaxlen > 1) ||
2567 (!my_charset_same(from_cs, cast_cs) &&
2568 from_cs != &my_charset_bin &&
2569 cast_cs != &my_charset_bin);
2570 collation.set(cast_cs, DERIVATION_IMPLICIT);
2571 char_length= (cast_length >= 0) ? cast_length :
2572 args[0]->max_length /
2573 (cast_cs == &my_charset_bin ? 1 : args[0]->collation.collation->mbmaxlen);
2574 max_length= char_length * cast_cs->mbmaxlen;
2578 String *Item_datetime_typecast::val_str(String *str)
2580 DBUG_ASSERT(fixed == 1);
2581 MYSQL_TIME ltime;
2583 if (!get_arg0_date(&ltime, TIME_FUZZY_DATE) &&
2584 !make_datetime(ltime.second_part ? DATE_TIME_MICROSECOND : DATE_TIME,
2585 &ltime, str))
2586 return str;
2588 null_value=1;
2589 return 0;
2593 longlong Item_datetime_typecast::val_int()
2595 DBUG_ASSERT(fixed == 1);
2596 MYSQL_TIME ltime;
2597 if (get_arg0_date(&ltime,1))
2599 null_value= 1;
2600 return 0;
2603 return TIME_to_ulonglong_datetime(&ltime);
2607 bool Item_time_typecast::get_time(MYSQL_TIME *ltime)
2609 bool res= get_arg0_time(ltime);
2611 For MYSQL_TIMESTAMP_TIME value we can have non-zero day part,
2612 which we should not lose.
2614 if (ltime->time_type == MYSQL_TIMESTAMP_DATETIME)
2615 ltime->year= ltime->month= ltime->day= 0;
2616 ltime->time_type= MYSQL_TIMESTAMP_TIME;
2617 return res;
2621 longlong Item_time_typecast::val_int()
2623 MYSQL_TIME ltime;
2624 if (get_time(&ltime))
2626 null_value= 1;
2627 return 0;
2629 return ltime.hour * 10000L + ltime.minute * 100 + ltime.second;
2632 String *Item_time_typecast::val_str(String *str)
2634 DBUG_ASSERT(fixed == 1);
2635 MYSQL_TIME ltime;
2637 if (!get_arg0_time(&ltime) &&
2638 !make_datetime(ltime.second_part ? TIME_MICROSECOND : TIME_ONLY,
2639 &ltime, str))
2640 return str;
2642 null_value=1;
2643 return 0;
2647 bool Item_date_typecast::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
2649 bool res= get_arg0_date(ltime, TIME_FUZZY_DATE);
2650 ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0;
2651 ltime->time_type= MYSQL_TIMESTAMP_DATE;
2652 return res;
2656 bool Item_date_typecast::get_time(MYSQL_TIME *ltime)
2658 bzero((char *)ltime, sizeof(MYSQL_TIME));
2659 return args[0]->null_value;
2663 String *Item_date_typecast::val_str(String *str)
2665 DBUG_ASSERT(fixed == 1);
2666 MYSQL_TIME ltime;
2668 if (!get_arg0_date(&ltime, TIME_FUZZY_DATE) &&
2669 !str->alloc(MAX_DATE_STRING_REP_LENGTH))
2671 make_date((DATE_TIME_FORMAT *) 0, &ltime, str);
2672 return str;
2675 null_value=1;
2676 return 0;
2679 longlong Item_date_typecast::val_int()
2681 DBUG_ASSERT(fixed == 1);
2682 MYSQL_TIME ltime;
2683 if ((null_value= args[0]->get_date(&ltime, TIME_FUZZY_DATE)))
2684 return 0;
2685 return (longlong) (ltime.year * 10000L + ltime.month * 100 + ltime.day);
2689 MAKEDATE(a,b) is a date function that creates a date value
2690 from a year and day value.
2692 NOTES:
2693 As arguments are integers, we can't know if the year is a 2 digit or 4 digit year.
2694 In this case we treat all years < 100 as 2 digit years. Ie, this is not safe
2695 for dates between 0000-01-01 and 0099-12-31
2698 String *Item_func_makedate::val_str(String *str)
2700 DBUG_ASSERT(fixed == 1);
2701 MYSQL_TIME l_time;
2702 long daynr= (long) args[1]->val_int();
2703 long year= (long) args[0]->val_int();
2704 long days;
2706 if (args[0]->null_value || args[1]->null_value ||
2707 year < 0 || year > 9999 || daynr <= 0)
2708 goto err;
2710 if (year < 100)
2711 year= year_2000_handling(year);
2713 days= calc_daynr(year,1,1) + daynr - 1;
2714 /* Day number from year 0 to 9999-12-31 */
2715 if (days >= 0 && days <= MAX_DAY_NUMBER)
2717 null_value=0;
2718 get_date_from_daynr(days,&l_time.year,&l_time.month,&l_time.day);
2719 if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
2720 goto err;
2721 make_date((DATE_TIME_FORMAT *) 0, &l_time, str);
2722 return str;
2725 err:
2726 null_value=1;
2727 return 0;
2732 MAKEDATE(a,b) is a date function that creates a date value
2733 from a year and day value.
2735 NOTES:
2736 As arguments are integers, we can't know if the year is a 2 digit or 4 digit year.
2737 In this case we treat all years < 100 as 2 digit years. Ie, this is not safe
2738 for dates between 0000-01-01 and 0099-12-31
2741 longlong Item_func_makedate::val_int()
2743 DBUG_ASSERT(fixed == 1);
2744 MYSQL_TIME l_time;
2745 long daynr= (long) args[1]->val_int();
2746 long year= (long) args[0]->val_int();
2747 long days;
2749 if (args[0]->null_value || args[1]->null_value ||
2750 year < 0 || year > 9999 || daynr <= 0)
2751 goto err;
2753 if (year < 100)
2754 year= year_2000_handling(year);
2756 days= calc_daynr(year,1,1) + daynr - 1;
2757 /* Day number from year 0 to 9999-12-31 */
2758 if (days >= 0 && days < MAX_DAY_NUMBER)
2760 null_value=0;
2761 get_date_from_daynr(days,&l_time.year,&l_time.month,&l_time.day);
2762 return (longlong) (l_time.year * 10000L + l_time.month * 100 + l_time.day);
2765 err:
2766 null_value= 1;
2767 return 0;
2771 void Item_func_add_time::fix_length_and_dec()
2773 enum_field_types arg0_field_type;
2774 decimals=0;
2775 max_length=MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
2776 maybe_null= 1;
2779 The field type for the result of an Item_func_add_time function is defined
2780 as follows:
2782 - If first arg is a MYSQL_TYPE_DATETIME or MYSQL_TYPE_TIMESTAMP
2783 result is MYSQL_TYPE_DATETIME
2784 - If first arg is a MYSQL_TYPE_TIME result is MYSQL_TYPE_TIME
2785 - Otherwise the result is MYSQL_TYPE_STRING
2788 cached_field_type= MYSQL_TYPE_STRING;
2789 arg0_field_type= args[0]->field_type();
2790 if (arg0_field_type == MYSQL_TYPE_DATE ||
2791 arg0_field_type == MYSQL_TYPE_DATETIME ||
2792 arg0_field_type == MYSQL_TYPE_TIMESTAMP)
2793 cached_field_type= MYSQL_TYPE_DATETIME;
2794 else if (arg0_field_type == MYSQL_TYPE_TIME)
2795 cached_field_type= MYSQL_TYPE_TIME;
2799 ADDTIME(t,a) and SUBTIME(t,a) are time functions that calculate a
2800 time/datetime value
2802 t: time_or_datetime_expression
2803 a: time_expression
2805 Result: Time value or datetime value
2808 String *Item_func_add_time::val_str(String *str)
2810 DBUG_ASSERT(fixed == 1);
2811 MYSQL_TIME l_time1, l_time2, l_time3;
2812 bool is_time= 0;
2813 long days, microseconds;
2814 longlong seconds;
2815 int l_sign= sign;
2817 null_value=0;
2818 if (is_date) // TIMESTAMP function
2820 if (get_arg0_date(&l_time1, TIME_FUZZY_DATE) ||
2821 args[1]->get_time(&l_time2) ||
2822 l_time1.time_type == MYSQL_TIMESTAMP_TIME ||
2823 l_time2.time_type != MYSQL_TIMESTAMP_TIME)
2824 goto null_date;
2826 else // ADDTIME function
2828 if (args[0]->get_time(&l_time1) ||
2829 args[1]->get_time(&l_time2) ||
2830 l_time2.time_type == MYSQL_TIMESTAMP_DATETIME)
2831 goto null_date;
2832 is_time= (l_time1.time_type == MYSQL_TIMESTAMP_TIME);
2834 if (l_time1.neg != l_time2.neg)
2835 l_sign= -l_sign;
2837 bzero((char *)&l_time3, sizeof(l_time3));
2839 l_time3.neg= calc_time_diff(&l_time1, &l_time2, -l_sign,
2840 &seconds, &microseconds);
2843 If first argument was negative and diff between arguments
2844 is non-zero we need to swap sign to get proper result.
2846 if (l_time1.neg && (seconds || microseconds))
2847 l_time3.neg= 1-l_time3.neg; // Swap sign of result
2849 if (!is_time && l_time3.neg)
2850 goto null_date;
2852 days= (long)(seconds/86400L);
2854 calc_time_from_sec(&l_time3, (long)(seconds%86400L), microseconds);
2856 if (!is_time)
2858 get_date_from_daynr(days,&l_time3.year,&l_time3.month,&l_time3.day);
2859 if (l_time3.day &&
2860 !make_datetime(l_time1.second_part || l_time2.second_part ?
2861 DATE_TIME_MICROSECOND : DATE_TIME,
2862 &l_time3, str))
2863 return str;
2864 goto null_date;
2867 l_time3.hour+= days*24;
2868 if (!make_datetime_with_warn(l_time1.second_part || l_time2.second_part ?
2869 TIME_MICROSECOND : TIME_ONLY,
2870 &l_time3, str))
2871 return str;
2873 null_date:
2874 null_value=1;
2875 return 0;
2879 void Item_func_add_time::print(String *str, enum_query_type query_type)
2881 if (is_date)
2883 DBUG_ASSERT(sign > 0);
2884 str->append(STRING_WITH_LEN("timestamp("));
2886 else
2888 if (sign > 0)
2889 str->append(STRING_WITH_LEN("addtime("));
2890 else
2891 str->append(STRING_WITH_LEN("subtime("));
2893 args[0]->print(str, query_type);
2894 str->append(',');
2895 args[1]->print(str, query_type);
2896 str->append(')');
2901 TIMEDIFF(t,s) is a time function that calculates the
2902 time value between a start and end time.
2904 t and s: time_or_datetime_expression
2905 Result: Time value
2908 String *Item_func_timediff::val_str(String *str)
2910 DBUG_ASSERT(fixed == 1);
2911 longlong seconds;
2912 long microseconds;
2913 int l_sign= 1;
2914 MYSQL_TIME l_time1 ,l_time2, l_time3;
2916 null_value= 0;
2917 if (args[0]->get_time(&l_time1) ||
2918 args[1]->get_time(&l_time2) ||
2919 l_time1.time_type != l_time2.time_type)
2920 goto null_date;
2922 if (l_time1.neg != l_time2.neg)
2923 l_sign= -l_sign;
2925 bzero((char *)&l_time3, sizeof(l_time3));
2927 l_time3.neg= calc_time_diff(&l_time1, &l_time2, l_sign,
2928 &seconds, &microseconds);
2931 For MYSQL_TIMESTAMP_TIME only:
2932 If first argument was negative and diff between arguments
2933 is non-zero we need to swap sign to get proper result.
2935 if (l_time1.neg && (seconds || microseconds))
2936 l_time3.neg= 1-l_time3.neg; // Swap sign of result
2938 calc_time_from_sec(&l_time3, (long) seconds, microseconds);
2940 if (!make_datetime_with_warn(l_time1.second_part || l_time2.second_part ?
2941 TIME_MICROSECOND : TIME_ONLY,
2942 &l_time3, str))
2943 return str;
2945 null_date:
2946 null_value=1;
2947 return 0;
2951 MAKETIME(h,m,s) is a time function that calculates a time value
2952 from the total number of hours, minutes, and seconds.
2953 Result: Time value
2956 String *Item_func_maketime::val_str(String *str)
2958 DBUG_ASSERT(fixed == 1);
2959 MYSQL_TIME ltime;
2960 bool overflow= 0;
2962 longlong hour= args[0]->val_int();
2963 longlong minute= args[1]->val_int();
2964 longlong second= args[2]->val_int();
2966 if ((null_value=(args[0]->null_value ||
2967 args[1]->null_value ||
2968 args[2]->null_value ||
2969 minute < 0 || minute > 59 ||
2970 second < 0 || second > 59 ||
2971 str->alloc(MAX_DATE_STRING_REP_LENGTH))))
2972 return 0;
2974 bzero((char *)&ltime, sizeof(ltime));
2975 ltime.neg= 0;
2977 /* Check for integer overflows */
2978 if (hour < 0)
2980 if (args[0]->unsigned_flag)
2981 overflow= 1;
2982 else
2983 ltime.neg= 1;
2985 if (-hour > UINT_MAX || hour > UINT_MAX)
2986 overflow= 1;
2988 if (!overflow)
2990 ltime.hour= (uint) ((hour < 0 ? -hour : hour));
2991 ltime.minute= (uint) minute;
2992 ltime.second= (uint) second;
2994 else
2996 ltime.hour= TIME_MAX_HOUR;
2997 ltime.minute= TIME_MAX_MINUTE;
2998 ltime.second= TIME_MAX_SECOND;
2999 char buf[28];
3000 char *ptr= longlong10_to_str(hour, buf, args[0]->unsigned_flag ? 10 : -10);
3001 int len = (int)(ptr - buf) +
3002 sprintf(ptr, ":%02u:%02u", (uint) minute, (uint) second);
3003 make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
3004 buf, len, MYSQL_TIMESTAMP_TIME,
3005 NullS);
3008 if (make_time_with_warn((DATE_TIME_FORMAT *) 0, &ltime, str))
3010 null_value= 1;
3011 return 0;
3013 return str;
3018 MICROSECOND(a) is a function ( extraction) that extracts the microseconds
3019 from a.
3021 a: Datetime or time value
3022 Result: int value
3025 longlong Item_func_microsecond::val_int()
3027 DBUG_ASSERT(fixed == 1);
3028 MYSQL_TIME ltime;
3029 if (!get_arg0_time(&ltime))
3030 return ltime.second_part;
3031 return 0;
3035 longlong Item_func_timestamp_diff::val_int()
3037 MYSQL_TIME ltime1, ltime2;
3038 longlong seconds;
3039 long microseconds;
3040 long months= 0;
3041 int neg= 1;
3043 null_value= 0;
3044 if (args[0]->get_date(&ltime1, TIME_NO_ZERO_DATE) ||
3045 args[1]->get_date(&ltime2, TIME_NO_ZERO_DATE))
3046 goto null_date;
3048 if (calc_time_diff(&ltime2,&ltime1, 1,
3049 &seconds, &microseconds))
3050 neg= -1;
3052 if (int_type == INTERVAL_YEAR ||
3053 int_type == INTERVAL_QUARTER ||
3054 int_type == INTERVAL_MONTH)
3056 uint year_beg, year_end, month_beg, month_end, day_beg, day_end;
3057 uint years= 0;
3058 uint second_beg, second_end, microsecond_beg, microsecond_end;
3060 if (neg == -1)
3062 year_beg= ltime2.year;
3063 year_end= ltime1.year;
3064 month_beg= ltime2.month;
3065 month_end= ltime1.month;
3066 day_beg= ltime2.day;
3067 day_end= ltime1.day;
3068 second_beg= ltime2.hour * 3600 + ltime2.minute * 60 + ltime2.second;
3069 second_end= ltime1.hour * 3600 + ltime1.minute * 60 + ltime1.second;
3070 microsecond_beg= ltime2.second_part;
3071 microsecond_end= ltime1.second_part;
3073 else
3075 year_beg= ltime1.year;
3076 year_end= ltime2.year;
3077 month_beg= ltime1.month;
3078 month_end= ltime2.month;
3079 day_beg= ltime1.day;
3080 day_end= ltime2.day;
3081 second_beg= ltime1.hour * 3600 + ltime1.minute * 60 + ltime1.second;
3082 second_end= ltime2.hour * 3600 + ltime2.minute * 60 + ltime2.second;
3083 microsecond_beg= ltime1.second_part;
3084 microsecond_end= ltime2.second_part;
3087 /* calc years */
3088 years= year_end - year_beg;
3089 if (month_end < month_beg || (month_end == month_beg && day_end < day_beg))
3090 years-= 1;
3092 /* calc months */
3093 months= 12*years;
3094 if (month_end < month_beg || (month_end == month_beg && day_end < day_beg))
3095 months+= 12 - (month_beg - month_end);
3096 else
3097 months+= (month_end - month_beg);
3099 if (day_end < day_beg)
3100 months-= 1;
3101 else if ((day_end == day_beg) &&
3102 ((second_end < second_beg) ||
3103 (second_end == second_beg && microsecond_end < microsecond_beg)))
3104 months-= 1;
3107 switch (int_type) {
3108 case INTERVAL_YEAR:
3109 return months/12*neg;
3110 case INTERVAL_QUARTER:
3111 return months/3*neg;
3112 case INTERVAL_MONTH:
3113 return months*neg;
3114 case INTERVAL_WEEK:
3115 return seconds/86400L/7L*neg;
3116 case INTERVAL_DAY:
3117 return seconds/86400L*neg;
3118 case INTERVAL_HOUR:
3119 return seconds/3600L*neg;
3120 case INTERVAL_MINUTE:
3121 return seconds/60L*neg;
3122 case INTERVAL_SECOND:
3123 return seconds*neg;
3124 case INTERVAL_MICROSECOND:
3126 In MySQL difference between any two valid datetime values
3127 in microseconds fits into longlong.
3129 return (seconds*1000000L+microseconds)*neg;
3130 default:
3131 break;
3134 null_date:
3135 null_value=1;
3136 return 0;
3140 void Item_func_timestamp_diff::print(String *str, enum_query_type query_type)
3142 str->append(func_name());
3143 str->append('(');
3145 switch (int_type) {
3146 case INTERVAL_YEAR:
3147 str->append(STRING_WITH_LEN("YEAR"));
3148 break;
3149 case INTERVAL_QUARTER:
3150 str->append(STRING_WITH_LEN("QUARTER"));
3151 break;
3152 case INTERVAL_MONTH:
3153 str->append(STRING_WITH_LEN("MONTH"));
3154 break;
3155 case INTERVAL_WEEK:
3156 str->append(STRING_WITH_LEN("WEEK"));
3157 break;
3158 case INTERVAL_DAY:
3159 str->append(STRING_WITH_LEN("DAY"));
3160 break;
3161 case INTERVAL_HOUR:
3162 str->append(STRING_WITH_LEN("HOUR"));
3163 break;
3164 case INTERVAL_MINUTE:
3165 str->append(STRING_WITH_LEN("MINUTE"));
3166 break;
3167 case INTERVAL_SECOND:
3168 str->append(STRING_WITH_LEN("SECOND"));
3169 break;
3170 case INTERVAL_MICROSECOND:
3171 str->append(STRING_WITH_LEN("SECOND_FRAC"));
3172 break;
3173 default:
3174 break;
3177 for (uint i=0 ; i < 2 ; i++)
3179 str->append(',');
3180 args[i]->print(str, query_type);
3182 str->append(')');
3186 String *Item_func_get_format::val_str(String *str)
3188 DBUG_ASSERT(fixed == 1);
3189 const char *format_name;
3190 KNOWN_DATE_TIME_FORMAT *format;
3191 String *val= args[0]->val_str(str);
3192 ulong val_len;
3194 if ((null_value= args[0]->null_value))
3195 return 0;
3197 val_len= val->length();
3198 for (format= &known_date_time_formats[0];
3199 (format_name= format->format_name);
3200 format++)
3202 uint format_name_len;
3203 format_name_len= (uint) strlen(format_name);
3204 if (val_len == format_name_len &&
3205 !my_strnncoll(&my_charset_latin1,
3206 (const uchar *) val->ptr(), val_len,
3207 (const uchar *) format_name, val_len))
3209 const char *format_str= get_date_time_format_str(format, type);
3210 str->set(format_str, (uint) strlen(format_str), &my_charset_bin);
3211 return str;
3215 null_value= 1;
3216 return 0;
3220 void Item_func_get_format::print(String *str, enum_query_type query_type)
3222 str->append(func_name());
3223 str->append('(');
3225 switch (type) {
3226 case MYSQL_TIMESTAMP_DATE:
3227 str->append(STRING_WITH_LEN("DATE, "));
3228 break;
3229 case MYSQL_TIMESTAMP_DATETIME:
3230 str->append(STRING_WITH_LEN("DATETIME, "));
3231 break;
3232 case MYSQL_TIMESTAMP_TIME:
3233 str->append(STRING_WITH_LEN("TIME, "));
3234 break;
3235 default:
3236 DBUG_ASSERT(0);
3238 args[0]->print(str, query_type);
3239 str->append(')');
3244 Get type of datetime value (DATE/TIME/...) which will be produced
3245 according to format string.
3247 @param format format string
3248 @param length length of format string
3250 @note
3251 We don't process day format's characters('D', 'd', 'e') because day
3252 may be a member of all date/time types.
3254 @note
3255 Format specifiers supported by this function should be in sync with
3256 specifiers supported by extract_date_time() function.
3258 @return
3259 One of date_time_format_types values:
3260 - DATE_TIME_MICROSECOND
3261 - DATE_TIME
3262 - DATE_ONLY
3263 - TIME_MICROSECOND
3264 - TIME_ONLY
3267 static date_time_format_types
3268 get_date_time_result_type(const char *format, uint length)
3270 const char *time_part_frms= "HISThiklrs";
3271 const char *date_part_frms= "MVUXYWabcjmvuxyw";
3272 bool date_part_used= 0, time_part_used= 0, frac_second_used= 0;
3274 const char *val= format;
3275 const char *end= format + length;
3277 for (; val != end && val != end; val++)
3279 if (*val == '%' && val+1 != end)
3281 val++;
3282 if (*val == 'f')
3283 frac_second_used= time_part_used= 1;
3284 else if (!time_part_used && strchr(time_part_frms, *val))
3285 time_part_used= 1;
3286 else if (!date_part_used && strchr(date_part_frms, *val))
3287 date_part_used= 1;
3288 if (date_part_used && frac_second_used)
3291 frac_second_used implies time_part_used, and thus we already
3292 have all types of date-time components and can end our search.
3294 return DATE_TIME_MICROSECOND;
3299 /* We don't have all three types of date-time components */
3300 if (frac_second_used)
3301 return TIME_MICROSECOND;
3302 if (time_part_used)
3304 if (date_part_used)
3305 return DATE_TIME;
3306 return TIME_ONLY;
3308 return DATE_ONLY;
3312 void Item_func_str_to_date::fix_length_and_dec()
3314 maybe_null= 1;
3315 decimals=0;
3316 cached_format_type= DATE_TIME;
3317 cached_field_type= MYSQL_TYPE_DATETIME;
3318 max_length= MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
3319 cached_timestamp_type= MYSQL_TIMESTAMP_NONE;
3320 if ((const_item= args[1]->const_item()))
3322 char format_buff[64];
3323 String format_str(format_buff, sizeof(format_buff), &my_charset_bin);
3324 String *format= args[1]->val_str(&format_str);
3325 if (!args[1]->null_value)
3327 cached_format_type= get_date_time_result_type(format->ptr(),
3328 format->length());
3329 switch (cached_format_type) {
3330 case DATE_ONLY:
3331 cached_timestamp_type= MYSQL_TIMESTAMP_DATE;
3332 cached_field_type= MYSQL_TYPE_DATE;
3333 max_length= MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN;
3334 break;
3335 case TIME_ONLY:
3336 case TIME_MICROSECOND:
3337 cached_timestamp_type= MYSQL_TIMESTAMP_TIME;
3338 cached_field_type= MYSQL_TYPE_TIME;
3339 max_length= MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN;
3340 break;
3341 default:
3342 cached_timestamp_type= MYSQL_TIMESTAMP_DATETIME;
3343 cached_field_type= MYSQL_TYPE_DATETIME;
3344 break;
3351 bool Item_func_str_to_date::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
3353 DATE_TIME_FORMAT date_time_format;
3354 char val_buff[64], format_buff[64];
3355 String val_string(val_buff, sizeof(val_buff), &my_charset_bin), *val;
3356 String format_str(format_buff, sizeof(format_buff), &my_charset_bin), *format;
3358 val= args[0]->val_str(&val_string);
3359 format= args[1]->val_str(&format_str);
3360 if (args[0]->null_value || args[1]->null_value)
3361 goto null_date;
3363 null_value= 0;
3364 bzero((char*) ltime, sizeof(*ltime));
3365 date_time_format.format.str= (char*) format->ptr();
3366 date_time_format.format.length= format->length();
3367 if (extract_date_time(&date_time_format, val->ptr(), val->length(),
3368 ltime, cached_timestamp_type, 0, "datetime") ||
3369 ((fuzzy_date & TIME_NO_ZERO_DATE) &&
3370 (ltime->year == 0 || ltime->month == 0 || ltime->day == 0)))
3371 goto null_date;
3372 if (cached_timestamp_type == MYSQL_TIMESTAMP_TIME && ltime->day)
3375 Day part for time type can be nonzero value and so
3376 we should add hours from day part to hour part to
3377 keep valid time value.
3379 ltime->hour+= ltime->day*24;
3380 ltime->day= 0;
3382 return 0;
3384 null_date:
3385 return (null_value=1);
3389 String *Item_func_str_to_date::val_str(String *str)
3391 DBUG_ASSERT(fixed == 1);
3392 MYSQL_TIME ltime;
3394 if (Item_func_str_to_date::get_date(&ltime, TIME_FUZZY_DATE))
3395 return 0;
3397 if (!make_datetime((const_item ? cached_format_type :
3398 (ltime.second_part ? DATE_TIME_MICROSECOND : DATE_TIME)),
3399 &ltime, str))
3400 return str;
3401 return 0;
3405 bool Item_func_last_day::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
3407 if (get_arg0_date(ltime, fuzzy_date & ~TIME_FUZZY_DATE) ||
3408 (ltime->month == 0))
3410 null_value= 1;
3411 return 1;
3413 null_value= 0;
3414 uint month_idx= ltime->month-1;
3415 ltime->day= days_in_month[month_idx];
3416 if ( month_idx == 1 && calc_days_in_year(ltime->year) == 366)
3417 ltime->day= 29;
3418 ltime->hour= ltime->minute= ltime->second= 0;
3419 ltime->second_part= 0;
3420 ltime->time_type= MYSQL_TIMESTAMP_DATE;
3421 return 0;