~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/field/date.cc

  • Committer: Brian Aker
  • Date: 2008-07-28 18:01:38 UTC
  • Revision ID: brian@tangent.org-20080728180138-q2pxlq0qiapvqsdn
Remove YEAR field type

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* - mode: c++ c-basic-offset: 2; indent-tabs-mode: nil; -*-
 
1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
3
 *
4
4
 *  Copyright (C) 2008 MySQL
18
18
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19
19
 */
20
20
 
21
 
#include "config.h"
22
 
#include "drizzled/field/date.h"
23
 
#include "drizzled/error.h"
24
 
#include "drizzled/table.h"
25
 
#include "drizzled/temporal.h"
26
 
#include "drizzled/session.h"
27
 
#include "drizzled/time_functions.h"
28
 
 
29
 
#include <math.h>
30
 
 
31
 
#include <sstream>
32
 
#include <string>
33
 
 
 
21
#ifdef USE_PRAGMA_IMPLEMENTATION
 
22
#pragma implementation                          // gcc: Class implementation
 
23
#endif
 
24
 
 
25
#include <drizzled/field/date.h>
34
26
 
35
27
/****************************************************************************
36
 
** Drizzle date type stored in 3 bytes
 
28
** The new date type
 
29
** This is identical to the old date type, but stored on 3 bytes instead of 4
37
30
** In number context: YYYYMMDD
38
31
****************************************************************************/
39
32
 
41
34
  Store string into a date field
42
35
 
43
36
  SYNOPSIS
44
 
    Field_date::store()
 
37
    Field_newdate::store()
45
38
    from                Date string
46
39
    len                 Length of date field
47
40
    cs                  Character set (not used)
55
48
       nearly-identical class Field_date doesn't ever return 3 from its
56
49
       store function.
57
50
*/
58
 
int Field_date::store(const char *from,
59
 
                         uint32_t len,
60
 
                         const CHARSET_INFO * const )
 
51
 
 
52
int Field_newdate::store(const char *from,
 
53
                         uint len,
 
54
                         CHARSET_INFO *cs __attribute__((unused)))
61
55
{
62
 
#ifdef NOTDEFINED
63
56
  long tmp;
64
 
  DRIZZLE_TIME l_time;
 
57
  MYSQL_TIME l_time;
65
58
  int error;
66
 
  Session *session= table ? table->in_use : current_session;
67
 
  enum enum_drizzle_timestamp_type ret;
 
59
  THD *thd= table ? table->in_use : current_thd;
 
60
  enum enum_mysql_timestamp_type ret;
68
61
  if ((ret= str_to_datetime(from, len, &l_time,
69
62
                            (TIME_FUZZY_DATE |
70
 
                             (session->variables.sql_mode &
71
 
                              (MODE_NO_ZERO_DATE | MODE_INVALID_DATES))),
72
 
                            &error)) <= DRIZZLE_TIMESTAMP_ERROR)
 
63
                             (thd->variables.sql_mode &
 
64
                              (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
 
65
                               MODE_INVALID_DATES))),
 
66
                            &error)) <= MYSQL_TIMESTAMP_ERROR)
