~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/field/timestamp.cc

  • Committer: Monty Taylor
  • Date: 2009-03-04 02:48:12 UTC
  • mto: (917.1.2 mordred)
  • mto: This revision was merged to the branch mainline in revision 918.
  • Revision ID: mordred@inaugust.com-20090304024812-5wb6wpye5c1iitbq
Applied atomic patch to current tree.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19
19
 */
20
20
 
21
 
#include "config.h"
22
 
#include <boost/lexical_cast.hpp>
 
21
 
 
22
#include <drizzled/server_includes.h>
23
23
#include <drizzled/field/timestamp.h>
24
24
#include <drizzled/error.h>
25
25
#include <drizzled/tztime.h>
26
26
#include <drizzled/table.h>
27
27
#include <drizzled/session.h>
28
 
 
29
 
#include <math.h>
30
 
 
31
 
#include <sstream>
32
 
 
33
 
#include "drizzled/temporal.h"
34
 
 
35
 
namespace drizzled
36
 
{
 
28
#include CMATH_H
 
29
 
 
30
#if defined(CMATH_NAMESPACE)
 
31
using namespace CMATH_NAMESPACE;
 
32
#endif
37
33
 
38
34
/**
39
35
  TIMESTAMP type holds datetime values in range from 1970-01-01 00:00:01 UTC to
78
74
  course is non-standard.) In most cases user won't notice any change, only
79
75
  exception is different behavior of old/new timestamps during ALTER TABLE.
80
76
 */
 
77
 
81
78
Field_timestamp::Field_timestamp(unsigned char *ptr_arg,
82
 
                                 uint32_t,
83
 
                                 unsigned char *null_ptr_arg,
84
 
                                 unsigned char null_bit_arg,
 
79
                                 uint32_t ,
 
80
                                 unsigned char *null_ptr_arg, unsigned char null_bit_arg,
85
81
                                 enum utype unireg_check_arg,
86
82
                                 const char *field_name_arg,
87
 
                                 TableShare *share,
 
83
                                 TABLE_SHARE *share,
88
84
                                 const CHARSET_INFO * const cs)
89
 
  :Field_str(ptr_arg,
90
 
             DateTime::MAX_STRING_LENGTH - 1 /* no \0 */,
91
 
             null_ptr_arg,
92
 
             null_bit_arg,
93
 
             field_name_arg,
94
 
             cs)
 
85
  :Field_str(ptr_arg, MAX_DATETIME_WIDTH, null_ptr_arg, null_bit_arg,
 
86
             unireg_check_arg, field_name_arg, cs)
95
87
{
96
88
  /* For 4.0 MYD and 4.0 InnoDB compatibility */
97
89
  flags|= UNSIGNED_FLAG;
98
 
  unireg_check= unireg_check_arg;
99
 
  if (! share->getTimestampField() && unireg_check != NONE)
 
90
  if (!share->timestamp_field && unireg_check != NONE)
100
91
  {
101
92
    /* This timestamp has auto-update */
102
 
    share->setTimestampField(this);
103
 
    flags|= FUNCTION_DEFAULT_FLAG;
 
93
    share->timestamp_field= this;
 
94
    flags|= TIMESTAMP_FLAG;
104
95
    if (unireg_check != TIMESTAMP_DN_FIELD)
105
96
      flags|= ON_UPDATE_NOW_FLAG;
106
97
  }
107
98
}
108
99
 
 
100
 
109
101
Field_timestamp::Field_timestamp(bool maybe_null_arg,
110
102
                                 const char *field_name_arg,
111
103
                                 const CHARSET_INFO * const cs)
112
 
  :Field_str((unsigned char*) NULL,
113
 
             DateTime::MAX_STRING_LENGTH - 1 /* no \0 */,
114
 
             maybe_null_arg ? (unsigned char*) "": 0,
115
 
             0,
116
 
             field_name_arg,
117
 
             cs)
 
104
  :Field_str((unsigned char*) 0, MAX_DATETIME_WIDTH,
 
105
             maybe_null_arg ? (unsigned char*) "": 0, 0,
 
106
             NONE, field_name_arg, cs)
118
107
{
119
108
  /* For 4.0 MYD and 4.0 InnoDB compatibility */
120
109
  flags|= UNSIGNED_FLAG;
121
 
  if (unireg_check != TIMESTAMP_DN_FIELD)
122
 
    flags|= ON_UPDATE_NOW_FLAG;
 
110
    if (unireg_check != TIMESTAMP_DN_FIELD)
 
111
      flags|= ON_UPDATE_NOW_FLAG;
123
112
}
124
113
 
 
114
 
125
115
/**
126
116
  Get auto-set type for TIMESTAMP field.
127
117
 
142
132
      function should be called only for first of them (i.e. the one
143
133
      having auto-set property).
144
134
    */
145
 
    assert(getTable()->timestamp_field == this);
 
135
    assert(table->timestamp_field == this);
146
136
    /* Fall-through */
147
137
  case TIMESTAMP_DNUN_FIELD:
148
138
    return TIMESTAMP_AUTO_SET_ON_BOTH;
156
146
  }
