~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/item/timefunc.cc

  • Committer: Monty Taylor
  • Date: 2008-11-24 05:39:31 UTC
  • mto: This revision was merged to the branch mainline in revision 610.
  • Revision ID: mordred@solanthus.local-20081124053931-tzlxsgkdvs3b7n8n
Reverted libuuid check code. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
 
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 
3
 *
 
4
 *  Copyright (C) 2008 Sun Microsystems
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; version 2 of the License.
 
9
 *
 
10
 *  This program is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
18
 */
 
19
 
 
20
 
 
21
/**
 
22
  @file
 
23
 
 
24
  @brief
 
25
  This file defines all time functions
 
26
 
 
27
  @todo
 
28
    Move month and days to language files
 
29
*/
 
30
#include <drizzled/server_includes.h>
 
31
#include <time.h>
 
32
#include <drizzled/error.h>
 
33
#include <drizzled/tztime.h>
 
34
#include <drizzled/item/timefunc.h>
 
35
#include <drizzled/sql_locale.h>
 
36
#include <drizzled/session.h>
 
37
 
 
38
/*
 
39
  Date formats corresponding to compound %r and %T conversion specifiers
 
40
 
 
41
  Note: We should init at least first element of "positions" array
 
42
        (first member) or hpux11 compiler will die horribly.
 
43
*/
 
44
static DATE_TIME_FORMAT time_ampm_format= {{0}, '\0', 0,
 
45
                                           {(char *)"%I:%i:%S %p", 11}};
 
46
static DATE_TIME_FORMAT time_24hrs_format= {{0}, '\0', 0,
 
47
                                            {(char *)"%H:%i:%S", 8}};
 
48
 
 
49
/**
 
50
  Extract datetime value to DRIZZLE_TIME struct from string value
 
51
  according to format string.
 
52
 
 
53
  @param format         date/time format specification
 
54
  @param val                    String to decode
 
55
  @param length         Length of string
 
56
  @param l_time         Store result here
 
57
  @param cached_timestamp_type  It uses to get an appropriate warning
 
58
                                in the case when the value is truncated.
 
59
  @param sub_pattern_end    if non-zero then we are parsing string which
 
60
                            should correspond compound specifier (like %T or
 
61
                            %r) and this parameter is pointer to place where
 
62
                            pointer to end of string matching this specifier
 
63
                            should be stored.
 
64
 
 
65
  @note
 
66
    Possibility to parse strings matching to patterns equivalent to compound
 
67
    specifiers is mainly intended for use from inside of this function in
 
68
    order to understand %T and %r conversion specifiers, so number of
 
69
    conversion specifiers that can be used in such sub-patterns is limited.
 
70
    Also most of checks are skipped in this case.
 
71
 
 
72
  @note
 
73
    If one adds new format specifiers to this function he should also
 
74
    consider adding them to get_date_time_result_type() function.
 
75
 
 
76
  @retval
 
77
    0   ok
 
78
  @retval
 
79
    1   error
 
80
*/
 
81
 
 
82
static bool extract_date_time(DATE_TIME_FORMAT *format,
 
83
                              const char *val, uint32_t length, DRIZZLE_TIME *l_time,
 
84
                              enum enum_drizzle_timestamp_type cached_timestamp_type,
 
85
                              const char **sub_pattern_end,
 
86
                              const char *date_time_type)
 
87
{
 
88
  int weekday= 0, yearday= 0, daypart= 0;
 
89
  int week_number= -1;
 
90
  int error= 0;
 
91
  int  strict_week_number_year= -1;
 
92
  int frac_part;
 
93
  bool usa_time= 0;
 
94
  bool sunday_first_n_first_week_non_iso= false;
 
95
  bool strict_week_number= false;
 
96
  bool strict_week_number_year_type= false;
 
97
  const char *val_begin= val;
 
98
  const char *val_end= val + length;
 
99
  const char *ptr= format->format.str;
 
100
  const char *end= ptr + format->format.length;
 
101
  const CHARSET_INFO * const cs= &my_charset_bin;
 
102
 
 
103
  if (!sub_pattern_end)
 
104
    memset(l_time, 0, sizeof(*l_time));
 
105
 
 
106
  for (; ptr != end && val != val_end; ptr++)
 
107
  {
 
108
    /* Skip pre-space between each argument */
 
109
    while (val != val_end && my_isspace(cs, *val))
 
110
      val++;
 
111
 
 
112
    if (*ptr == '%' && ptr+1 != end)
 
113
    {
 
114
      int val_len;
 
115
      char *tmp;
 
116
 
 
117
      error= 0;
 
118
 
 
119
      val_len= (uint) (val_end - val);
 
120
      switch (*++ptr) {
 
121
        /* Year */
 
122
      case 'Y':
 
123
        tmp= (char*) val + cmin(4, val_len);
 
124
        l_time->year= (int) my_strtoll10(val, &tmp, &error);
 
125
        if ((int) (tmp-val) <= 2)
 
126
          l_time->year= year_2000_handling(l_time->year);
 
127
        val= tmp;
 
128
        break;
 
129
      case 'y':
 
130
        tmp= (char*) val + cmin(2, val_len);
 
131
        l_time->year= (int) my_strtoll10(val, &tmp, &error);
 
132
        val= tmp;
 
133
        l_time->year= year_2000_handling(l_time->year);
 
134
        break;
 
135
 
 
136
        /* Month */
 
137
      case 'm':
 
138
      case 'c':
 
139
        tmp= (char*) val + cmin(2, val_len);
 
140
        l_time->month= (int) my_strtoll10(val, &tmp, &error);
 
141
        val= tmp;
 
142
        break;
 
143
      case 'M':
 
144
        if ((l_time->month= check_word(my_locale_en_US.month_names,
 
145
                                       val, val_end, &val)) <= 0)
 
146
          goto err;
 
147
        break;
 
148
      case 'b':
 
149
        if ((l_time->month= check_word(my_locale_en_US.ab_month_names,
 
150
                                       val, val_end, &val)) <= 0)
 
151
          goto err;
 
152
        break;
 
153
        /* Day */
 
154
      case 'd':
 
155
      case 'e':
 
156
        tmp= (char*) val + cmin(2, val_len);
 
157
        l_time->day= (int) my_strtoll10(val, &tmp, &error);
 
158
        val= tmp;
 
159
        break;
 
160
      case 'D':
 
161
        tmp= (char*) val + cmin(2, val_len);
 
162
        l_time->day= (int) my_strtoll10(val, &tmp, &error);
 
163
        /* Skip 'st, 'nd, 'th .. */
 
164
        val= tmp + cmin((int) (val_end-tmp), 2);
 
165
        break;
 
166
 
 
167
        /* Hour */
 
168
      case 'h':
 
169
      case 'I':
 
170
      case 'l':
 
171
        usa_time= 1;
 
172
        /* fall through */
 
173
      case 'k':
 
174
      case 'H':
 
175
        tmp= (char*) val + cmin(2, val_len);
 
176
        l_time->hour= (int) my_strtoll10(val, &tmp, &error);
 
177
        val= tmp;
 
178
        break;
 
179
 
 
180
        /* Minute */
 
181
      case 'i':
 
182
        tmp= (char*) val + cmin(2, val_len);
 
183
        l_time->minute= (int) my_strtoll10(val, &tmp, &error);
 
184
        val= tmp;
 
185
        break;
 
186
 
 
187
        /* Second */
 
188
      case 's':
 
189
      case 'S':
 
190
        tmp= (char*) val + cmin(2, val_len);
 
191
        l_time->second= (int) my_strtoll10(val, &tmp, &error);
 
192
        val= tmp;
 
193
        break;
 
194
 
 
195
        /* Second part */
 
196
      case 'f':
 
197
        tmp= (char*) val_end;
 
198
        if (tmp - val > 6)
 
199
          tmp= (char*) val + 6;
 
200
        l_time->second_part= (int) my_strtoll10(val, &tmp, &error);
 
201
        frac_part= 6 - (tmp - val);
 
202
        if (frac_part > 0)
 
203
          l_time->second_part*= (ulong) log_10_int[frac_part];
 
204
        val= tmp;
 
205
        break;
 
206
 
 
207
        /* AM / PM */
 
208
      case 'p':
 
209
        if (val_len < 2 || ! usa_time)
 
210
          goto err;
 
211
        if (!my_strnncoll(&my_charset_utf8_general_ci,
 
212
                          (const unsigned char *) val, 2, 
 
213
                          (const unsigned char *) "PM", 2))
 
214
          daypart= 12;
 
215
        else if (my_strnncoll(&my_charset_utf8_general_ci,
 
216
                              (const unsigned char *) val, 2, 
 
217
                              (const unsigned char *) "AM", 2))
 
218
          goto err;
 
219
        val+= 2;
 
220
        break;
 
221
 
 
222
        /* Exotic things */
 
223
      case 'W':
 
224
        if ((weekday= check_word(my_locale_en_US.day_names, val, val_end, &val)) <= 0)
 
225
          goto err;
 
226
        break;
 
227
      case 'a':
 
228
        if ((weekday= check_word(my_locale_en_US.ab_day_names, val, val_end, &val)) <= 0)
 
229
          goto err;
 
230
        break;
 
231
      case 'w':
 
232
        tmp= (char*) val + 1;
 
233
        if ((weekday= (int) my_strtoll10(val, &tmp, &error)) < 0 ||
 
234
            weekday >= 7)
 
235
          goto err;
 
236
        /* We should use the same 1 - 7 scale for %w as for %W */
 
237
        if (!weekday)
 
238
          weekday= 7;
 
239
        val= tmp;
 
240
        break;
 
241
      case 'j':
 
242
        tmp= (char*) val + cmin(val_len, 3);
 
243
        yearday= (int) my_strtoll10(val, &tmp, &error);
 
244
        val= tmp;
 
245
        break;
 
246
 
 
247
        /* Week numbers */
 
248
      case 'V':
 
249
      case 'U':
 
250
      case 'v':
 
251
      case 'u':
 
252
        sunday_first_n_first_week_non_iso= (*ptr=='U' || *ptr== 'V');
 
253
        strict_week_number= (*ptr=='V' || *ptr=='v');
 
254
        tmp= (char*) val + cmin(val_len, 2);
 
255
        if ((week_number= (int) my_strtoll10(val, &tmp, &error)) < 0 ||
 
256
            (strict_week_number && !week_number) ||
 
257
            week_number > 53)
 
258
          goto err;
 
259
        val= tmp;
 
260
        break;
 
261
 
 
262
        /* Year used with 'strict' %V and %v week numbers */
 
263
      case 'X':
 
264
      case 'x':
 
265
        strict_week_number_year_type= (*ptr=='X');
 
266
        tmp= (char*) val + cmin(4, val_len);
 
267
        strict_week_number_year= (int) my_strtoll10(val, &tmp, &error);
 
268
        val= tmp;
 
269
        break;
 
270
 
 
271
        /* Time in AM/PM notation */
 
272
      case 'r':
 
273
        /*
 
274
          We can't just set error here, as we don't want to generate two
 
275
          warnings in case of errors
 
276
        */
 
277
        if (extract_date_time(&time_ampm_format, val,
 
278
                              (uint)(val_end - val), l_time,
 
279
                              cached_timestamp_type, &val, "time"))
 
280
          return(1);
 
281
        break;
 
282
 
 
283
        /* Time in 24-hour notation */
 
284
      case 'T':
 
285
        if (extract_date_time(&time_24hrs_format, val,
 
286
                              (uint)(val_end - val), l_time,
 
287
                              cached_timestamp_type, &val, "time"))
 
288
          return(1);
 
289
        break;
 
290
 
 
291
        /* Conversion specifiers that match classes of characters */
 
292
      case '.':
 
293
        while (my_ispunct(cs, *val) && val != val_end)
 
294
          val++;
 
295
        break;
 
296
      case '@':
 
297
        while (my_isalpha(cs, *val) && val != val_end)
 
298
          val++;
 
299
        break;
 
300
      case '#':
 
301
        while (my_isdigit(cs, *val) && val != val_end)
 
302
          val++;
 
303
        break;
 
304
      default:
 
305
        goto err;
 
306
      }
 
307
      if (error)                                // Error from my_strtoll10
 
308
        goto err;
 
309
    }
 
310
    else if (!my_isspace(cs, *ptr))
 
311
    {
 
312
      if (*val != *ptr)
 
313
        goto err;
 
314
      val++;
 
315
    }
 
316
  }
 
317
  if (usa_time)
 
318
  {
 
319
    if (l_time->hour > 12 || l_time->hour < 1)
 
320
      goto err;
 
321
    l_time->hour= l_time->hour%12+daypart;
 
322
  }
 
323
 
 
324
  /*
 
325
    If we are recursively called for parsing string matching compound
 
326
    specifiers we are already done.
 
327
  */
 
328
  if (sub_pattern_end)
 
329
  {
 
330
    *sub_pattern_end= val;
 
331
    return(0);
 
332
  }
 
333
 
 
334
  if (yearday > 0)
 
335
  {
 
336
    uint32_t days;
 
337
    days= calc_daynr(l_time->year,1,1) +  yearday - 1;
 
338
    if (days <= 0 || days > MAX_DAY_NUMBER)
 
339
      goto err;
 
340
    get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day);
 
341
  }
 
