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