157
147
}
158
148
 
 
149
 
159
150
int Field_timestamp::store(const char *from,
160
151
                           uint32_t len,
161
152
                           const CHARSET_INFO * const )
162
153
{
163
 
  Timestamp temporal;
164
 
 
165
 
  ASSERT_COLUMN_MARKED_FOR_WRITE;
166
 
 
167
 
  if (! temporal.from_string(from, (size_t) len))
168
 
  {
169
 
    my_error(ER_INVALID_UNIX_TIMESTAMP_VALUE, MYF(ME_FATALERROR), from);
170
 
    return 1;
171
 
  }
172
 
 
173
 
  time_t tmp;
174
 
  temporal.to_time_t(&tmp);
175
 
 
176
 
  store_timestamp(tmp);
177
 
  return 0;
178
 
}
179
 
 
180
 
int Field_timestamp::store(double from)
181
 
{
182
 
  ASSERT_COLUMN_MARKED_FOR_WRITE;
183
 
 
184
 
  if (from < 0 || from > 99991231235959.0)
185
 
  {
186
 
    /* Convert the double to a string using stringstream */
187
 
    std::stringstream ss;
188
 
    std::string tmp;
189
 
    ss.precision(18); /* 18 places should be fine for error display of double input. */
190
 
    ss << from; 
191
 
    ss >> tmp;
192
 
 
193
 
    my_error(ER_INVALID_UNIX_TIMESTAMP_VALUE, MYF(ME_FATALERROR), tmp.c_str());
194
 
    return 2;
195
 
  }
196
 
  return Field_timestamp::store((int64_t) rint(from), false);
197
 
}
198
 
 
199
 
int Field_timestamp::store(int64_t from, bool)
200
 
{
201
 
  ASSERT_COLUMN_MARKED_FOR_WRITE;
202
 
 
203
 
  /* 
204
 
   * Try to create a DateTime from the supplied integer.  Throw an error
205
 
   * if unable to create a valid DateTime.  
206
 
   */
207
 
  Timestamp temporal;
208
 
  if (! temporal.from_int64_t(from))
209
 
  {
210
 
    /* Convert the integer to a string using boost::lexical_cast */
211
 
    std::string tmp(boost::lexical_cast<std::string>(from));
212
 
 
213
 
    my_error(ER_INVALID_UNIX_TIMESTAMP_VALUE, MYF(ME_FATALERROR), tmp.c_str());
214
 
    return 2;
215
 
  }
216
 
 
217
 
  time_t tmp;
218
 
  temporal.to_time_t(&tmp);
219
 
 
220
 
  store_timestamp(tmp);
221
 
  return 0;
 
154
  DRIZZLE_TIME l_time;
 
155
  time_t tmp= 0;
 
156
  int error;
 
157
  bool have_smth_to_conv;
 
158
  bool in_dst_time_gap;
 
159
  Session *session= table ? table->in_use : current_session;
 
160
 
 
161
  /* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */
 
162
  have_smth_to_conv= (str_to_datetime(from, len, &l_time, 1, &error) >
 
163
                      DRIZZLE_TIMESTAMP_ERROR);
 
164
 
 
165
  if (error || !have_smth_to_conv)
 
166
  {
 
167
    error= 1;
 
168
    set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED,
 
169
                         from, len, DRIZZLE_TIMESTAMP_DATETIME, 1);
 
170
  }
 
