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