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