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