~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2010-01-22 00:53:13 UTC
  • Revision ID: brian@gaz-20100122005313-jmizcbcdi1lt4tcx
Revert db patch.

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
}