~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/function/time/to_days.cc

  • Committer: Brian Aker
  • Date: 2009-12-29 01:38:38 UTC
  • mfrom: (1251.1.1 drizzle)
  • Revision ID: brian@gaz-20091229013838-03kb2z5xbqw03ddt
Merge of Diego fix.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
20
#include "config.h"
 
21
#include CSTDINT_H
 
22
#include "drizzled/function/time/to_days.h"
 
23
#include "drizzled/error.h"
 
24
#include "drizzled/temporal.h"
 
25
 
 
26
/* 
 
27
 * We intepret the first argument as a DateTime and then convert
 
28
 * it to a Julian Day Number and return it.
 
29
 */
 
30
int64_t Item_func_to_days::val_int()
 
31
{
 
32
  assert(fixed);
 
33
 
 
34
  /* We return NULL from FROM_DAYS() only when supplied a NULL argument */
 
35
  if (args[0]->null_value)
 
36
  {
 
37
    null_value= true;
 
38
    return false;
 
39
  }
 
40
 
 
41
  /*
 
42
   * We attempt to convert the first argument into a
 
43
   * temporal value.  If the conversion is successful, 
 
44
   * we know that a conversion to a Julian Day Number
 
45
   * is always possible.  Upon successful conversion, 
 
46
   * we return the Julian Day Number.  If no conversion
 
47
   * was possible into a temporal value, we throw an 
 
48
   * error and return 0, setting the null_value flag to true.
 
49
   */
 
50
  /* Grab the first argument as a DateTime object */
 
51
  drizzled::DateTime temporal;
 
52
  Item_result arg0_result_type= args[0]->result_type();
 
53
  
 
54
  switch (arg0_result_type)
 
55
  {
 
56
    case REAL_RESULT:
 
57
    case DECIMAL_RESULT: 
 
58
      /* 
 
59
       * For doubles supplied, interpret the arg as a string, 
 
60
       * so intentionally fall-through here...
 
61
       * This allows us to accept double parameters like 
 
62
       * 19971231235959.01 and interpret it the way MySQL does:
 
63
       * as a TIMESTAMP-like thing with a microsecond component.
 
64
       * Ugh, but need to keep backwards-compat.
 
65
       */
 
66
    case STRING_RESULT:
 
67
      {
 
68
        char buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
 
69
        String tmp(buff,sizeof(buff), &my_charset_utf8_bin);
 
70
        String *res= args[0]->val_str(&tmp);
 
71
 
 
72
        if (! res)
 
73
        {
 
74
          /* 
 
75
           * Likely a nested function issue where the nested
 
76
           * function had bad input.  We rely on the nested
 
77
           * function my_error() and simply return false here.
 
78
           */
 
79
          return false;
 
80
        }
 
81
 
 
82
        if (! temporal.from_string(res->c_ptr(), res->length()))
 
83
        {
 
84
          /* 
 
85
          * Could not interpret the function argument as a temporal value, 
 
86
          * so throw an error and return 0
 
87
          */
 
88
          my_error(ER_INVALID_DATETIME_VALUE, MYF(0), res->c_ptr());
 
89
          return 0;
 
90
        }
 
91
      }
 
92
      break;
 
93
    case INT_RESULT:
 
94
      if (temporal.from_int64_t(args[0]->val_int()))
 
95
        break;
 
96
      /* Intentionally fall-through on invalid conversion from integer */
 
97
    default:
 
98
      {
 
99
        /* 
 
100
        * Could not interpret the function argument as a temporal value, 
 
101
        * so throw an error and return 0
 
102
        */
 
103
        null_value= true;
 
104
        char buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
 
105
        String tmp(buff,sizeof(buff), &my_charset_utf8_bin);
 
106
        String *res;
 
107
 
 
108
        res= args[0]->val_str(&tmp);
 
109
 
 
110
        if (! res)
 
111
        {
 
112
          /* 
 
113
           * Likely a nested function issue where the nested
 
114
           * function had bad input.  We rely on the nested
 
115
           * function my_error() and simply return false here.
 
116
           */
 
117
          return false;
 
118
        }
 
119
 
 
120
        my_error(ER_INVALID_DATETIME_VALUE, MYF(0), res->c_ptr());
 
121
        return 0;
 
122
      }
 
123
  }
 
124
  int64_t julian_day_number;
 
125
  temporal.to_julian_day_number(&julian_day_number);
 
126
  return julian_day_number;
 
127
}
 
128
 
 
129
int64_t Item_func_to_days::val_int_endpoint(bool left_endp, bool *incl_endp)
 
