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);
116
if (! datetime_temporal.from_string(res->c_ptr(), res->length()))
119
* Could not interpret the function argument as a temporal value,
120
* so throw an error and return 0
122
my_error(ER_INVALID_DATETIME_VALUE, MYF(0), res->c_ptr());
128
if (datetime_temporal.from_int64_t(args[0]->val_int()))
130
/* Intentionally fall-through on invalid conversion from integer */
134
* Could not interpret the function argument as a temporal value,
135
* so throw an error and return 0
138
char buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
139
String tmp(buff,sizeof(buff), &my_charset_utf8_bin);
142
res= args[0]->val_str(&tmp);
144
my_error(ER_INVALID_DATETIME_VALUE, MYF(0), res->c_ptr());
149
* If we got here, we have a successfully converted DateTime temporal.
150
* Point our working temporal to this.
152
temporal= &datetime_temporal;
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!
169
* Oh, and Brian Aker MADE me do this. :) --JRP
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()))
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...
182
Item_result arg0_result_type= args[0]->result_type();
184
switch (arg0_result_type)
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.
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()))
203
* Could not interpret the function argument as a temporal value,
204
* so throw an error and return 0
206
my_error(ER_INVALID_DATETIME_VALUE, MYF(0), res->c_ptr());
212
if (datetime_temporal.from_int64_t(args[0]->val_int()))
214
/* Intentionally fall-through on invalid conversion from integer */
218
* Could not interpret the function argument as a temporal value,
219
* so throw an error and return 0
222
char buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
223
String tmp(buff,sizeof(buff), &my_charset_utf8_bin);
226
res= args[0]->val_str(&tmp);
228
my_error(ER_INVALID_DATETIME_VALUE, MYF(0), res->c_ptr());
232
/* If we're here, our time failed, but our datetime succeeded... */
233
temporal= &datetime_temporal;
237
/* If we're here, our time succeeded... */
238
temporal= &time_temporal;
242
/* Return the requested datetime component */
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;
251
return (int64_t) temporal->months();
253
return iso_week_number_from_gregorian_date(temporal->years()
256
, NULL); /* NULL is year_out parameter, which is not needed */
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:
267
(int64_t) (temporal->days() * 1000000L)
268
+ (int64_t) (temporal->hours() * 10000L)
269
+ (temporal->minutes() * 100L)
270
+ temporal->seconds());
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:
292
(int64_t) (temporal->days() * 1000000L)
293
+ (int64_t) (temporal->hours() * 10000L)
294
+ (temporal->minutes() * 100L)
295
+ temporal->seconds()
299
+ temporal->useconds();
300
case INTERVAL_HOUR_MICROSECOND:
304
(int64_t) (temporal->hours() * 10000L)
305
+ (temporal->minutes() * 100L)
306
+ temporal->seconds()
310
+ temporal->useconds();
311
case INTERVAL_MINUTE_MICROSECOND:
315
(temporal->minutes() * 100L)
316
+ temporal->seconds()
320
+ temporal->useconds();
321
case INTERVAL_SECOND_MICROSECOND:
322
return (int64_t) (temporal->seconds() * 1000000L)
323
+ temporal->useconds();
331
bool Item_extract::eq(const Item *item, bool binary_cmp) const
335
if (item->type() != FUNC_ITEM ||
336
functype() != ((Item_func*)item)->functype())
339
Item_extract* ie= (Item_extract*)item;
340
if (ie->int_type != int_type)
343
if (!args[0]->eq(ie->args[0], binary_cmp))
348
} /* namespace drizzled */