342
 
 
343
  if (week_number >= 0 && weekday)
 
344
  {
 
345
    int days;
 
346
    uint32_t weekday_b;
 
347
 
 
348
    /*
 
349
      %V,%v require %X,%x resprectively,
 
350
      %U,%u should be used with %Y and not %X or %x
 
351
    */
 
352
    if ((strict_week_number &&
 
353
        (strict_week_number_year < 0 || (strict_week_number_year_type != sunday_first_n_first_week_non_iso))) ||
 
354
        (!strict_week_number && strict_week_number_year >= 0))
 
355
      goto err;
 
356
 
 
357
    /* Number of days since year 0 till 1st Jan of this year */
 
358
    days= calc_daynr((strict_week_number ? strict_week_number_year :
 
359
                                           l_time->year),
 
360
                     1, 1);
 
361
    /* Which day of week is 1st Jan of this year */
 
362
    weekday_b= calc_weekday(days, sunday_first_n_first_week_non_iso);
 
363
 
 
364
    /*
 
365
      Below we are going to sum:
 
366
      1) number of days since year 0 till 1st day of 1st week of this year
 
367
      2) number of days between 1st week and our week
 
368
      3) and position of our day in the week
 
369
    */
 
370
    if (sunday_first_n_first_week_non_iso)
 
371
    {
 
372
      days+= ((weekday_b == 0) ? 0 : 7) - weekday_b +
 
373
             (week_number - 1) * 7 +
 
374
             weekday % 7;
 
375
    }
 
376
    else
 
377
    {
 
378
      days+= ((weekday_b <= 3) ? 0 : 7) - weekday_b +
 
379
             (week_number - 1) * 7 +
 
380
             (weekday - 1);
 
381
    }
 
382
 
 
383
    if (days <= 0 || days > MAX_DAY_NUMBER)
 
384
      goto err;
 
385
    get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day);
 
386
  }
 
387
 
 
388
  if (l_time->month > 12 || l_time->day > 31 || l_time->hour > 23 || 
 
389
      l_time->minute > 59 || l_time->second > 59)
 
390
    goto err;
 
391
 
 
392
  if (val != val_end)
 
393
  {
 
394
    do
 
395
    {
 
396
      if (!my_isspace(&my_charset_utf8_general_ci,*val))
 
397
      {
 
398
        make_truncated_value_warning(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
399
                                     val_begin, length,
 
400
                                     cached_timestamp_type, NULL);
 
401
        break;
 
402
      }
 
403
    } while (++val != val_end);
 
404
  }
 
405
  return(0);
 
406
 
 
407
err:
 
408
  {
 
409
    char buff[128];
 
410
    strmake(buff, val_begin, cmin(length, (uint)sizeof(buff)-1));
 
411
    push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
412
                        ER_WRONG_VALUE_FOR_TYPE, ER(ER_WRONG_VALUE_FOR_TYPE),
 
413
                        date_time_type, buff, "str_to_date");
 
414
  }
 
415
  return(1);
 
416
}
 
417
 
 
418
 
 
419
/**
 
420
  Create a formated date/time value in a string.
 
421
*/
 
422
 
 
423
bool make_date_time(DATE_TIME_FORMAT *format, DRIZZLE_TIME *l_time,
 
424
                    enum enum_drizzle_timestamp_type type, String *str)
 
