~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

Cleanup around SAFEMALLOC

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
 
          if (! datetime_temporal.from_string(res->c_ptr(), res->length()))
117
 
          {
118
 
            /* 
119
 
            * Could not interpret the function argument as a temporal value, 
120
 
            * so throw an error and return 0
121
 
            */
122
 
            my_error(ER_INVALID_DATETIME_VALUE, MYF(0), res->c_ptr());
123
 
            return 0;
124
 
          }
125
 
        }
126
 
        break;
127
 
      case INT_RESULT:
128
 
        if (datetime_temporal.from_int64_t(args[0]->val_int()))
129
 
          break;
130
 
        /* Intentionally fall-through on invalid conversion from integer */
131
 
      default:
132
 
        {
133
 
          /* 
134
 
          * Could not interpret the function argument as a temporal value, 
135
 
          * so throw an error and return 0
136
 
          */
137
 
          null_value= true;
138
 
          char buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
139
 
          String tmp(buff,sizeof(buff), &my_charset_utf8_bin);
140
 
          String *res;
141
 
 
142
 
          res= args[0]->val_str(&tmp);
143
 
 
144
 
          my_error(ER_INVALID_DATETIME_VALUE, MYF(0), res->c_ptr());
145
 
          return 0;
146
 
        }
147
 
    }
148
 
    /* 
149
 
     * If we got here, we have a successfully converted DateTime temporal. 
150
 
     * Point our working temporal to this.
151
 
     */
152
 
    temporal= &datetime_temporal;
153
 
  }
154
 
  else
155
 
  {
156
 
    /* 
157
 
     * Because of the ridiculous way in which MySQL handles
158
 
     * TIME values (it does implicit integer -> string conversions
159
 
     * but only for DATETIME, not TIME values) we must first 
160
 
     * try a conversion into a TIME from a string.  If this
161
 
     * fails, we fall back on a DATETIME conversion.  This is
162
 
     * necessary because of the fact that DateTime::from_string()
163
 
     * looks first for DATETIME, then DATE regex matches.  6 consecutive
164
 
     * numbers, say 231130, will match the DATE regex YYMMDD
165
 
     * with no TIME part, but MySQL actually implicitly treats
166
 
     * parameters to SECOND(), HOUR(), and MINUTE() as TIME-only
167
 
     * values and matches 231130 as HHmmSS!
168
 
     *
169
 
     * Oh, and Brian Aker MADE me do this. :) --JRP
170
 
     */
171
 
    
172
 
    char time_buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
173
 
    String tmp_time(time_buff,sizeof(time_buff), &my_charset_utf8_bin);
174
 
    String *time_res= args[0]->val_str(&tmp_time);
175
 
    if (! time_temporal.from_string(time_res->c_ptr(), time_res->length()))
176
 
    {
177
 
      /* 
178
 
       * OK, we failed to match the first argument as a string
179
 
       * representing a time value, so we grab the first argument 
180
 
       * as a DateTime object and try that for a match...
181
 
       */
182
 
      Item_result arg0_result_type= args[0]->result_type();
183
 
      
184
 
      switch (arg0_result_type)
185
 
      {
186
 
        case DECIMAL_RESULT: 
187
 
          /* 
188
 
           * For doubles supplied, interpret the arg as a string, 
189
 
           * so intentionally fall-through here...
190
 
           * This allows us to accept double parameters like 
191
 
           * 19971231235959.01 and interpret it the way MySQL does:
192
 
           * as a TIMESTAMP-like thing with a microsecond component.
193
 
           * Ugh, but need to keep backwards-compat.
194
 
           */
195
 
        case STRING_RESULT:
196
 
          {
197
 
            char buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
198
 
            String tmp(buff,sizeof(buff), &my_charset_utf8_bin);
199
 
            String *res= args[0]->val_str(&tmp);
200
 
            if (! datetime_temporal.from_string(res->c_ptr(), res->length()))
201
 
            {
202
 
              /* 
203
 
               * Could not interpret the function argument as a temporal value, 
204
 
               * so throw an error and return 0
205
 
               */
206
 
              my_error(ER_INVALID_DATETIME_VALUE, MYF(0), res->c_ptr());
207
 
              return 0;
208
 
            }
209
 
          }
210
 
          break;
211
 
        case INT_RESULT:
212
 
          if (datetime_temporal.from_int64_t(args[0]->val_int()))
213
 
            break;
214
 
          /* Intentionally fall-through on invalid conversion from integer */
215
 
        default:
216
 
          {
217
 
            /* 
218
 
             * Could not interpret the function argument as a temporal value, 
219
 
             * so throw an error and return 0
220
 
             */
221
 
            null_value= true;
222
 
            char buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
223
 
            String tmp(buff,sizeof(buff), &my_charset_utf8_bin);
224
 
            String *res;
225
 
 
226
 
            res= args[0]->val_str(&tmp);
227
 
 
228
 
            my_error(ER_INVALID_DATETIME_VALUE, MYF(0), res->c_ptr());
229
 
            return 0;
230
 
          }
231
 
      }
232
 
      /* If we're here, our time failed, but our datetime succeeded... */
233
 
      temporal= &datetime_temporal;
234
 
    }
235
 
    else
236
 
    {
237
 
      /* If we're here, our time succeeded... */
238
 
      temporal= &time_temporal;
239
 
    }
240
 
  }