130
{
 
131
  assert(fixed);
 
132
 
 
133
  /*
 
134
   * We attempt to convert the first argument into a
 
135
   * temporal value.  If the conversion is successful, 
 
136
   * we know that a conversion to a Julian Day Number
 
137
   * is always possible. Depending on whether the 
 
138
   * first argument is a Date, or a DateTime with no
 
139
   * time-portion, we return the Julian Day Number or
 
140
   * the appropriate end-point integer.
 
141
   */
 
142
  /* Grab the first argument as a DateTime object */
 
143
  drizzled::DateTime temporal;
 
144
  Item_result arg0_result_type= args[0]->result_type();
 
145
  
 
146
  switch (arg0_result_type)
 
147
  {
 
148
    case REAL_RESULT:
 
149
    case DECIMAL_RESULT: 
 
150
      /* 
 
151
       * For doubles supplied, interpret the arg as a string, 
 
152
       * so intentionally fall-through here...
 
153
       * This allows us to accept double parameters like 
 
154
       * 19971231235959.01 and interpret it the way MySQL does:
 
155
       * as a TIMESTAMP-like thing with a microsecond component.
 
156
       * Ugh, but need to keep backwards-compat.
 
157
       */
 
158
    case STRING_RESULT:
 
159
      {
 
160
        char buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
 
161
        String tmp(buff,sizeof(buff), &my_charset_utf8_bin);
 
162
        String *res= args[0]->val_str(&tmp);
 
163
 
 
164
        if (! res)
 
165
        {
 
166
          /* 
 
167
           * Likely a nested function issue where the nested
 
168
           * function had bad input.  We rely on the nested
 
169
           * function my_error() and simply return false here.
 
170
           */
 
171
          return 0;
 
172
        }
 
173
 
 
174
        if (! temporal.from_string(res->c_ptr(), res->length()))
 
175
        {
 
176
          /* 
 
177
          * Could not interpret the function argument as a temporal value, 
 
178
          * so throw an error and return 0
 
179
          */
 
180
          my_error(ER_INVALID_DATETIME_VALUE, MYF(0), res->c_ptr());
 
181
          return 0;
 
182
        }
 
183
      }
 
184
      break;
 
185
    case INT_RESULT:
 
186
      if (temporal.from_int64_t(args[0]->val_int()))
 
187
        break;
 
188
      /* Intentionally fall-through on invalid conversion from integer */
 
189
    default:
 
190
      {
 
191
        /* 
 
192
        * Could not interpret the function argument as a temporal value, 
 
193
        * so throw an error and return 0
 
194
        */
 
195
        null_value= true;
 
196
        char buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
 
197
        String tmp(buff,sizeof(buff), &my_charset_utf8_bin);
 
198
        String *res;
 
199
 
 
200
        res= args[0]->val_str(&tmp);
 
201
 
 
202
        if (! res)
 
203
        {
 
204
          /* 
 
205
           * Likely a nested function issue where the nested
 
206
           * function had bad input.  We rely on the nested
 
207
           * function my_error() and simply return false here.
 
208
           */
 
209
          return 0;
 
210
        }
 
211
 
 
212
        my_error(ER_INVALID_DATETIME_VALUE, MYF(0), res->c_ptr());
 
213
        return 0;
 
214
      }
 
215
  }
 
216
 
 
217
  if (null_value == true)
 
218
  {
 
219
    /* got NULL, leave the incl_endp intact */
 
220
    return INT64_MIN;
 
221
  }
 
222
 
 
223
  int64_t julian_day_number;
 
224
  temporal.to_julian_day_number(&julian_day_number);
 
225
 
 
226
  if (args[0]->field_type() == DRIZZLE_TYPE_DATE)
 
227
  {
 
228
    /* TO_DAYS() is strictly monotonic for dates, leave incl_endp intact */
 
229
    return julian_day_number;
 
230
  }
 
231
 
 
232
  /*
 
233
    Handle the special but practically useful case of datetime values that
 
234
    point to day bound ("strictly less" comparison stays intact):
 
235
 
 
236
      col < '2007-09-15 00:00:00'  -> TO_DAYS(col) <  TO_DAYS('2007-09-15')
 
237
 
 
238
    which is different from the general case ("strictly less" changes to
 
239
    "less or equal"):
 
240
 
 
241
      col < '2007-09-15 12:34:56'  -> TO_DAYS(col) <= TO_DAYS('2007-09-15')
 
242
  */
 
243
  if (!left_endp && ! (
 
244
                    temporal.hours() 
 
245
                    || temporal.minutes()
 
246
                    || temporal.seconds() 
 
247
                    || temporal.useconds()
 
248
                    || temporal.nseconds()
 
249
                    )
 
250
                    )
 
251
    ; /* do nothing */
 
252
  else
 
253
    *incl_endp= true;
 
254
  return julian_day_number;
 
255
}