171
 
 
172
  /* Only convert a correct date (not a zero date) */
 
173
  if (have_smth_to_conv && l_time.month)
 
174
  {
 
175
    if (!(tmp= TIME_to_timestamp(session, &l_time, &in_dst_time_gap)))
 
176
    {
 
177
      set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
178
                           ER_WARN_DATA_OUT_OF_RANGE,
 
179
                           from, len, DRIZZLE_TIMESTAMP_DATETIME, !error);
 
180
      error= 1;
 
181
    }
 
182
    else if (in_dst_time_gap)
 
183
    {
 
184
      set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
185
                           ER_WARN_INVALID_TIMESTAMP,
 
186
                           from, len, DRIZZLE_TIMESTAMP_DATETIME, !error);
 
187
      error= 1;
 
188
    }
 
189
  }
 
190
  store_timestamp(tmp);
 
191
  return error;
 
192
}
 
193
 
 
194
 
 
195
int Field_timestamp::store(double nr)
 
196
{
 
197
  int error= 0;
 
198
  if (nr < 0 || nr > 99991231235959.0)
 
199
  {
 
200
    set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
201
                         ER_WARN_DATA_OUT_OF_RANGE,
 
202
                         nr, DRIZZLE_TIMESTAMP_DATETIME);
 
203
    nr= 0;                                      // Avoid overflow on buff
 
204
    error= 1;
 
205
  }
 
206
  error|= Field_timestamp::store((int64_t) rint(nr), false);
 
207
  return error;
 
208
}
 
209
 
 
210
 
 
211
int Field_timestamp::store(int64_t nr,
 
212
                           bool )
 
213
{
 
214
  DRIZZLE_TIME l_time;
 
215
  time_t timestamp= 0;
 
216
  int error;
 
217
  bool in_dst_time_gap;
 
218
  Session *session= table ? table->in_use : current_session;
 
219
 
 
220
  /* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */
 
221
  int64_t tmp= number_to_datetime(nr, &l_time, (session->variables.sql_mode &
 
222
                                                 MODE_NO_ZERO_DATE), &error);
 
223
  if (tmp == INT64_C(-1))
 
224
  {
 
225
    error= 2;
 
226
  }
 
227
 
 
228
  if (!error && tmp)
 
229
  {
 
230
    if (!(timestamp= TIME_to_timestamp(session, &l_time, &in_dst_time_gap)))
 
231
    {
 
232
      set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
233
                           ER_WARN_DATA_OUT_OF_RANGE,
 
234
                           nr, DRIZZLE_TIMESTAMP_DATETIME, 1);
 
235
      error= 1;
 
236
    }
 
237
    if (in_dst_time_gap)
 
238
    {
 
239
      set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
240
                           ER_WARN_INVALID_TIMESTAMP,
 
241
                           nr, DRIZZLE_TIMESTAMP_DATETIME, 1);
 
242
      error= 1;
 
243
    }
 
244
  } else if (error)
 
245
    set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
246
                         ER_WARN_DATA_TRUNCATED,
 
247
                         nr, DRIZZLE_TIMESTAMP_DATETIME, 1);
 
248
 
 
249
  store_timestamp(timestamp);
 
250
  return error;
222
251
}
223
252
 
224
253
double Field_timestamp::val_real(void)
228
257
 