425
{
 
426
  char intbuff[15];
 
427
  uint32_t hours_i;
 
428
  uint32_t weekday;
 
429
  ulong length;
 
430
  const char *ptr, *end;
 
431
  Session *session= current_session;
 
432
  MY_LOCALE *locale= session->variables.lc_time_names;
 
433
 
 
434
  str->length(0);
 
435
 
 
436
  if (l_time->neg)
 
437
    str->append('-');
 
438
  
 
439
  end= (ptr= format->format.str) + format->format.length;
 
440
  for (; ptr != end ; ptr++)
 
441
  {
 
442
    if (*ptr != '%' || ptr+1 == end)
 
443
      str->append(*ptr);
 
444
    else
 
445
    {
 
446
      switch (*++ptr) {
 
447
      case 'M':
 
448
        if (!l_time->month)
 
449
          return 1;
 
450
        str->append(locale->month_names->type_names[l_time->month-1],
 
451
                    strlen(locale->month_names->type_names[l_time->month-1]),
 
452
                    system_charset_info);
 
453
        break;
 
454
      case 'b':
 
455
        if (!l_time->month)
 
456
          return 1;
 
457
        str->append(locale->ab_month_names->type_names[l_time->month-1],
 
458
                    strlen(locale->ab_month_names->type_names[l_time->month-1]),
 
459
                    system_charset_info);
 
460
        break;
 
461
      case 'W':
 
462
        if (type == DRIZZLE_TIMESTAMP_TIME)
 
463
          return 1;
 
464
        weekday= calc_weekday(calc_daynr(l_time->year,l_time->month,
 
465
                              l_time->day),0);
 
466
        str->append(locale->day_names->type_names[weekday],
 
467
                    strlen(locale->day_names->type_names[weekday]),
 
468
                    system_charset_info);
 
469
        break;
 
470
      case 'a':
 
471
        if (type == DRIZZLE_TIMESTAMP_TIME)
 
472
          return 1;
 
473
        weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,
 
474
                             l_time->day),0);
 
475
        str->append(locale->ab_day_names->type_names[weekday],
 
476
                    strlen(locale->ab_day_names->type_names[weekday]),
 
477
                    system_charset_info);
 
478
        break;
 
479
      case 'D':
 
480
        if (type == DRIZZLE_TIMESTAMP_TIME)
 
481
          return 1;
 
482
        length= int10_to_str(l_time->day, intbuff, 10) - intbuff;
 
483
        str->append_with_prefill(intbuff, length, 1, '0');
 
484
        if (l_time->day >= 10 &&  l_time->day <= 19)
 
485
          str->append(STRING_WITH_LEN("th"));
 
486
        else
 
487
        {
 
488
          switch (l_time->day %10) {
 
489
          case 1:
 
490
            str->append(STRING_WITH_LEN("st"));
 
491
            break;
 
492
          case 2:
 
493
            str->append(STRING_WITH_LEN("nd"));
 
494
            break;
 
495
          case 3:
 
496
            str->append(STRING_WITH_LEN("rd"));
 
497
            break;
 
498
          default:
 
499
            str->append(STRING_WITH_LEN("th"));
 
500
            break;
 
501
          }
 
502
        }
 
503
        break;
 
504
      case 'Y':
 
505
        length= int10_to_str(l_time->year, intbuff, 10) - intbuff;
 
506
        str->append_with_prefill(intbuff, length, 4, '0');
 
507
        break;
 
508
      case 'y':
 
509
        length= int10_to_str(l_time->year%100, intbuff, 10) - intbuff;
 
510
        str->append_with_prefill(intbuff, length, 2, '0');
 
511
        break;
 
512
      case 'm':
 
513
        length= int10_to_str(l_time->month, intbuff, 10) - intbuff;
 
514
        str->append_with_prefill(intbuff, length, 2, '0');
 
515
        break;
 
516
      case 'c':
 
517
        length= int10_to_str(l_time->month, intbuff, 10) - intbuff;
 
518
        str->append_with_prefill(intbuff, length, 1, '0');
 
519
        break;
 
520
      case 'd':
 
521
        length= int10_to_str(l_time->day, intbuff, 10) - intbuff;
 
522
        str->append_with_prefill(intbuff, length, 2, '0');
 
523
        break;
 
524
      case 'e':
 
525
        length= int10_to_str(l_time->day, intbuff, 10) - intbuff;
 
526
        str->append_with_prefill(intbuff, length, 1, '0');
 
527
        break;
 
528
      case 'f':
 
529
        length= int10_to_str(l_time->second_part, intbuff, 10) - intbuff;
 
530
        str->append_with_prefill(intbuff, length, 6, '0');
 
531
        break;
 
532
      case 'H':
 
533
        length= int10_to_str(l_time->hour, intbuff, 10) - intbuff;
 
534
        str->append_with_prefill(intbuff, length, 2, '0');
 
535
        break;
 
536
      case 'h':
 
537
      case 'I':
 
538
        hours_i= (l_time->hour%24 + 11)%12+1;
 
539
        length= int10_to_str(hours_i, intbuff, 10) - intbuff;
 
540
        str->append_with_prefill(intbuff, length, 2, '0');
 
541
        break;
 
542
      case 'i':                                 /* minutes */
 
543
        length= int10_to_str(l_time->minute, intbuff, 10) - intbuff;
 
544
        str->append_with_prefill(intbuff, length, 2, '0');
 
545
        break;
 
546
      case 'j':
 
547
        if (type == DRIZZLE_TIMESTAMP_TIME)
 
548
          return 1;
 
549
        length= int10_to_str(calc_daynr(l_time->year,l_time->month,
 
550
                                        l_time->day) - 
 
551
                     calc_daynr(l_time->year,1,1) + 1, intbuff, 10) - intbuff;
 
552
        str->append_with_prefill(intbuff, length, 3, '0');
 
553
        break;
 
554
      case 'k':
 
555
        length= int10_to_str(l_time->hour, intbuff, 10) - intbuff;
 
556
        str->append_with_prefill(intbuff, length, 1, '0');
 
557
        break;
 
558
      case 'l':
 
559
        hours_i= (l_time->hour%24 + 11)%12+1;
 
560
        length= int10_to_str(hours_i, intbuff, 10) - intbuff;
 
561
        str->append_with_prefill(intbuff, length, 1, '0');
 
562
        break;
 
563
      case 'p':
 
564
        hours_i= l_time->hour%24;
 
565
        str->append(hours_i < 12 ? "AM" : "PM",2);
 
566
        break;
 
567
      case 'r':
 
568
        length= sprintf(intbuff, 
 
569
                    ((l_time->hour % 24) < 12) ?
 
570
                    "%02d:%02d:%02d AM" : "%02d:%02d:%02d PM",
 
571
                    (l_time->hour+11)%12+1,
 
572
                    l_time->minute,
 
573
                    l_time->second);
 
574
        str->append(intbuff, length);
 
575
        break;
 
576
      case 'S':
 
577
      case 's':
 
578
        length= int10_to_str(l_time->second, intbuff, 10) - intbuff;
 
579
        str->append_with_prefill(intbuff, length, 2, '0');
 
580
        break;
 
581
      case 'T':
 
582
        length= sprintf(intbuff, 
 
583
                    "%02d:%02d:%02d", 
 
584
                    l_time->hour, 
 
585
                    l_time->minute,
 
586
                    l_time->second);
 
587
        str->append(intbuff, length);
 
588
        break;
 
589
      case 'U':
 
590
      case 'u':
 
591
      {
 
592
        uint32_t year;
 
593
        if (type == DRIZZLE_TIMESTAMP_TIME)
 
594
          return 1;
 
595
        length= int10_to_str(calc_week(l_time,
 
596
                                       (*ptr) == 'U' ?
 
597
                                       WEEK_FIRST_WEEKDAY : WEEK_MONDAY_FIRST,
 
598
                                       &year),
 
599
                             intbuff, 10) - intbuff;
 
600
        str->append_with_prefill(intbuff, length, 2, '0');
 
601
      }
 
602
      break;
 
603
      case 'v':
 
604
      case 'V':
 
605
      {
 
606
        uint32_t year;
 
607
        if (type == DRIZZLE_TIMESTAMP_TIME)
 
608
          return 1;
 
609
        length= int10_to_str(calc_week(l_time,
 
610
                                       ((*ptr) == 'V' ?
 
611
                                        (WEEK_YEAR | WEEK_FIRST_WEEKDAY) :
 
612
                                        (WEEK_YEAR | WEEK_MONDAY_FIRST)),
 
613
                                       &year),
 
614
                             intbuff, 10) - intbuff;
 
615
        str->append_with_prefill(intbuff, length, 2, '0');
 
616
      }
 
617
      break;
 
618
      case 'x':
 
619
      case 'X':
 
620
      {
 
621
        uint32_t year;
 
622
        if (type == DRIZZLE_TIMESTAMP_TIME)
 
623
          return 1;
 
624
        (void) calc_week(l_time,
 
625
                         ((*ptr) == 'X' ?
 
626
                          WEEK_YEAR | WEEK_FIRST_WEEKDAY :
 
627
                          WEEK_YEAR | WEEK_MONDAY_FIRST),
 
628
                         &year);
 
629
        length= int10_to_str(year, intbuff, 10) - intbuff;
 
630
        str->append_with_prefill(intbuff, length, 4, '0');
 
631
      }
 
632
      break;
 
633
      case 'w':
 
634
        if (type == DRIZZLE_TIMESTAMP_TIME)
 
635
          return 1;
 
636
        weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,
 
637
                                        l_time->day),1);
 
