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