229
258
int64_t Field_timestamp::val_int(void)
230
259
{
231
 
  uint64_t temp;
232
 
 
233
 
  ASSERT_COLUMN_MARKED_FOR_READ;
 
260
  uint32_t temp;
 
261
  DRIZZLE_TIME time_tmp;
 
262
  Session  *session= table ? table->in_use : current_session;
234
263
 
235
264
#ifdef WORDS_BIGENDIAN
236
 
  if (getTable() && getTable()->getShare()->db_low_byte_first)
237
 
    temp= uint8korr(ptr);
 
265
  if (table && table->s->db_low_byte_first)
 
266
    temp=uint4korr(ptr);
238
267
  else
239
268
#endif
240
 
    int64_tget(temp, ptr);
241
 
 
242
 
  Timestamp temporal;
243
 
  (void) temporal.from_time_t((time_t) temp);
244
 
 
245
 
  /* We must convert into a "timestamp-formatted integer" ... */
246
 
  int64_t result;
247
 
  temporal.to_int64_t(&result);
248
 
  return result;
 
269
    longget(temp,ptr);
 
270
 
 
271
  if (temp == 0L)                               // No time
 
272
    return(0);                                  /* purecov: inspected */
 
273
 
 
274
  session->variables.time_zone->gmt_sec_to_TIME(&time_tmp, (time_t)temp);
 
275
 
 
276
  return time_tmp.year * INT64_C(10000000000) +
 
277
         time_tmp.month * INT64_C(100000000) +
 
278
         time_tmp.day * 1000000 + time_tmp.hour * 10000 +
 
279
         time_tmp.minute * 100 + time_tmp.second;
249
280
}
250
281
 
251
 
String *Field_timestamp::val_str(String *val_buffer, String *)
 
282
 
 
283
String *Field_timestamp::val_str(String *val_buffer, String *val_ptr)
252
284
{
253
 
  uint64_t temp;
 
285
  uint32_t temp, temp2;
 
286
  DRIZZLE_TIME time_tmp;
 
287
  Session *session= table ? table->in_use : current_session;
254
288
  char *to;
255
 
  int to_len= field_length + 1;
256
289
 
257
 
  val_buffer->alloc(to_len);
258
 
  to= (char *) val_buffer->ptr();
 
290
  val_buffer->alloc(field_length+1);
 
291
  to= (char*) val_buffer->ptr();
 
292
  val_buffer->length(field_length);
259
293
 
260
294
#ifdef WORDS_BIGENDIAN
261
 
  if (getTable() && getTable()->getShare()->db_low_byte_first)
262
 
    temp= uint8korr(ptr);
 
295
  if (table && table->s->db_low_byte_first)
 
296
    temp=uint4korr(ptr);
263
297
  else
264
298
#endif
265
 
    int64_tget(temp, ptr);
266
 
 
267
 
  val_buffer->set_charset(&my_charset_bin);     /* Safety */
268
 
 
269
 
  Timestamp temporal;
270
 
  (void) temporal.from_time_t((time_t) temp);
271
 
 
272
 
  int rlen;
273
 
  rlen= temporal.to_string(to, to_len);
274
 
  assert(rlen < to_len);
275
 
 
276
 
  val_buffer->length(rlen);
 
299
    longget(temp,ptr);
 
300
 
 
301
  if (temp == 0L)
 
302
  {                                   /* Zero time is "000000" */
 
303
    val_ptr->set(STRING_WITH_LEN("0000-00-00 00:00:00"), &my_charset_bin);
 
304
    return val_ptr;
 
305
  }
 
306
  val_buffer->set_charset(&my_charset_bin);     // Safety
 
307
 
 
308
  session->variables.time_zone->gmt_sec_to_TIME(&time_tmp,(time_t)temp);
 
309
 
 
310
  temp= time_tmp.year % 100;
 
311
  if (temp < YY_PART_YEAR - 1)
 
312
  {
 
313
    *to++= '2';
 
314
    *to++= '0';
 
315
  }
 
316
  else
 
317
  {
 
318
    *to++= '1';
 
319
    *to++= '9';
 
320
  }
 
321
  temp2=temp/10; temp=temp-temp2*10;
 
322
  *to++= (char) ('0'+(char) (temp2));
 
323
  *to++= (char) ('0'+(char) (temp));
 
324
  *to++= '-';
 
325
  temp=time_tmp.month;
 
326
  temp2=temp/10; temp=temp-temp2*10;
 
327
  *to++= (char) ('0'+(char) (temp2));
 
328
  *to++= (char) ('0'+(char) (temp));
 
329
  *to++= '-';
 
330
  temp=time_tmp.day;
 
331
  temp2=temp/10; temp=temp-temp2*10;
 
332
  *to++= (char) ('0'+(char) (temp2));
 
333
  *to++= (char) ('0'+(char) (temp));
 
334
  *to++= ' ';
 
335
  temp=time_tmp.hour;
 
336
  temp2=temp/10; temp=temp-temp2*10;
 
337
  *to++= (char) ('0'+(char) (temp2));
 
338
  *to++= (char) ('0'+(char) (temp));
 
339
  *to++= ':';
 
340
  temp=time_tmp.minute;
 
341
  temp2=temp/10; temp=temp-temp2*10;
 
342
  *to++= (char) ('0'+(char) (temp2));
 
343
  *to++= (char) ('0'+(char) (temp));
 
344
  *to++= ':';
 
345
  temp=time_tmp.second;
 
346
  temp2=temp/10; temp=temp-temp2*10;
 
347
  *to++= (char) ('0'+(char) (temp2));
 
348
  *to++= (char) ('0'+(char) (temp));
 
349
  *to= 0;
277
350
  return val_buffer;
278
351
}
279
352
 