73
67
  {
74
68
    tmp= 0;
75
69
    error= 2;
77
71
  else
78
72
  {
79
73
    tmp= l_time.day + l_time.month*32 + l_time.year*16*32;
80
 
    if (!error && (ret != DRIZZLE_TIMESTAMP_DATE) &&
 
74
    if (!error && (ret != MYSQL_TIMESTAMP_DATE) &&
81
75
        (l_time.hour || l_time.minute || l_time.second || l_time.second_part))
82
76
      error= 3;                                 // Datetime was cut (note)
83
77
  }
84
78
 
85
79
  if (error)
86
 
    set_datetime_warning(error == 3 ? DRIZZLE_ERROR::WARN_LEVEL_NOTE :
87
 
                         DRIZZLE_ERROR::WARN_LEVEL_WARN,
88
 
                         ER_WARN_DATA_TRUNCATED,
89
 
                         from, len, DRIZZLE_TIMESTAMP_DATE, 1);
 
80
    set_datetime_warning(error == 3 ? MYSQL_ERROR::WARN_LEVEL_NOTE :
 
81
                         MYSQL_ERROR::WARN_LEVEL_WARN,
 
82
                         WARN_DATA_TRUNCATED,
 
83
                         from, len, MYSQL_TIMESTAMP_DATE, 1);
90
84
 
91
85
  int3store(ptr, tmp);
92
 
#endif /* NOTDEFINED */
93
 
  /* 
94
 
   * Try to create a DateTime from the supplied string.  Throw an error
95
 
   * if unable to create a valid DateTime.  A DateTime is used so that
96
 
   * automatic conversion from the higher-storage DateTime can be used
97
 
   * and matches on datetime format strings can occur.
98
 
   */
99
 
  ASSERT_COLUMN_MARKED_FOR_WRITE;
100
 
  drizzled::DateTime temporal;
101
 
  if (! temporal.from_string(from, (size_t) len))
102
 
  {
103
 
    my_error(ER_INVALID_DATETIME_VALUE, MYF(ME_FATALERROR), from);
104
 
    return 2;
105
 
  }
106
 
  /* Create the stored integer format. @TODO This should go away. Should be up to engine... */
107
 
  uint32_t int_value= (temporal.years() * 16 * 32) + (temporal.months() * 32) + temporal.days();
108
 
  int3store(ptr, int_value);
109
 
  return 0;
110
 
}
111
 
 
112
 
int Field_date::store(double from)
113
 
{
114
 
  ASSERT_COLUMN_MARKED_FOR_WRITE;
115
 
  if (from < 0.0 || from > 99991231235959.0)
116
 
  {
117
 
    /* Convert the double to a string using stringstream */
118
 
    std::stringstream ss;
119
 
    std::string tmp;
120
 
    ss.precision(18); /* 18 places should be fine for error display of double input. */
121
 
    ss << from; ss >> tmp;
122
 
 
123
 
    my_error(ER_INVALID_DATETIME_VALUE, MYF(ME_FATALERROR), tmp.c_str());
124
 
    return 2;
125
 
  }
126
 
  return Field_date::store((int64_t) rint(from), false);
127
 
}
128
 
 
129
 
int Field_date::store(int64_t from, bool)
130
 
{
131
 
  /* 
132
 
   * Try to create a DateTime from the supplied integer.  Throw an error
133
 
   * if unable to create a valid DateTime.  
134
 
   */
135
 
  ASSERT_COLUMN_MARKED_FOR_WRITE;
136
 
  drizzled::DateTime temporal;
137
 
  if (! temporal.from_int64_t(from))
138
 
  {
139
 
    /* Convert the integer to a string using stringstream */
140
 
    std::stringstream ss;
141
 
    std::string tmp;
142
 
    ss << from; ss >> tmp;
143
 
 
144
 
    my_error(ER_INVALID_DATETIME_VALUE, MYF(ME_FATALERROR), tmp.c_str());
145
 
    return 2;
146
 
  }
147
 
 
148
 
  /* Create the stored integer format. @TODO This should go away. Should be up to engine... */
149
 
  uint32_t int_value= (temporal.years() * 16 * 32) + (temporal.months() * 32) + temporal.days();
150
 
  int3store(ptr, int_value);
151
 
  return 0;
152
 
}
153
 
 
154
 
int Field_date::store_time(DRIZZLE_TIME *ltime,
155
 
                              enum enum_drizzle_timestamp_type time_type)
 
86
  return error;
 
87
}
 
88
 
 
89
 
 
90
int Field_newdate::store(double nr)
 
91
{
 
92
  if (nr < 0.0 || nr > 99991231235959.0)
 
93
  {
 
94
    int3store(ptr,(int32_t) 0);
 
95
    set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
 
96
                         WARN_DATA_TRUNCATED, nr, MYSQL_TIMESTAMP_DATE);
 
97
    return 1;
 
98
  }
 
99
  return Field_newdate::store((int64_t) rint(nr), false);
 
100
}
 
101
 
 
102
 
 
103
int Field_newdate::store(int64_t nr,
 
104
                         bool unsigned_val __attribute__((unused)))
 
