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