~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to server/field/date.cc

Merge work from Toru

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 MySQL
 
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; either version 2 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  This program is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with this program; if not, write to the Free Software
 
18
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
19
 */
 
20
 
 
21
#ifdef USE_PRAGMA_IMPLEMENTATION
 
22
#pragma implementation                          // gcc: Class implementation
 
23
#endif
 
24
 
 
25
#include "date.h"
 
26
 
 
27
/****************************************************************************
 
28
** The new date type
 
29
** This is identical to the old date type, but stored on 3 bytes instead of 4
 
30
** In number context: YYYYMMDD
 
31
****************************************************************************/
 
32
 
 
33
/*
 
34
  Store string into a date field
 
35
 
 
36
  SYNOPSIS
 
37
    Field_newdate::store()
 
38
    from                Date string
 
39
    len                 Length of date field
 
40
    cs                  Character set (not used)
 
41
 
 
42
  RETURN
 
43
    0  ok
 
44
    1  Value was cut during conversion
 
45
    2  Wrong date string
 
46
    3  Datetime value that was cut (warning level NOTE)
 
47
       This is used by opt_range.cc:get_mm_leaf(). Note that there is a
 
48
       nearly-identical class Field_date doesn't ever return 3 from its
 
49
       store function.
 
50
*/
 
51
 
 
52
int Field_newdate::store(const char *from,
 
53
                         uint len,
 
54
                         CHARSET_INFO *cs __attribute__((__unused__)))
 
55
{
 
56
  long tmp;
 
57
  MYSQL_TIME l_time;
 
58
  int error;
 
59
  THD *thd= table ? table->in_use : current_thd;
 
60
  enum enum_mysql_timestamp_type ret;
 
61
  if ((ret= str_to_datetime(from, len, &l_time,
 
62
                            (TIME_FUZZY_DATE |
 
63
                             (thd->variables.sql_mode &
 
64
                              (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
 
65
                               MODE_INVALID_DATES))),
 
66
                            &error)) <= MYSQL_TIMESTAMP_ERROR)
 
67
  {
 
68
    tmp= 0;
 
69
    error= 2;
 
70
  }
 
71
  else
 
72
  {
 
73
    tmp= l_time.day + l_time.month*32 + l_time.year*16*32;
 
74
    if (!error && (ret != MYSQL_TIMESTAMP_DATE) &&
 
75
        (l_time.hour || l_time.minute || l_time.second || l_time.second_part))
 
76
      error= 3;                                 // Datetime was cut (note)
 
77
  }
 
78
 
 
79
  if (error)
 
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);
 
84
 
 
85
  int3store(ptr, tmp);
 
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) 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)
 
140
{
 
141
  long tmp;
 
142
  int error= 0;
 
143
  if (time_type == MYSQL_TIMESTAMP_DATE ||
 
144
      time_type == MYSQL_TIMESTAMP_DATETIME)
 
145
  {
 
146
    tmp=ltime->year*16*32+ltime->month*32+ltime->day;
 
147
    if (check_date(ltime, tmp != 0,
 
148
                   (TIME_FUZZY_DATE |
 
149
                    (current_thd->variables.sql_mode &
 
150
                     (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
 
151
                      MODE_INVALID_DATES))), &error))
 
152
    {
 
153
      char buff[MAX_DATE_STRING_REP_LENGTH];
 
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);
 
158
    }
 
159
    if (!error && ltime->time_type != MYSQL_TIMESTAMP_DATE &&
 
160
        (ltime->hour || ltime->minute || ltime->second || ltime->second_part))
 
161
    {
 
162
      char buff[MAX_DATE_STRING_REP_LENGTH];
 
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);
 
168
      error= 3;
 
169
    }
 
170
  }
 
171
  else
 
172
  {
 
173
    tmp=0;
 
174
    error= 1;
 
175
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
 
176
  }
 
177
  int3store(ptr,tmp);
 
178
  return error;
 
179
}
 
180
 
 
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);
 
199
  j= (j % 32L)+(j / 32L % 16L)*100L + (j/(16L*32L))*10000L;
 
200
  return (int64_t) j;
 
201
}
 
202
 
 
203
 
 
204
String *Field_newdate::val_str(String *val_buffer,
 
205
                               String *val_ptr __attribute__((unused)))
 
206
{
 
207
  val_buffer->alloc(field_length);
 
208
  val_buffer->length(field_length);
 
209
  uint32 tmp=(uint32) uint3korr(ptr);
 
210
  int part;
 
211
  char *pos=(char*) val_buffer->ptr()+10;
 
212
 
 
213
  /* Open coded to get more speed */
 
214
  *pos--=0;                                     // End NULL
 
215
  part=(int) (tmp & 31);
 
216
  *pos--= (char) ('0'+part%10);
 
217
  *pos--= (char) ('0'+part/10);
 
218
  *pos--= '-';
 
219
  part=(int) (tmp >> 5 & 15);
 
220
  *pos--= (char) ('0'+part%10);
 
221
  *pos--= (char) ('0'+part/10);
 
222
  *pos--= '-';
 
223
  part=(int) (tmp >> 9);
 
224
  *pos--= (char) ('0'+part%10); part/=10;
 
225
  *pos--= (char) ('0'+part%10); part/=10;
 
226
  *pos--= (char) ('0'+part%10); part/=10;
 
227
  *pos=   (char) ('0'+part);
 
228
  return val_buffer;
 
229
}
 
230
 
 
231
 
 
232
bool Field_newdate::get_date(MYSQL_TIME *ltime,uint fuzzydate)
 
233
{
 
234
  uint32 tmp=(uint32) uint3korr(ptr);
 
235
  ltime->day=   tmp & 31;
 
236
  ltime->month= (tmp >> 5) & 15;
 
237
  ltime->year=  (tmp >> 9);
 
238
  ltime->time_type= MYSQL_TIMESTAMP_DATE;
 
239
  ltime->hour= ltime->minute= ltime->second= ltime->second_part= ltime->neg= 0;
 
240
  return ((!(fuzzydate & TIME_FUZZY_DATE) && (!ltime->month || !ltime->day)) ?
 
241
          1 : 0);
 
242
}
 
243
 
 
244
 
 
245
bool Field_newdate::get_time(MYSQL_TIME *ltime)
 
246
{
 
247
  return Field_newdate::get_date(ltime,0);
 
248
}
 
249
 
 
250
 
 
251
int Field_newdate::cmp(const uchar *a_ptr, const uchar *b_ptr)
 
252
{
 
253
  uint32 a,b;
 
254
  a=(uint32) uint3korr(a_ptr);
 
255
  b=(uint32) uint3korr(b_ptr);
 
256
  return (a < b) ? -1 : (a > b) ? 1 : 0;
 
257
}
 
258
 
 
259
 
 
260
void Field_newdate::sort_string(uchar *to,uint length __attribute__((unused)))
 
261
{
 
262
  to[0] = ptr[2];
 
263
  to[1] = ptr[1];
 
264
  to[2] = ptr[0];
 
265
}
 
266
 
 
267
 
 
268
void Field_newdate::sql_type(String &res) const
 
269
{
 
270
  res.set_ascii(STRING_WITH_LEN("date"));
 
271
}
 
272