638
        length= int10_to_str(weekday, intbuff, 10) - intbuff;
 
639
        str->append_with_prefill(intbuff, length, 1, '0');
 
640
        break;
 
641
 
 
642
      default:
 
643
        str->append(*ptr);
 
644
        break;
 
645
      }
 
646
    }
 
647
  }
 
648
  return 0;
 
649
}
 
650
 
 
651
 
 
652
/**
 
653
  @details
 
654
  Get a array of positive numbers from a string object.
 
655
  Each number is separated by 1 non digit character
 
656
  Return error if there is too many numbers.
 
657
  If there is too few numbers, assume that the numbers are left out
 
658
  from the high end. This allows one to give:
 
659
  DAY_TO_SECOND as "D MM:HH:SS", "MM:HH:SS" "HH:SS" or as seconds.
 
660
 
 
661
  @param length:         length of str
 
662
  @param cs:             charset of str
 
663
  @param values:         array of results
 
664
  @param count:          count of elements in result array
 
665
  @param transform_msec: if value is true we suppose
 
666
                         that the last part of string value is microseconds
 
667
                         and we should transform value to six digit value.
 
668
                         For example, '1.1' -> '1.100000'
 
669
*/
 
670
 
 
671
static bool get_interval_info(const char *str,uint32_t length, const CHARSET_INFO * const cs,
 
672
                              uint32_t count, uint64_t *values,
 
673
                              bool transform_msec)
 
674
{
 
675
  const char *end=str+length;
 
676
  uint32_t i;
 
677
  while (str != end && !my_isdigit(cs,*str))
 
678
    str++;
 
679
 
 
680
  for (i=0 ; i < count ; i++)
 
681
  {
 
682
    int64_t value;
 
683
    const char *start= str;
 
684
    for (value=0; str != end && my_isdigit(cs,*str) ; str++)
 
685
      value= value * 10L + (int64_t) (*str - '0');
 
686
    if (transform_msec && i == count - 1) // microseconds always last
 
687
    {
 
688
      long msec_length= 6 - (str - start);
 
689
      if (msec_length > 0)
 
690
        value*= (long) log_10_int[msec_length];
 
691
    }
 
692
    values[i]= value;
 
693
    while (str != end && !my_isdigit(cs,*str))
 
694
      str++;
 
695
    if (str == end && i != count-1)
 
696
    {
 
697
      i++;
 
698
      /* Change values[0...i-1] -> values[0...count-1] */
 
699
      bmove_upp((unsigned char*) (values+count), (unsigned char*) (values+i),
 
700
                sizeof(*values)*i);
 
701
      memset(values, 0, sizeof(*values)*(count-i));
 
702
      break;
 
703
    }
 
704
  }
 
705
  return (str != end);
 
706
}
 
707
 
 
708
/**
 
709
  Convert a string to a interval value.
 
710
 
 
711
  To make code easy, allow interval objects without separators.
 
712
*/
 
713
 
 
714
bool get_interval_value(Item *args,interval_type int_type,
 
715
                               String *str_value, INTERVAL *interval)
 
716
{
 
717
  uint64_t array[5];
 
718
  int64_t value= 0;
 
719
  const char *str= NULL;
 
720
  size_t length= 0;
 
721
  const CHARSET_INFO * const cs= str_value->charset();
 
722
 
 
723
  memset(interval, 0, sizeof(*interval));
 
724
  if ((int) int_type <= INTERVAL_MICROSECOND)
 
725
  {
 
726
    value= args->val_int();
 
727
    if (args->null_value)
 
728
      return 1;
 
729
    if (value < 0)
 
730
    {
 
731
      interval->neg=1;
 
732
      value= -value;
 
733
    }
 
734
  }
 
735
  else
 
736
  {
 
737
    String *res;
 
738
    if (!(res=args->val_str(str_value)))
 
739
      return (1);
 
740
 
 
741
    /* record negative intervalls in interval->neg */
 
742
    str=res->ptr();
 
743
    const char *end=str+res->length();
 
744
    while (str != end && my_isspace(cs,*str))
 
745
      str++;
 
746
    if (str != end && *str == '-')
 
747
    {
 
748
      interval->neg=1;
 
749
      str++;
 
750
    }
 
751
    length= (size_t) (end-str);         // Set up pointers to new str
 
752
  }
 
753
 
 
754
  switch (int_type) {
 
755
  case INTERVAL_YEAR:
 
756
    interval->year= (ulong) value;
 
757
    break;
 
758
  case INTERVAL_QUARTER:
 
759
    interval->month= (ulong)(value*3);
 
760
    break;
 
761
  case INTERVAL_MONTH:
 
762
    interval->month= (ulong) value;
 
763
    break;
 
764
  case INTERVAL_WEEK:
 
765
    interval->day= (ulong)(value*7);
 
766
    break;
 
767
  case INTERVAL_DAY:
 
768
    interval->day= (ulong) value;
 
769
    break;
 
770
  case INTERVAL_HOUR:
 
771
    interval->hour= (ulong) value;
 
772
    break;
 
773
  case INTERVAL_MICROSECOND:
 
774
    interval->second_part=value;
 
775
    break;
 
776
  case INTERVAL_MINUTE:
 
777
    interval->minute=value;
 
778
    break;
 
779
  case INTERVAL_SECOND:
 
780
    interval->second=value;
 
781
    break;
 
782
  case INTERVAL_YEAR_MONTH:                     // Allow YEAR-MONTH YYYYYMM
 
783
    if (get_interval_info(str,length,cs,2,array,0))
 
784
      return (1);
 
785
    interval->year=  (ulong) array[0];
 
786
    interval->month= (ulong) array[1];
 
787
    break;
 
788
  case INTERVAL_DAY_HOUR:
 
789
    if (get_interval_info(str,length,cs,2,array,0))
 
790
      return (1);
 
791
    interval->day=  (ulong) array[0];
 
792
    interval->hour= (ulong) array[1];
 
793
    break;
 
794
  case INTERVAL_DAY_MICROSECOND:
 
795
    if (get_interval_info(str,length,cs,5,array,1))
 
796
      return (1);
 
797
    interval->day=    (ulong) array[0];
 
798
    interval->hour=   (ulong) array[1];
 
799
    interval->minute= array[2];
 
800
    interval->second= array[3];
 
801
    interval->second_part= array[4];
 
802
    break;
 
803
  case INTERVAL_DAY_MINUTE:
 
804
    if (get_interval_info(str,length,cs,3,array,0))
 
805
      return (1);
 
806
    interval->day=    (ulong) array[0];
 
807
    interval->hour=   (ulong) array[1];
 
808
    interval->minute= array[2];
 
809
    break;
 
810
  case INTERVAL_DAY_SECOND:
 
811
    if (get_interval_info(str,length,cs,4,array,0))
 
812
      return (1);
 
813
    interval->day=    (ulong) array[0];
 
814
    interval->hour=   (ulong) array[1];
 
815
    interval->minute= array[2];
 
816
    interval->second= array[3];
 
817
    break;
 
818
  case INTERVAL_HOUR_MICROSECOND:
 
819
    if (get_interval_info(str,length,cs,4,array,1))
 
820
      return (1);
 
821
    interval->hour=   (ulong) array[0];
 
822
    interval->minute= array[1];
 
823
    interval->second= array[2];
 
824
    interval->second_part= array[3];
 
825
    break;
 
826
  case INTERVAL_HOUR_MINUTE:
 
827
    if (get_interval_info(str,length,cs,2,array,0))
 
828
      return (1);
 
829
    interval->hour=   (ulong) array[0];
 
830
    interval->minute= array[1];
 
831
    break;
 
832
  case INTERVAL_HOUR_SECOND:
 
833
    if (get_interval_info(str,length,cs,3,array,0))
 
834
      return (1);
 
835
    interval->hour=   (ulong) array[0];
 
836
    interval->minute= array[1];
 
837
    interval->second= array[2];
 
838
    break;
 
839
  case INTERVAL_MINUTE_MICROSECOND:
 
840
    if (get_interval_info(str,length,cs,3,array,1))
 
841
      return (1);
 
842
    interval->minute= array[0];
 
843
    interval->second= array[1];
 
844
    interval->second_part= array[2];
 
845
    break;
 
846
  case INTERVAL_MINUTE_SECOND:
 
847
    if (get_interval_info(str,length,cs,2,array,0))
 
848
      return (1);
 
849
    interval->minute= array[0];
 
850
    interval->second= array[1];
 
851
    break;
 
852
  case INTERVAL_SECOND_MICROSECOND:
 
853
    if (get_interval_info(str,length,cs,2,array,1))
 
854
      return (1);
 
855
    interval->second= array[0];
 
856
    interval->second_part= array[1];
 
857
    break;
 
858
  case INTERVAL_LAST: /* purecov: begin deadcode */
 
859
    assert(0); 
 
860
    break;            /* purecov: end */
 
861
  }
 
862
  return 0;
 
863
}
 
