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