105
{
 
106
  MYSQL_TIME l_time;
 
107
  int64_t tmp;
 
108
  int error;
 
109
  THD *thd= table ? table->in_use : current_thd;
 
110
  if (number_to_datetime(nr, &l_time,
 
111
                         (TIME_FUZZY_DATE |
 
112
                          (thd->variables.sql_mode &
 
113
                           (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
 
114
                            MODE_INVALID_DATES))),
 
115
                         &error) == -1LL)
 
116
  {
 
117
    tmp= 0L;
 
118
    error= 2;
 
119
  }
 
120
  else
 
121
    tmp= l_time.day + l_time.month*32 + l_time.year*16*32;
 
122
 
 
123
  if (!error && l_time.time_type != MYSQL_TIMESTAMP_DATE &&
 
124
      (l_time.hour || l_time.minute || l_time.second || l_time.second_part))
 
125
    error= 3;
 
126
 
 
127
  if (error)
 
128
    set_datetime_warning(error == 3 ? MYSQL_ERROR::WARN_LEVEL_NOTE :
 
129
                         MYSQL_ERROR::WARN_LEVEL_WARN,
 
130
                         error == 2 ? 
 
131
                         ER_WARN_DATA_OUT_OF_RANGE : WARN_DATA_TRUNCATED,
 
132
                         nr,MYSQL_TIMESTAMP_DATE, 1);
 
133
 
 
134
  int3store(ptr,tmp);
 
135
  return error;
 
136
}
 
137
 
 
138
 
 
139
int Field_newdate::store_time(MYSQL_TIME *ltime,timestamp_type time_type)
156
140
{
157
141
  long tmp;
158
142
  int error= 0;
159
 
  if (time_type == DRIZZLE_TIMESTAMP_DATE ||
160
 
      time_type == DRIZZLE_TIMESTAMP_DATETIME)
 
143
  if (time_type == MYSQL_TIMESTAMP_DATE ||
 
144
      time_type == MYSQL_TIMESTAMP_DATETIME)
161
145
  {
162
146
    tmp=ltime->year*16*32+ltime->month*32+ltime->day;
163
147
    if (check_date(ltime, tmp != 0,
164
148
                   (TIME_FUZZY_DATE |
165
 
                    (current_session->variables.sql_mode &
166
 
                     (MODE_NO_ZERO_DATE | MODE_INVALID_DATES))), &error))
 
149
                    (current_thd->variables.sql_mode &
 
150
                     (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
 
151
                      MODE_INVALID_DATES))), &error))
167
152
    {
168
153
      char buff[MAX_DATE_STRING_REP_LENGTH];
169
 
      String str(buff, sizeof(buff), &my_charset_utf8_general_ci);
170
 
      make_date(ltime, &str);
171
 
      set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED,
172
 
                           str.ptr(), str.length(), DRIZZLE_TIMESTAMP_DATE, 1);
 
154
      String str(buff, sizeof(buff), &my_charset_latin1);
 
155
      make_date((DATE_TIME_FORMAT *) 0, ltime, &str);
 
156
      set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED,
 
157
                           str.ptr(), str.length(), MYSQL_TIMESTAMP_DATE, 1);
173
158
    }
174
 
    if (!error && ltime->time_type != DRIZZLE_TIMESTAMP_DATE &&
 
159
    if (!error && ltime->time_type != MYSQL_TIMESTAMP_DATE &&
175
160
        (ltime->hour || ltime->minute || ltime->second || ltime->second_part))
176
161
    {
177
162
      char buff[MAX_DATE_STRING_REP_LENGTH];
178
 
      String str(buff, sizeof(buff), &my_charset_utf8_general_ci);
179
 
      make_datetime(ltime, &str);
180
 
      set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_NOTE,
181
 
                           ER_WARN_DATA_TRUNCATED,
182
 
                           str.ptr(), str.length(), DRIZZLE_TIMESTAMP_DATE, 1);
 
163
      String str(buff, sizeof(buff), &my_charset_latin1);
 
164
      make_datetime((DATE_TIME_FORMAT *) 0, ltime, &str);
 
165
      set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_NOTE,
 
166
                           WARN_DATA_TRUNCATED,
 
167
                           str.ptr(), str.length(), MYSQL_TIMESTAMP_DATE, 1);
183
168
      error= 3;
184
169
    }
185
170
  }
187
172
  {
188
173
    tmp=0;
189
174
    error= 1;
190
 
    set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
 
175
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
191
176
  }
192
177
  int3store(ptr,tmp);
193
178
  return error;
194
179
}
195
180
 
