1/*
2 Copyright (c) 2000, 2012, Oracle and/or its affiliates.
3 Copyright (c) 2009, 2016, MariaDB
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; version 2 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
17
18
19/**
20 @file
21
22 @brief
23 This file defines all time functions
24
25 @todo
26 Move month and days to language files
27*/
28
29#ifdef USE_PRAGMA_IMPLEMENTATION
30#pragma implementation // gcc: Class implementation
31#endif
32
33#include "mariadb.h"
34#include "sql_priv.h"
35/*
36 It is necessary to include set_var.h instead of item.h because there
37 are dependencies on include order for set_var.h and item.h. This
38 will be resolved later.
39*/
40#include "sql_class.h" // set_var.h: THD
41#include "set_var.h"
42#include "sql_locale.h" // MY_LOCALE my_locale_en_US
43#include "strfunc.h" // check_word
44#include "sql_time.h" // make_truncated_value_warning,
45 // get_date_from_daynr,
46 // calc_weekday, calc_week,
47 // convert_month_to_period,
48 // convert_period_to_month,
49 // TIME_to_timestamp,
50 // calc_time_diff,
51 // calc_time_from_sec,
52 // get_date_time_format_str
53#include "tztime.h" // struct Time_zone
54#include "sql_class.h" // THD
55#include <m_ctype.h>
56#include <time.h>
57
58/** Day number for Dec 31st, 9999. */
59#define MAX_DAY_NUMBER 3652424L
60
61/*
62 Date formats corresponding to compound %r and %T conversion specifiers
63
64 Note: We should init at least first element of "positions" array
65 (first member) or hpux11 compiler will die horribly.
66*/
67static DATE_TIME_FORMAT time_ampm_format= {{0}, '\0', 0,
68 {(char *)"%I:%i:%S %p", 11}};
69static DATE_TIME_FORMAT time_24hrs_format= {{0}, '\0', 0,
70 {(char *)"%H:%i:%S", 8}};
71
72/**
73 Extract datetime value to MYSQL_TIME struct from string value
74 according to format string.
75
76 @param format date/time format specification
77 @param val String to decode
78 @param length Length of string
79 @param l_time Store result here
80 @param cached_timestamp_type It uses to get an appropriate warning
81 in the case when the value is truncated.
82 @param sub_pattern_end if non-zero then we are parsing string which
83 should correspond compound specifier (like %T or
84 %r) and this parameter is pointer to place where
85 pointer to end of string matching this specifier
86 should be stored.
87
88 @note
89 Possibility to parse strings matching to patterns equivalent to compound
90 specifiers is mainly intended for use from inside of this function in
91 order to understand %T and %r conversion specifiers, so number of
92 conversion specifiers that can be used in such sub-patterns is limited.
93 Also most of checks are skipped in this case.
94
95 @note
96 If one adds new format specifiers to this function he should also
97 consider adding them to get_date_time_result_type() function.
98
99 @retval
100 0 ok
101 @retval
102 1 error
103*/
104
105static bool extract_date_time(DATE_TIME_FORMAT *format,
106 const char *val, uint length, MYSQL_TIME *l_time,
107 timestamp_type cached_timestamp_type,
108 const char **sub_pattern_end,
109 const char *date_time_type,
110 ulonglong fuzzy_date)
111{
112 int weekday= 0, yearday= 0, daypart= 0;
113 int week_number= -1;
114 int error= 0;
115 int strict_week_number_year= -1;
116 int frac_part;
117 bool usa_time= 0;
118 bool UNINIT_VAR(sunday_first_n_first_week_non_iso);
119 bool UNINIT_VAR(strict_week_number);
120 bool UNINIT_VAR(strict_week_number_year_type);
121 const char *val_begin= val;
122 const char *val_end= val + length;
123 const char *ptr= format->format.str;
124 const char *end= ptr + format->format.length;
125 CHARSET_INFO *cs= &my_charset_bin;
126 DBUG_ENTER("extract_date_time");
127
128 if (!sub_pattern_end)
129 bzero((char*) l_time, sizeof(*l_time));
130
131 l_time->time_type= cached_timestamp_type;
132
133 for (; ptr != end && val != val_end; ptr++)
134 {
135 /* Skip pre-space between each argument */
136 if ((val+= cs->cset->scan(cs, val, val_end, MY_SEQ_SPACES)) >= val_end)
137 break;
138
139 if (*ptr == '%' && ptr+1 != end)
140 {
141 int val_len;
142 char *tmp;
143
144 error= 0;
145
146 val_len= (uint) (val_end - val);
147 switch (*++ptr) {
148 /* Year */
149 case 'Y':
150 tmp= (char*) val + MY_MIN(4, val_len);
151 l_time->year= (int) my_strtoll10(val, &tmp, &error);
152 if ((int) (tmp-val) <= 2)
153 l_time->year= year_2000_handling(l_time->year);
154 val= tmp;
155 break;
156 case 'y':
157 tmp= (char*) val + MY_MIN(2, val_len);
158 l_time->year= (int) my_strtoll10(val, &tmp, &error);
159 val= tmp;
160 l_time->year= year_2000_handling(l_time->year);
161 break;
162
163 /* Month */
164 case 'm':
165 case 'c':
166 tmp= (char*) val + MY_MIN(2, val_len);
167 l_time->month= (int) my_strtoll10(val, &tmp, &error);
168 val= tmp;
169 break;
170 case 'M':
171 if ((l_time->month= check_word(my_locale_en_US.month_names,
172 val, val_end, &val)) <= 0)
173 goto err;
174 break;
175 case 'b':
176 if ((l_time->month= check_word(my_locale_en_US.ab_month_names,
177 val, val_end, &val)) <= 0)
178 goto err;
179 break;
180 /* Day */
181 case 'd':
182 case 'e':
183 tmp= (char*) val + MY_MIN(2, val_len);
184 l_time->day= (int) my_strtoll10(val, &tmp, &error);
185 val= tmp;
186 break;
187 case 'D':
188 tmp= (char*) val + MY_MIN(2, val_len);
189 l_time->day= (int) my_strtoll10(val, &tmp, &error);
190 /* Skip 'st, 'nd, 'th .. */
191 val= tmp + MY_MIN((int) (val_end-tmp), 2);
192 break;
193
194 /* Hour */
195 case 'h':
196 case 'I':
197 case 'l':
198 usa_time= 1;
199 /* fall through */
200 case 'k':
201 case 'H':
202 tmp= (char*) val + MY_MIN(2, val_len);
203 l_time->hour= (int) my_strtoll10(val, &tmp, &error);
204 val= tmp;
205 break;
206
207 /* Minute */
208 case 'i':
209 tmp= (char*) val + MY_MIN(2, val_len);
210 l_time->minute= (int) my_strtoll10(val, &tmp, &error);
211 val= tmp;
212 break;
213
214 /* Second */
215 case 's':
216 case 'S':
217 tmp= (char*) val + MY_MIN(2, val_len);
218 l_time->second= (int) my_strtoll10(val, &tmp, &error);
219 val= tmp;
220 break;
221
222 /* Second part */
223 case 'f':
224 tmp= (char*) val_end;
225 if (tmp - val > 6)
226 tmp= (char*) val + 6;
227 l_time->second_part= (int) my_strtoll10(val, &tmp, &error);
228 frac_part= 6 - (int) (tmp - val);
229 if (frac_part > 0)
230 l_time->second_part*= (ulong) log_10_int[frac_part];
231 val= tmp;
232 break;
233
234 /* AM / PM */
235 case 'p':
236 if (val_len < 2 || ! usa_time)
237 goto err;
238 if (!my_strnncoll(&my_charset_latin1,
239 (const uchar *) val, 2,
240 (const uchar *) "PM", 2))
241 daypart= 12;
242 else if (my_strnncoll(&my_charset_latin1,
243 (const uchar *) val, 2,
244 (const uchar *) "AM", 2))
245 goto err;
246 val+= 2;
247 break;
248
249 /* Exotic things */
250 case 'W':
251 if ((weekday= check_word(my_locale_en_US.day_names, val, val_end, &val)) <= 0)
252 goto err;
253 break;
254 case 'a':
255 if ((weekday= check_word(my_locale_en_US.ab_day_names, val, val_end, &val)) <= 0)
256 goto err;
257 break;
258 case 'w':
259 tmp= (char*) val + 1;
260 if (unlikely((weekday= (int) my_strtoll10(val, &tmp, &error)) < 0 ||
261 weekday >= 7))
262 goto err;
263 /* We should use the same 1 - 7 scale for %w as for %W */
264 if (!weekday)
265 weekday= 7;
266 val= tmp;
267 break;
268 case 'j':
269 tmp= (char*) val + MY_MIN(val_len, 3);
270 yearday= (int) my_strtoll10(val, &tmp, &error);
271 val= tmp;
272 break;
273
274 /* Week numbers */
275 case 'V':
276 case 'U':
277 case 'v':
278 case 'u':
279 sunday_first_n_first_week_non_iso= (*ptr=='U' || *ptr== 'V');
280 strict_week_number= (*ptr=='V' || *ptr=='v');
281 tmp= (char*) val + MY_MIN(val_len, 2);
282 if (unlikely((week_number=
283 (int) my_strtoll10(val, &tmp, &error)) < 0 ||
284 (strict_week_number && !week_number) ||
285 week_number > 53))
286 goto err;
287 val= tmp;
288 break;
289
290 /* Year used with 'strict' %V and %v week numbers */
291 case 'X':
292 case 'x':
293 strict_week_number_year_type= (*ptr=='X');
294 tmp= (char*) val + MY_MIN(4, val_len);
295 strict_week_number_year= (int) my_strtoll10(val, &tmp, &error);
296 val= tmp;
297 break;
298
299 /* Time in AM/PM notation */
300 case 'r':
301 /*
302 We can't just set error here, as we don't want to generate two
303 warnings in case of errors
304 */
305 if (extract_date_time(&time_ampm_format, val,
306 (uint)(val_end - val), l_time,
307 cached_timestamp_type, &val, "time", fuzzy_date))
308 DBUG_RETURN(1);
309 break;
310
311 /* Time in 24-hour notation */
312 case 'T':
313 if (extract_date_time(&time_24hrs_format, val,
314 (uint)(val_end - val), l_time,
315 cached_timestamp_type, &val, "time", fuzzy_date))
316 DBUG_RETURN(1);
317 break;
318
319 /* Conversion specifiers that match classes of characters */
320 case '.':
321 while (my_ispunct(cs, *val) && val != val_end)
322 val++;
323 break;
324 case '@':
325 while (my_isalpha(cs, *val) && val != val_end)
326 val++;
327 break;
328 case '#':
329 while (my_isdigit(cs, *val) && val != val_end)
330 val++;
331 break;
332 default:
333 goto err;
334 }
335 if (unlikely(error)) // Error from my_strtoll10
336 goto err;
337 }
338 else if (!my_isspace(cs, *ptr))
339 {
340 if (*val != *ptr)
341 goto err;
342 val++;
343 }
344 }
345 if (usa_time)
346 {
347 if (l_time->hour > 12 || l_time->hour < 1)
348 goto err;
349 l_time->hour= l_time->hour%12+daypart;
350 }
351
352 /*
353 If we are recursively called for parsing string matching compound
354 specifiers we are already done.
355 */
356 if (sub_pattern_end)
357 {
358 *sub_pattern_end= val;
359 DBUG_RETURN(0);
360 }
361
362 if (yearday > 0)
363 {
364 uint days;
365 days= calc_daynr(l_time->year,1,1) + yearday - 1;
366 if (get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day))
367 goto err;
368 }
369
370 if (week_number >= 0 && weekday)
371 {
372 int days;
373 uint weekday_b;
374
375 /*
376 %V,%v require %X,%x resprectively,
377 %U,%u should be used with %Y and not %X or %x
378 */
379 if ((strict_week_number &&
380 (strict_week_number_year < 0 ||
381 strict_week_number_year_type !=
382 sunday_first_n_first_week_non_iso)) ||
383 (!strict_week_number && strict_week_number_year >= 0))
384 goto err;
385
386 /* Number of days since year 0 till 1st Jan of this year */
387 days= calc_daynr((strict_week_number ? strict_week_number_year :
388 l_time->year),
389 1, 1);
390 /* Which day of week is 1st Jan of this year */
391 weekday_b= calc_weekday(days, sunday_first_n_first_week_non_iso);
392
393 /*
394 Below we are going to sum:
395 1) number of days since year 0 till 1st day of 1st week of this year
396 2) number of days between 1st week and our week
397 3) and position of our day in the week
398 */
399 if (sunday_first_n_first_week_non_iso)
400 {
401 days+= ((weekday_b == 0) ? 0 : 7) - weekday_b +
402 (week_number - 1) * 7 +
403 weekday % 7;
404 }
405 else
406 {
407 days+= ((weekday_b <= 3) ? 0 : 7) - weekday_b +
408 (week_number - 1) * 7 +
409 (weekday - 1);
410 }
411
412 if (get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day))
413 goto err;
414 }
415
416 if (l_time->month > 12 || l_time->day > 31 || l_time->hour > 23 ||
417 l_time->minute > 59 || l_time->second > 59)
418 goto err;
419
420 int was_cut;
421 if (check_date(l_time, fuzzy_date | TIME_INVALID_DATES, &was_cut))
422 goto err;
423
424 if (val != val_end)
425 {
426 do
427 {
428 if (!my_isspace(&my_charset_latin1,*val))
429 {
430 make_truncated_value_warning(current_thd,
431 Sql_condition::WARN_LEVEL_WARN,
432 val_begin, length,
433 cached_timestamp_type, NullS);
434 break;
435 }
436 } while (++val != val_end);
437 }
438 DBUG_RETURN(0);
439
440err:
441 {
442 THD *thd= current_thd;
443 char buff[128];
444 strmake(buff, val_begin, MY_MIN(length, sizeof(buff)-1));
445 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
446 ER_WRONG_VALUE_FOR_TYPE,
447 ER_THD(thd, ER_WRONG_VALUE_FOR_TYPE),
448 date_time_type, buff, "str_to_date");
449 }
450 DBUG_RETURN(1);
451}
452
453
454/**
455 Create a formated date/time value in a string.
456*/
457
458static bool make_date_time(DATE_TIME_FORMAT *format, MYSQL_TIME *l_time,
459 timestamp_type type, const MY_LOCALE *locale,
460 String *str)
461{
462 char intbuff[15];
463 uint hours_i;
464 uint weekday;
465 ulong length;
466 const char *ptr, *end;
467
468 str->length(0);
469
470 if (l_time->neg)
471 str->append('-');
472
473 end= (ptr= format->format.str) + format->format.length;
474 for (; ptr != end ; ptr++)
475 {
476 if (*ptr != '%' || ptr+1 == end)
477 str->append(*ptr);
478 else
479 {
480 switch (*++ptr) {
481 case 'M':
482 if (type == MYSQL_TIMESTAMP_TIME || !l_time->month)
483 return 1;
484 str->append(locale->month_names->type_names[l_time->month-1],
485 (uint) strlen(locale->month_names->type_names[l_time->month-1]),
486 system_charset_info);
487 break;
488 case 'b':
489 if (type == MYSQL_TIMESTAMP_TIME || !l_time->month)
490 return 1;
491 str->append(locale->ab_month_names->type_names[l_time->month-1],
492 (uint) strlen(locale->ab_month_names->type_names[l_time->month-1]),
493 system_charset_info);
494 break;
495 case 'W':
496 if (type == MYSQL_TIMESTAMP_TIME || !(l_time->month || l_time->year))
497 return 1;
498 weekday= calc_weekday(calc_daynr(l_time->year,l_time->month,
499 l_time->day),0);
500 str->append(locale->day_names->type_names[weekday],
501 (uint) strlen(locale->day_names->type_names[weekday]),
502 system_charset_info);
503 break;
504 case 'a':
505 if (type == MYSQL_TIMESTAMP_TIME || !(l_time->month || l_time->year))
506 return 1;
507 weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,
508 l_time->day),0);
509 str->append(locale->ab_day_names->type_names[weekday],
510 (uint) strlen(locale->ab_day_names->type_names[weekday]),
511 system_charset_info);
512 break;
513 case 'D':
514 if (type == MYSQL_TIMESTAMP_TIME)
515 return 1;
516 length= (uint) (int10_to_str(l_time->day, intbuff, 10) - intbuff);
517 str->append_with_prefill(intbuff, length, 1, '0');
518 if (l_time->day >= 10 && l_time->day <= 19)
519 str->append(STRING_WITH_LEN("th"));
520 else
521 {
522 switch (l_time->day %10) {
523 case 1:
524 str->append(STRING_WITH_LEN("st"));
525 break;
526 case 2:
527 str->append(STRING_WITH_LEN("nd"));
528 break;
529 case 3:
530 str->append(STRING_WITH_LEN("rd"));
531 break;
532 default:
533 str->append(STRING_WITH_LEN("th"));
534 break;
535 }
536 }
537 break;
538 case 'Y':
539 if (type == MYSQL_TIMESTAMP_TIME)
540 return 1;
541 length= (uint) (int10_to_str(l_time->year, intbuff, 10) - intbuff);
542 str->append_with_prefill(intbuff, length, 4, '0');
543 break;
544 case 'y':
545 if (type == MYSQL_TIMESTAMP_TIME)
546 return 1;
547 length= (uint) (int10_to_str(l_time->year%100, intbuff, 10) - intbuff);
548 str->append_with_prefill(intbuff, length, 2, '0');
549 break;
550 case 'm':
551 if (type == MYSQL_TIMESTAMP_TIME)
552 return 1;
553 length= (uint) (int10_to_str(l_time->month, intbuff, 10) - intbuff);
554 str->append_with_prefill(intbuff, length, 2, '0');
555 break;
556 case 'c':
557 if (type == MYSQL_TIMESTAMP_TIME)
558 return 1;
559 length= (uint) (int10_to_str(l_time->month, intbuff, 10) - intbuff);
560 str->append_with_prefill(intbuff, length, 1, '0');
561 break;
562 case 'd':
563 if (type == MYSQL_TIMESTAMP_TIME)
564 return 1;
565 length= (uint) (int10_to_str(l_time->day, intbuff, 10) - intbuff);
566 str->append_with_prefill(intbuff, length, 2, '0');
567 break;
568 case 'e':
569 if (type == MYSQL_TIMESTAMP_TIME)
570 return 1;
571 length= (uint) (int10_to_str(l_time->day, intbuff, 10) - intbuff);
572 str->append_with_prefill(intbuff, length, 1, '0');
573 break;
574 case 'f':
575 length= (uint) (int10_to_str(l_time->second_part, intbuff, 10) - intbuff);
576 str->append_with_prefill(intbuff, length, 6, '0');
577 break;
578 case 'H':
579 length= (uint) (int10_to_str(l_time->hour, intbuff, 10) - intbuff);
580 str->append_with_prefill(intbuff, length, 2, '0');
581 break;
582 case 'h':
583 case 'I':
584 hours_i= (l_time->hour%24 + 11)%12+1;
585 length= (uint) (int10_to_str(hours_i, intbuff, 10) - intbuff);
586 str->append_with_prefill(intbuff, length, 2, '0');
587 break;
588 case 'i': /* minutes */
589 length= (uint) (int10_to_str(l_time->minute, intbuff, 10) - intbuff);
590 str->append_with_prefill(intbuff, length, 2, '0');
591 break;
592 case 'j':
593 if (type == MYSQL_TIMESTAMP_TIME)
594 return 1;
595 length= (uint) (int10_to_str(calc_daynr(l_time->year,l_time->month,
596 l_time->day) -
597 calc_daynr(l_time->year,1,1) + 1, intbuff, 10) - intbuff);
598 str->append_with_prefill(intbuff, length, 3, '0');
599 break;
600 case 'k':
601 length= (uint) (int10_to_str(l_time->hour, intbuff, 10) - intbuff);
602 str->append_with_prefill(intbuff, length, 1, '0');
603 break;
604 case 'l':
605 hours_i= (l_time->hour%24 + 11)%12+1;
606 length= (uint) (int10_to_str(hours_i, intbuff, 10) - intbuff);
607 str->append_with_prefill(intbuff, length, 1, '0');
608 break;
609 case 'p':
610 hours_i= l_time->hour%24;
611 str->append(hours_i < 12 ? "AM" : "PM",2);
612 break;
613 case 'r':
614 length= sprintf(intbuff, ((l_time->hour % 24) < 12) ?
615 "%02d:%02d:%02d AM" : "%02d:%02d:%02d PM",
616 (l_time->hour+11)%12+1,
617 l_time->minute,
618 l_time->second);
619 str->append(intbuff, length);
620 break;
621 case 'S':
622 case 's':
623 length= (uint) (int10_to_str(l_time->second, intbuff, 10) - intbuff);
624 str->append_with_prefill(intbuff, length, 2, '0');
625 break;
626 case 'T':
627 length= sprintf(intbuff, "%02d:%02d:%02d",
628 l_time->hour, l_time->minute, l_time->second);
629 str->append(intbuff, length);
630 break;
631 case 'U':
632 case 'u':
633 {
634 uint year;
635 if (type == MYSQL_TIMESTAMP_TIME)
636 return 1;
637 length= (uint) (int10_to_str(calc_week(l_time,
638 (*ptr) == 'U' ?
639 WEEK_FIRST_WEEKDAY : WEEK_MONDAY_FIRST,
640 &year),
641 intbuff, 10) - intbuff);
642 str->append_with_prefill(intbuff, length, 2, '0');
643 }
644 break;
645 case 'v':
646 case 'V':
647 {
648 uint year;
649 if (type == MYSQL_TIMESTAMP_TIME)
650 return 1;
651 length= (uint) (int10_to_str(calc_week(l_time,
652 ((*ptr) == 'V' ?
653 (WEEK_YEAR | WEEK_FIRST_WEEKDAY) :
654 (WEEK_YEAR | WEEK_MONDAY_FIRST)),
655 &year),
656 intbuff, 10) - intbuff);
657 str->append_with_prefill(intbuff, length, 2, '0');
658 }
659 break;
660 case 'x':
661 case 'X':
662 {
663 uint year;
664 if (type == MYSQL_TIMESTAMP_TIME)
665 return 1;
666 (void) calc_week(l_time,
667 ((*ptr) == 'X' ?
668 WEEK_YEAR | WEEK_FIRST_WEEKDAY :
669 WEEK_YEAR | WEEK_MONDAY_FIRST),
670 &year);
671 length= (uint) (int10_to_str(year, intbuff, 10) - intbuff);
672 str->append_with_prefill(intbuff, length, 4, '0');
673 }
674 break;
675 case 'w':
676 if (type == MYSQL_TIMESTAMP_TIME || !(l_time->month || l_time->year))
677 return 1;
678 weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,
679 l_time->day),1);
680 length= (uint) (int10_to_str(weekday, intbuff, 10) - intbuff);
681 str->append_with_prefill(intbuff, length, 1, '0');
682 break;
683
684 default:
685 str->append(*ptr);
686 break;
687 }
688 }
689 }
690 return 0;
691}
692
693
694/**
695 @details
696 Get a array of positive numbers from a string object.
697 Each number is separated by 1 non digit character
698 Return error if there is too many numbers.
699 If there is too few numbers, assume that the numbers are left out
700 from the high end. This allows one to give:
701 DAY_TO_SECOND as "D MM:HH:SS", "MM:HH:SS" "HH:SS" or as seconds.
702
703 @param length: length of str
704 @param cs: charset of str
705 @param values: array of results
706 @param count: count of elements in result array
707 @param transform_msec: if value is true we suppose
708 that the last part of string value is microseconds
709 and we should transform value to six digit value.
710 For example, '1.1' -> '1.100000'
711*/
712
713static bool get_interval_info(const char *str, size_t length,CHARSET_INFO *cs, size_t count, ulonglong *values,
714 bool transform_msec)
715{
716 const char *end=str+length;
717 uint i;
718 size_t field_length= 0;
719
720 while (str != end && !my_isdigit(cs,*str))
721 str++;
722
723 for (i=0 ; i < count ; i++)
724 {
725 longlong value;
726 const char *start= str;
727 for (value= 0; str != end && my_isdigit(cs, *str); str++)
728 value= value*10 + *str - '0';
729 if ((field_length= (size_t)(str - start)) >= 20)
730 return true;
731 values[i]= value;
732 while (str != end && !my_isdigit(cs,*str))
733 str++;
734 if (str == end && i != count-1)
735 {
736 i++;
737 /* Change values[0...i-1] -> values[0...count-1] */
738 bmove_upp((uchar*) (values+count), (uchar*) (values+i),
739 sizeof(*values)*i);
740 bzero((uchar*) values, sizeof(*values)*(count-i));
741 break;
742 }
743 }
744
745 if (transform_msec && field_length > 0)
746 {
747 if (field_length < 6)
748 values[count - 1] *= log_10_int[6 - field_length];
749 else if (field_length > 6)
750 values[count - 1] /= log_10_int[field_length - 6];
751 }
752
753 return (str != end);
754}
755
756
757longlong Item_func_period_add::val_int()
758{
759 DBUG_ASSERT(fixed == 1);
760 ulong period=(ulong) args[0]->val_int();
761 int months=(int) args[1]->val_int();
762
763 if ((null_value=args[0]->null_value || args[1]->null_value) ||
764 period == 0L)
765 return 0; /* purecov: inspected */
766 return (longlong)
767 convert_month_to_period((uint) ((int) convert_period_to_month(period)+
768 months));
769}
770
771
772longlong Item_func_period_diff::val_int()
773{
774 DBUG_ASSERT(fixed == 1);
775 ulong period1=(ulong) args[0]->val_int();
776 ulong period2=(ulong) args[1]->val_int();
777
778 if ((null_value=args[0]->null_value || args[1]->null_value))
779 return 0; /* purecov: inspected */
780 return (longlong) ((long) convert_period_to_month(period1)-
781 (long) convert_period_to_month(period2));
782}
783
784
785
786longlong Item_func_to_days::val_int()
787{
788 DBUG_ASSERT(fixed == 1);
789 MYSQL_TIME ltime;
790 if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE))
791 return 0;
792 return (longlong) calc_daynr(ltime.year,ltime.month,ltime.day);
793}
794
795
796longlong Item_func_to_seconds::val_int_endpoint(bool left_endp,
797 bool *incl_endp)
798{
799 DBUG_ASSERT(fixed == 1);
800 MYSQL_TIME ltime;
801 longlong seconds;
802 longlong days;
803 int dummy; /* unused */
804 if (get_arg0_date(&ltime, TIME_FUZZY_DATES))
805 {
806 /* got NULL, leave the incl_endp intact */
807 return LONGLONG_MIN;
808 }
809 seconds= ltime.hour * 3600L + ltime.minute * 60 + ltime.second;
810 seconds= ltime.neg ? -seconds : seconds;
811 days= (longlong) calc_daynr(ltime.year, ltime.month, ltime.day);
812 seconds+= days * 24L * 3600L;
813 /* Set to NULL if invalid date, but keep the value */
814 null_value= check_date(&ltime,
815 (ltime.year || ltime.month || ltime.day),
816 (TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE),
817 &dummy);
818 /*
819 Even if the evaluation return NULL, seconds is useful for pruning
820 */
821 return seconds;
822}
823
824longlong Item_func_to_seconds::val_int()
825{
826 DBUG_ASSERT(fixed == 1);
827 MYSQL_TIME ltime;
828 longlong seconds;
829 longlong days;
830 if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE))
831 return 0;
832 seconds= ltime.hour * 3600L + ltime.minute * 60 + ltime.second;
833 seconds=ltime.neg ? -seconds : seconds;
834 days= (longlong) calc_daynr(ltime.year, ltime.month, ltime.day);
835 return seconds + days * 24L * 3600L;
836}
837
838/*
839 Get information about this Item tree monotonicity
840
841 SYNOPSIS
842 Item_func_to_days::get_monotonicity_info()
843
844 DESCRIPTION
845 Get information about monotonicity of the function represented by this item
846 tree.
847
848 RETURN
849 See enum_monotonicity_info.
850*/
851
852enum_monotonicity_info Item_func_to_days::get_monotonicity_info() const
853{
854 if (args[0]->type() == Item::FIELD_ITEM)
855 {
856 if (args[0]->field_type() == MYSQL_TYPE_DATE)
857 return MONOTONIC_STRICT_INCREASING_NOT_NULL;
858 if (args[0]->field_type() == MYSQL_TYPE_DATETIME)
859 return MONOTONIC_INCREASING_NOT_NULL;
860 }
861 return NON_MONOTONIC;
862}
863
864enum_monotonicity_info Item_func_to_seconds::get_monotonicity_info() const
865{
866 if (args[0]->type() == Item::FIELD_ITEM)
867 {
868 if (args[0]->field_type() == MYSQL_TYPE_DATE ||
869 args[0]->field_type() == MYSQL_TYPE_DATETIME)
870 return MONOTONIC_STRICT_INCREASING_NOT_NULL;
871 }
872 return NON_MONOTONIC;
873}
874
875
876longlong Item_func_to_days::val_int_endpoint(bool left_endp, bool *incl_endp)
877{
878 DBUG_ASSERT(fixed == 1);
879 MYSQL_TIME ltime;
880 longlong res;
881 int dummy; /* unused */
882 if (get_arg0_date(&ltime, 0))
883 {
884 /* got NULL, leave the incl_endp intact */
885 return LONGLONG_MIN;
886 }
887 res=(longlong) calc_daynr(ltime.year,ltime.month,ltime.day);
888 /* Set to NULL if invalid date, but keep the value */
889 null_value= check_date(&ltime,
890 (TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE),
891 &dummy);
892 if (null_value)
893 {
894 /*
895 Even if the evaluation return NULL, the calc_daynr is useful for pruning
896 */
897 if (args[0]->field_type() != MYSQL_TYPE_DATE)
898 *incl_endp= TRUE;
899 return res;
900 }
901
902 if (args[0]->field_type() == MYSQL_TYPE_DATE)
903 {
904 // TO_DAYS() is strictly monotonic for dates, leave incl_endp intact
905 return res;
906 }
907
908 /*
909 Handle the special but practically useful case of datetime values that
910 point to day bound ("strictly less" comparison stays intact):
911
912 col < '2007-09-15 00:00:00' -> TO_DAYS(col) < TO_DAYS('2007-09-15')
913 col > '2007-09-15 23:59:59' -> TO_DAYS(col) > TO_DAYS('2007-09-15')
914
915 which is different from the general case ("strictly less" changes to
916 "less or equal"):
917
918 col < '2007-09-15 12:34:56' -> TO_DAYS(col) <= TO_DAYS('2007-09-15')
919 */
920 if ((!left_endp && !(ltime.hour || ltime.minute || ltime.second ||
921 ltime.second_part)) ||
922 (left_endp && ltime.hour == 23 && ltime.minute == 59 &&
923 ltime.second == 59))
924 /* do nothing */
925 ;
926 else
927 *incl_endp= TRUE;
928 return res;
929}
930
931
932longlong Item_func_dayofyear::val_int()
933{
934 DBUG_ASSERT(fixed == 1);
935 MYSQL_TIME ltime;
936 if (get_arg0_date(&ltime, TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE))
937 return 0;
938 return (longlong) calc_daynr(ltime.year,ltime.month,ltime.day) -
939 calc_daynr(ltime.year,1,1) + 1;
940}
941
942longlong Item_func_dayofmonth::val_int()
943{
944 DBUG_ASSERT(fixed == 1);
945 MYSQL_TIME ltime;
946 return get_arg0_date(&ltime, 0) ? 0 : (longlong) ltime.day;
947}
948
949longlong Item_func_month::val_int()
950{
951 DBUG_ASSERT(fixed == 1);
952 MYSQL_TIME ltime;
953 return get_arg0_date(&ltime, 0) ? 0 : (longlong) ltime.month;
954}
955
956
957void Item_func_monthname::fix_length_and_dec()
958{
959 THD* thd= current_thd;
960 CHARSET_INFO *cs= thd->variables.collation_connection;
961 locale= thd->variables.lc_time_names;
962 collation.set(cs, DERIVATION_COERCIBLE, locale->repertoire());
963 decimals=0;
964 max_length= locale->max_month_name_length * collation.collation->mbmaxlen;
965 maybe_null=1;
966}
967
968
969String* Item_func_monthname::val_str(String* str)
970{
971 DBUG_ASSERT(fixed == 1);
972 const char *month_name;
973 uint err;
974 MYSQL_TIME ltime;
975
976 if ((null_value= (get_arg0_date(&ltime, 0) || !ltime.month)))
977 return (String *) 0;
978
979 month_name= locale->month_names->type_names[ltime.month - 1];
980 str->copy(month_name, (uint) strlen(month_name), &my_charset_utf8_bin,
981 collation.collation, &err);
982 return str;
983}
984
985
986/**
987 Returns the quarter of the year.
988*/
989
990longlong Item_func_quarter::val_int()
991{
992 DBUG_ASSERT(fixed == 1);
993 MYSQL_TIME ltime;
994 if (get_arg0_date(&ltime, 0))
995 return 0;
996 return (longlong) ((ltime.month+2)/3);
997}
998
999longlong Item_func_hour::val_int()
1000{
1001 DBUG_ASSERT(fixed == 1);
1002 Time tm(args[0], Time::Options_for_cast());
1003 return (null_value= !tm.is_valid_time()) ? 0 : tm.get_mysql_time()->hour;
1004}
1005
1006longlong Item_func_minute::val_int()
1007{
1008 DBUG_ASSERT(fixed == 1);
1009 Time tm(args[0], Time::Options_for_cast());
1010 return (null_value= !tm.is_valid_time()) ? 0 : tm.get_mysql_time()->minute;
1011}
1012
1013/**
1014 Returns the second in time_exp in the range of 0 - 59.
1015*/
1016longlong Item_func_second::val_int()
1017{
1018 DBUG_ASSERT(fixed == 1);
1019 Time tm(args[0], Time::Options_for_cast());
1020 return (null_value= !tm.is_valid_time()) ? 0 : tm.get_mysql_time()->second;
1021}
1022
1023
1024uint week_mode(uint mode)
1025{
1026 uint week_format= (mode & 7);
1027 if (!(week_format & WEEK_MONDAY_FIRST))
1028 week_format^= WEEK_FIRST_WEEKDAY;
1029 return week_format;
1030}
1031
1032/**
1033 @verbatim
1034 The bits in week_format(for calc_week() function) has the following meaning:
1035 WEEK_MONDAY_FIRST (0) If not set Sunday is first day of week
1036 If set Monday is first day of week
1037 WEEK_YEAR (1) If not set Week is in range 0-53
1038
1039 Week 0 is returned for the the last week of the previous year (for
1040 a date at start of january) In this case one can get 53 for the
1041 first week of next year. This flag ensures that the week is
1042 relevant for the given year. Note that this flag is only
1043 releveant if WEEK_JANUARY is not set.
1044
1045 If set Week is in range 1-53.
1046
1047 In this case one may get week 53 for a date in January (when
1048 the week is that last week of previous year) and week 1 for a
1049 date in December.
1050
1051 WEEK_FIRST_WEEKDAY (2) If not set Weeks are numbered according
1052 to ISO 8601:1988
1053 If set The week that contains the first
1054 'first-day-of-week' is week 1.
1055
1056 ISO 8601:1988 means that if the week containing January 1 has
1057 four or more days in the new year, then it is week 1;
1058 Otherwise it is the last week of the previous year, and the
1059 next week is week 1.
1060 @endverbatim
1061*/
1062
1063longlong Item_func_week::val_int()
1064{
1065 DBUG_ASSERT(fixed == 1);
1066 uint year, week_format;
1067 MYSQL_TIME ltime;
1068 if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE))
1069 return 0;
1070 if (arg_count > 1)
1071 week_format= (uint)args[1]->val_int();
1072 else
1073 week_format= current_thd->variables.default_week_format;
1074 return (longlong) calc_week(&ltime, week_mode(week_format), &year);
1075}
1076
1077
1078longlong Item_func_yearweek::val_int()
1079{
1080 DBUG_ASSERT(fixed == 1);
1081 uint year,week;
1082 MYSQL_TIME ltime;
1083 if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE))
1084 return 0;
1085 week= calc_week(&ltime,
1086 (week_mode((uint) args[1]->val_int()) | WEEK_YEAR),
1087 &year);
1088 return week+year*100;
1089}
1090
1091
1092longlong Item_func_weekday::val_int()
1093{
1094 DBUG_ASSERT(fixed == 1);
1095 MYSQL_TIME ltime;
1096
1097 if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE))
1098 return 0;
1099
1100 return (longlong) calc_weekday(calc_daynr(ltime.year, ltime.month,
1101 ltime.day),
1102 odbc_type) + MY_TEST(odbc_type);
1103}
1104
1105void Item_func_dayname::fix_length_and_dec()
1106{
1107 THD* thd= current_thd;
1108 CHARSET_INFO *cs= thd->variables.collation_connection;
1109 locale= thd->variables.lc_time_names;
1110 collation.set(cs, DERIVATION_COERCIBLE, locale->repertoire());
1111 decimals=0;
1112 max_length= locale->max_day_name_length * collation.collation->mbmaxlen;
1113 maybe_null=1;
1114}
1115
1116
1117String* Item_func_dayname::val_str(String* str)
1118{
1119 DBUG_ASSERT(fixed == 1);
1120 uint weekday=(uint) val_int(); // Always Item_func_weekday()
1121 const char *day_name;
1122 uint err;
1123
1124 if (null_value)
1125 return (String*) 0;
1126
1127 day_name= locale->day_names->type_names[weekday];
1128 str->copy(day_name, (uint) strlen(day_name), &my_charset_utf8_bin,
1129 collation.collation, &err);
1130 return str;
1131}
1132
1133
1134longlong Item_func_year::val_int()
1135{
1136 DBUG_ASSERT(fixed == 1);
1137 MYSQL_TIME ltime;
1138 return get_arg0_date(&ltime, 0) ? 0 : (longlong) ltime.year;
1139}
1140
1141
1142/*
1143 Get information about this Item tree monotonicity
1144
1145 SYNOPSIS
1146 Item_func_year::get_monotonicity_info()
1147
1148 DESCRIPTION
1149 Get information about monotonicity of the function represented by this item
1150 tree.
1151
1152 RETURN
1153 See enum_monotonicity_info.
1154*/
1155
1156enum_monotonicity_info Item_func_year::get_monotonicity_info() const
1157{
1158 if (args[0]->type() == Item::FIELD_ITEM &&
1159 (args[0]->field_type() == MYSQL_TYPE_DATE ||
1160 args[0]->field_type() == MYSQL_TYPE_DATETIME))
1161 return MONOTONIC_INCREASING;
1162 return NON_MONOTONIC;
1163}
1164
1165
1166longlong Item_func_year::val_int_endpoint(bool left_endp, bool *incl_endp)
1167{
1168 DBUG_ASSERT(fixed == 1);
1169 MYSQL_TIME ltime;
1170 if (get_arg0_date(&ltime, 0))
1171 {
1172 /* got NULL, leave the incl_endp intact */
1173 return LONGLONG_MIN;
1174 }
1175
1176 /*
1177 Handle the special but practically useful case of datetime values that
1178 point to year bound ("strictly less" comparison stays intact) :
1179
1180 col < '2007-01-01 00:00:00' -> YEAR(col) < 2007
1181
1182 which is different from the general case ("strictly less" changes to
1183 "less or equal"):
1184
1185 col < '2007-09-15 23:00:00' -> YEAR(col) <= 2007
1186 */
1187 if (!left_endp && ltime.day == 1 && ltime.month == 1 &&
1188 !(ltime.hour || ltime.minute || ltime.second || ltime.second_part))
1189 ; /* do nothing */
1190 else
1191 *incl_endp= TRUE;
1192 return ltime.year;
1193}
1194
1195
1196bool Item_func_unix_timestamp::get_timestamp_value(my_time_t *seconds,
1197 ulong *second_part)
1198{
1199 DBUG_ASSERT(fixed == 1);
1200 if (args[0]->type() == FIELD_ITEM)
1201 { // Optimize timestamp field
1202 Field *field=((Item_field*) args[0])->field;
1203 if (field->type() == MYSQL_TYPE_TIMESTAMP)
1204 {
1205 if ((null_value= field->is_null()))
1206 return 1;
1207 *seconds= ((Field_timestamp*)field)->get_timestamp(second_part);
1208 return 0;
1209 }
1210 }
1211
1212 MYSQL_TIME ltime;
1213 if (get_arg0_date(&ltime, TIME_NO_ZERO_IN_DATE))
1214 return 1;
1215
1216 uint error_code;
1217 *seconds= TIME_to_timestamp(current_thd, &ltime, &error_code);
1218 *second_part= ltime.second_part;
1219 return (null_value= (error_code == ER_WARN_DATA_OUT_OF_RANGE));
1220}
1221
1222
1223longlong Item_func_unix_timestamp::int_op()
1224{
1225 if (arg_count == 0)
1226 return (longlong) current_thd->query_start();
1227
1228 ulong second_part;
1229 my_time_t seconds;
1230 if (get_timestamp_value(&seconds, &second_part))
1231 return 0;
1232
1233 return seconds;
1234}
1235
1236
1237my_decimal *Item_func_unix_timestamp::decimal_op(my_decimal* buf)
1238{
1239 ulong second_part;
1240 my_time_t seconds;
1241 if (get_timestamp_value(&seconds, &second_part))
1242 return 0;
1243
1244 return seconds2my_decimal(seconds < 0, seconds < 0 ? -seconds : seconds,
1245 second_part, buf);
1246}
1247
1248
1249enum_monotonicity_info Item_func_unix_timestamp::get_monotonicity_info() const
1250{
1251 if (args[0]->type() == Item::FIELD_ITEM &&
1252 (args[0]->field_type() == MYSQL_TYPE_TIMESTAMP))
1253 return MONOTONIC_INCREASING;
1254 return NON_MONOTONIC;
1255}
1256
1257
1258longlong Item_func_unix_timestamp::val_int_endpoint(bool left_endp, bool *incl_endp)
1259{
1260 DBUG_ASSERT(fixed == 1);
1261 DBUG_ASSERT(arg_count == 1 &&
1262 args[0]->type() == Item::FIELD_ITEM &&
1263 args[0]->field_type() == MYSQL_TYPE_TIMESTAMP);
1264 Field_timestamp *field=(Field_timestamp *)(((Item_field*)args[0])->field);
1265 /* Leave the incl_endp intact */
1266 ulong unused;
1267 my_time_t ts= field->get_timestamp(&unused);
1268 null_value= field->is_null();
1269 return ts;
1270}
1271
1272
1273longlong Item_func_time_to_sec::int_op()
1274{
1275 DBUG_ASSERT(fixed == 1);
1276 Time tm(args[0], Time::Options_for_cast());
1277 return ((null_value= !tm.is_valid_time())) ? 0 : tm.to_seconds();
1278}
1279
1280
1281my_decimal *Item_func_time_to_sec::decimal_op(my_decimal* buf)
1282{
1283 DBUG_ASSERT(fixed == 1);
1284 Time tm(args[0], Time::Options_for_cast());
1285 if ((null_value= !tm.is_valid_time()))
1286 return 0;
1287 const MYSQL_TIME *ltime= tm.get_mysql_time();
1288 longlong seconds= tm.to_seconds_abs();
1289 return seconds2my_decimal(ltime->neg, seconds, ltime->second_part, buf);
1290}
1291
1292
1293/**
1294 Convert a string to a interval value.
1295
1296 To make code easy, allow interval objects without separators.
1297*/
1298
1299bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval)
1300{
1301 ulonglong array[5];
1302 longlong UNINIT_VAR(value);
1303 const char *UNINIT_VAR(str);
1304 size_t UNINIT_VAR(length);
1305 CHARSET_INFO *UNINIT_VAR(cs);
1306 char buf[100];
1307 String str_value(buf, sizeof(buf), &my_charset_bin);
1308
1309 bzero((char*) interval,sizeof(*interval));
1310 if (int_type == INTERVAL_SECOND && args->decimals)
1311 {
1312 my_decimal decimal_value, *val;
1313 ulonglong second;
1314 ulong second_part;
1315 if (!(val= args->val_decimal(&decimal_value)))
1316 return true;
1317 interval->neg= my_decimal2seconds(val, &second, &second_part);
1318 if (second == LONGLONG_MAX)
1319 {
1320 THD *thd= current_thd;
1321 ErrConvDecimal err(val);
1322 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
1323 ER_TRUNCATED_WRONG_VALUE,
1324 ER_THD(thd, ER_TRUNCATED_WRONG_VALUE), "DECIMAL",
1325 err.ptr());
1326 return true;
1327 }
1328
1329 interval->second= second;
1330 interval->second_part= second_part;
1331 return false;
1332 }
1333 else if ((int) int_type <= INTERVAL_MICROSECOND)
1334 {
1335 value= args->val_int();
1336 if (args->null_value)
1337 return 1;
1338 if (value < 0)
1339 {
1340 interval->neg=1;
1341 value= -value;
1342 }
1343 }
1344 else
1345 {
1346 String *res;
1347 if (!(res= args->val_str_ascii(&str_value)))
1348 return (1);
1349
1350 /* record negative intervalls in interval->neg */
1351 str=res->ptr();
1352 cs= res->charset();
1353 const char *end=str+res->length();
1354 while (str != end && my_isspace(cs,*str))
1355 str++;
1356 if (str != end && *str == '-')
1357 {
1358 interval->neg=1;
1359 str++;
1360 }
1361 length= (size_t) (end-str); // Set up pointers to new str
1362 }
1363
1364 switch (int_type) {
1365 case INTERVAL_YEAR:
1366 interval->year= (ulong) value;
1367 break;
1368 case INTERVAL_QUARTER:
1369 interval->month= (ulong)(value*3);
1370 break;
1371 case INTERVAL_MONTH:
1372 interval->month= (ulong) value;
1373 break;
1374 case INTERVAL_WEEK:
1375 interval->day= (ulong)(value*7);
1376 break;
1377 case INTERVAL_DAY:
1378 interval->day= (ulong) value;
1379 break;
1380 case INTERVAL_HOUR:
1381 interval->hour= (ulong) value;
1382 break;
1383 case INTERVAL_MICROSECOND:
1384 interval->second_part=value;
1385 break;
1386 case INTERVAL_MINUTE:
1387 interval->minute=value;
1388 break;
1389 case INTERVAL_SECOND:
1390 interval->second=value;
1391 break;
1392 case INTERVAL_YEAR_MONTH: // Allow YEAR-MONTH YYYYYMM
1393 if (get_interval_info(str,length,cs,2,array,0))
1394 return (1);
1395 interval->year= (ulong) array[0];
1396 interval->month= (ulong) array[1];
1397 break;
1398 case INTERVAL_DAY_HOUR:
1399 if (get_interval_info(str,length,cs,2,array,0))
1400 return (1);
1401 interval->day= (ulong) array[0];
1402 interval->hour= (ulong) array[1];
1403 break;
1404 case INTERVAL_DAY_MICROSECOND:
1405 if (get_interval_info(str,length,cs,5,array,1))
1406 return (1);
1407 interval->day= (ulong) array[0];
1408 interval->hour= (ulong) array[1];
1409 interval->minute= array[2];
1410 interval->second= array[3];
1411 interval->second_part= array[4];
1412 break;
1413 case INTERVAL_DAY_MINUTE:
1414 if (get_interval_info(str,length,cs,3,array,0))
1415 return (1);
1416 interval->day= (ulong) array[0];
1417 interval->hour= (ulong) array[1];
1418 interval->minute= array[2];
1419 break;
1420 case INTERVAL_DAY_SECOND:
1421 if (get_interval_info(str,length,cs,4,array,0))
1422 return (1);
1423 interval->day= (ulong) array[0];
1424 interval->hour= (ulong) array[1];
1425 interval->minute= array[2];
1426 interval->second= array[3];
1427 break;
1428 case INTERVAL_HOUR_MICROSECOND:
1429 if (get_interval_info(str,length,cs,4,array,1))
1430 return (1);
1431 interval->hour= (ulong) array[0];
1432 interval->minute= array[1];
1433 interval->second= array[2];
1434 interval->second_part= array[3];
1435 break;
1436 case INTERVAL_HOUR_MINUTE:
1437 if (get_interval_info(str,length,cs,2,array,0))
1438 return (1);
1439 interval->hour= (ulong) array[0];
1440 interval->minute= array[1];
1441 break;
1442 case INTERVAL_HOUR_SECOND:
1443 if (get_interval_info(str,length,cs,3,array,0))
1444 return (1);
1445 interval->hour= (ulong) array[0];
1446 interval->minute= array[1];
1447 interval->second= array[2];
1448 break;
1449 case INTERVAL_MINUTE_MICROSECOND:
1450 if (get_interval_info(str,length,cs,3,array,1))
1451 return (1);
1452 interval->minute= array[0];
1453 interval->second= array[1];
1454 interval->second_part= array[2];
1455 break;
1456 case INTERVAL_MINUTE_SECOND:
1457 if (get_interval_info(str,length,cs,2,array,0))
1458 return (1);
1459 interval->minute= array[0];
1460 interval->second= array[1];
1461 break;
1462 case INTERVAL_SECOND_MICROSECOND:
1463 if (get_interval_info(str,length,cs,2,array,1))
1464 return (1);
1465 interval->second= array[0];
1466 interval->second_part= array[1];
1467 break;
1468 case INTERVAL_LAST: /* purecov: begin deadcode */
1469 DBUG_ASSERT(0);
1470 break; /* purecov: end */
1471 }
1472 return 0;
1473}
1474
1475
1476String *Item_temporal_func::val_str(String *str)
1477{
1478 DBUG_ASSERT(fixed == 1);
1479 return val_string_from_date(str);
1480}
1481
1482
1483bool Item_temporal_hybrid_func::fix_temporal_type(MYSQL_TIME *ltime)
1484{
1485 if (ltime->time_type < 0) /* MYSQL_TIMESTAMP_NONE, MYSQL_TIMESTAMP_ERROR */
1486 return false;
1487
1488 if (ltime->time_type != MYSQL_TIMESTAMP_TIME)
1489 goto date_or_datetime_value;
1490
1491 /* Convert TIME to DATE or DATETIME */
1492 switch (field_type())
1493 {
1494 case MYSQL_TYPE_DATE:
1495 case MYSQL_TYPE_DATETIME:
1496 case MYSQL_TYPE_TIMESTAMP:
1497 {
1498 MYSQL_TIME tmp;
1499 if (time_to_datetime_with_warn(current_thd, ltime, &tmp, 0))
1500 return (null_value= true);
1501 *ltime= tmp;
1502 if (field_type() == MYSQL_TYPE_DATE)
1503 datetime_to_date(ltime);
1504 return false;
1505 }
1506 case MYSQL_TYPE_TIME:
1507 case MYSQL_TYPE_STRING: /* DATE_ADD, ADDTIME can return VARCHAR */
1508 return false;
1509 default:
1510 DBUG_ASSERT(0);
1511 return (null_value= true);
1512 }
1513
1514date_or_datetime_value:
1515 /* Convert DATE or DATETIME to TIME, DATE, or DATETIME */
1516 switch (field_type())
1517 {
1518 case MYSQL_TYPE_TIME:
1519 datetime_to_time(ltime);
1520 return false;
1521 case MYSQL_TYPE_DATETIME:
1522 case MYSQL_TYPE_TIMESTAMP:
1523 date_to_datetime(ltime);
1524 return false;
1525 case MYSQL_TYPE_DATE:
1526 datetime_to_date(ltime);
1527 return false;
1528 case MYSQL_TYPE_STRING: /* DATE_ADD, ADDTIME can return VARCHAR */
1529 return false;
1530 default:
1531 DBUG_ASSERT(0);
1532 return (null_value= true);
1533 }
1534 return false;
1535}
1536
1537
1538String *Item_temporal_hybrid_func::val_str_ascii(String *str)
1539{
1540 DBUG_ASSERT(fixed == 1);
1541 MYSQL_TIME ltime;
1542
1543 if (get_date(&ltime, 0) || fix_temporal_type(&ltime) ||
1544 (null_value= my_TIME_to_str(&ltime, str, decimals)))
1545 return (String *) 0;
1546
1547 /* Check that the returned timestamp type matches to the function type */
1548 DBUG_ASSERT(field_type() == MYSQL_TYPE_STRING ||
1549 ltime.time_type == MYSQL_TIMESTAMP_NONE ||
1550 ltime.time_type == mysql_timestamp_type());
1551 return str;
1552}
1553
1554
1555bool Item_func_from_days::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
1556{
1557 longlong value=args[0]->val_int();
1558 if ((null_value= (args[0]->null_value ||
1559 ((fuzzy_date & TIME_NO_ZERO_DATE) && value == 0))))
1560 return true;
1561 bzero(ltime, sizeof(MYSQL_TIME));
1562 if (get_date_from_daynr((long) value, &ltime->year, &ltime->month,
1563 &ltime->day))
1564 return 0;
1565
1566 ltime->time_type= MYSQL_TIMESTAMP_DATE;
1567 return 0;
1568}
1569
1570
1571/**
1572 Converts current time in my_time_t to MYSQL_TIME represenatation for local
1573 time zone. Defines time zone (local) used for whole CURDATE function.
1574*/
1575void Item_func_curdate_local::store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)
1576{
1577 thd->variables.time_zone->gmt_sec_to_TIME(now_time, thd->query_start());
1578 thd->time_zone_used= 1;
1579}
1580
1581
1582/**
1583 Converts current time in my_time_t to MYSQL_TIME represenatation for UTC
1584 time zone. Defines time zone (UTC) used for whole UTC_DATE function.
1585*/
1586void Item_func_curdate_utc::store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)
1587{
1588 my_tz_UTC->gmt_sec_to_TIME(now_time, thd->query_start());
1589 /*
1590 We are not flagging this query as using time zone, since it uses fixed
1591 UTC-SYSTEM time-zone.
1592 */
1593}
1594
1595
1596bool Item_func_curdate::get_date(MYSQL_TIME *res,
1597 ulonglong fuzzy_date __attribute__((unused)))
1598{
1599 THD *thd= current_thd;
1600 query_id_t query_id= thd->query_id;
1601 /* Cache value for this query */
1602 if (last_query_id != query_id)
1603 {
1604 last_query_id= query_id;
1605 store_now_in_TIME(thd, &ltime);
1606 /* We don't need to set second_part and neg because they already 0 */
1607 ltime.hour= ltime.minute= ltime.second= 0;
1608 ltime.time_type= MYSQL_TIMESTAMP_DATE;
1609 }
1610 *res=ltime;
1611 return 0;
1612}
1613
1614
1615bool Item_func_curtime::fix_fields(THD *thd, Item **items)
1616{
1617 if (decimals > TIME_SECOND_PART_DIGITS)
1618 {
1619 my_error(ER_TOO_BIG_PRECISION, MYF(0), static_cast<ulonglong>(decimals),
1620 func_name(), TIME_SECOND_PART_DIGITS);
1621 return 1;
1622 }
1623 return Item_timefunc::fix_fields(thd, items);
1624}
1625
1626bool Item_func_curtime::get_date(MYSQL_TIME *res,
1627 ulonglong fuzzy_date __attribute__((unused)))
1628{
1629 THD *thd= current_thd;
1630 query_id_t query_id= thd->query_id;
1631 /* Cache value for this query */
1632 if (last_query_id != query_id)
1633 {
1634 last_query_id= query_id;
1635 store_now_in_TIME(thd, &ltime);
1636 }
1637 *res= ltime;
1638 return 0;
1639}
1640
1641void Item_func_curtime::print(String *str, enum_query_type query_type)
1642{
1643 str->append(func_name());
1644 str->append('(');
1645 if (decimals)
1646 str->append_ulonglong(decimals);
1647 str->append(')');
1648}
1649
1650static void set_sec_part(ulong sec_part, MYSQL_TIME *ltime, Item *item)
1651{
1652 DBUG_ASSERT(item->decimals == AUTO_SEC_PART_DIGITS ||
1653 item->decimals <= TIME_SECOND_PART_DIGITS);
1654 if (item->decimals)
1655 {
1656 ltime->second_part= sec_part;
1657 if (item->decimals < TIME_SECOND_PART_DIGITS)
1658 my_time_trunc(ltime, item->decimals);
1659 }
1660}
1661
1662/**
1663 Converts current time in my_time_t to MYSQL_TIME represenatation for local
1664 time zone. Defines time zone (local) used for whole CURTIME function.
1665*/
1666void Item_func_curtime_local::store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)
1667{
1668 thd->variables.time_zone->gmt_sec_to_TIME(now_time, thd->query_start());
1669 now_time->year= now_time->month= now_time->day= 0;
1670 now_time->time_type= MYSQL_TIMESTAMP_TIME;
1671 set_sec_part(thd->query_start_sec_part(), now_time, this);
1672 thd->time_zone_used= 1;
1673}
1674
1675
1676/**
1677 Converts current time in my_time_t to MYSQL_TIME represenatation for UTC
1678 time zone. Defines time zone (UTC) used for whole UTC_TIME function.
1679*/
1680void Item_func_curtime_utc::store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)
1681{
1682 my_tz_UTC->gmt_sec_to_TIME(now_time, thd->query_start());
1683 now_time->year= now_time->month= now_time->day= 0;
1684 now_time->time_type= MYSQL_TIMESTAMP_TIME;
1685 set_sec_part(thd->query_start_sec_part(), now_time, this);
1686 /*
1687 We are not flagging this query as using time zone, since it uses fixed
1688 UTC-SYSTEM time-zone.
1689 */
1690}
1691
1692bool Item_func_now::fix_fields(THD *thd, Item **items)
1693{
1694 if (decimals > TIME_SECOND_PART_DIGITS)
1695 {
1696 my_error(ER_TOO_BIG_PRECISION, MYF(0), static_cast<ulonglong>(decimals),
1697 func_name(), TIME_SECOND_PART_DIGITS);
1698 return 1;
1699 }
1700 return Item_temporal_func::fix_fields(thd, items);
1701}
1702
1703void Item_func_now::print(String *str, enum_query_type query_type)
1704{
1705 str->append(func_name());
1706 str->append('(');
1707 if (decimals)
1708 str->append_ulonglong(decimals);
1709 str->append(')');
1710}
1711
1712
1713int Item_func_now_local::save_in_field(Field *field, bool no_conversions)
1714{
1715 if (field->type() == MYSQL_TYPE_TIMESTAMP)
1716 {
1717 THD *thd= field->get_thd();
1718 my_time_t ts= thd->query_start();
1719 uint dec= MY_MIN(decimals, field->decimals());
1720 ulong sec_part= dec ? thd->query_start_sec_part() : 0;
1721 sec_part-= my_time_fraction_remainder(sec_part, dec);
1722 field->set_notnull();
1723 ((Field_timestamp*)field)->store_TIME(ts, sec_part);
1724 return 0;
1725 }
1726 else
1727 return Item_temporal_func::save_in_field(field, no_conversions);
1728}
1729
1730
1731/**
1732 Converts current time in my_time_t to MYSQL_TIME represenatation for local
1733 time zone. Defines time zone (local) used for whole NOW function.
1734*/
1735void Item_func_now_local::store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)
1736{
1737 thd->variables.time_zone->gmt_sec_to_TIME(now_time, thd->query_start());
1738 set_sec_part(thd->query_start_sec_part(), now_time, this);
1739 thd->time_zone_used= 1;
1740}
1741
1742
1743/**
1744 Converts current time in my_time_t to MYSQL_TIME represenatation for UTC
1745 time zone. Defines time zone (UTC) used for whole UTC_TIMESTAMP function.
1746*/
1747void Item_func_now_utc::store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)
1748{
1749 my_tz_UTC->gmt_sec_to_TIME(now_time, thd->query_start());
1750 set_sec_part(thd->query_start_sec_part(), now_time, this);
1751 /*
1752 We are not flagging this query as using time zone, since it uses fixed
1753 UTC-SYSTEM time-zone.
1754 */
1755}
1756
1757
1758bool Item_func_now::get_date(MYSQL_TIME *res,
1759 ulonglong fuzzy_date __attribute__((unused)))
1760{
1761 THD *thd= current_thd;
1762 query_id_t query_id= thd->query_id;
1763 /* Cache value for this query */
1764 if (last_query_id != query_id)
1765 {
1766 last_query_id= query_id;
1767 store_now_in_TIME(thd, &ltime);
1768 }
1769 *res= ltime;
1770 return 0;
1771}
1772
1773
1774/**
1775 Converts current time in my_time_t to MYSQL_TIME represenatation for local
1776 time zone. Defines time zone (local) used for whole SYSDATE function.
1777*/
1778void Item_func_sysdate_local::store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)
1779{
1780 my_hrtime_t now= my_hrtime();
1781 thd->variables.time_zone->gmt_sec_to_TIME(now_time, hrtime_to_my_time(now));
1782 set_sec_part(hrtime_sec_part(now), now_time, this);
1783 thd->time_zone_used= 1;
1784}
1785
1786
1787bool Item_func_sysdate_local::get_date(MYSQL_TIME *res,
1788 ulonglong fuzzy_date __attribute__((unused)))
1789{
1790 store_now_in_TIME(current_thd, res);
1791 return 0;
1792}
1793
1794bool Item_func_sec_to_time::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
1795{
1796 DBUG_ASSERT(fixed == 1);
1797 bool sign;
1798 ulonglong sec;
1799 ulong sec_part;
1800
1801 bzero((char *)ltime, sizeof(*ltime));
1802 ltime->time_type= MYSQL_TIMESTAMP_TIME;
1803
1804 sign= args[0]->get_seconds(&sec, &sec_part);
1805
1806 if ((null_value= args[0]->null_value))
1807 return 1;
1808
1809 ltime->neg= sign;
1810 if (sec > TIME_MAX_VALUE_SECONDS)
1811 goto overflow;
1812
1813 DBUG_ASSERT(sec_part <= TIME_MAX_SECOND_PART);
1814
1815 ltime->hour= (uint) (sec/3600);
1816 ltime->minute= (uint) (sec % 3600) /60;
1817 ltime->second= (uint) sec % 60;
1818 ltime->second_part= sec_part;
1819
1820 return 0;
1821
1822overflow:
1823 /* use check_time_range() to set ltime to the max value depending on dec */
1824 int unused;
1825 char buf[100];
1826 String tmp(buf, sizeof(buf), &my_charset_bin), *err= args[0]->val_str(&tmp);
1827
1828 ltime->hour= TIME_MAX_HOUR+1;
1829 check_time_range(ltime, decimals, &unused);
1830 if (!err)
1831 {
1832 ErrConvInteger err2(sec, unsigned_flag);
1833 make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN,
1834 &err2, MYSQL_TIMESTAMP_TIME, NullS);
1835 }
1836 else
1837 {
1838 ErrConvString err2(err);
1839 make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN,
1840 &err2, MYSQL_TIMESTAMP_TIME, NullS);
1841 }
1842 return 0;
1843}
1844
1845void Item_func_date_format::fix_length_and_dec()
1846{
1847 THD* thd= current_thd;
1848 if (!is_time_format)
1849 {
1850 if (arg_count < 3)
1851 locale= thd->variables.lc_time_names;
1852 else
1853 if (args[2]->basic_const_item())
1854 locale= args[2]->locale_from_val_str();
1855 }
1856
1857 /*
1858 Must use this_item() in case it's a local SP variable
1859 (for ->max_length and ->str_value)
1860 */
1861 Item *arg1= args[1]->this_item();
1862
1863 decimals=0;
1864 CHARSET_INFO *cs= thd->variables.collation_connection;
1865 uint32 repertoire= arg1->collation.repertoire;
1866 if (!thd->variables.lc_time_names->is_ascii)
1867 repertoire|= MY_REPERTOIRE_EXTENDED;
1868 collation.set(cs, arg1->collation.derivation, repertoire);
1869 StringBuffer<STRING_BUFFER_USUAL_SIZE> buffer;
1870 String *str;
1871 if (args[1]->basic_const_item() && (str= args[1]->val_str(&buffer)))
1872 { // Optimize the normal case
1873 fixed_length=1;
1874 max_length= format_length(str) * collation.collation->mbmaxlen;
1875 }
1876 else
1877 {
1878 fixed_length=0;
1879 max_length=MY_MIN(arg1->max_length, MAX_BLOB_WIDTH) * 10 *
1880 collation.collation->mbmaxlen;
1881 set_if_smaller(max_length,MAX_BLOB_WIDTH);
1882 }
1883 maybe_null=1; // If wrong date
1884}
1885
1886
1887bool Item_func_date_format::eq(const Item *item, bool binary_cmp) const
1888{
1889 Item_func_date_format *item_func;
1890
1891 if (item->type() != FUNC_ITEM)
1892 return 0;
1893 if (func_name() != ((Item_func*) item)->func_name())
1894 return 0;
1895 if (this == item)
1896 return 1;
1897 item_func= (Item_func_date_format*) item;
1898 if (arg_count != item_func->arg_count)
1899 return 0;
1900 if (!args[0]->eq(item_func->args[0], binary_cmp))
1901 return 0;
1902 /*
1903 We must compare format string case sensitive.
1904 This needed because format modifiers with different case,
1905 for example %m and %M, have different meaning.
1906 */
1907 if (!args[1]->eq(item_func->args[1], 1))
1908 return 0;
1909 if (arg_count > 2 && !args[2]->eq(item_func->args[2], 1))
1910 return 0;
1911 return 1;
1912}
1913
1914
1915
1916uint Item_func_date_format::format_length(const String *format)
1917{
1918 uint size=0;
1919 const char *ptr=format->ptr();
1920 const char *end=ptr+format->length();
1921
1922 for (; ptr != end ; ptr++)
1923 {
1924 if (*ptr != '%' || ptr == end-1)
1925 size++;
1926 else
1927 {
1928 switch(*++ptr) {
1929 case 'M': /* month, textual */
1930 case 'W': /* day (of the week), textual */
1931 size += 64; /* large for UTF8 locale data */
1932 break;
1933 case 'D': /* day (of the month), numeric plus english suffix */
1934 case 'Y': /* year, numeric, 4 digits */
1935 case 'x': /* Year, used with 'v' */
1936 case 'X': /* Year, used with 'v, where week starts with Monday' */
1937 size += 4;
1938 break;
1939 case 'a': /* locale's abbreviated weekday name (Sun..Sat) */
1940 case 'b': /* locale's abbreviated month name (Jan.Dec) */
1941 size += 32; /* large for UTF8 locale data */
1942 break;
1943 case 'j': /* day of year (001..366) */
1944 size += 3;
1945 break;
1946 case 'U': /* week (00..52) */
1947 case 'u': /* week (00..52), where week starts with Monday */
1948 case 'V': /* week 1..53 used with 'x' */
1949 case 'v': /* week 1..53 used with 'x', where week starts with Monday */
1950 case 'y': /* year, numeric, 2 digits */
1951 case 'm': /* month, numeric */
1952 case 'd': /* day (of the month), numeric */
1953 case 'h': /* hour (01..12) */
1954 case 'I': /* --||-- */
1955 case 'i': /* minutes, numeric */
1956 case 'l': /* hour ( 1..12) */
1957 case 'p': /* locale's AM or PM */
1958 case 'S': /* second (00..61) */
1959 case 's': /* seconds, numeric */
1960 case 'c': /* month (0..12) */
1961 case 'e': /* day (0..31) */
1962 size += 2;
1963 break;
1964 case 'k': /* hour ( 0..23) */
1965 case 'H': /* hour (00..23; value > 23 OK, padding always 2-digit) */
1966 size += 7; /* docs allow > 23, range depends on sizeof(unsigned int) */
1967 break;
1968 case 'r': /* time, 12-hour (hh:mm:ss [AP]M) */
1969 size += 11;
1970 break;
1971 case 'T': /* time, 24-hour (hh:mm:ss) */
1972 size += 8;
1973 break;
1974 case 'f': /* microseconds */
1975 size += 6;
1976 break;
1977 case 'w': /* day (of the week), numeric */
1978 case '%':
1979 default:
1980 size++;
1981 break;
1982 }
1983 }
1984 }
1985 return size;
1986}
1987
1988
1989String *Item_func_date_format::val_str(String *str)
1990{
1991 String *format;
1992 MYSQL_TIME l_time;
1993 uint size;
1994 const MY_LOCALE *lc= 0;
1995 DBUG_ASSERT(fixed == 1);
1996
1997 if ((null_value= args[0]->get_date(&l_time, is_time_format ? TIME_TIME_ONLY : 0)))
1998 return 0;
1999
2000 if (!(format = args[1]->val_str(str)) || !format->length())
2001 goto null_date;
2002
2003 if (!is_time_format && !(lc= locale) && !(lc= args[2]->locale_from_val_str()))
2004 goto null_date; // invalid locale
2005
2006 if (fixed_length)
2007 size=max_length;
2008 else
2009 size=format_length(format);
2010
2011 if (size < MAX_DATE_STRING_REP_LENGTH)
2012 size= MAX_DATE_STRING_REP_LENGTH;
2013
2014 if (format == str)
2015 str= &value; // Save result here
2016 if (str->alloc(size))
2017 goto null_date;
2018
2019 DATE_TIME_FORMAT date_time_format;
2020 date_time_format.format.str= (char*) format->ptr();
2021 date_time_format.format.length= format->length();
2022
2023 /* Create the result string */
2024 str->set_charset(collation.collation);
2025 if (!make_date_time(&date_time_format, &l_time,
2026 is_time_format ? MYSQL_TIMESTAMP_TIME :
2027 MYSQL_TIMESTAMP_DATE,
2028 lc, str))
2029 return str;
2030
2031null_date:
2032 null_value=1;
2033 return 0;
2034}
2035
2036
2037void Item_func_from_unixtime::fix_length_and_dec()
2038{
2039 THD *thd= current_thd;
2040 thd->time_zone_used= 1;
2041 tz= thd->variables.time_zone;
2042 fix_attributes_datetime_not_fixed_dec(args[0]->decimals);
2043 maybe_null= true;
2044}
2045
2046
2047bool Item_func_from_unixtime::get_date(MYSQL_TIME *ltime,
2048 ulonglong fuzzy_date __attribute__((unused)))
2049{
2050 bool sign;
2051 ulonglong sec;
2052 ulong sec_part;
2053
2054 bzero((char *)ltime, sizeof(*ltime));
2055 ltime->time_type= MYSQL_TIMESTAMP_TIME;
2056
2057 sign= args[0]->get_seconds(&sec, &sec_part);
2058
2059 if (args[0]->null_value || sign || sec > TIMESTAMP_MAX_VALUE)
2060 return (null_value= 1);
2061
2062 tz->gmt_sec_to_TIME(ltime, (my_time_t)sec);
2063
2064 ltime->second_part= sec_part;
2065
2066 return (null_value= 0);
2067}
2068
2069
2070bool Item_func_convert_tz::get_date(MYSQL_TIME *ltime,
2071 ulonglong fuzzy_date __attribute__((unused)))
2072{
2073 my_time_t my_time_tmp;
2074 String str;
2075 THD *thd= current_thd;
2076
2077 if (!from_tz_cached)
2078 {
2079 from_tz= my_tz_find(thd, args[1]->val_str_ascii(&str));
2080 from_tz_cached= args[1]->const_item();
2081 }
2082
2083 if (!to_tz_cached)
2084 {
2085 to_tz= my_tz_find(thd, args[2]->val_str_ascii(&str));
2086 to_tz_cached= args[2]->const_item();
2087 }
2088
2089 if (from_tz==0 || to_tz==0 ||
2090 get_arg0_date(ltime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE))
2091 return (null_value= 1);
2092
2093 {
2094 uint not_used;
2095 my_time_tmp= from_tz->TIME_to_gmt_sec(ltime, &not_used);
2096 ulong sec_part= ltime->second_part;
2097 /* my_time_tmp is guranteed to be in the allowed range */
2098 if (my_time_tmp)
2099 to_tz->gmt_sec_to_TIME(ltime, my_time_tmp);
2100 /* we rely on the fact that no timezone conversion can change sec_part */
2101 ltime->second_part= sec_part;
2102 }
2103
2104 return (null_value= 0);
2105}
2106
2107
2108void Item_func_convert_tz::cleanup()
2109{
2110 from_tz_cached= to_tz_cached= 0;
2111 Item_temporal_func::cleanup();
2112}
2113
2114
2115void Item_date_add_interval::fix_length_and_dec()
2116{
2117 enum_field_types arg0_field_type;
2118
2119 if (!args[0]->type_handler()->is_traditional_type())
2120 {
2121 my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0),
2122 args[0]->type_handler()->name().ptr(),
2123 "interval", func_name());
2124 return;
2125 }
2126 /*
2127 The field type for the result of an Item_datefunc is defined as
2128 follows:
2129
2130 - If first arg is a MYSQL_TYPE_DATETIME result is MYSQL_TYPE_DATETIME
2131 - If first arg is a MYSQL_TYPE_DATE and the interval type uses hours,
2132 minutes or seconds then type is MYSQL_TYPE_DATETIME
2133 otherwise it's MYSQL_TYPE_DATE
2134 - if first arg is a MYSQL_TYPE_TIME and the interval type isn't using
2135 anything larger than days, then the result is MYSQL_TYPE_TIME,
2136 otherwise - MYSQL_TYPE_DATETIME.
2137 - Otherwise the result is MYSQL_TYPE_STRING
2138 (This is because you can't know if the string contains a DATE,
2139 MYSQL_TIME or DATETIME argument)
2140 */
2141 arg0_field_type= args[0]->field_type();
2142 uint interval_dec= 0;
2143 if (int_type == INTERVAL_MICROSECOND ||
2144 (int_type >= INTERVAL_DAY_MICROSECOND &&
2145 int_type <= INTERVAL_SECOND_MICROSECOND))
2146 interval_dec= TIME_SECOND_PART_DIGITS;
2147 else if (int_type == INTERVAL_SECOND && args[1]->decimals > 0)
2148 interval_dec= MY_MIN(args[1]->decimals, TIME_SECOND_PART_DIGITS);
2149
2150 if (arg0_field_type == MYSQL_TYPE_DATETIME ||
2151 arg0_field_type == MYSQL_TYPE_TIMESTAMP)
2152 {
2153 uint dec= MY_MAX(args[0]->datetime_precision(), interval_dec);
2154 set_handler(&type_handler_datetime);
2155 fix_attributes_datetime(dec);
2156 }
2157 else if (arg0_field_type == MYSQL_TYPE_DATE)
2158 {
2159 if (int_type <= INTERVAL_DAY || int_type == INTERVAL_YEAR_MONTH)
2160 {
2161 set_handler(&type_handler_newdate);
2162 fix_attributes_date();
2163 }
2164 else
2165 {
2166 set_handler(&type_handler_datetime2);
2167 fix_attributes_datetime(interval_dec);
2168 }
2169 }
2170 else if (arg0_field_type == MYSQL_TYPE_TIME)
2171 {
2172 uint dec= MY_MAX(args[0]->time_precision(), interval_dec);
2173 if (int_type >= INTERVAL_DAY && int_type != INTERVAL_YEAR_MONTH)
2174 {
2175 set_handler(&type_handler_time2);
2176 fix_attributes_time(dec);
2177 }
2178 else
2179 {
2180 set_handler(&type_handler_datetime2);
2181 fix_attributes_datetime(dec);
2182 }
2183 }
2184 else
2185 {
2186 uint dec= MY_MAX(args[0]->datetime_precision(), interval_dec);
2187 set_handler(&type_handler_string);
2188 collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
2189 fix_char_length_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec);
2190 }
2191 maybe_null= true;
2192}
2193
2194
2195bool Item_date_add_interval::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
2196{
2197 INTERVAL interval;
2198
2199 if (args[0]->get_date(ltime,
2200 field_type() == MYSQL_TYPE_TIME ?
2201 TIME_TIME_ONLY : 0) ||
2202 get_interval_value(args[1], int_type, &interval))
2203 return (null_value=1);
2204
2205 if (ltime->time_type != MYSQL_TIMESTAMP_TIME &&
2206 check_date_with_warn(ltime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE,
2207 MYSQL_TIMESTAMP_ERROR))
2208 return (null_value=1);
2209
2210 if (date_sub_interval)
2211 interval.neg = !interval.neg;
2212
2213 if (date_add_interval(ltime, int_type, interval))
2214 return (null_value=1);
2215 return (null_value= 0);
2216}
2217
2218
2219bool Item_date_add_interval::eq(const Item *item, bool binary_cmp) const
2220{
2221 Item_date_add_interval *other= (Item_date_add_interval*) item;
2222 if (!Item_func::eq(item, binary_cmp))
2223 return 0;
2224 return ((int_type == other->int_type) &&
2225 (date_sub_interval == other->date_sub_interval));
2226}
2227
2228/*
2229 'interval_names' reflects the order of the enumeration interval_type.
2230 See item_timefunc.h
2231 */
2232
2233static const char *interval_names[]=
2234{
2235 "year", "quarter", "month", "week", "day",
2236 "hour", "minute", "second", "microsecond",
2237 "year_month", "day_hour", "day_minute",
2238 "day_second", "hour_minute", "hour_second",
2239 "minute_second", "day_microsecond",
2240 "hour_microsecond", "minute_microsecond",
2241 "second_microsecond"
2242};
2243
2244void Item_date_add_interval::print(String *str, enum_query_type query_type)
2245{
2246 args[0]->print_parenthesised(str, query_type, ADDINTERVAL_PRECEDENCE);
2247 str->append(date_sub_interval?" - interval ":" + interval ");
2248 args[1]->print_parenthesised(str, query_type, INTERVAL_PRECEDENCE);
2249 str->append(' ');
2250 str->append(interval_names[int_type]);
2251}
2252
2253void Item_extract::print(String *str, enum_query_type query_type)
2254{
2255 str->append(STRING_WITH_LEN("extract("));
2256 str->append(interval_names[int_type]);
2257 str->append(STRING_WITH_LEN(" from "));
2258 args[0]->print(str, query_type);
2259 str->append(')');
2260}
2261
2262void Item_extract::fix_length_and_dec()
2263{
2264 maybe_null=1; // If wrong date
2265 switch (int_type) {
2266 case INTERVAL_YEAR: set_date_length(4); break; // YYYY
2267 case INTERVAL_YEAR_MONTH: set_date_length(6); break; // YYYYMM
2268 case INTERVAL_QUARTER: set_date_length(2); break; // 1..4
2269 case INTERVAL_MONTH: set_date_length(2); break; // MM
2270 case INTERVAL_WEEK: set_date_length(2); break; // 0..52
2271 case INTERVAL_DAY: set_date_length(2); break; // DD
2272 case INTERVAL_DAY_HOUR: set_time_length(4); break; // DDhh
2273 case INTERVAL_DAY_MINUTE: set_time_length(6); break; // DDhhmm
2274 case INTERVAL_DAY_SECOND: set_time_length(8); break; // DDhhmmss
2275 case INTERVAL_HOUR: set_time_length(2); break; // hh
2276 case INTERVAL_HOUR_MINUTE: set_time_length(4); break; // hhmm
2277 case INTERVAL_HOUR_SECOND: set_time_length(6); break; // hhmmss
2278 case INTERVAL_MINUTE: set_time_length(2); break; // mm
2279 case INTERVAL_MINUTE_SECOND: set_time_length(4); break; // mmss
2280 case INTERVAL_SECOND: set_time_length(2); break; // ss
2281 case INTERVAL_MICROSECOND: set_time_length(6); break; // ffffff
2282 case INTERVAL_DAY_MICROSECOND: set_time_length(14); break; // DDhhmmssffffff
2283 case INTERVAL_HOUR_MICROSECOND: set_time_length(12); break; // hhmmssffffff
2284 case INTERVAL_MINUTE_MICROSECOND: set_time_length(10); break; // mmssffffff
2285 case INTERVAL_SECOND_MICROSECOND: set_time_length(8); break; // ssffffff
2286 case INTERVAL_LAST: DBUG_ASSERT(0); break; /* purecov: deadcode */
2287 }
2288}
2289
2290
2291longlong Item_extract::val_int()
2292{
2293 DBUG_ASSERT(fixed == 1);
2294 MYSQL_TIME ltime;
2295 uint year;
2296 ulong week_format;
2297 long neg;
2298 int is_time_flag = date_value ? 0 : TIME_TIME_ONLY;
2299
2300 // Not using get_arg0_date to avoid automatic TIME to DATETIME conversion
2301 if ((null_value= args[0]->get_date(&ltime, is_time_flag)))
2302 return 0;
2303
2304 neg= ltime.neg ? -1 : 1;
2305
2306 DBUG_ASSERT(ltime.time_type != MYSQL_TIMESTAMP_TIME || ltime.day == 0);
2307 if (ltime.time_type == MYSQL_TIMESTAMP_TIME)
2308 time_to_daytime_interval(&ltime);
2309
2310 switch (int_type) {
2311 case INTERVAL_YEAR: return ltime.year;
2312 case INTERVAL_YEAR_MONTH: return ltime.year*100L+ltime.month;
2313 case INTERVAL_QUARTER: return (ltime.month+2)/3;
2314 case INTERVAL_MONTH: return ltime.month;
2315 case INTERVAL_WEEK:
2316 {
2317 week_format= current_thd->variables.default_week_format;
2318 return calc_week(&ltime, week_mode(week_format), &year);
2319 }
2320 case INTERVAL_DAY: return ltime.day;
2321 case INTERVAL_DAY_HOUR: return (long) (ltime.day*100L+ltime.hour)*neg;
2322 case INTERVAL_DAY_MINUTE: return (long) (ltime.day*10000L+
2323 ltime.hour*100L+
2324 ltime.minute)*neg;
2325 case INTERVAL_DAY_SECOND: return ((longlong) ltime.day*1000000L+
2326 (longlong) (ltime.hour*10000L+
2327 ltime.minute*100+
2328 ltime.second))*neg;
2329 case INTERVAL_HOUR: return (long) ltime.hour*neg;
2330 case INTERVAL_HOUR_MINUTE: return (long) (ltime.hour*100+ltime.minute)*neg;
2331 case INTERVAL_HOUR_SECOND: return (long) (ltime.hour*10000+ltime.minute*100+
2332 ltime.second)*neg;
2333 case INTERVAL_MINUTE: return (long) ltime.minute*neg;
2334 case INTERVAL_MINUTE_SECOND: return (long) (ltime.minute*100+ltime.second)*neg;
2335 case INTERVAL_SECOND: return (long) ltime.second*neg;
2336 case INTERVAL_MICROSECOND: return (long) ltime.second_part*neg;
2337 case INTERVAL_DAY_MICROSECOND: return (((longlong)ltime.day*1000000L +
2338 (longlong)ltime.hour*10000L +
2339 ltime.minute*100 +
2340 ltime.second)*1000000L +
2341 ltime.second_part)*neg;
2342 case INTERVAL_HOUR_MICROSECOND: return (((longlong)ltime.hour*10000L +
2343 ltime.minute*100 +
2344 ltime.second)*1000000L +
2345 ltime.second_part)*neg;
2346 case INTERVAL_MINUTE_MICROSECOND: return (((longlong)(ltime.minute*100+
2347 ltime.second))*1000000L+
2348 ltime.second_part)*neg;
2349 case INTERVAL_SECOND_MICROSECOND: return ((longlong)ltime.second*1000000L+
2350 ltime.second_part)*neg;
2351 case INTERVAL_LAST: DBUG_ASSERT(0); break; /* purecov: deadcode */
2352 }
2353 return 0; // Impossible
2354}
2355
2356bool Item_extract::eq(const Item *item, bool binary_cmp) const
2357{
2358 if (this == item)
2359 return 1;
2360 if (item->type() != FUNC_ITEM ||
2361 functype() != ((Item_func*)item)->functype())
2362 return 0;
2363
2364 Item_extract* ie= (Item_extract*)item;
2365 if (ie->int_type != int_type)
2366 return 0;
2367
2368 if (!args[0]->eq(ie->args[0], binary_cmp))
2369 return 0;
2370 return 1;
2371}
2372
2373
2374bool Item_char_typecast::eq(const Item *item, bool binary_cmp) const
2375{
2376 if (this == item)
2377 return 1;
2378 if (item->type() != FUNC_ITEM ||
2379 functype() != ((Item_func*)item)->functype())
2380 return 0;
2381
2382 Item_char_typecast *cast= (Item_char_typecast*)item;
2383 if (cast_length != cast->cast_length ||
2384 cast_cs != cast->cast_cs)
2385 return 0;
2386
2387 if (!args[0]->eq(cast->args[0], binary_cmp))
2388 return 0;
2389 return 1;
2390}
2391
2392void Item_temporal_typecast::print(String *str, enum_query_type query_type)
2393{
2394 char buf[32];
2395 str->append(STRING_WITH_LEN("cast("));
2396 args[0]->print(str, query_type);
2397 str->append(STRING_WITH_LEN(" as "));
2398 str->append(cast_type());
2399 if (decimals && decimals != NOT_FIXED_DEC)
2400 {
2401 str->append('(');
2402 str->append(llstr(decimals, buf));
2403 str->append(')');
2404 }
2405 str->append(')');
2406}
2407
2408
2409void Item_char_typecast::print(String *str, enum_query_type query_type)
2410{
2411 str->append(STRING_WITH_LEN("cast("));
2412 args[0]->print(str, query_type);
2413 str->append(STRING_WITH_LEN(" as char"));
2414 if (cast_length != ~0U)
2415 {
2416 str->append('(');
2417 char buffer[20];
2418 // my_charset_bin is good enough for numbers
2419 String st(buffer, sizeof(buffer), &my_charset_bin);
2420 st.set(static_cast<ulonglong>(cast_length), &my_charset_bin);
2421 str->append(st);
2422 str->append(')');
2423 }
2424 if (cast_cs)
2425 {
2426 str->append(STRING_WITH_LEN(" charset "));
2427 str->append(cast_cs->csname);
2428 }
2429 str->append(')');
2430}
2431
2432
2433void Item_char_typecast::check_truncation_with_warn(String *src, size_t dstlen)
2434{
2435 if (dstlen < src->length())
2436 {
2437 THD *thd= current_thd;
2438 char char_type[40];
2439 ErrConvString err(src);
2440 bool save_abort_on_warning= thd->abort_on_warning;
2441 thd->abort_on_warning&= !m_suppress_warning_to_error_escalation;
2442 my_snprintf(char_type, sizeof(char_type), "%s(%lu)",
2443 cast_cs == &my_charset_bin ? "BINARY" : "CHAR",
2444 (ulong) cast_length);
2445 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
2446 ER_TRUNCATED_WRONG_VALUE,
2447 ER_THD(thd, ER_TRUNCATED_WRONG_VALUE), char_type,
2448 err.ptr());
2449 thd->abort_on_warning= save_abort_on_warning;
2450 }
2451}
2452
2453
2454String *Item_char_typecast::reuse(String *src, size_t length)
2455{
2456 DBUG_ASSERT(length <= src->length());
2457 check_truncation_with_warn(src, length);
2458 tmp_value.set(src->ptr(), length, cast_cs);
2459 return &tmp_value;
2460}
2461
2462
2463/*
2464 Make a copy, to handle conversion or fix bad bytes.
2465*/
2466String *Item_char_typecast::copy(String *str, CHARSET_INFO *strcs)
2467{
2468 String_copier_for_item copier(current_thd);
2469 if (copier.copy_with_warn(cast_cs, &tmp_value, strcs,
2470 str->ptr(), str->length(), cast_length))
2471 {
2472 null_value= 1; // EOM
2473 return 0;
2474 }
2475 check_truncation_with_warn(str, (uint)(copier.source_end_pos() - str->ptr()));
2476 return &tmp_value;
2477}
2478
2479
2480uint Item_char_typecast::adjusted_length_with_warn(uint length)
2481{
2482 if (length <= current_thd->variables.max_allowed_packet)
2483 return length;
2484
2485 THD *thd= current_thd;
2486 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
2487 ER_WARN_ALLOWED_PACKET_OVERFLOWED,
2488 ER_THD(thd, ER_WARN_ALLOWED_PACKET_OVERFLOWED),
2489 cast_cs == &my_charset_bin ?
2490 "cast_as_binary" : func_name(),
2491 thd->variables.max_allowed_packet);
2492 return thd->variables.max_allowed_packet;
2493}
2494
2495
2496String *Item_char_typecast::val_str(String *str)
2497{
2498 DBUG_ASSERT(fixed == 1);
2499 String *res;
2500
2501 if (has_explicit_length())
2502 cast_length= adjusted_length_with_warn(cast_length);
2503
2504 if (!(res= args[0]->val_str(str)))
2505 {
2506 null_value= 1;
2507 return 0;
2508 }
2509
2510 if (cast_cs == &my_charset_bin &&
2511 has_explicit_length() &&
2512 cast_length > res->length())
2513 {
2514 // Special case: pad binary value with trailing 0x00
2515 DBUG_ASSERT(cast_length <= current_thd->variables.max_allowed_packet);
2516 if (res->alloced_length() < cast_length)
2517 {
2518 str_value.alloc(cast_length);
2519 str_value.copy(*res);
2520 res= &str_value;
2521 }
2522 bzero((char*) res->ptr() + res->length(), cast_length - res->length());
2523 res->length(cast_length);
2524 res->set_charset(&my_charset_bin);
2525 }
2526 else
2527 {
2528 /*
2529 from_cs is 0 in the case where the result set may vary between calls,
2530 for example with dynamic columns.
2531 */
2532 CHARSET_INFO *cs= from_cs ? from_cs : res->charset();
2533 if (!charset_conversion)
2534 {
2535 // Try to reuse the original string (if well formed).
2536 Well_formed_prefix prefix(cs, res->ptr(), res->end(), cast_length);
2537 if (!prefix.well_formed_error_pos())
2538 res= reuse(res, prefix.length());
2539 goto end;
2540 }
2541 // Character set conversion, or bad bytes were found.
2542 if (!(res= copy(res, cs)))
2543 return 0;
2544 }
2545
2546end:
2547 return ((null_value= (res->length() >
2548 adjusted_length_with_warn(res->length())))) ? 0 : res;
2549}
2550
2551
2552void Item_char_typecast::fix_length_and_dec_numeric()
2553{
2554 fix_length_and_dec_internal(from_cs= cast_cs->mbminlen == 1 ?
2555 cast_cs :
2556 &my_charset_latin1);
2557}
2558
2559
2560void Item_char_typecast::fix_length_and_dec_generic()
2561{
2562 fix_length_and_dec_internal(from_cs= args[0]->dynamic_result() ?
2563 0 :
2564 args[0]->collation.collation);
2565}
2566
2567
2568void Item_char_typecast::fix_length_and_dec_internal(CHARSET_INFO *from_cs)
2569{
2570 uint32 char_length;
2571 /*
2572 We always force character set conversion if cast_cs
2573 is a multi-byte character set. It garantees that the
2574 result of CAST is a well-formed string.
2575 For single-byte character sets we allow just to copy
2576 from the argument. A single-byte character sets string
2577 is always well-formed.
2578
2579 There is a special trick to convert form a number to ucs2.
2580 As numbers have my_charset_bin as their character set,
2581 it wouldn't do conversion to ucs2 without an additional action.
2582 To force conversion, we should pretend to be non-binary.
2583 Let's choose from_cs this way:
2584 - If the argument in a number and cast_cs is ucs2 (i.e. mbminlen > 1),
2585 then from_cs is set to latin1, to perform latin1 -> ucs2 conversion.
2586 - If the argument is a number and cast_cs is ASCII-compatible
2587 (i.e. mbminlen == 1), then from_cs is set to cast_cs,
2588 which allows just to take over the args[0]->val_str() result
2589 and thus avoid unnecessary character set conversion.
2590 - If the argument is not a number, then from_cs is set to
2591 the argument's charset.
2592 - If argument has a dynamic collation (can change from call to call)
2593 we set from_cs to 0 as a marker that we have to take the collation
2594 from the result string.
2595
2596 Note (TODO): we could use repertoire technique here.
2597 */
2598 charset_conversion= !from_cs || (cast_cs->mbmaxlen > 1) ||
2599 (!my_charset_same(from_cs, cast_cs) &&
2600 from_cs != &my_charset_bin &&
2601 cast_cs != &my_charset_bin);
2602 collation.set(cast_cs, DERIVATION_IMPLICIT);
2603 char_length= ((cast_length != ~0U) ? cast_length :
2604 args[0]->max_length /
2605 (cast_cs == &my_charset_bin ? 1 :
2606 args[0]->collation.collation->mbmaxlen));
2607 max_length= char_length * cast_cs->mbmaxlen;
2608}
2609
2610
2611bool Item_time_typecast::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
2612{
2613 Time tm(args[0], Time::Options_for_cast());
2614 if ((null_value= !tm.is_valid_time()))
2615 return true;
2616 tm.copy_to_mysql_time(ltime);
2617 if (decimals < TIME_SECOND_PART_DIGITS)
2618 my_time_trunc(ltime, decimals);
2619 return (fuzzy_date & TIME_TIME_ONLY) ? 0 :
2620 (null_value= check_date_with_warn(ltime, fuzzy_date,
2621 MYSQL_TIMESTAMP_ERROR));
2622}
2623
2624
2625bool Item_date_typecast::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
2626{
2627 fuzzy_date |= sql_mode_for_dates(current_thd);
2628 if (get_arg0_date(ltime, fuzzy_date & ~TIME_TIME_ONLY))
2629 return 1;
2630
2631 if (make_date_with_warn(ltime, fuzzy_date, MYSQL_TIMESTAMP_DATE))
2632 return (null_value= 1);
2633
2634 return 0;
2635}
2636
2637
2638bool Item_datetime_typecast::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
2639{
2640 fuzzy_date |= sql_mode_for_dates(current_thd);
2641 if (get_arg0_date(ltime, fuzzy_date & ~TIME_TIME_ONLY))
2642 return 1;
2643
2644 if (decimals < TIME_SECOND_PART_DIGITS)
2645 my_time_trunc(ltime, decimals);
2646
2647 DBUG_ASSERT(ltime->time_type != MYSQL_TIMESTAMP_TIME);
2648 ltime->time_type= MYSQL_TIMESTAMP_DATETIME;
2649 return 0;
2650}
2651
2652
2653/**
2654 MAKEDATE(a,b) is a date function that creates a date value
2655 from a year and day value.
2656
2657 NOTES:
2658 As arguments are integers, we can't know if the year is a 2 digit
2659 or 4 digit year. In this case we treat all years < 100 as 2 digit
2660 years. Ie, this is not safe for dates between 0000-01-01 and
2661 0099-12-31
2662*/
2663
2664bool Item_func_makedate::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
2665{
2666 DBUG_ASSERT(fixed == 1);
2667 long daynr= (long) args[1]->val_int();
2668 long year= (long) args[0]->val_int();
2669 long days;
2670
2671 if (args[0]->null_value || args[1]->null_value ||
2672 year < 0 || year > 9999 || daynr <= 0)
2673 goto err;
2674
2675 if (year < 100)
2676 year= year_2000_handling(year);
2677
2678 days= calc_daynr(year,1,1) + daynr - 1;
2679 if (get_date_from_daynr(days, &ltime->year, &ltime->month, &ltime->day))
2680 goto err;
2681 ltime->time_type= MYSQL_TIMESTAMP_DATE;
2682 ltime->neg= 0;
2683 ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0;
2684 return (null_value= 0);
2685
2686err:
2687 return (null_value= 1);
2688}
2689
2690
2691void Item_func_add_time::fix_length_and_dec()
2692{
2693 enum_field_types arg0_field_type;
2694
2695 if (!args[0]->type_handler()->is_traditional_type() ||
2696 !args[1]->type_handler()->is_traditional_type())
2697 {
2698 my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0),
2699 args[0]->type_handler()->name().ptr(),
2700 args[1]->type_handler()->name().ptr(), func_name());
2701 return;
2702 }
2703 /*
2704 The field type for the result of an Item_func_add_time function is defined
2705 as follows:
2706
2707 - If first arg is a MYSQL_TYPE_DATETIME or MYSQL_TYPE_TIMESTAMP
2708 result is MYSQL_TYPE_DATETIME
2709 - If first arg is a MYSQL_TYPE_TIME result is MYSQL_TYPE_TIME
2710 - Otherwise the result is MYSQL_TYPE_STRING
2711 */
2712
2713 arg0_field_type= args[0]->field_type();
2714 if (arg0_field_type == MYSQL_TYPE_DATE ||
2715 arg0_field_type == MYSQL_TYPE_DATETIME ||
2716 arg0_field_type == MYSQL_TYPE_TIMESTAMP ||
2717 is_date)
2718 {
2719 uint dec= MY_MAX(args[0]->datetime_precision(), args[1]->time_precision());
2720 set_handler(&type_handler_datetime2);
2721 fix_attributes_datetime(dec);
2722 }
2723 else if (arg0_field_type == MYSQL_TYPE_TIME)
2724 {
2725 uint dec= MY_MAX(args[0]->time_precision(), args[1]->time_precision());
2726 set_handler(&type_handler_time2);
2727 fix_attributes_time(dec);
2728 }
2729 else
2730 {
2731 uint dec= MY_MAX(args[0]->decimals, args[1]->decimals);
2732 set_handler(&type_handler_string);
2733 collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
2734 fix_char_length_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec);
2735 }
2736 maybe_null= true;
2737}
2738
2739/**
2740 ADDTIME(t,a) and SUBTIME(t,a) are time functions that calculate a
2741 time/datetime value
2742
2743 t: time_or_datetime_expression
2744 a: time_expression
2745
2746 Result: Time value or datetime value
2747*/
2748
2749bool Item_func_add_time::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
2750{
2751 DBUG_ASSERT(fixed == 1);
2752 MYSQL_TIME l_time1, l_time2;
2753 bool is_time= 0;
2754 long days, microseconds;
2755 longlong seconds;
2756 int l_sign= sign;
2757
2758 if (Item_func_add_time::field_type() == MYSQL_TYPE_DATETIME)
2759 {
2760 // TIMESTAMP function OR the first argument is DATE/DATETIME/TIMESTAMP
2761 if (get_arg0_date(&l_time1, 0) ||
2762 args[1]->get_time(&l_time2) ||
2763 l_time1.time_type == MYSQL_TIMESTAMP_TIME ||
2764 l_time2.time_type != MYSQL_TIMESTAMP_TIME)
2765 return (null_value= 1);
2766 }
2767 else
2768 {
2769 // ADDTIME function AND the first argument is TIME
2770 if (args[0]->get_time(&l_time1) ||
2771 args[1]->get_time(&l_time2) ||
2772 l_time2.time_type != MYSQL_TIMESTAMP_TIME)
2773 return (null_value= 1);
2774 is_time= (l_time1.time_type == MYSQL_TIMESTAMP_TIME);
2775 }
2776 if (l_time1.neg != l_time2.neg)
2777 l_sign= -l_sign;
2778
2779 bzero(ltime, sizeof(*ltime));
2780
2781 ltime->neg= calc_time_diff(&l_time1, &l_time2, -l_sign,
2782 &seconds, &microseconds);
2783
2784 /*
2785 If first argument was negative and diff between arguments
2786 is non-zero we need to swap sign to get proper result.
2787 */
2788 if (l_time1.neg && (seconds || microseconds))
2789 ltime->neg= 1-ltime->neg; // Swap sign of result
2790
2791 if (!is_time && ltime->neg)
2792 return (null_value= 1);
2793
2794 days= (long) (seconds / SECONDS_IN_24H);
2795
2796 calc_time_from_sec(ltime, (long)(seconds % SECONDS_IN_24H), microseconds);
2797
2798 ltime->time_type= is_time ? MYSQL_TIMESTAMP_TIME : MYSQL_TIMESTAMP_DATETIME;
2799
2800 if (!is_time)
2801 {
2802 if (get_date_from_daynr(days,&ltime->year,&ltime->month,&ltime->day) ||
2803 !ltime->day)
2804 return (null_value= 1);
2805 return (null_value= 0);
2806 }
2807
2808 ltime->hour+= days*24;
2809 return (null_value= adjust_time_range_with_warn(ltime, decimals));
2810}
2811
2812
2813void Item_func_add_time::print(String *str, enum_query_type query_type)
2814{
2815 if (is_date)
2816 {
2817 DBUG_ASSERT(sign > 0);
2818 str->append(STRING_WITH_LEN("timestamp("));
2819 }
2820 else
2821 {
2822 if (sign > 0)
2823 str->append(STRING_WITH_LEN("addtime("));
2824 else
2825 str->append(STRING_WITH_LEN("subtime("));
2826 }
2827 args[0]->print(str, query_type);
2828 str->append(',');
2829 args[1]->print(str, query_type);
2830 str->append(')');
2831}
2832
2833
2834/**
2835 TIMEDIFF(t,s) is a time function that calculates the
2836 time value between a start and end time.
2837
2838 t and s: time_or_datetime_expression
2839 Result: Time value
2840*/
2841
2842bool Item_func_timediff::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
2843{
2844 DBUG_ASSERT(fixed == 1);
2845 int l_sign= 1;
2846 MYSQL_TIME l_time1,l_time2,l_time3;
2847 ErrConvTime str(&l_time3);
2848
2849 /* the following may be true in, for example, date_add(timediff(...), ... */
2850 if (fuzzy_date & TIME_NO_ZERO_IN_DATE)
2851 return (null_value= 1);
2852
2853 if (args[0]->get_time(&l_time1) ||
2854 args[1]->get_time(&l_time2) ||
2855 l_time1.time_type != l_time2.time_type)
2856 return (null_value= 1);
2857
2858 if (l_time1.neg != l_time2.neg)
2859 l_sign= -l_sign;
2860
2861 if (calc_time_diff(&l_time1, &l_time2, l_sign, &l_time3, fuzzy_date))
2862 return (null_value= 1);
2863
2864 *ltime= l_time3;
2865 return (null_value= adjust_time_range_with_warn(ltime, decimals));
2866}
2867
2868/**
2869 MAKETIME(h,m,s) is a time function that calculates a time value
2870 from the total number of hours, minutes, and seconds.
2871 Result: Time value
2872*/
2873
2874bool Item_func_maketime::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
2875{
2876 DBUG_ASSERT(fixed == 1);
2877 bool overflow= 0;
2878 longlong hour= args[0]->val_int();
2879 longlong minute= args[1]->val_int();
2880 ulonglong second;
2881 ulong microsecond;
2882 bool neg= args[2]->get_seconds(&second, &microsecond);
2883
2884 if (args[0]->null_value || args[1]->null_value || args[2]->null_value ||
2885 minute < 0 || minute > 59 || neg || second > 59)
2886 return (null_value= 1);
2887
2888 bzero(ltime, sizeof(*ltime));
2889 ltime->time_type= MYSQL_TIMESTAMP_TIME;
2890
2891 /* Check for integer overflows */
2892 if (hour < 0)
2893 {
2894 if (args[0]->unsigned_flag)
2895 overflow= 1;
2896 else
2897 ltime->neg= 1;
2898 }
2899 if (-hour > TIME_MAX_HOUR || hour > TIME_MAX_HOUR)
2900 overflow= 1;
2901
2902 if (!overflow)
2903 {
2904 ltime->hour= (uint) ((hour < 0 ? -hour : hour));
2905 ltime->minute= (uint) minute;
2906 ltime->second= (uint) second;
2907 ltime->second_part= microsecond;
2908 }
2909 else
2910 {
2911 ltime->hour= TIME_MAX_HOUR;
2912 ltime->minute= TIME_MAX_MINUTE;
2913 ltime->second= TIME_MAX_SECOND;
2914 char buf[28];
2915 char *ptr= longlong10_to_str(hour, buf, args[0]->unsigned_flag ? 10 : -10);
2916 int len = (int)(ptr - buf) + sprintf(ptr, ":%02u:%02u", (uint)minute, (uint)second);
2917 make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN,
2918 buf, len, MYSQL_TIMESTAMP_TIME,
2919 NullS);
2920 }
2921
2922 return (null_value= 0);
2923}
2924
2925
2926/**
2927 MICROSECOND(a) is a function ( extraction) that extracts the microseconds
2928 from a.
2929
2930 a: Datetime or time value
2931 Result: int value
2932*/
2933
2934longlong Item_func_microsecond::val_int()
2935{
2936 DBUG_ASSERT(fixed == 1);
2937 Time tm(args[0], Time::Options_for_cast());
2938 return ((null_value= !tm.is_valid_time())) ?
2939 0 : tm.get_mysql_time()->second_part;
2940}
2941
2942
2943longlong Item_func_timestamp_diff::val_int()
2944{
2945 MYSQL_TIME ltime1, ltime2;
2946 longlong seconds;
2947 long microseconds;
2948 long months= 0;
2949 int neg= 1;
2950 THD *thd= current_thd;
2951 ulonglong fuzzydate= TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE;
2952
2953 null_value= 0;
2954
2955 if (Datetime(thd, args[0], fuzzydate).copy_to_mysql_time(&ltime1) ||
2956 Datetime(thd, args[1], fuzzydate).copy_to_mysql_time(&ltime2))
2957 goto null_date;
2958
2959 if (calc_time_diff(&ltime2,&ltime1, 1,
2960 &seconds, &microseconds))
2961 neg= -1;
2962
2963 if (int_type == INTERVAL_YEAR ||
2964 int_type == INTERVAL_QUARTER ||
2965 int_type == INTERVAL_MONTH)
2966 {
2967 uint year_beg, year_end, month_beg, month_end, day_beg, day_end;
2968 uint years= 0;
2969 uint second_beg, second_end, microsecond_beg, microsecond_end;
2970
2971 if (neg == -1)
2972 {
2973 year_beg= ltime2.year;
2974 year_end= ltime1.year;
2975 month_beg= ltime2.month;
2976 month_end= ltime1.month;
2977 day_beg= ltime2.day;
2978 day_end= ltime1.day;
2979 second_beg= ltime2.hour * 3600 + ltime2.minute * 60 + ltime2.second;
2980 second_end= ltime1.hour * 3600 + ltime1.minute * 60 + ltime1.second;
2981 microsecond_beg= ltime2.second_part;
2982 microsecond_end= ltime1.second_part;
2983 }
2984 else
2985 {
2986 year_beg= ltime1.year;
2987 year_end= ltime2.year;
2988 month_beg= ltime1.month;
2989 month_end= ltime2.month;
2990 day_beg= ltime1.day;
2991 day_end= ltime2.day;
2992 second_beg= ltime1.hour * 3600 + ltime1.minute * 60 + ltime1.second;
2993 second_end= ltime2.hour * 3600 + ltime2.minute * 60 + ltime2.second;
2994 microsecond_beg= ltime1.second_part;
2995 microsecond_end= ltime2.second_part;
2996 }
2997
2998 /* calc years */
2999 years= year_end - year_beg;
3000 if (month_end < month_beg || (month_end == month_beg && day_end < day_beg))
3001 years-= 1;
3002
3003 /* calc months */
3004 months= 12*years;
3005 if (month_end < month_beg || (month_end == month_beg && day_end < day_beg))
3006 months+= 12 - (month_beg - month_end);
3007 else
3008 months+= (month_end - month_beg);
3009
3010 if (day_end < day_beg)
3011 months-= 1;
3012 else if ((day_end == day_beg) &&
3013 ((second_end < second_beg) ||
3014 (second_end == second_beg && microsecond_end < microsecond_beg)))
3015 months-= 1;
3016 }
3017
3018 switch (int_type) {
3019 case INTERVAL_YEAR:
3020 return months/12*neg;
3021 case INTERVAL_QUARTER:
3022 return months/3*neg;
3023 case INTERVAL_MONTH:
3024 return months*neg;
3025 case INTERVAL_WEEK:
3026 return seconds / SECONDS_IN_24H / 7L * neg;
3027 case INTERVAL_DAY:
3028 return seconds / SECONDS_IN_24H * neg;
3029 case INTERVAL_HOUR:
3030 return seconds/3600L*neg;
3031 case INTERVAL_MINUTE:
3032 return seconds/60L*neg;
3033 case INTERVAL_SECOND:
3034 return seconds*neg;
3035 case INTERVAL_MICROSECOND:
3036 /*
3037 In MySQL difference between any two valid datetime values
3038 in microseconds fits into longlong.
3039 */
3040 return (seconds*1000000L+microseconds)*neg;
3041 default:
3042 break;
3043 }
3044
3045null_date:
3046 null_value=1;
3047 return 0;
3048}
3049
3050
3051void Item_func_timestamp_diff::print(String *str, enum_query_type query_type)
3052{
3053 str->append(func_name());
3054 str->append('(');
3055
3056 switch (int_type) {
3057 case INTERVAL_YEAR:
3058 str->append(STRING_WITH_LEN("YEAR"));
3059 break;
3060 case INTERVAL_QUARTER:
3061 str->append(STRING_WITH_LEN("QUARTER"));
3062 break;
3063 case INTERVAL_MONTH:
3064 str->append(STRING_WITH_LEN("MONTH"));
3065 break;
3066 case INTERVAL_WEEK:
3067 str->append(STRING_WITH_LEN("WEEK"));
3068 break;
3069 case INTERVAL_DAY:
3070 str->append(STRING_WITH_LEN("DAY"));
3071 break;
3072 case INTERVAL_HOUR:
3073 str->append(STRING_WITH_LEN("HOUR"));
3074 break;
3075 case INTERVAL_MINUTE:
3076 str->append(STRING_WITH_LEN("MINUTE"));
3077 break;
3078 case INTERVAL_SECOND:
3079 str->append(STRING_WITH_LEN("SECOND"));
3080 break;
3081 case INTERVAL_MICROSECOND:
3082 str->append(STRING_WITH_LEN("MICROSECOND"));
3083 break;
3084 default:
3085 break;
3086 }
3087
3088 for (uint i=0 ; i < 2 ; i++)
3089 {
3090 str->append(',');
3091 args[i]->print(str, query_type);
3092 }
3093 str->append(')');
3094}
3095
3096
3097String *Item_func_get_format::val_str_ascii(String *str)
3098{
3099 DBUG_ASSERT(fixed == 1);
3100 const char *format_name;
3101 KNOWN_DATE_TIME_FORMAT *format;
3102 String *val= args[0]->val_str_ascii(str);
3103 ulong val_len;
3104
3105 if ((null_value= args[0]->null_value))
3106 return 0;
3107
3108 val_len= val->length();
3109 for (format= &known_date_time_formats[0];
3110 (format_name= format->format_name);
3111 format++)
3112 {
3113 uint format_name_len;
3114 format_name_len= (uint) strlen(format_name);
3115 if (val_len == format_name_len &&
3116 !my_strnncoll(&my_charset_latin1,
3117 (const uchar *) val->ptr(), val_len,
3118 (const uchar *) format_name, val_len))
3119 {
3120 const char *format_str= get_date_time_format_str(format, type);
3121 str->set(format_str, (uint) strlen(format_str), &my_charset_numeric);
3122 return str;
3123 }
3124 }
3125
3126 null_value= 1;
3127 return 0;
3128}
3129
3130
3131void Item_func_get_format::print(String *str, enum_query_type query_type)
3132{
3133 str->append(func_name());
3134 str->append('(');
3135
3136 switch (type) {
3137 case MYSQL_TIMESTAMP_DATE:
3138 str->append(STRING_WITH_LEN("DATE, "));
3139 break;
3140 case MYSQL_TIMESTAMP_DATETIME:
3141 str->append(STRING_WITH_LEN("DATETIME, "));
3142 break;
3143 case MYSQL_TIMESTAMP_TIME:
3144 str->append(STRING_WITH_LEN("TIME, "));
3145 break;
3146 default:
3147 DBUG_ASSERT(0);
3148 }
3149 args[0]->print(str, query_type);
3150 str->append(')');
3151}
3152
3153
3154/**
3155 Get type of datetime value (DATE/TIME/...) which will be produced
3156 according to format string.
3157
3158 @param format format string
3159 @param length length of format string
3160
3161 @note
3162 We don't process day format's characters('D', 'd', 'e') because day
3163 may be a member of all date/time types.
3164
3165 @note
3166 Format specifiers supported by this function should be in sync with
3167 specifiers supported by extract_date_time() function.
3168
3169 @return
3170 One of date_time_format_types values:
3171 - DATE_TIME_MICROSECOND
3172 - DATE_TIME
3173 - DATE_ONLY
3174 - TIME_MICROSECOND
3175 - TIME_ONLY
3176*/
3177
3178static date_time_format_types
3179get_date_time_result_type(const char *format, uint length)
3180{
3181 const char *time_part_frms= "HISThiklrs";
3182 const char *date_part_frms= "MVUXYWabcjmvuxyw";
3183 bool date_part_used= 0, time_part_used= 0, frac_second_used= 0;
3184
3185 const char *val= format;
3186 const char *end= format + length;
3187
3188 for (; val != end; val++)
3189 {
3190 if (*val == '%' && val+1 != end)
3191 {
3192 val++;
3193 if (*val == 'f')
3194 frac_second_used= time_part_used= 1;
3195 else if (!time_part_used && strchr(time_part_frms, *val))
3196 time_part_used= 1;
3197 else if (!date_part_used && strchr(date_part_frms, *val))
3198 date_part_used= 1;
3199 if (date_part_used && frac_second_used)
3200 {
3201 /*
3202 frac_second_used implies time_part_used, and thus we already
3203 have all types of date-time components and can end our search.
3204 */
3205 return DATE_TIME_MICROSECOND;
3206 }
3207 }
3208 }
3209
3210 /* We don't have all three types of date-time components */
3211 if (frac_second_used)
3212 return TIME_MICROSECOND;
3213 if (time_part_used)
3214 {
3215 if (date_part_used)
3216 return DATE_TIME;
3217 return TIME_ONLY;
3218 }
3219 return DATE_ONLY;
3220}
3221
3222
3223void Item_func_str_to_date::fix_length_and_dec()
3224{
3225 if (!args[0]->type_handler()->is_traditional_type() ||
3226 !args[1]->type_handler()->is_traditional_type())
3227 {
3228 my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0),
3229 args[0]->type_handler()->name().ptr(),
3230 args[1]->type_handler()->name().ptr(), func_name());
3231 return;
3232 }
3233 if (agg_arg_charsets(collation, args, 2, MY_COLL_ALLOW_CONV, 1))
3234 return;
3235 if (collation.collation->mbminlen > 1)
3236 internal_charset= &my_charset_utf8mb4_general_ci;
3237
3238 maybe_null= true;
3239 set_handler(&type_handler_datetime2);
3240 fix_attributes_datetime(TIME_SECOND_PART_DIGITS);
3241
3242 if ((const_item= args[1]->const_item()))
3243 {
3244 char format_buff[64];
3245 String format_str(format_buff, sizeof(format_buff), &my_charset_bin);
3246 String *format= args[1]->val_str(&format_str, &format_converter,
3247 internal_charset);
3248 decimals= 0;
3249 if (!args[1]->null_value)
3250 {
3251 date_time_format_types cached_format_type=
3252 get_date_time_result_type(format->ptr(), format->length());
3253 switch (cached_format_type) {
3254 case DATE_ONLY:
3255 set_handler(&type_handler_newdate);
3256 fix_attributes_date();
3257 break;
3258 case TIME_MICROSECOND:
3259 set_handler(&type_handler_time2);
3260 fix_attributes_time(TIME_SECOND_PART_DIGITS);
3261 break;
3262 case TIME_ONLY:
3263 set_handler(&type_handler_time2);
3264 fix_attributes_time(0);
3265 break;
3266 case DATE_TIME_MICROSECOND:
3267 set_handler(&type_handler_datetime2);
3268 fix_attributes_datetime(TIME_SECOND_PART_DIGITS);
3269 break;
3270 case DATE_TIME:
3271 set_handler(&type_handler_datetime2);
3272 fix_attributes_datetime(0);
3273 break;
3274 }
3275 }
3276 }
3277 cached_timestamp_type= mysql_timestamp_type();
3278}
3279
3280
3281bool Item_func_str_to_date::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
3282{
3283 DATE_TIME_FORMAT date_time_format;
3284 char val_buff[64], format_buff[64];
3285 String val_string(val_buff, sizeof(val_buff), &my_charset_bin), *val;
3286 String format_str(format_buff, sizeof(format_buff), &my_charset_bin),
3287 *format;
3288
3289 val= args[0]->val_str(&val_string, &subject_converter, internal_charset);
3290 format= args[1]->val_str(&format_str, &format_converter, internal_charset);
3291 if (args[0]->null_value || args[1]->null_value)
3292 return (null_value=1);
3293
3294 date_time_format.format.str= (char*) format->ptr();
3295 date_time_format.format.length= format->length();
3296 if (extract_date_time(&date_time_format, val->ptr(), val->length(),
3297 ltime, cached_timestamp_type, 0, "datetime",
3298 fuzzy_date | sql_mode_for_dates(current_thd)))
3299 return (null_value=1);
3300 if (cached_timestamp_type == MYSQL_TIMESTAMP_TIME && ltime->day)
3301 {
3302 /*
3303 Day part for time type can be nonzero value and so
3304 we should add hours from day part to hour part to
3305 keep valid time value.
3306 */
3307 ltime->hour+= ltime->day*24;
3308 ltime->day= 0;
3309 }
3310 return (null_value= 0);
3311}
3312
3313
3314bool Item_func_last_day::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
3315{
3316 if (get_arg0_date(ltime, fuzzy_date & ~TIME_TIME_ONLY) ||
3317 (ltime->month == 0))
3318 return (null_value=1);
3319 uint month_idx= ltime->month-1;
3320 ltime->day= days_in_month[month_idx];
3321 if ( month_idx == 1 && calc_days_in_year(ltime->year) == 366)
3322 ltime->day= 29;
3323 ltime->hour= ltime->minute= ltime->second= 0;
3324 ltime->second_part= 0;
3325 ltime->time_type= MYSQL_TIMESTAMP_DATE;
3326 return (null_value= 0);
3327}
3328