280
 
bool Field_timestamp::get_date(DRIZZLE_TIME *ltime, uint32_t)
 
353
 
 
354
bool Field_timestamp::get_date(DRIZZLE_TIME *ltime, uint32_t fuzzydate)
281
355
{
282
 
  uint64_t temp;
283
 
 
 
356
  long temp;
 
357
  Session *session= table ? table->in_use : current_session;
284
358
#ifdef WORDS_BIGENDIAN
285
 
  if (getTable() && getTable()->getShare()->db_low_byte_first)
286
 
    temp= uint8korr(ptr);
 
359
  if (table && table->s->db_low_byte_first)
 
360
    temp=uint4korr(ptr);
287
361
  else
288
362
#endif
289
 
    int64_tget(temp, ptr);
290
 
  
291
 
  memset(ltime, 0, sizeof(*ltime));
292
 
 
293
 
  Timestamp temporal;
294
 
  (void) temporal.from_time_t((time_t) temp);
295
 
 
296
 
  /* @TODO Goodbye the below code when DRIZZLE_TIME is finally gone.. */
297
 
 
298
 
  ltime->time_type= DRIZZLE_TIMESTAMP_DATETIME;
299
 
  ltime->year= temporal.years();
300
 
  ltime->month= temporal.months();
301
 
  ltime->day= temporal.days();
302
 
  ltime->hour= temporal.hours();
303
 
  ltime->minute= temporal.minutes();
304
 
  ltime->second= temporal.seconds();
305
 
 
 
363
    longget(temp,ptr);
 
364
  if (temp == 0L)
 
365
  {                                   /* Zero time is "000000" */
 
366
    if (fuzzydate & TIME_NO_ZERO_DATE)
 
367
      return 1;
 
368
    memset(ltime, 0, sizeof(*ltime));
 
369
  }
 
370
  else
 
371
  {
 
372
    session->variables.time_zone->gmt_sec_to_TIME(ltime, (time_t)temp);
 
373
  }
306
374
  return 0;
307
375
}
308
376
 
313
381
 
314
382
int Field_timestamp::cmp(const unsigned char *a_ptr, const unsigned char *b_ptr)
315
383
{
316
 
  int64_t a,b;
 
384
  int32_t a,b;
317
385
#ifdef WORDS_BIGENDIAN
318
 
  if (getTable() && getTable()->getShare()->db_low_byte_first)
 
386
  if (table && table->s->db_low_byte_first)
319
387
  {
320
 
    a=sint8korr(a_ptr);
321
 
    b=sint8korr(b_ptr);
 
388
    a=sint4korr(a_ptr);
 
389
    b=sint4korr(b_ptr);
322
390
  }
323
391
  else
324
392
#endif
325
393
  {
326
 
    int64_tget(a, a_ptr);
327
 
    int64_tget(b, b_ptr);
 
394
  longget(a,a_ptr);
 
395
  longget(b,b_ptr);
328
396
  }
329
 
  return ((uint64_t) a < (uint64_t) b) ? -1 : ((uint64_t) a > (uint64_t) b) ? 1 : 0;
 
397
  return ((uint32_t) a < (uint32_t) b) ? -1 : ((uint32_t) a > (uint32_t) b) ? 1 : 0;
330
398
}
331
399
 