864
 
 
865
 
 
866
void Item_date_add_interval::fix_length_and_dec()
 
867
{
 
868
  enum_field_types arg0_field_type;
 
869
 
 
870
  collation.set(&my_charset_bin);
 
871
  maybe_null=1;
 
872
  max_length=MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
 
873
  value.alloc(max_length);
 
874
 
 
875
  /*
 
876
    The field type for the result of an Item_date function is defined as
 
877
    follows:
 
878
 
 
879
    - If first arg is a DRIZZLE_TYPE_DATETIME result is DRIZZLE_TYPE_DATETIME
 
880
    - If first arg is a DRIZZLE_TYPE_DATE and the interval type uses hours,
 
881
      minutes or seconds then type is DRIZZLE_TYPE_DATETIME.
 
882
    - Otherwise the result is DRIZZLE_TYPE_VARCHAR
 
883
      (This is because you can't know if the string contains a DATE, DRIZZLE_TIME or
 
884
      DATETIME argument)
 
885
  */
 
886
  cached_field_type= DRIZZLE_TYPE_VARCHAR;
 
887
  arg0_field_type= args[0]->field_type();
 
888
  if (arg0_field_type == DRIZZLE_TYPE_DATETIME ||
 
889
      arg0_field_type == DRIZZLE_TYPE_TIMESTAMP)
 
890
    cached_field_type= DRIZZLE_TYPE_DATETIME;
 
891
  else if (arg0_field_type == DRIZZLE_TYPE_DATE)
 
892
  {
 
893
    if (int_type <= INTERVAL_DAY || int_type == INTERVAL_YEAR_MONTH)
 
894
      cached_field_type= arg0_field_type;
 
895
    else
 
896
      cached_field_type= DRIZZLE_TYPE_DATETIME;
 
897
  }
 
898
}
 
899
 
 
900
 
 
901
/* Here arg[1] is a Item_interval object */
 
902
 
 
903
bool Item_date_add_interval::get_date(DRIZZLE_TIME *ltime, uint32_t fuzzy_date __attribute__((unused)))
 
904
{
 
905
  INTERVAL interval;
 
906
 
 
907
  if (args[0]->get_date(ltime, TIME_NO_ZERO_DATE) ||
 
908
      get_interval_value(args[1], int_type, &value, &interval))
 
909
    return (null_value=1);
 
910
 
 
911
  if (date_sub_interval)
 
912
    interval.neg = !interval.neg;
 
913
 
 
914
  if ((null_value= date_add_interval(ltime, int_type, interval)))
 
915
    return 1;
 
916
  return 0;
 
917
}
 
918
 
 
919
 
 
920
String *Item_date_add_interval::val_str(String *str)
 
921
{
 
922
  assert(fixed == 1);
 
923
  DRIZZLE_TIME ltime;
 
924
  enum date_time_format_types format;
 
925
 
 
926
  if (Item_date_add_interval::get_date(&ltime, TIME_NO_ZERO_DATE))
 
927
    return 0;
 
928
 
 
929
  if (ltime.time_type == DRIZZLE_TIMESTAMP_DATE)
 
930
    format= DATE_ONLY;
 
931
  else if (ltime.second_part)
 
932
    format= DATE_TIME_MICROSECOND;
 
933
  else
 
934
    format= DATE_TIME;
 
935
 
 
936
  if (!make_datetime(format, &ltime, str))
 
937
    return str;
 
938
 
 
939
  null_value=1;
 
940
  return 0;
 
941
}
 
942
 
 
943
 
 
944
int64_t Item_date_add_interval::val_int()
 
945
{
 
946
  assert(fixed == 1);
 
947
  DRIZZLE_TIME ltime;
 
948
  int64_t date;
 
949
  if (Item_date_add_interval::get_date(&ltime, TIME_NO_ZERO_DATE))
 
950
    return (int64_t) 0;
 
951
  date = (ltime.year*100L + ltime.month)*100L + ltime.day;
 
952
  return ltime.time_type == DRIZZLE_TIMESTAMP_DATE ? date :
 
953
    ((date*100L + ltime.hour)*100L+ ltime.minute)*100L + ltime.second;
 
954
}
 
955
 
 
956
 
 
957
 
 
958
bool Item_date_add_interval::eq(const Item *item, bool binary_cmp) const
 
959
{
 
960
  Item_date_add_interval *other= (Item_date_add_interval*) item;
 
961
  if (!Item_func::eq(item, binary_cmp))
 
962
    return 0;
 
963
  return ((int_type == other->int_type) &&
 
964
          (date_sub_interval == other->date_sub_interval));
 
965
}
 
966
 
 
967
/*
 
968
   'interval_names' reflects the order of the enumeration interval_type.
 
969
   See item_timefunc.h
 
970
 */
 
971
 
 
972
static const char *interval_names[]=
 
973
{
 
974
  "year", "quarter", "month", "week", "day",  
 
975
  "hour", "minute", "second", "microsecond",
 
976
  "year_month", "day_hour", "day_minute", 
 
977
  "day_second", "hour_minute", "hour_second",
 
978
  "minute_second", "day_microsecond",
 
979
  "hour_microsecond", "minute_microsecond",
 
980
  "second_microsecond"
 
981
};
 
982
 
 
983
void Item_date_add_interval::print(String *str, enum_query_type query_type)
 
984
{
 
985
  str->append('(');
 
986
  args[0]->print(str, query_type);
 
987
  str->append(date_sub_interval?" - interval ":" + interval ");
 
988
  args[1]->print(str, query_type);
 
989
  str->append(' ');
 
990
  str->append(interval_names[int_type]);
 
991
  str->append(')');
 
992
}
 
993
 
 
994
void Item_extract::print(String *str, enum_query_type query_type)
 
995
{
 
996
  str->append(STRING_WITH_LEN("extract("));
 
997
  str->append(interval_names[int_type]);
 
998
  str->append(STRING_WITH_LEN(" from "));
 
999
  args[0]->print(str, query_type);
 
1000
  str->append(')');
 
1001
}
 
1002
 
 
1003
void Item_extract::fix_length_and_dec()
 
1004
{
 
1005
  value.alloc(32);                              // alloc buffer
 
1006
 
 
1007
  maybe_null=1;                                 // If wrong date
 
1008
  switch (int_type) {
 
1009
  case INTERVAL_YEAR:           max_length=4; date_value=1; break;
 
1010
  case INTERVAL_YEAR_MONTH:     max_length=6; date_value=1; break;
 
1011
  case INTERVAL_QUARTER:        max_length=2; date_value=1; break;
 
1012
  case INTERVAL_MONTH:          max_length=2; date_value=1; break;
 
1013
  case INTERVAL_WEEK:           max_length=2; date_value=1; break;
 
1014
  case INTERVAL_DAY:            max_length=2; date_value=1; break;
 
1015
  case INTERVAL_DAY_HOUR:       max_length=9; date_value=0; break;
 
1016
  case INTERVAL_DAY_MINUTE:     max_length=11; date_value=0; break;
 
1017
  case INTERVAL_DAY_SECOND:     max_length=13; date_value=0; break;
 
1018
  case INTERVAL_HOUR:           max_length=2; date_value=0; break;
 
1019
  case INTERVAL_HOUR_MINUTE:    max_length=4; date_value=0; break;
 
1020
  case INTERVAL_HOUR_SECOND:    max_length=6; date_value=0; break;
 
1021
  case INTERVAL_MINUTE:         max_length=2; date_value=0; break;
 
1022
  case INTERVAL_MINUTE_SECOND:  max_length=4; date_value=0; break;
 
1023
  case INTERVAL_SECOND:         max_length=2; date_value=0; break;
 
1024
  case INTERVAL_MICROSECOND:    max_length=2; date_value=0; break;
 
1025
  case INTERVAL_DAY_MICROSECOND: max_length=20; date_value=0; break;
 
1026
  case INTERVAL_HOUR_MICROSECOND: max_length=13; date_value=0; break;
 
1027
  case INTERVAL_MINUTE_MICROSECOND: max_length=11; date_value=0; break;
 
1028
  case INTERVAL_SECOND_MICROSECOND: max_length=9; date_value=0; break;
 
1029
  case INTERVAL_LAST: assert(0); break; /* purecov: deadcode */
 
1030
  }
 
1031
}
 
