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