~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

Merged in changes. 
Edited a the comment test case so deal with our version bump.

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