196
 
double Field_date::val_real(void)
197
 
{
198
 
  return (double) Field_date::val_int();
199
 
}
200
 
 
201
 
int64_t Field_date::val_int(void)
202
 
{
203
 
  uint32_t j;
204
 
 
205
 
  ASSERT_COLUMN_MARKED_FOR_READ;
206
 
 
207
 
  j= uint3korr(ptr);
 
181
 
 
182
bool Field_newdate::send_binary(Protocol *protocol)
 
183
{
 
184
  MYSQL_TIME tm;
 
185
  Field_newdate::get_date(&tm,0);
 
186
  return protocol->store_date(&tm);
 
187
}
 
188
 
 
189
 
 
190
double Field_newdate::val_real(void)
 
191
{
 
192
  return (double) Field_newdate::val_int();
 
193
}
 
194
 
 
195
 
 
196
int64_t Field_newdate::val_int(void)
 
197
{
 
198
  ulong j= uint3korr(ptr);
208
199
  j= (j % 32L)+(j / 32L % 16L)*100L + (j/(16L*32L))*10000L;
209
 
 
210
200
  return (int64_t) j;
211
201
}
212
202
 
213
 
String *Field_date::val_str(String *val_buffer,
214
 
                               String *)
 
203
 
 
204
String *Field_newdate::val_str(String *val_buffer,
 
205
                               String *val_ptr __attribute__((unused)))
215
206
{
216
207
  val_buffer->alloc(field_length);
217
208
  val_buffer->length(field_length);
219
210
  int part;
220
211
  char *pos=(char*) val_buffer->ptr()+10;
221
212
 
222
 
  ASSERT_COLUMN_MARKED_FOR_READ;
223
 
 
224
213
  /* Open coded to get more speed */
225
214
  *pos--=0;                                     // End NULL
226
215
  part=(int) (tmp & 31);
239
228
  return val_buffer;
240
229
}
241
230
 
242
 
bool Field_date::get_date(DRIZZLE_TIME *ltime,uint32_t fuzzydate)
 
231
 
 
232
bool Field_newdate::get_date(MYSQL_TIME *ltime,uint fuzzydate)
243
233
{
244
234
  uint32_t tmp=(uint32_t) uint3korr(ptr);
245
235
  ltime->day=   tmp & 31;
246
236
  ltime->month= (tmp >> 5) & 15;
247
237
  ltime->year=  (tmp >> 9);
248
 
  ltime->time_type= DRIZZLE_TIMESTAMP_DATE;
 
238
  ltime->time_type= MYSQL_TIMESTAMP_DATE;
249
239
  ltime->hour= ltime->minute= ltime->second= ltime->second_part= ltime->neg= 0;
250
240
  return ((!(fuzzydate & TIME_FUZZY_DATE) && (!ltime->month || !ltime->day)) ?
251
241
          1 : 0);
252
242
}
253
243
 
254
 
bool Field_date::get_time(DRIZZLE_TIME *ltime)
 
244
 
 
245
bool Field_newdate::get_time(MYSQL_TIME *ltime)
255
246
{
256
 
  return Field_date::get_date(ltime,0);
 
247
  return Field_newdate::get_date(ltime,0);
257
248
}
258
249
 
259
 
int Field_date::cmp(const unsigned char *a_ptr, const unsigned char *b_ptr)
 
250
 
 
251
int Field_newdate::cmp(const uchar *a_ptr, const uchar *b_ptr)
260
252
{
261
253
  uint32_t a,b;
262
254
  a=(uint32_t) uint3korr(a_ptr);
264
256
  return (a < b) ? -1 : (a > b) ? 1 : 0;
265
257
}
266
258
 
267
 
void Field_date::sort_string(unsigned char *to,uint32_t )
 
259
 
 
260
void Field_newdate::sort_string(uchar *to,uint length __attribute__((unused)))
268
261
{
269
262
  to[0] = ptr[2];
270
263
  to[1] = ptr[1];
271
264
  to[2] = ptr[0];
272
265
}
273
266
 
274
 
void Field_date::sql_type(String &res) const
 
267
 
 
268
void Field_newdate::sql_type(String &res) const
275
269
{
276
270
  res.set_ascii(STRING_WITH_LEN("date"));
277
271
}
 
272