1032
 
 
1033
 
 
1034
int64_t Item_extract::val_int()
 
1035
{
 
1036
  assert(fixed == 1);
 
1037
  DRIZZLE_TIME ltime;
 
1038
  uint32_t year;
 
1039
  ulong week_format;
 
1040
  long neg;
 
1041
  if (date_value)
 
1042
  {
 
1043
    if (get_arg0_date(&ltime, TIME_FUZZY_DATE))
 
1044
      return 0;
 
1045
    neg=1;
 
1046
  }
 
1047
  else
 
1048
  {
 
1049
    String *res= args[0]->val_str(&value);
 
1050
    if (!res || str_to_time_with_warn(res->ptr(), res->length(), &ltime))
 
1051
    {
 
1052
      null_value=1;
 
1053
      return 0;
 
1054
    }
 
1055
    neg= ltime.neg ? -1 : 1;
 
1056
    null_value=0;
 
1057
  }
 
1058
  switch (int_type) {
 
1059
  case INTERVAL_YEAR:           return ltime.year;
 
1060
  case INTERVAL_YEAR_MONTH:     return ltime.year*100L+ltime.month;
 
1061
  case INTERVAL_QUARTER:        return (ltime.month+2)/3;
 
1062
  case INTERVAL_MONTH:          return ltime.month;
 
1063
  case INTERVAL_WEEK:
 
1064
  {
 
1065
    week_format= current_session->variables.default_week_format;
 
1066
    return calc_week(&ltime, week_mode(week_format), &year);
 
1067
  }
 
1068
  case INTERVAL_DAY:            return ltime.day;
 
1069
  case INTERVAL_DAY_HOUR:       return (long) (ltime.day*100L+ltime.hour)*neg;
 
1070
  case INTERVAL_DAY_MINUTE:     return (long) (ltime.day*10000L+
 
1071
                                               ltime.hour*100L+
 
1072
                                               ltime.minute)*neg;
 
1073
  case INTERVAL_DAY_SECOND:      return ((int64_t) ltime.day*1000000L+
 
1074
                                         (int64_t) (ltime.hour*10000L+
 
1075
                                                     ltime.minute*100+
 
1076
                                                     ltime.second))*neg;
 
1077
  case INTERVAL_HOUR:           return (long) ltime.hour*neg;
 
1078
  case INTERVAL_HOUR_MINUTE:    return (long) (ltime.hour*100+ltime.minute)*neg;
 
1079
  case INTERVAL_HOUR_SECOND:    return (long) (ltime.hour*10000+ltime.minute*100+
 
1080
                                               ltime.second)*neg;
 
1081
  case INTERVAL_MINUTE:         return (long) ltime.minute*neg;
 
1082
  case INTERVAL_MINUTE_SECOND:  return (long) (ltime.minute*100+ltime.second)*neg;
 
1083
  case INTERVAL_SECOND:         return (long) ltime.second*neg;
 
1084
  case INTERVAL_MICROSECOND:    return (long) ltime.second_part*neg;
 
1085
  case INTERVAL_DAY_MICROSECOND: return (((int64_t)ltime.day*1000000L +
 
1086
                                          (int64_t)ltime.hour*10000L +
 
1087
                                          ltime.minute*100 +
 
1088
                                          ltime.second)*1000000L +
 
1089
                                         ltime.second_part)*neg;
 
1090
  case INTERVAL_HOUR_MICROSECOND: return (((int64_t)ltime.hour*10000L +
 
1091
                                           ltime.minute*100 +
 
1092
                                           ltime.second)*1000000L +
 
1093
                                          ltime.second_part)*neg;
 
1094
  case INTERVAL_MINUTE_MICROSECOND: return (((int64_t)(ltime.minute*100+
 
1095
                                                        ltime.second))*1000000L+
 
1096
                                            ltime.second_part)*neg;
 
1097
  case INTERVAL_SECOND_MICROSECOND: return ((int64_t)ltime.second*1000000L+
 
1098
                                            ltime.second_part)*neg;
 
1099
  case INTERVAL_LAST: assert(0); break;  /* purecov: deadcode */
 
1100
  }
 
1101
  return 0;                                     // Impossible
 
1102
}
 
1103
 
 
1104
bool Item_extract::eq(const Item *item, bool binary_cmp) const
 
1105
{
 
1106
  if (this == item)
 
1107
    return 1;
 
1108
  if (item->type() != FUNC_ITEM ||
 
1109
      functype() != ((Item_func*)item)->functype())
 
1110
    return 0;
 
1111
 
 
1112
  Item_extract* ie= (Item_extract*)item;
 
1113
  if (ie->int_type != int_type)
 
1114
    return 0;
 
1115
 
 
1116
  if (!args[0]->eq(ie->args[0], binary_cmp))
 
1117
      return 0;
 
1118
  return 1;
 
1119
}
 
1120
 
 
1121
 
 
1122
bool Item_char_typecast::eq(const Item *item, bool binary_cmp) const
 
1123
{
 
1124
  if (this == item)
 
1125
    return 1;
 
1126
  if (item->type() != FUNC_ITEM ||
 
1127
      functype() != ((Item_func*)item)->functype())
 
1128
    return 0;
 
1129
 
 
1130
  Item_char_typecast *cast= (Item_char_typecast*)item;
 
1131
  if (cast_length != cast->cast_length ||
 
1132
      cast_cs     != cast->cast_cs)
 
1133
    return 0;
 
1134
 
 
1135
  if (!args[0]->eq(cast->args[0], binary_cmp))
 
1136
      return 0;
 
1137
  return 1;
 
1138
}
 
1139
 
 
1140
void Item_typecast::print(String *str, enum_query_type query_type)
 
1141
{
 
1142
  str->append(STRING_WITH_LEN("cast("));
 
1143
  args[0]->print(str, query_type);
 
1144
  str->append(STRING_WITH_LEN(" as "));
 
1145
  str->append(cast_type());
 
1146
  str->append(')');
 
1147
}
 
1148
 
 
1149
 
 
1150
void Item_char_typecast::print(String *str, enum_query_type query_type)
 
1151
{
 
1152
  str->append(STRING_WITH_LEN("cast("));
 
1153
  args[0]->print(str, query_type);
 
1154
  str->append(STRING_WITH_LEN(" as char"));
 
1155
  if (cast_length >= 0)
 
1156
  {
 
1157
    str->append('(');
 
1158
    char buffer[20];
 
1159
    // my_charset_bin is good enough for numbers
 
1160
    String st(buffer, sizeof(buffer), &my_charset_bin);
 
1161
    st.set((uint64_t)cast_length, &my_charset_bin);
 
1162
    str->append(st);
 
1163
    str->append(')');
 
1164
  }
 
1165
  if (cast_cs)
 
1166
  {
 
1167
    str->append(STRING_WITH_LEN(" charset "));
 
1168
    str->append(cast_cs->csname);
 
1169
  }
 
1170
  str->append(')');
 
1171
}
 
1172
 
 
1173
String *Item_char_typecast::val_str(String *str)
 
