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