~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/function/time/extract.cc

  • Committer: Monty Taylor
  • Date: 2008-10-10 23:04:21 UTC
  • mto: (509.1.1 codestyle)
  • mto: This revision was merged to the branch mainline in revision 511.
  • Revision ID: monty@inaugust.com-20081010230421-zohe1eppxievpw8d
Removed O_NOFOLLOW

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
 
#include "config.h"
21
 
 
22
 
#include "drizzled/temporal.h"
23
 
#include "drizzled/error.h"
24
 
#include "drizzled/session.h"
25
 
#include "drizzled/calendar.h"
26
 
#include "drizzled/function/time/extract.h"
27
 
 
28
 
namespace drizzled
29
 
{
30
 
 
31
 
/*
32
 
   'interval_names' reflects the order of the enumeration interval_type.
33
 
   See item/time.h
34
 
 */
35
 
 
36
 
extern const char *interval_names[];
37
 
 
38
 
void Item_extract::print(String *str, enum_query_type query_type)
39
 
{
40
 
  str->append(STRING_WITH_LEN("extract("));
41
 
  str->append(interval_names[int_type]);
42
 
  str->append(STRING_WITH_LEN(" from "));
43
 
  args[0]->print(str, query_type);
44
 
  str->append(')');
45
 
}
46
 
 
47
 
void Item_extract::fix_length_and_dec()
48
 
{
49
 
  value.alloc(DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING);                           
50
 
 
51
 
  maybe_null= 1;                                        /* If NULL supplied only */
52
 
  switch (int_type) {
53
 
  case INTERVAL_YEAR:           max_length=4; date_value=1; break;
54
 
  case INTERVAL_YEAR_MONTH:     max_length=6; date_value=1; break;
55
 
  case INTERVAL_QUARTER:        max_length=2; date_value=1; break;
56
 
  case INTERVAL_MONTH:          max_length=2; date_value=1; break;
57
 
  case INTERVAL_WEEK:           max_length=2; date_value=1; break;
58
 
  case INTERVAL_DAY:            max_length=2; date_value=1; break;
59
 
  case INTERVAL_DAY_HOUR:       max_length=9; date_value=0; break;
60
 
  case INTERVAL_DAY_MINUTE:     max_length=11; date_value=0; break;
61
 
  case INTERVAL_DAY_SECOND:     max_length=13; date_value=0; break;
62
 
  case INTERVAL_HOUR:           max_length=2; date_value=0; break;
63
 
  case INTERVAL_HOUR_MINUTE:    max_length=4; date_value=0; break;
64
 
  case INTERVAL_HOUR_SECOND:    max_length=6; date_value=0; break;
65
 
  case INTERVAL_MINUTE:         max_length=2; date_value=0; break;
66
 
  case INTERVAL_MINUTE_SECOND:  max_length=4; date_value=0; break;
67
 
  case INTERVAL_SECOND:         max_length=2; date_value=0; break;
68
 
  case INTERVAL_MICROSECOND:    max_length=2; date_value=0; break;
69
 
  case INTERVAL_DAY_MICROSECOND: max_length=20; date_value=0; break;
70
 
  case INTERVAL_HOUR_MICROSECOND: max_length=13; date_value=0; break;
71
 
  case INTERVAL_MINUTE_MICROSECOND: max_length=11; date_value=0; break;
72
 
  case INTERVAL_SECOND_MICROSECOND: max_length=9; date_value=0; break;
73
 
  case INTERVAL_LAST: assert(0); break;
74
 
  }
75
 
}
76
 
 
77
 
int64_t Item_extract::val_int()
78
 
{
79
 
  assert(fixed);
80
 
 
81
 
  if (args[0]->is_null())
82
 
  {
83
 
    /* For NULL argument, we return a NULL result */
84
 
    null_value= true;
85
 
    return 0;
86
 
  }
87
 
 
88
 
  /* We could have either a datetime or a time.. */
89
 
  DateTime datetime_temporal;
90
 
  Time time_temporal;
91
 
 
92
 
  /* Abstract pointer type we'll use in the final switch */
93
 
  Temporal *temporal;
94
 
 
95
 
  if (date_value)
96
 
  {
97
 
    /* Grab the first argument as a DateTime object */
98
 
    Item_result arg0_result_type= args[0]->result_type();
99
 
    
100
 
    switch (arg0_result_type)
101
 
    {
102
 
      case DECIMAL_RESULT: 
103
 
        /* 
104
 
        * For doubles supplied, interpret the arg as a string, 
105
 
        * so intentionally fall-through here...
106
 
        * This allows us to accept double parameters like 
107
 
        * 19971231235959.01 and interpret it the way MySQL does:
108
 
        * as a TIMESTAMP-like thing with a microsecond component.
109
 
        * Ugh, but need to keep backwards-compat.
110
 
        */
111
 
      case STRING_RESULT:
112
 
        {
113
 
          char buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
114
 
          String tmp(buff,sizeof(buff), &my_charset_utf8_bin);
115
 
          String *res= args[0]->val_str(&tmp);
116
 
 
117
 
          if (res && (res != &tmp))
118
 
          {
119
 
            tmp.copy(*res);
120
 
          }
121
 
 
122
 
          if (! datetime_temporal.from_string(tmp.c_ptr(), tmp.length()))
123
 
          {
124
 
            /* 
125
 
            * Could not interpret the function argument as a temporal value, 
126
 
            * so throw an error and return 0
127
 
            */
128
 
            my_error(ER_INVALID_DATETIME_VALUE, MYF(0), tmp.c_ptr());
129
 
            return 0;
130
 
          }
131
 
        }
132
 
        break;
133
 
      case INT_RESULT:
134
 
        if (datetime_temporal.from_int64_t(args[0]->val_int()))
135
 
          break;
136
 
        /* Intentionally fall-through on invalid conversion from integer */
137
 
      default:
138
 
        {
139
 
          /* 
140
 
          * Could not interpret the function argument as a temporal value, 
141
 
          * so throw an error and return 0
142
 
          */
143
 
          null_value= true;
144
 
          char buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
145
 
          String tmp(buff,sizeof(buff), &my_charset_utf8_bin);
146
 
          String *res;
147
 
 
148
 
          res= args[0]->val_str(&tmp);
149
 
 
150
 
          if (res && (res != &tmp))
151
 
          {
152
 
            tmp.copy(*res);
153
 
          }
154
 
 
155
 
          my_error(ER_INVALID_DATETIME_VALUE, MYF(0), tmp.c_ptr());
156
 
          return 0;
157
 
        }
158
 
    }
159
 
    /* 
160
 
     * If we got here, we have a successfully converted DateTime temporal. 
161
 
     * Point our working temporal to this.
162
 
     */
163
 
    temporal= &datetime_temporal;
164
 
  }
165
 
  else
166
 
  {
167
 
    /* 
168
 
     * Because of the ridiculous way in which MySQL handles
169
 
     * TIME values (it does implicit integer -> string conversions
170
 
     * but only for DATETIME, not TIME values) we must first 
171
 
     * try a conversion into a TIME from a string.  If this
172
 
     * fails, we fall back on a DATETIME conversion.  This is
173
 
     * necessary because of the fact that DateTime::from_string()
174
 
     * looks first for DATETIME, then DATE regex matches.  6 consecutive
175
 
     * numbers, say 231130, will match the DATE regex YYMMDD
176
 
     * with no TIME part, but MySQL actually implicitly treats
177
 
     * parameters to SECOND(), HOUR(), and MINUTE() as TIME-only
178
 
     * values and matches 231130 as HHmmSS!
179
 
     *
180
 
     * Oh, and Brian Aker MADE me do this. :) --JRP
181
 
     */
182
 
    
183
 
    char time_buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
184
 
    String tmp_time(time_buff,sizeof(time_buff), &my_charset_utf8_bin);
185
 
    String *time_res= args[0]->val_str(&tmp_time);
186
 
 
187
 
    if (time_res && (time_res != &tmp_time))
188
 
    {
189
 
      tmp_time.copy(*time_res);
190
 
    }
191
 
 
192
 
    if (! time_temporal.from_string(tmp_time.c_ptr(), tmp_time.length()))
193
 
    {
194
 
      /* 
195
 
       * OK, we failed to match the first argument as a string
196
 
       * representing a time value, so we grab the first argument 
197
 
       * as a DateTime object and try that for a match...
198
 
       */
199
 
      Item_result arg0_result_type= args[0]->result_type();
200
 
      
201
 
      switch (arg0_result_type)
202
 
      {
203
 
        case DECIMAL_RESULT: 
204
 
          /* 
205
 
           * For doubles supplied, interpret the arg as a string, 
206
 
           * so intentionally fall-through here...
207
 
           * This allows us to accept double parameters like 
208
 
           * 19971231235959.01 and interpret it the way MySQL does:
209
 
           * as a TIMESTAMP-like thing with a microsecond component.
210
 
           * Ugh, but need to keep backwards-compat.
211
 
           */
212
 
        case STRING_RESULT:
213
 
          {
214
 
            char buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
215
 
            String tmp(buff,sizeof(buff), &my_charset_utf8_bin);
216
 
            String *res= args[0]->val_str(&tmp);
217
 
 
218
 
            if (res && (res != &tmp))
219
 
            {
220
 
              tmp.copy(*res);
221
 
            }
222
 
 
223
 
            if (! datetime_temporal.from_string(tmp.c_ptr(), tmp.length()))
224
 
            {
225
 
              /* 
226
 
               * Could not interpret the function argument as a temporal value, 
227
 
               * so throw an error and return 0
228
 
               */
229
 
              my_error(ER_INVALID_DATETIME_VALUE, MYF(0), tmp.c_ptr());
230
 
              return 0;
231
 
            }
232
 
          }
233
 
          break;
234
 
        case INT_RESULT:
235
 
          if (datetime_temporal.from_int64_t(args[0]->val_int()))
236
 
            break;
237
 
          /* Intentionally fall-through on invalid conversion from integer */
238
 
        default:
239
 
          {
240
 
            /* 
241
 
             * Could not interpret the function argument as a temporal value, 
242
 
             * so throw an error and return 0
243
 
             */
244
 
            null_value= true;
245
 
            char buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
246
 
            String tmp(buff,sizeof(buff), &my_charset_utf8_bin);
247
 
            String *res;
248
 
 
249
 
            res= args[0]->val_str(&tmp);
250
 
 
251
 
            my_error(ER_INVALID_DATETIME_VALUE, MYF(0), res->c_ptr());
252
 
            return 0;
253
 
          }
254
 
      }
255
 
      /* If we're here, our time failed, but our datetime succeeded... */
256
 
      temporal= &datetime_temporal;
257
 
    }
258
 
    else
259
 
    {
260
 
      /* If we're here, our time succeeded... */
261
 
      temporal= &time_temporal;
262
 
    }
263
 
  }
264
 
 
265
 
  /* Return the requested datetime component */
266
 
  switch (int_type) {
267
 
    case INTERVAL_YEAR:         
268
 
      return (int64_t) temporal->years();
269
 
    case INTERVAL_YEAR_MONTH:   
270
 
      return (int64_t) ((temporal->years() * 100L) + temporal->months());
271
 
    case INTERVAL_QUARTER:
272
 
      return (int64_t) (temporal->months() + 2) / 3;
273
 
    case INTERVAL_MONTH:
274
 
      return (int64_t) temporal->months();
275
 
    case INTERVAL_WEEK:
276
 
      return iso_week_number_from_gregorian_date(temporal->years()
277
 
                                               , temporal->months()
278
 
                                               , temporal->days()
279
 
                                               , NULL); /* NULL is year_out parameter, which is not needed */
280
 
    case INTERVAL_DAY:
281
 
      return (int64_t) temporal->days();
282
 
    case INTERVAL_DAY_HOUR:     
283
 
      return (int64_t) ((temporal->days() * 100L) + temporal->hours());
284
 
    case INTERVAL_DAY_MINUTE:   
285
 
      return (int64_t) ((temporal->days() * 10000L)
286
 
            + (temporal->hours() * 100L) 
287
 
            + temporal->minutes());
288
 
    case INTERVAL_DAY_SECOND:    
289
 
      return (int64_t) (
290
 
              (int64_t) (temporal->days() * 1000000L) 
291
 
            + (int64_t) (temporal->hours() * 10000L)
292
 
            + (temporal->minutes() * 100L) 
293
 
            + temporal->seconds());
294
 
    case INTERVAL_HOUR:         
295
 
      return (int64_t) temporal->hours();
296
 
    case INTERVAL_HOUR_MINUTE:  
297
 
      return (int64_t) (temporal->hours() * 100L) 
298
 
            + temporal->minutes();
299
 
    case INTERVAL_HOUR_SECOND:  
300
 
      return (int64_t) (temporal->hours() * 10000L) 
301
 
            + (temporal->minutes() * 100L) 
302
 
            + temporal->seconds();
303
 
    case INTERVAL_MINUTE:
304
 
      return (int64_t) temporal->minutes();
305
 
    case INTERVAL_MINUTE_SECOND:        
306
 
      return (int64_t) (temporal->minutes() * 100L) + temporal->seconds();
307
 
    case INTERVAL_SECOND:
308
 
      return (int64_t) temporal->seconds();
309
 
    case INTERVAL_MICROSECOND:  
310
 
      return (int64_t) temporal->useconds();
311
 
    case INTERVAL_DAY_MICROSECOND: 
312
 
      return (int64_t) 
313
 
              (
314
 
              (
315
 
              (int64_t) (temporal->days() * 1000000L) 
316
 
            + (int64_t) (temporal->hours() * 10000L) 
317
 
            + (temporal->minutes() * 100L) 
318
 
            + temporal->seconds()
319
 
              ) 
320
 
              * 1000000L
321
 
              ) 
322
 
            + temporal->useconds();
323
 
    case INTERVAL_HOUR_MICROSECOND:
324
 
        return (int64_t)
325
 
              (
326
 
              (
327
 
              (int64_t) (temporal->hours() * 10000L) 
328
 
            + (temporal->minutes() * 100L) 
329
 
            + temporal->seconds()
330
 
              ) 
331
 
              * 1000000L
332
 
              ) 
333
 
            + temporal->useconds();
334
 
    case INTERVAL_MINUTE_MICROSECOND:
335
 
        return (int64_t)
336
 
              (
337
 
              (
338
 
              (temporal->minutes() * 100L) 
339
 
            + temporal->seconds()
340
 
              ) 
341
 
              * 1000000L
342
 
              ) 
343
 
            + temporal->useconds();
344
 
    case INTERVAL_SECOND_MICROSECOND: 
345
 
        return (int64_t) (temporal->seconds() * 1000000L)
346
 
            + temporal->useconds();
347
 
    case INTERVAL_LAST: 
348
 
    default:
349
 
        assert(0); 
350
 
        return 0;
351
 
  }
352
 
}
353
 
 
354
 
bool Item_extract::eq(const Item *item, bool binary_cmp) const
355
 
{
356
 
  if (this == item)
357
 
    return 1;
358
 
  if (item->type() != FUNC_ITEM ||
359
 
      functype() != ((Item_func*)item)->functype())
360
 
    return 0;
361
 
 
362
 
  Item_extract* ie= (Item_extract*)item;
363
 
  if (ie->int_type != int_type)
364
 
    return 0;
365
 
 
366
 
  if (!args[0]->eq(ie->args[0], binary_cmp))
367
 
      return 0;
368
 
  return 1;
369
 
}
370
 
 
371
 
} /* namespace drizzled */