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