1174
{
 
1175
  assert(fixed == 1);
 
1176
  String *res;
 
1177
  uint32_t length;
 
1178
 
 
1179
  if (!charset_conversion)
 
1180
  {
 
1181
    if (!(res= args[0]->val_str(str)))
 
1182
    {
 
1183
      null_value= 1;
 
1184
      return 0;
 
1185
    }
 
1186
  }
 
1187
  else
 
1188
  {
 
1189
    // Convert character set if differ
 
1190
    uint32_t dummy_errors;
 
1191
    if (!(res= args[0]->val_str(&tmp_value)) ||
 
1192
        str->copy(res->ptr(), res->length(), from_cs,
 
1193
        cast_cs, &dummy_errors))
 
1194
    {
 
1195
      null_value= 1;
 
1196
      return 0;
 
1197
    }
 
1198
    res= str;
 
1199
  }
 
1200
 
 
1201
  res->set_charset(cast_cs);
 
1202
 
 
1203
  /*
 
1204
    Cut the tail if cast with length
 
1205
    and the result is longer than cast length, e.g.
 
1206
    CAST('string' AS CHAR(1))
 
1207
  */
 
1208
  if (cast_length >= 0)
 
1209
  {
 
1210
    if (res->length() > (length= (uint32_t) res->charpos(cast_length)))
 
1211
    {                                           // Safe even if const arg
 
1212
      char char_type[40];
 
1213
      snprintf(char_type, sizeof(char_type), "%s(%lu)",
 
1214
               cast_cs == &my_charset_bin ? "BINARY" : "CHAR",
 
1215
               (ulong) length);
 
1216
 
 
1217
      if (!res->alloced_length())
 
1218
      {                                         // Don't change const str
 
1219
        str_value= *res;                        // Not malloced string
 
1220
        res= &str_value;
 
1221
      }
 
1222
      push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
1223
                          ER_TRUNCATED_WRONG_VALUE,
 
1224
                          ER(ER_TRUNCATED_WRONG_VALUE), char_type,
 
1225
                          res->c_ptr_safe());
 
1226
      res->length((uint) length);
 
1227
    }
 
1228
    else if (cast_cs == &my_charset_bin && res->length() < (uint) cast_length)
 
1229
    {
 
1230
      if (res->alloced_length() < (uint) cast_length)
 
1231
      {
 
1232
        str->alloc(cast_length);
 
1233
        str->copy(*res);
 
1234
        res= str;
 
1235
      }
 
1236
      memset(res->ptr() + res->length(), 0,
 
1237
             (uint) cast_length - res->length());
 
1238
      res->length(cast_length);
 
1239
    }
 
1240
  }
 
1241
  null_value= 0;
 
1242
  return res;
 
1243
}
 
1244
 
 
1245
 
 
1246
void Item_char_typecast::fix_length_and_dec()
 
1247
{
 
1248
  uint32_t char_length;
 
1249
  /* 
 
1250
     We always force character set conversion if cast_cs
 
1251
     is a multi-byte character set. It garantees that the
 
1252
     result of CAST is a well-formed string.
 
1253
     For single-byte character sets we allow just to copy
 
1254
     from the argument. A single-byte character sets string
 
1255
     is always well-formed. 
 
1256
     
 
1257
     There is a special trick to convert form a number to ucs2.
 
1258
     As numbers have my_charset_bin as their character set,
 
1259
     it wouldn't do conversion to ucs2 without an additional action.
 
1260
     To force conversion, we should pretend to be non-binary.
 
1261
     Let's choose from_cs this way:
 
1262
     - If the argument in a number and cast_cs is ucs2 (i.e. mbminlen > 1),
 
1263
       then from_cs is set to latin1, to perform latin1 -> ucs2 conversion.
 
1264
     - If the argument is a number and cast_cs is ASCII-compatible
 
1265
       (i.e. mbminlen == 1), then from_cs is set to cast_cs,
 
1266
       which allows just to take over the args[0]->val_str() result
 
1267
       and thus avoid unnecessary character set conversion.
 
1268
     - If the argument is not a number, then from_cs is set to
 
1269
       the argument's charset.
 
1270
  */
 
1271
  from_cs= (args[0]->result_type() == INT_RESULT || 
 
1272
            args[0]->result_type() == DECIMAL_RESULT ||
 
1273
            args[0]->result_type() == REAL_RESULT) ?
 
1274
           (cast_cs->mbminlen == 1 ? cast_cs : &my_charset_utf8_general_ci) :
 
1275
           args[0]->collation.collation;
 
1276
  charset_conversion= (cast_cs->mbmaxlen > 1) ||
 
1277
                      (!my_charset_same(from_cs, cast_cs) && from_cs != &my_charset_bin && cast_cs != &my_charset_bin);
 
1278
  collation.set(cast_cs, DERIVATION_IMPLICIT);
 
1279
  char_length= (cast_length >= 0) ? cast_length : 
 
1280
               args[0]->max_length/from_cs->mbmaxlen;
 
1281
  max_length= char_length * cast_cs->mbmaxlen;
 
1282
}
 
1283
 
 
1284
 
 
1285
String *Item_datetime_typecast::val_str(String *str)
 
1286
{
 
1287
  assert(fixed == 1);
 
1288
  DRIZZLE_TIME ltime;
 
1289
 
 
1290
  if (!get_arg0_date(&ltime, TIME_FUZZY_DATE) &&
 
1291
      !make_datetime(ltime.second_part ? DATE_TIME_MICROSECOND : DATE_TIME, 
 
1292
                     &ltime, str))
 
1293
    return str;
 
1294
 
 
1295
  null_value=1;
 
1296
  return 0;
 
1297
}
 
1298
 
 
1299
 
 
1300
int64_t Item_datetime_typecast::val_int()
 
1301
{
 
1302
  assert(fixed == 1);
 
1303
  DRIZZLE_TIME ltime;
 
1304
  if (get_arg0_date(&ltime,1))
 
1305
  {
 
1306
    null_value= 1;
 
1307
    return 0;
 
1308
  }
 
1309
 
 
1310
  return TIME_to_uint64_t_datetime(&ltime);
 
1311
}
 
1312
 
 
1313
 
 
1314
bool Item_time_typecast::get_time(DRIZZLE_TIME *ltime)
 
1315
{
 
1316
  bool res= get_arg0_time(ltime);
 
1317
  /*
 
1318
    For DRIZZLE_TIMESTAMP_TIME value we can have non-zero day part,
 
1319
    which we should not lose.
 
1320
  */
 
1321
  if (ltime->time_type == DRIZZLE_TIMESTAMP_DATETIME)
 
1322
    ltime->year= ltime->month= ltime->day= 0;
 
1323
  ltime->time_type= DRIZZLE_TIMESTAMP_TIME;
 
1324
  return res;
 
1325
}
 
1326
 
 
1327
 
 
1328
int64_t Item_time_typecast::val_int()
 
1329
{
 
1330
  DRIZZLE_TIME ltime;
 
1331
  if (get_time(&ltime))
 
1332
  {
 
1333
    null_value= 1;
 
1334
    return 0;
 
1335
  }
 
1336
  return ltime.hour * 10000L + ltime.minute * 100 + ltime.second;
 
1337
}
 
1338
 
 
1339
String *Item_time_typecast::val_str(String *str)
 
1340
{
 
1341
  assert(fixed == 1);
 
1342
  DRIZZLE_TIME ltime;
 
1343
 
 
1344
  if (!get_arg0_time(&ltime) &&
 
1345
      !make_datetime(ltime.second_part ? TIME_MICROSECOND : TIME_ONLY,
 
1346
                     &ltime, str))
 
1347
    return str;
 
1348
 
 
1349
  null_value=1;
 
1350
  return 0;
 
1351
}
 
1352
 
 
1353
 
 
1354
bool Item_date_typecast::get_date(DRIZZLE_TIME *ltime, uint32_t fuzzy_date __attribute__((unused)))
 
1355
{
 
1356
  bool res= get_arg0_date(ltime, TIME_FUZZY_DATE);
 
1357
  ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0;
 
1358
  ltime->time_type= DRIZZLE_TIMESTAMP_DATE;
 
1359
  return res;
 
1360
}
 
1361
 
 
1362
 
 
1363
bool Item_date_typecast::get_time(DRIZZLE_TIME *ltime)
 
1364
{
 
1365
  memset(ltime, 0, sizeof(DRIZZLE_TIME));
 
1366
  return args[0]->null_value;
 
1367
}
 
1368
 
 
1369
 
 
1370
String *Item_date_typecast::val_str(String *str)
 
1371
{
 
1372
  assert(fixed == 1);
 
1373
  DRIZZLE_TIME ltime;
 
1374
 
 
1375
  if (!get_arg0_date(&ltime, TIME_FUZZY_DATE) &&
 
1376
      !str->alloc(MAX_DATE_STRING_REP_LENGTH))
 
1377
  {
 
1378
    make_date((DATE_TIME_FORMAT *) 0, &ltime, str);
 
1379
    return str;
 
1380
  }
 
1381
 
 
1382
  null_value=1;
 
1383
  return 0;
 
1384
}
 