332
400
 
333
401
void Field_timestamp::sort_string(unsigned char *to,uint32_t )
334
402
{
335
403
#ifdef WORDS_BIGENDIAN
336
 
  if (!getTable() || !getTable()->getShare()->db_low_byte_first)
 
404
  if (!table || !table->s->db_low_byte_first)
337
405
  {
338
406
    to[0] = ptr[0];
339
407
    to[1] = ptr[1];
340
408
    to[2] = ptr[2];
341
409
    to[3] = ptr[3];
342
 
    to[4] = ptr[4];
343
 
    to[5] = ptr[5];
344
 
    to[6] = ptr[6];
345
 
    to[7] = ptr[7];
346
410
  }
347
411
  else
348
412
#endif
349
413
  {
350
 
    to[0] = ptr[7];
351
 
    to[1] = ptr[6];
352
 
    to[2] = ptr[5];
353
 
    to[3] = ptr[4];
354
 
    to[4] = ptr[3];
355
 
    to[5] = ptr[2];
356
 
    to[6] = ptr[1];
357
 
    to[7] = ptr[0];
 
414
    to[0] = ptr[3];
 
415
    to[1] = ptr[2];
 
416
    to[2] = ptr[1];
 
417
    to[3] = ptr[0];
358
418
  }
359
419
}
360
420
 
 
421
 
361
422
void Field_timestamp::sql_type(String &res) const
362
423
{
363
424
  res.set_ascii(STRING_WITH_LEN("timestamp"));
364
425
}
365
426
 
 
427
 
366
428
void Field_timestamp::set_time()
367
429
{
368
 
  Session *session= getTable() ? getTable()->in_use : current_session;
369
 
  time_t tmp= session->query_start();
 
430
  Session *session= table ? table->in_use : current_session;
 
431
  long tmp= (long) session->query_start();
370
432
  set_notnull();
371
433
  store_timestamp(tmp);
372
434
}
373
435
 
 
436
 
374
437
void Field_timestamp::set_default()
375
438
{
376
 
  if (getTable()->timestamp_field == this &&
 
439
  if (table->timestamp_field == this &&
377
440
      unireg_check != TIMESTAMP_UN_FIELD)
378
441
    set_time();
379
442
  else
385
448
  if ((*null_value= is_null()))
386
449
    return 0;
387
450
#ifdef WORDS_BIGENDIAN
388
 
  if (getTable() && getTable()->getShare()->db_low_byte_first)
389
 
    return sint8korr(ptr);
 
451
  if (table && table->s->db_low_byte_first)
 
452
    return sint4korr(ptr);
390
453
#endif
391
 
  int64_t tmp;
392
 
  int64_tget(tmp, ptr);
 
454
  long tmp;
 
455
  longget(tmp,ptr);
393
456
  return tmp;
394
457
}
395
458
 
396
 
void Field_timestamp::store_timestamp(int64_t timestamp)
 
459
 
 
460
void Field_timestamp::store_timestamp(time_t timestamp)
397
461
{
398
462
#ifdef WORDS_BIGENDIAN
399
 
  if (getTable() && getTable()->getShare()->db_low_byte_first)
 
463
  if (table && table->s->db_low_byte_first)
400
464
  {
401
 
    int8store(ptr, timestamp);
 
465
    int4store(ptr,timestamp);
402
466
  }
403
467
  else
404
468
#endif
405
 
    int64_tstore(ptr, timestamp);
 
469
    longstore(ptr,(uint32_t) timestamp);
406
470
}
407
471
 
408
 
} /* namespace drizzled */