~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
1241.9.36 by Monty Taylor
ZOMG. I deleted drizzled/server_includes.h.
20
#include "config.h"
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
21
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
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
28
namespace drizzled
29
{
30
574.3.22 by Lee
moving functions from drizzled/item/timefunc to drizzled/functions/time
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
{
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.
49
  value.alloc(DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING);				
574.3.22 by Lee
moving functions from drizzled/item/timefunc to drizzled/functions/time
50
813.1.22 by Jay Pipes
default_week_format variable has gone the way of the Dodo, as have the
51
  maybe_null= 1;					/* If NULL supplied only */
574.3.22 by Lee
moving functions from drizzled/item/timefunc to drizzled/functions/time
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;
971.6.11 by Eric Day
Removed purecov messages.
73
  case INTERVAL_LAST: assert(0); break;
574.3.22 by Lee
moving functions from drizzled/item/timefunc to drizzled/functions/time
74
  }
75
}
76
77
int64_t Item_extract::val_int()
78
{
813.1.22 by Jay Pipes
default_week_format variable has gone the way of the Dodo, as have the
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.. */
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
89
  DateTime datetime_temporal;
90
  Time time_temporal;
813.1.22 by Jay Pipes
default_week_format variable has gone the way of the Dodo, as have the
91
92
  /* Abstract pointer type we'll use in the final switch */
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
93
  Temporal *temporal;
813.1.22 by Jay Pipes
default_week_format variable has gone the way of the Dodo, as have the
94
574.3.22 by Lee
moving functions from drizzled/item/timefunc to drizzled/functions/time
95
  if (date_value)
96
  {
813.1.22 by Jay Pipes
default_week_format variable has gone the way of the Dodo, as have the
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;
574.3.22 by Lee
moving functions from drizzled/item/timefunc to drizzled/functions/time
153
  }
154
  else
155
  {
813.1.22 by Jay Pipes
default_week_format variable has gone the way of the Dodo, as have the
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()))
574.3.22 by Lee
moving functions from drizzled/item/timefunc to drizzled/functions/time
176
    {
813.1.22 by Jay Pipes
default_week_format variable has gone the way of the Dodo, as have the
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;
574.3.22 by Lee
moving functions from drizzled/item/timefunc to drizzled/functions/time
234
    }
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.
235
    else
236
    {
237
      /* If we're here, our time succeeded... */
238
      temporal= &time_temporal;
239
    }
574.3.22 by Lee
moving functions from drizzled/item/timefunc to drizzled/functions/time
240
  }
813.1.22 by Jay Pipes
default_week_format variable has gone the way of the Dodo, as have the
241
242
  /* Return the requested datetime component */
574.3.22 by Lee
moving functions from drizzled/item/timefunc to drizzled/functions/time
243
  switch (int_type) {
813.1.22 by Jay Pipes
default_week_format variable has gone the way of the Dodo, as have the
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); 
971.6.11 by Eric Day
Removed purecov messages.
327
        return 0;
813.1.22 by Jay Pipes
default_week_format variable has gone the way of the Dodo, as have the
328
  }
574.3.22 by Lee
moving functions from drizzled/item/timefunc to drizzled/functions/time
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
}
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
347
348
} /* namespace drizzled */