~drizzle-trunk/drizzle/development

574.3.22 by Lee
moving functions from drizzled/item/timefunc to drizzled/functions/time
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
813.1.22 by Jay Pipes
default_week_format variable has gone the way of the Dodo, as have the
20
#include "drizzled/server_includes.h"
574.3.22 by Lee
moving functions from drizzled/item/timefunc to drizzled/functions/time
21
#include CSTDINT_H
813.1.22 by Jay Pipes
default_week_format variable has gone the way of the Dodo, as have the
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"
574.3.22 by Lee
moving functions from drizzled/item/timefunc to drizzled/functions/time
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
{
813.1.24 by Jay Pipes
fixed logic error in EXTRACT() function whereby datetime temporals were improperly pointing to the time temporals. Fixed test cases for func_time and func_sapdb to remove the week and weekofyear functions.
46
  value.alloc(DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING);				
574.3.22 by Lee
moving functions from drizzled/item/timefunc to drizzled/functions/time
47
813.1.22 by Jay Pipes
default_week_format variable has gone the way of the Dodo, as have the
48
  maybe_null= 1;					/* If NULL supplied only */
574.3.22 by Lee
moving functions from drizzled/item/timefunc to drizzled/functions/time
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;
971.6.11 by Eric Day
Removed purecov messages.
70
  case INTERVAL_LAST: assert(0); break;
574.3.22 by Lee
moving functions from drizzled/item/timefunc to drizzled/functions/time
71
  }
72
}
73
74
int64_t Item_extract::val_int()
75
{
813.1.22 by Jay Pipes
default_week_format variable has gone the way of the Dodo, as have the
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
574.3.22 by Lee
moving functions from drizzled/item/timefunc to drizzled/functions/time
92
  if (date_value)
93
  {
813.1.22 by Jay Pipes
default_week_format variable has gone the way of the Dodo, as have the
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;
574.3.22 by Lee
moving functions from drizzled/item/timefunc to drizzled/functions/time
150
  }
151
  else
152
  {
813.1.22 by Jay Pipes
default_week_format variable has gone the way of the Dodo, as have the
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()))
574.3.22 by Lee
moving functions from drizzled/item/timefunc to drizzled/functions/time
173
    {
813.1.22 by Jay Pipes
default_week_format variable has gone the way of the Dodo, as have the
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;
574.3.22 by Lee
moving functions from drizzled/item/timefunc to drizzled/functions/time
231
    }
813.1.24 by Jay Pipes
fixed logic error in EXTRACT() function whereby datetime temporals were improperly pointing to the time temporals. Fixed test cases for func_time and func_sapdb to remove the week and weekofyear functions.
232
    else
233
    {
234
      /* If we're here, our time succeeded... */
235
      temporal= &time_temporal;
236
    }
574.3.22 by Lee
moving functions from drizzled/item/timefunc to drizzled/functions/time
237
  }
813.1.22 by Jay Pipes
default_week_format variable has gone the way of the Dodo, as have the
238
239
  /* Return the requested datetime component */
574.3.22 by Lee
moving functions from drizzled/item/timefunc to drizzled/functions/time
240
  switch (int_type) {
813.1.22 by Jay Pipes
default_week_format variable has gone the way of the Dodo, as have the
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); 
971.6.11 by Eric Day
Removed purecov messages.
324
        return 0;
813.1.22 by Jay Pipes
default_week_format variable has gone the way of the Dodo, as have the
325
  }
574.3.22 by Lee
moving functions from drizzled/item/timefunc to drizzled/functions/time
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
}