~stewart/drizzle/embedded-innodb-create-select-transaction-arrgh

« back to all changes in this revision

Viewing changes to sql/item_timefunc.cc

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

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