1385
 
 
1386
int64_t Item_date_typecast::val_int()
 
1387
{
 
1388
  assert(fixed == 1);
 
1389
  DRIZZLE_TIME ltime;
 
1390
  if ((null_value= args[0]->get_date(&ltime, TIME_FUZZY_DATE)))
 
1391
    return 0;
 
1392
  return (int64_t) (ltime.year * 10000L + ltime.month * 100 + ltime.day);
 
1393
}
 
1394
 
 
1395
/**
 
1396
  Get type of datetime value (DATE/TIME/...) which will be produced
 
1397
  according to format string.
 
1398
 
 
1399
  @param format   format string
 
1400
  @param length   length of format string
 
1401
 
 
1402
  @note
 
1403
    We don't process day format's characters('D', 'd', 'e') because day
 
1404
    may be a member of all date/time types.
 
1405
 
 
1406
  @note
 
1407
    Format specifiers supported by this function should be in sync with
 
1408
    specifiers supported by extract_date_time() function.
 
1409
 
 
1410
  @return
 
1411
    One of date_time_format_types values:
 
1412
    - DATE_TIME_MICROSECOND
 
1413
    - DATE_TIME
 
1414
    - DATE_ONLY
 
1415
    - TIME_MICROSECOND
 
1416
    - TIME_ONLY
 
1417
*/
 
1418
 
 
1419
static date_time_format_types
 
1420
get_date_time_result_type(const char *format, uint32_t length)
 
1421
{
 
1422
  const char *time_part_frms= "HISThiklrs";
 
1423
  const char *date_part_frms= "MVUXYWabcjmvuxyw";
 
1424
  bool date_part_used= 0, time_part_used= 0, frac_second_used= 0;
 
1425
  
 
1426
  const char *val= format;
 
1427
  const char *end= format + length;
 
1428
 
 
1429
  for (; val != end && val != end; val++)
 
1430
  {
 
1431
    if (*val == '%' && val+1 != end)
 
1432
    {
 
1433
      val++;
 
1434
      if (*val == 'f')
 
1435
        frac_second_used= time_part_used= 1;
 
1436
      else if (!time_part_used && strchr(time_part_frms, *val))
 
1437
        time_part_used= 1;
 
1438
      else if (!date_part_used && strchr(date_part_frms, *val))
 
1439
        date_part_used= 1;
 
1440
      if (date_part_used && frac_second_used)
 
1441
      {
 
1442
        /*
 
1443
          frac_second_used implies time_part_used, and thus we already
 
1444
          have all types of date-time components and can end our search.
 
1445
        */
 
1446
        return DATE_TIME_MICROSECOND;
 
1447
    }
 
1448
  }
 
1449
  }
 
1450
 
 
1451
  /* We don't have all three types of date-time components */
 
1452
  if (frac_second_used)
 
1453
    return TIME_MICROSECOND;
 
1454
  if (time_part_used)
 
1455
  {
 
1456
    if (date_part_used)
 
1457
      return DATE_TIME;
 
1458
    return TIME_ONLY;
 
1459
  }
 
1460
  return DATE_ONLY;
 
1461
}
 
1462
 
 
1463
 
 
1464
void Item_func_str_to_date::fix_length_and_dec()
 
1465
{
 
1466
  maybe_null= 1;
 
1467
  decimals=0;
 
1468
  cached_field_type= DRIZZLE_TYPE_DATETIME;
 
1469
  max_length= MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
 
1470
  cached_timestamp_type= DRIZZLE_TIMESTAMP_NONE;
 
1471
  if ((const_item= args[1]->const_item()))
 
1472
  {
 
1473
    char format_buff[64];
 
1474
    String format_str(format_buff, sizeof(format_buff), &my_charset_bin);
 
1475
    String *format= args[1]->val_str(&format_str);
 
1476
    if (!args[1]->null_value)
 
1477
    {
 
1478
      cached_format_type= get_date_time_result_type(format->ptr(),
 
1479
                                                    format->length());
 
1480
      switch (cached_format_type) {
 
1481
      case DATE_ONLY:
 
1482
        cached_timestamp_type= DRIZZLE_TIMESTAMP_DATE;
 
1483
        cached_field_type= DRIZZLE_TYPE_DATE; 
 
1484
        max_length= MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN;
 
1485
        break;
 
1486
      case TIME_ONLY:
 
1487
      case TIME_MICROSECOND:
 
1488
        cached_timestamp_type= DRIZZLE_TIMESTAMP_TIME;
 
1489
        cached_field_type= DRIZZLE_TYPE_TIME; 
 
1490
        max_length= MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN;
 
1491
        break;
 
1492
      default:
 
1493
        cached_timestamp_type= DRIZZLE_TIMESTAMP_DATETIME;
 
1494
        cached_field_type= DRIZZLE_TYPE_DATETIME; 
 
1495
        break;
 
1496
      }
 
1497
    }
 
1498
  }
 
1499
}
 
1500
 
 
1501
 
 
1502
bool Item_func_str_to_date::get_date(DRIZZLE_TIME *ltime, uint32_t fuzzy_date)
 
1503
{
 
1504
  DATE_TIME_FORMAT date_time_format;
 
1505
  char val_buff[64], format_buff[64];
 
1506
  String val_string(val_buff, sizeof(val_buff), &my_charset_bin), *val;
 
1507
  String format_str(format_buff, sizeof(format_buff), &my_charset_bin), *format;
 
1508
 
 
1509
  val=    args[0]->val_str(&val_string);
 
1510
  format= args[1]->val_str(&format_str);
 
1511
  if (args[0]->null_value || args[1]->null_value)
 
1512
    goto null_date;
 
1513
 
 
1514
  null_value= 0;
 
1515
  memset(ltime, 0, sizeof(*ltime));
 
1516
  date_time_format.format.str=    (char*) format->ptr();
 
1517
  date_time_format.format.length= format->length();
 
1518
  if (extract_date_time(&date_time_format, val->ptr(), val->length(),
 
1519
                        ltime, cached_timestamp_type, 0, "datetime") ||
 
1520
      ((fuzzy_date & TIME_NO_ZERO_DATE) &&
 
1521
       (ltime->year == 0 || ltime->month == 0 || ltime->day == 0)))
 
1522
    goto null_date;
 
1523
  if (cached_timestamp_type == DRIZZLE_TIMESTAMP_TIME && ltime->day)
 
1524
  {
 
1525
    /*
 
1526
      Day part for time type can be nonzero value and so 
 
1527
      we should add hours from day part to hour part to
 
1528
      keep valid time value.
 
1529
    */
 
1530
    ltime->hour+= ltime->day*24;
 
1531
    ltime->day= 0;
 
1532
  }
 
1533
  return 0;
 
1534
 
 
1535
null_date:
 
1536
  return (null_value=1);
 
1537
}
 
1538
 
 
1539
 
 
1540
String *Item_func_str_to_date::val_str(String *str)
 
1541
{
 
1542
  assert(fixed == 1);
 
1543
  DRIZZLE_TIME ltime;
 
1544
 
 
1545
  if (Item_func_str_to_date::get_date(&ltime, TIME_FUZZY_DATE))
 
1546
    return 0;
 
1547
 
 
1548
  if (!make_datetime((const_item ? cached_format_type :
 
1549
                     (ltime.second_part ? DATE_TIME_MICROSECOND : DATE_TIME)),
 
1550
                     &ltime, str))
 
1551
    return str;
 
1552
  return 0;
 
1553
}
 
1554
 
 
1555
 
 
1556
bool Item_func_last_day::get_date(DRIZZLE_TIME *ltime, uint32_t fuzzy_date)
 
1557
{
 
1558
  if (get_arg0_date(ltime, fuzzy_date & ~TIME_FUZZY_DATE) ||
 
1559
      (ltime->month == 0))
 
1560
  {
 
1561
    null_value= 1;
 
1562
    return 1;
 
1563
  }
 
1564
  null_value= 0;
 
1565
  uint32_t month_idx= ltime->month-1;
 
1566
  ltime->day= days_in_month[month_idx];
 
1567
  if ( month_idx == 1 && calc_days_in_year(ltime->year) == 366)
 
1568
    ltime->day= 29;
 
1569
  ltime->hour= ltime->minute= ltime->second= 0;
 
1570
  ltime->second_part= 0;
 
1571
  ltime->time_type= DRIZZLE_TIMESTAMP_DATE;
 
1572
  return 0;
 
1573
}