1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2008 Sun Microsystems
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.
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.
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
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"
29
'interval_names' reflects the order of the enumeration interval_type.
33
extern const char *interval_names[];
35
void Item_extract::print(String *str, enum_query_type query_type)
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);
44
void Item_extract::fix_length_and_dec()
46
value.alloc(DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING);
48
maybe_null= 1; /* If NULL supplied only */
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;
74
int64_t Item_extract::val_int()
78
if (args[0]->is_null())
80
/* For NULL argument, we return a NULL result */
85
/* We could have either a datetime or a time.. */
86
drizzled::DateTime datetime_temporal;
87
drizzled::Time time_temporal;
89
/* Abstract pointer type we'll use in the final switch */
90
drizzled::Temporal *temporal;
94
/* Grab the first argument as a DateTime object */
95
Item_result arg0_result_type= args[0]->result_type();
97
switch (arg0_result_type)
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.
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()))
116
* Could not interpret the function argument as a temporal value,
117
* so throw an error and return 0
119
my_error(ER_INVALID_DATETIME_VALUE, MYF(0), res->c_ptr());
125
if (datetime_temporal.from_int64_t(args[0]->val_int()))
127
/* Intentionally fall-through on invalid conversion from integer */
131
* Could not interpret the function argument as a temporal value,
132
* so throw an error and return 0
135
char buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
136
String tmp(buff,sizeof(buff), &my_charset_utf8_bin);
139
res= args[0]->val_str(&tmp);
141
my_error(ER_INVALID_DATETIME_VALUE, MYF(0), res->c_ptr());
146
* If we got here, we have a successfully converted DateTime temporal.
147
* Point our working temporal to this.
149
temporal= &datetime_temporal;
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!
166
* Oh, and Brian Aker MADE me do this. :) --JRP
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()))
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...
179
Item_result arg0_result_type= args[0]->result_type();
181
switch (arg0_result_type)
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.
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()))
200
* Could not interpret the function argument as a temporal value,
201
* so throw an error and return 0
203
my_error(ER_INVALID_DATETIME_VALUE, MYF(0), res->c_ptr());
209
if (datetime_temporal.from_int64_t(args[0]->val_int()))
211
/* Intentionally fall-through on invalid conversion from integer */
215
* Could not interpret the function argument as a temporal value,
216
* so throw an error and return 0
219
char buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
220
String tmp(buff,sizeof(buff), &my_charset_utf8_bin);
223
res= args[0]->val_str(&tmp);
225
my_error(ER_INVALID_DATETIME_VALUE, MYF(0), res->c_ptr());
229
/* If we're here, our time failed, but our datetime succeeded... */
230
temporal= &datetime_temporal;
234
/* If we're here, our time succeeded... */
235
temporal= &time_temporal;
239
/* Return the requested datetime component */
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;
248
return (int64_t) temporal->months();
250
return iso_week_number_from_gregorian_date(temporal->years()
253
, NULL); /* NULL is year_out parameter, which is not needed */
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:
264
(int64_t) (temporal->days() * 1000000L)
265
+ (int64_t) (temporal->hours() * 10000L)
266
+ (temporal->minutes() * 100L)
267
+ temporal->seconds());
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:
289
(int64_t) (temporal->days() * 1000000L)
290
+ (int64_t) (temporal->hours() * 10000L)
291
+ (temporal->minutes() * 100L)
292
+ temporal->seconds()
296
+ temporal->useconds();
297
case INTERVAL_HOUR_MICROSECOND:
301
(int64_t) (temporal->hours() * 10000L)
302
+ (temporal->minutes() * 100L)
303
+ temporal->seconds()
307
+ temporal->useconds();
308
case INTERVAL_MINUTE_MICROSECOND:
312
(temporal->minutes() * 100L)
313
+ temporal->seconds()
317
+ temporal->useconds();
318
case INTERVAL_SECOND_MICROSECOND:
319
return (int64_t) (temporal->seconds() * 1000000L)
320
+ temporal->useconds();
328
bool Item_extract::eq(const Item *item, bool binary_cmp) const
332
if (item->type() != FUNC_ITEM ||
333
functype() != ((Item_func*)item)->functype())
336
Item_extract* ie= (Item_extract*)item;
337
if (ie->int_type != int_type)
340
if (!args[0]->eq(ie->args[0], binary_cmp))