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"
32
'interval_names' reflects the order of the enumeration interval_type.
36
extern const char *interval_names[];
38
void Item_extract::print(String *str, enum_query_type query_type)
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);
47
void Item_extract::fix_length_and_dec()
49
value.alloc(DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING);
51
maybe_null= 1; /* If NULL supplied only */
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;
77
int64_t Item_extract::val_int()
81
if (args[0]->is_null())
83
/* For NULL argument, we return a NULL result */
88
/* We could have either a datetime or a time.. */
89
DateTime datetime_temporal;
92
/* Abstract pointer type we'll use in the final switch */
97
/* Grab the first argument as a DateTime object */
98
Item_result arg0_result_type= args[0]->result_type();
100
switch (arg0_result_type)
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.
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);
117
if (res && (res != &tmp))
122
if (! datetime_temporal.from_string(tmp.c_ptr(), tmp.length()))
125
* Could not interpret the function argument as a temporal value,
126
* so throw an error and return 0
128
my_error(ER_INVALID_DATETIME_VALUE, MYF(0), tmp.c_ptr());
134
if (datetime_temporal.from_int64_t(args[0]->val_int()))
136
/* Intentionally fall-through on invalid conversion from integer */
140
* Could not interpret the function argument as a temporal value,
141
* so throw an error and return 0
144
char buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
145
String tmp(buff,sizeof(buff), &my_charset_utf8_bin);
148
res= args[0]->val_str(&tmp);
150
if (res && (res != &tmp))
155
my_error(ER_INVALID_DATETIME_VALUE, MYF(0), tmp.c_ptr());
160
* If we got here, we have a successfully converted DateTime temporal.
161
* Point our working temporal to this.
163
temporal= &datetime_temporal;
168
* Because of the ridiculous way in which MySQL handles
169
* TIME values (it does implicit integer -> string conversions
170
* but only for DATETIME, not TIME values) we must first
171
* try a conversion into a TIME from a string. If this
172
* fails, we fall back on a DATETIME conversion. This is
173
* necessary because of the fact that DateTime::from_string()
174
* looks first for DATETIME, then DATE regex matches. 6 consecutive
175
* numbers, say 231130, will match the DATE regex YYMMDD
176
* with no TIME part, but MySQL actually implicitly treats
177
* parameters to SECOND(), HOUR(), and MINUTE() as TIME-only
178
* values and matches 231130 as HHmmSS!
180
* Oh, and Brian Aker MADE me do this. :) --JRP
183
char time_buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
184
String tmp_time(time_buff,sizeof(time_buff), &my_charset_utf8_bin);
185
String *time_res= args[0]->val_str(&tmp_time);
187
if (time_res && (time_res != &tmp_time))
189
tmp_time.copy(*time_res);
192
if (! time_temporal.from_string(tmp_time.c_ptr(), tmp_time.length()))
195
* OK, we failed to match the first argument as a string
196
* representing a time value, so we grab the first argument
197
* as a DateTime object and try that for a match...
199
Item_result arg0_result_type= args[0]->result_type();
201
switch (arg0_result_type)
205
* For doubles supplied, interpret the arg as a string,
206
* so intentionally fall-through here...
207
* This allows us to accept double parameters like
208
* 19971231235959.01 and interpret it the way MySQL does:
209
* as a TIMESTAMP-like thing with a microsecond component.
210
* Ugh, but need to keep backwards-compat.
214
char buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
215
String tmp(buff,sizeof(buff), &my_charset_utf8_bin);
216
String *res= args[0]->val_str(&tmp);
218
if (res && (res != &tmp))
223
if (! datetime_temporal.from_string(tmp.c_ptr(), tmp.length()))
226
* Could not interpret the function argument as a temporal value,
227
* so throw an error and return 0
229
my_error(ER_INVALID_DATETIME_VALUE, MYF(0), tmp.c_ptr());
235
if (datetime_temporal.from_int64_t(args[0]->val_int()))
237
/* Intentionally fall-through on invalid conversion from integer */
241
* Could not interpret the function argument as a temporal value,
242
* so throw an error and return 0
245
char buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
246
String tmp(buff,sizeof(buff), &my_charset_utf8_bin);
249
res= args[0]->val_str(&tmp);
251
my_error(ER_INVALID_DATETIME_VALUE, MYF(0), res->c_ptr());
255
/* If we're here, our time failed, but our datetime succeeded... */
256
temporal= &datetime_temporal;
260
/* If we're here, our time succeeded... */
261
temporal= &time_temporal;
265
/* Return the requested datetime component */
268
return (int64_t) temporal->years();
269
case INTERVAL_YEAR_MONTH:
270
return (int64_t) ((temporal->years() * 100L) + temporal->months());
271
case INTERVAL_QUARTER:
272
return (int64_t) (temporal->months() + 2) / 3;
274
return (int64_t) temporal->months();
276
return iso_week_number_from_gregorian_date(temporal->years()
279
, NULL); /* NULL is year_out parameter, which is not needed */
281
return (int64_t) temporal->days();
282
case INTERVAL_DAY_HOUR:
283
return (int64_t) ((temporal->days() * 100L) + temporal->hours());
284
case INTERVAL_DAY_MINUTE:
285
return (int64_t) ((temporal->days() * 10000L)
286
+ (temporal->hours() * 100L)
287
+ temporal->minutes());
288
case INTERVAL_DAY_SECOND:
290
(int64_t) (temporal->days() * 1000000L)
291
+ (int64_t) (temporal->hours() * 10000L)
292
+ (temporal->minutes() * 100L)
293
+ temporal->seconds());
295
return (int64_t) temporal->hours();
296
case INTERVAL_HOUR_MINUTE:
297
return (int64_t) (temporal->hours() * 100L)
298
+ temporal->minutes();
299
case INTERVAL_HOUR_SECOND:
300
return (int64_t) (temporal->hours() * 10000L)
301
+ (temporal->minutes() * 100L)
302
+ temporal->seconds();
303
case INTERVAL_MINUTE:
304
return (int64_t) temporal->minutes();
305
case INTERVAL_MINUTE_SECOND:
306
return (int64_t) (temporal->minutes() * 100L) + temporal->seconds();
307
case INTERVAL_SECOND:
308
return (int64_t) temporal->seconds();
309
case INTERVAL_MICROSECOND:
310
return (int64_t) temporal->useconds();
311
case INTERVAL_DAY_MICROSECOND:
315
(int64_t) (temporal->days() * 1000000L)
316
+ (int64_t) (temporal->hours() * 10000L)
317
+ (temporal->minutes() * 100L)
318
+ temporal->seconds()
322
+ temporal->useconds();
323
case INTERVAL_HOUR_MICROSECOND:
327
(int64_t) (temporal->hours() * 10000L)
328
+ (temporal->minutes() * 100L)
329
+ temporal->seconds()
333
+ temporal->useconds();
334
case INTERVAL_MINUTE_MICROSECOND:
338
(temporal->minutes() * 100L)
339
+ temporal->seconds()
343
+ temporal->useconds();
344
case INTERVAL_SECOND_MICROSECOND:
345
return (int64_t) (temporal->seconds() * 1000000L)
346
+ temporal->useconds();
354
bool Item_extract::eq(const Item *item, bool binary_cmp) const
358
if (item->type() != FUNC_ITEM ||
359
functype() != ((Item_func*)item)->functype())
362
Item_extract* ie= (Item_extract*)item;
363
if (ie->int_type != int_type)
366
if (!args[0]->eq(ie->args[0], binary_cmp))
371
} /* namespace drizzled */