Drizzled Public API Documentation

extract.cc
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, Inc.
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 
20 #include <config.h>
21 
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>
27 
28 namespace drizzled
29 {
30 
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 
39 {
40  str->append(STRING_WITH_LEN("extract("));
41  str->append(interval_names[int_type], strlen(interval_names[int_type]));
42  str->append(STRING_WITH_LEN(" from "));
43  args[0]->print(str);
44  str->append(')');
45 }
46 
47 void Item_extract::fix_length_and_dec()
48 {
49  value.alloc(DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING);
50 
51  maybe_null= 1; /* If NULL supplied only */
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;
73  case INTERVAL_LAST: assert(0); break;
74  }
75 }
76 
78 {
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.. */
89  DateTime datetime_temporal;
90  Time time_temporal;
91 
92  /* Abstract pointer type we'll use in the final switch */
93  Temporal *temporal;
94 
95  if (date_value)
96  {
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 
117  if (res && (res != &tmp))
118  {
119  tmp.copy(*res);
120  }
121 
122  if (! datetime_temporal.from_string(tmp.c_ptr(), tmp.length()))
123  {
124  /*
125  * Could not interpret the function argument as a temporal value,
126  * so throw an error and return 0
127  */
128  my_error(ER_INVALID_DATETIME_VALUE, MYF(0), tmp.c_ptr());
129  return 0;
130  }
131  }
132  break;
133  case INT_RESULT:
134  if (datetime_temporal.from_int64_t(args[0]->val_int()))
135  break;
136  /* Intentionally fall-through on invalid conversion from integer */
137  default:
138  {
139  /*
140  * Could not interpret the function argument as a temporal value,
141  * so throw an error and return 0
142  */
143  null_value= true;
144  char buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
145  String tmp(buff,sizeof(buff), &my_charset_utf8_bin);
146  String *res;
147 
148  res= args[0]->val_str(&tmp);
149 
150  if (res && (res != &tmp))
151  {
152  tmp.copy(*res);
153  }
154 
155  my_error(ER_INVALID_DATETIME_VALUE, MYF(0), tmp.c_ptr());
156  return 0;
157  }
158  }
159  /*
160  * If we got here, we have a successfully converted DateTime temporal.
161  * Point our working temporal to this.
162  */
163  temporal= &datetime_temporal;
164  }
165  else
166  {
167  /*
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!
179  *
180  * Oh, and Brian Aker MADE me do this. :) --JRP
181  */
182 
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);
186 
187  if (time_res && (time_res != &tmp_time))
188  {
189  tmp_time.copy(*time_res);
190  }
191 
192  if (! time_temporal.from_string(tmp_time.c_ptr(), tmp_time.length()))
193  {
194  /*
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...
198  */
199  Item_result arg0_result_type= args[0]->result_type();
200 
201  switch (arg0_result_type)
202  {
203  case DECIMAL_RESULT:
204  /*
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.
211  */
212  case STRING_RESULT:
213  {
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);
217 
218  if (res && (res != &tmp))
219  {
220  tmp.copy(*res);
221  }
222 
223  if (! datetime_temporal.from_string(tmp.c_ptr(), tmp.length()))
224  {
225  /*
226  * Could not interpret the function argument as a temporal value,
227  * so throw an error and return 0
228  */
229  my_error(ER_INVALID_DATETIME_VALUE, MYF(0), tmp.c_ptr());
230  return 0;
231  }
232  }
233  break;
234  case INT_RESULT:
235  if (datetime_temporal.from_int64_t(args[0]->val_int()))
236  break;
237  /* Intentionally fall-through on invalid conversion from integer */
238  default:
239  {
240  /*
241  * Could not interpret the function argument as a temporal value,
242  * so throw an error and return 0
243  */
244  null_value= true;
245  char buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
246  String tmp(buff,sizeof(buff), &my_charset_utf8_bin);
247  String *res;
248 
249  res= args[0]->val_str(&tmp);
250 
251  my_error(ER_INVALID_DATETIME_VALUE, MYF(0), res->c_ptr());
252  return 0;
253  }
254  }
255  /* If we're here, our time failed, but our datetime succeeded... */
256  temporal= &datetime_temporal;
257  }
258  else
259  {
260  /* If we're here, our time succeeded... */
261  temporal= &time_temporal;
262  }
263  }
264 
265  /* Return the requested datetime component */
266  switch (int_type) {
267  case INTERVAL_YEAR:
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;
273  case INTERVAL_MONTH:
274  return (int64_t) temporal->months();
275  case INTERVAL_WEEK:
276  return iso_week_number_from_gregorian_date(temporal->years()
277  , temporal->months()
278  , temporal->days());
279  case INTERVAL_DAY:
280  return (int64_t) temporal->days();
281  case INTERVAL_DAY_HOUR:
282  return (int64_t) ((temporal->days() * 100L) + temporal->hours());
283  case INTERVAL_DAY_MINUTE:
284  return (int64_t) ((temporal->days() * 10000L)
285  + (temporal->hours() * 100L)
286  + temporal->minutes());
287  case INTERVAL_DAY_SECOND:
288  return (int64_t) (
289  (int64_t) (temporal->days() * 1000000L)
290  + (int64_t) (temporal->hours() * 10000L)
291  + (temporal->minutes() * 100L)
292  + temporal->seconds());
293  case INTERVAL_HOUR:
294  return (int64_t) temporal->hours();
295  case INTERVAL_HOUR_MINUTE:
296  return (int64_t) (temporal->hours() * 100L)
297  + temporal->minutes();
298  case INTERVAL_HOUR_SECOND:
299  return (int64_t) (temporal->hours() * 10000L)
300  + (temporal->minutes() * 100L)
301  + temporal->seconds();
302  case INTERVAL_MINUTE:
303  return (int64_t) temporal->minutes();
304  case INTERVAL_MINUTE_SECOND:
305  return (int64_t) (temporal->minutes() * 100L) + temporal->seconds();
306  case INTERVAL_SECOND:
307  return (int64_t) temporal->seconds();
308  case INTERVAL_MICROSECOND:
309  return (int64_t) temporal->useconds();
310  case INTERVAL_DAY_MICROSECOND:
311  return (int64_t)
312  (
313  (
314  (int64_t) (temporal->days() * 1000000L)
315  + (int64_t) (temporal->hours() * 10000L)
316  + (temporal->minutes() * 100L)
317  + temporal->seconds()
318  )
319  * 1000000L
320  )
321  + temporal->useconds();
322  case INTERVAL_HOUR_MICROSECOND:
323  return (int64_t)
324  (
325  (
326  (int64_t) (temporal->hours() * 10000L)
327  + (temporal->minutes() * 100L)
328  + temporal->seconds()
329  )
330  * 1000000L
331  )
332  + temporal->useconds();
333  case INTERVAL_MINUTE_MICROSECOND:
334  return (int64_t)
335  (
336  (
337  (temporal->minutes() * 100L)
338  + temporal->seconds()
339  )
340  * 1000000L
341  )
342  + temporal->useconds();
343  case INTERVAL_SECOND_MICROSECOND:
344  return (int64_t) (temporal->seconds() * 1000000L)
345  + temporal->useconds();
346  case INTERVAL_LAST:
347  default:
348  assert(0);
349  return 0;
350  }
351 }
352 
353 bool Item_extract::eq(const Item *item, bool binary_cmp) const
354 {
355  if (this == item)
356  return 1;
357  if (item->type() != FUNC_ITEM ||
358  functype() != ((Item_func*)item)->functype())
359  return 0;
360 
361  Item_extract* ie= (Item_extract*)item;
362  if (ie->int_type != int_type)
363  return 0;
364 
365  if (!args[0]->eq(ie->args[0], binary_cmp))
366  return 0;
367  return 1;
368 }
369 
370 } /* namespace drizzled */
bool from_string(const char *from, size_t from_len)
Definition: temporal.cc:978
bool from_string(const char *from, size_t from_len)
Definition: temporal.cc:160
virtual int64_t val_int()=0
uint32_t useconds() const
Definition: temporal.h:116
uint32_t hours() const
Definition: temporal.h:138
bool fixed
Definition: item.h:120
TODO: Rename this file - func.h is stupid.
bool eq(const Item *item, bool binary_cmp) const
Definition: extract.cc:353
uint32_t months() const
Definition: temporal.h:146
bool null_value
Definition: item.h:122
virtual void print(String *str)
Definition: extract.cc:38
bool maybe_null
Definition: item.h:121
uint32_t minutes() const
Definition: temporal.h:134
bool from_int64_t(const int64_t from, bool convert)
Definition: temporal.cc:1144
bool is_null()
Definition: func.cc:512
uint32_t days() const
Definition: temporal.h:142
virtual String * val_str(String *str)=0
virtual void print(String *str)
Definition: item.cc:362
uint32_t iso_week_number_from_gregorian_date(uint32_t year, uint32_t month, uint32_t day)
Definition: calendar.cc:437
uint32_t years() const
Definition: temporal.h:150
uint32_t seconds() const
Definition: temporal.h:130