241
 
 
242
 
  /* Return the requested datetime component */
243
 
  switch (int_type) {
244
 
    case INTERVAL_YEAR:         
245
 
      return (int64_t) temporal->years();
246
 
    case INTERVAL_YEAR_MONTH:   
247
 
      return (int64_t) ((temporal->years() * 100L) + temporal->months());
248
 
    case INTERVAL_QUARTER:
249
 
      return (int64_t) (temporal->months() + 2) / 3;
250
 
    case INTERVAL_MONTH:
251
 
      return (int64_t) temporal->months();
252
 
    case INTERVAL_WEEK:
253
 
      return iso_week_number_from_gregorian_date(temporal->years()
254
 
                                               , temporal->months()
255
 
                                               , temporal->days()
256
 
                                               , NULL); /* NULL is year_out parameter, which is not needed */
257
 
    case INTERVAL_DAY:
258
 
      return (int64_t) temporal->days();
259
 
    case INTERVAL_DAY_HOUR:     
260
 
      return (int64_t) ((temporal->days() * 100L) + temporal->hours());
261
 
    case INTERVAL_DAY_MINUTE:   
262
 
      return (int64_t) ((temporal->days() * 10000L)
263
 
            + (temporal->hours() * 100L) 
264
 
            + temporal->minutes());
265
 
    case INTERVAL_DAY_SECOND:    
266
 
      return (int64_t) (
267
 
              (int64_t) (temporal->days() * 1000000L) 
268
 
            + (int64_t) (temporal->hours() * 10000L)
269
 
            + (temporal->minutes() * 100L) 
270
 
            + temporal->seconds());
271
 
    case INTERVAL_HOUR:         
272
 
      return (int64_t) temporal->hours();
273
 
    case INTERVAL_HOUR_MINUTE:  
274
 
      return (int64_t) (temporal->hours() * 100L) 
275
 
            + temporal->minutes();
276
 
    case INTERVAL_HOUR_SECOND:  
277
 
      return (int64_t) (temporal->hours() * 10000L) 
278
 
            + (temporal->minutes() * 100L) 
279
 
            + temporal->seconds();
280
 
    case INTERVAL_MINUTE:
281
 
      return (int64_t) temporal->minutes();
282
 
    case INTERVAL_MINUTE_SECOND:        
283
 
      return (int64_t) (temporal->minutes() * 100L) + temporal->seconds();
284
 
    case INTERVAL_SECOND:
285
 
      return (int64_t) temporal->seconds();
286
 
    case INTERVAL_MICROSECOND:  
287
 
      return (int64_t) temporal->useconds();
288
 
    case INTERVAL_DAY_MICROSECOND: 
289
 
      return (int64_t) 
290
 
              (
291
 
              (
292
 
              (int64_t) (temporal->days() * 1000000L) 
293
 
            + (int64_t) (temporal->hours() * 10000L) 
294
 
            + (temporal->minutes() * 100L) 
295
 
            + temporal->seconds()
296
 
              ) 
297
 
              * 1000000L
298
 
              ) 
299
 
            + temporal->useconds();
300
 
    case INTERVAL_HOUR_MICROSECOND:
301
 
        return (int64_t)
302
 
              (
303
 
              (
304
 
              (int64_t) (temporal->hours() * 10000L) 
305
 
            + (temporal->minutes() * 100L) 
306
 
            + temporal->seconds()
307
 
              ) 
308
 
              * 1000000L
309
 
              ) 
310
 
            + temporal->useconds();
311
 
    case INTERVAL_MINUTE_MICROSECOND:
312
 
        return (int64_t)
313
 
              (
314
 
              (
315
 
              (temporal->minutes() * 100L) 
316
 
            + temporal->seconds()
317
 
              ) 
318
 
              * 1000000L
319
 
              ) 
320
 
            + temporal->useconds();
321
 
    case INTERVAL_SECOND_MICROSECOND: 
322
 
        return (int64_t) (temporal->seconds() * 1000000L)
323
 
            + temporal->useconds();
324
 
    case INTERVAL_LAST: 
325
 
    default:
326
 
        assert(0); 
327
 
        return 0;
328
 
  }
329
 
}
330
 
 
331
 
bool Item_extract::eq(const Item *item, bool binary_cmp) const
332
 
{
333
 
  if (this == item)
334
 
    return 1;
335
 
  if (item->type() != FUNC_ITEM ||
336
 
      functype() != ((Item_func*)item)->functype())
337
 
    return 0;
338
 
 
339
 
  Item_extract* ie= (Item_extract*)item;
340
 
  if (ie->int_type != int_type)
341
 
    return 0;
342
 
 
343
 
  if (!args[0]->eq(ie->args[0], binary_cmp))
344
 
      return 0;
345
 
  return 1;
346
 
}
347
 
 
348
 
} /* namespace drizzled */