~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/field/timestamp.cc

  • Committer: Monty Taylor
  • Date: 2009-05-09 22:13:47 UTC
  • mto: This revision was merged to the branch mainline in revision 1009.
  • Revision ID: mordred@inaugust.com-20090509221347-l712szviusbobro0
Re-added bitset<> as a replacement for Bitmap<>

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
 
 *  Copyright (C) 2008 MySQL
 
4
 *  Copyright (C) 2008 Sun Microsystems
5
5
 *
6
6
 *  This program is free software; you can redistribute it and/or modify
7
7
 *  it under the terms of the GNU General Public License as published by
18
18
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19
19
 */
20
20
 
21
 
#ifdef USE_PRAGMA_IMPLEMENTATION
22
 
#pragma implementation                          // gcc: Class implementation
23
 
#endif
24
21
 
25
22
#include <drizzled/server_includes.h>
26
23
#include <drizzled/field/timestamp.h>
 
24
#include <drizzled/error.h>
 
25
#include <drizzled/tztime.h>
 
26
#include <drizzled/table.h>
 
27
#include <drizzled/session.h>
 
28
 
 
29
#include "drizzled/temporal.h"
 
30
 
27
31
 
28
32
/**
29
 
  TIMESTAMP type holds datetime values in range from 1970-01-01 00:00:01 UTC to 
30
 
  2038-01-01 00:00:00 UTC stored as number of seconds since Unix 
 
33
  TIMESTAMP type holds datetime values in range from 1970-01-01 00:00:01 UTC to
 
34
  2038-01-01 00:00:00 UTC stored as number of seconds since Unix
31
35
  Epoch in UTC.
32
 
  
33
 
  Up to one of timestamps columns in the table can be automatically 
 
36
 
 
37
  Up to one of timestamps columns in the table can be automatically
34
38
  set on row update and/or have NOW() as default value.
35
 
  TABLE::timestamp_field points to Field object for such timestamp with 
 
39
  TABLE::timestamp_field points to Field object for such timestamp with
36
40
  auto-set-on-update. TABLE::time_stamp holds offset in record + 1 for this
37
41
  field, and is used by handler code which performs updates required.
38
 
  
 
42
 
39
43
  Actually SQL-99 says that we should allow niladic functions (like NOW())
40
 
  as defaults for any field. Current limitations (only NOW() and only 
41
 
  for one TIMESTAMP field) are because of restricted binary .frm format 
 
44
  as defaults for any field. Current limitations (only NOW() and only
 
45
  for one TIMESTAMP field) are because of restricted binary .frm format
42
46
  and should go away in the future.
43
 
  
 
47
 
44
48
  Also because of this limitation of binary .frm format we use 5 different
45
49
  unireg_check values with TIMESTAMP field to distinguish various cases of
46
50
  DEFAULT or ON UPDATE values. These values are:
47
 
  
 
51
 
48
52
  TIMESTAMP_OLD_FIELD - old timestamp, if there was not any fields with
49
 
    auto-set-on-update (or now() as default) in this table before, then this 
50
 
    field has NOW() as default and is updated when row changes, else it is 
 
53
    auto-set-on-update (or now() as default) in this table before, then this
 
54
    field has NOW() as default and is updated when row changes, else it is
51
55
    field which has 0 as default value and is not automatically updated.
52
56
  TIMESTAMP_DN_FIELD - field with NOW() as default but not set on update
53
57
    automatically (TIMESTAMP DEFAULT NOW())
54
 
  TIMESTAMP_UN_FIELD - field which is set on update automatically but has not 
55
 
    NOW() as default (but it may has 0 or some other const timestamp as 
 
58
  TIMESTAMP_UN_FIELD - field which is set on update automatically but has not
 
59
    NOW() as default (but it may has 0 or some other const timestamp as
56
60
    default) (TIMESTAMP ON UPDATE NOW()).
57
 
  TIMESTAMP_DNUN_FIELD - field which has now() as default and is auto-set on 
 
61
  TIMESTAMP_DNUN_FIELD - field which has now() as default and is auto-set on
58
62
    update. (TIMESTAMP DEFAULT NOW() ON UPDATE NOW())
59
 
  NONE - field which is not auto-set on update with some other than NOW() 
 
63
  NONE - field which is not auto-set on update with some other than NOW()
60
64
    default value (TIMESTAMP DEFAULT 0).
61
65
 
62
 
  Note that TIMESTAMP_OLD_FIELDs are never created explicitly now, they are 
63
 
  left only for preserving ability to read old tables. Such fields replaced 
64
 
  with their newer analogs in CREATE TABLE and in SHOW CREATE TABLE. This is 
65
 
  because we want to prefer NONE unireg_check before TIMESTAMP_OLD_FIELD for 
66
 
  "TIMESTAMP DEFAULT 'Const'" field. (Old timestamps allowed such 
67
 
  specification too but ignored default value for first timestamp, which of 
 
66
  Note that TIMESTAMP_OLD_FIELDs are never created explicitly now, they are
 
67
  left only for preserving ability to read old tables. Such fields replaced
 
68
  with their newer analogs in CREATE TABLE and in SHOW CREATE TABLE. This is
 
69
  because we want to prefer NONE unireg_check before TIMESTAMP_OLD_FIELD for
 
70
  "TIMESTAMP DEFAULT 'Const'" field. (Old timestamps allowed such
 
71
  specification too but ignored default value for first timestamp, which of
68
72
  course is non-standard.) In most cases user won't notice any change, only
69
73
  exception is different behavior of old/new timestamps during ALTER TABLE.
70
74
 */
71
 
 
72
75
Field_timestamp::Field_timestamp(unsigned char *ptr_arg,
73
 
                                 uint32_t len_arg __attribute__((unused)),
 
76
                                 uint32_t ,
74
77
                                 unsigned char *null_ptr_arg, unsigned char null_bit_arg,
75
78
                                 enum utype unireg_check_arg,
76
79
                                 const char *field_name_arg,
77
 
                                 TABLE_SHARE *share,
 
80
                                 TableShare *share,
78
81
                                 const CHARSET_INFO * const cs)
79
82
  :Field_str(ptr_arg, MAX_DATETIME_WIDTH, null_ptr_arg, null_bit_arg,
80
83
             unireg_check_arg, field_name_arg, cs)
91
94
  }
92
95
}
93
96
 
94
 
 
95
97
Field_timestamp::Field_timestamp(bool maybe_null_arg,
96
98
                                 const char *field_name_arg,
97
99
                                 const CHARSET_INFO * const cs)
105
107
      flags|= ON_UPDATE_NOW_FLAG;
106
108
}
107
109
 
108
 
 
109
110
/**
110
111
  Get auto-set type for TIMESTAMP field.
111
112
 
140
141
  }
141
142
}
142
143
 
143
 
 
144
144
int Field_timestamp::store(const char *from,
145
145
                           uint32_t len,
146
 
                           const CHARSET_INFO * const cs __attribute__((unused)))
147
 
{
148
 
  DRIZZLE_TIME l_time;
149
 
  my_time_t tmp= 0;
150
 
  int error;
151
 
  bool have_smth_to_conv;
152
 
  bool in_dst_time_gap;
153
 
  THD *thd= table ? table->in_use : current_thd;
154
 
 
155
 
  /* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */
156
 
  have_smth_to_conv= (str_to_datetime(from, len, &l_time, 1, &error) >
157
 
                      DRIZZLE_TIMESTAMP_ERROR);
158
 
 
159
 
  if (error || !have_smth_to_conv)
160
 
  {
161
 
    error= 1;
162
 
    set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED,
163
 
                         from, len, DRIZZLE_TIMESTAMP_DATETIME, 1);
164
 
  }
165
 
 
166
 
  /* Only convert a correct date (not a zero date) */
167
 
  if (have_smth_to_conv && l_time.month)
168
 
  {
169
 
    if (!(tmp= TIME_to_timestamp(thd, &l_time, &in_dst_time_gap)))
170
 
    {
171
 
      set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
172
 
                           ER_WARN_DATA_OUT_OF_RANGE,
173
 
                           from, len, DRIZZLE_TIMESTAMP_DATETIME, !error);
174
 
      error= 1;
175
 
    }
176
 
    else if (in_dst_time_gap)
177
 
    {
178
 
      set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
179
 
                           ER_WARN_INVALID_TIMESTAMP,
180
 
                           from, len, DRIZZLE_TIMESTAMP_DATETIME, !error);
181
 
      error= 1;
182
 
    }
183
 
  }
184
 
  store_timestamp(tmp);
185
 
  return error;
186
 
}
187
 
 
188
 
 
189
 
int Field_timestamp::store(double nr)
190
 
{
191
 
  int error= 0;
192
 
  if (nr < 0 || nr > 99991231235959.0)
193
 
  {
194
 
    set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
195
 
                         ER_WARN_DATA_OUT_OF_RANGE,
196
 
                         nr, DRIZZLE_TIMESTAMP_DATETIME);
197
 
    nr= 0;                                      // Avoid overflow on buff
198
 
    error= 1;
199
 
  }
200
 
  error|= Field_timestamp::store((int64_t) rint(nr), false);
201
 
  return error;
202
 
}
203
 
 
204
 
 
205
 
int Field_timestamp::store(int64_t nr,
206
 
                           bool unsigned_val __attribute__((unused)))
207
 
{
208
 
  DRIZZLE_TIME l_time;
209
 
  my_time_t timestamp= 0;
210
 
  int error;
211
 
  bool in_dst_time_gap;
212
 
  THD *thd= table ? table->in_use : current_thd;
213
 
 
214
 
  /* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */
215
 
  int64_t tmp= number_to_datetime(nr, &l_time, (thd->variables.sql_mode &
216
 
                                                 MODE_NO_ZERO_DATE), &error);
217
 
  if (tmp == INT64_C(-1))
218
 
  {
219
 
    error= 2;
220
 
  }
221
 
 
222
 
  if (!error && tmp)
223
 
  {
224
 
    if (!(timestamp= TIME_to_timestamp(thd, &l_time, &in_dst_time_gap)))
225
 
    {
226
 
      set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
227
 
                           ER_WARN_DATA_OUT_OF_RANGE,
228
 
                           nr, DRIZZLE_TIMESTAMP_DATETIME, 1);
229
 
      error= 1;
230
 
    }
231
 
    if (in_dst_time_gap)
232
 
    {
233
 
      set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
234
 
                           ER_WARN_INVALID_TIMESTAMP,
235
 
                           nr, DRIZZLE_TIMESTAMP_DATETIME, 1);
236
 
      error= 1;
237
 
    }
238
 
  } else if (error)
239
 
    set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
240
 
                         ER_WARN_DATA_TRUNCATED,
241
 
                         nr, DRIZZLE_TIMESTAMP_DATETIME, 1);
242
 
 
243
 
  store_timestamp(timestamp);
244
 
  return error;
 
146
                           const CHARSET_INFO * const )
 
147
{
 
148
  drizzled::Timestamp temporal;
 
149
 
 
150
  if (! temporal.from_string(from, (size_t) len))
 
151
  {
 
152
    my_error(ER_INVALID_UNIX_TIMESTAMP_VALUE, MYF(ME_FATALERROR), from);
 
153
    return 1;
 
154
  }
 
155
 
 
156
  time_t tmp;
 
157
  temporal.to_time_t(&tmp);
 
158
 
 
159
  store_timestamp(tmp);
 
160
  return 0;
 
161
}
 
162
 
 
163
int Field_timestamp::store(double from)
 
164
{
 
165
  if (from < 0 || from > 99991231235959.0)
 
166
  {
 
167
    /* Convert the double to a string using stringstream */
 
168
    std::stringstream ss;
 
169
    std::string tmp;
 
170
    ss.precision(18); /* 18 places should be fine for error display of double input. */
 
171
    ss << from; ss >> tmp;
 
172
 
 
173
    my_error(ER_INVALID_UNIX_TIMESTAMP_VALUE, MYF(ME_FATALERROR), tmp.c_str());
 
174
    return 2;
 
175
  }
 
176
  return Field_timestamp::store((int64_t) rint(from), false);
 
177
}
 
178
 
 
179
int Field_timestamp::store(int64_t from, bool)
 
180
{
 
181
  /* 
 
182
   * Try to create a DateTime from the supplied integer.  Throw an error
 
183
   * if unable to create a valid DateTime.  
 
184
   */
 
185
  drizzled::Timestamp temporal;
 
186
  if (! temporal.from_int64_t(from))
 
187
  {
 
188
    /* Convert the integer to a string using stringstream */
 
189
    std::stringstream ss;
 
190
    std::string tmp;
 
191
    ss << from; ss >> tmp;
 
192
 
 
193
    my_error(ER_INVALID_UNIX_TIMESTAMP_VALUE, MYF(ME_FATALERROR), tmp.c_str());
 
194
    return 2;
 
195
  }
 
196
 
 
197
  time_t tmp;
 
198
  temporal.to_time_t(&tmp);
 
199
 
 
200
  store_timestamp(tmp);
 
201
  return 0;
245
202
}
246
203
 
247
204
double Field_timestamp::val_real(void)
252
209
int64_t Field_timestamp::val_int(void)
253
210
{
254
211
  uint32_t temp;
255
 
  DRIZZLE_TIME time_tmp;
256
 
  THD  *thd= table ? table->in_use : current_thd;
257
212
 
258
 
  thd->time_zone_used= 1;
259
213
#ifdef WORDS_BIGENDIAN
260
214
  if (table && table->s->db_low_byte_first)
261
 
    temp=uint4korr(ptr);
 
215
    temp= uint4korr(ptr);
262
216
  else
263
217
#endif
264
 
    longget(temp,ptr);
265
 
 
266
 
  if (temp == 0L)                               // No time
267
 
    return(0);                                  /* purecov: inspected */
268
 
  
269
 
  thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp, (my_time_t)temp);
270
 
  
271
 
  return time_tmp.year * INT64_C(10000000000) +
272
 
         time_tmp.month * INT64_C(100000000) +
273
 
         time_tmp.day * 1000000 + time_tmp.hour * 10000 +
274
 
         time_tmp.minute * 100 + time_tmp.second;
 
218
    longget(temp, ptr);
 
219
 
 
220
  drizzled::Timestamp temporal;
 
221
  (void) temporal.from_time_t((time_t) temp);
 
222
 
 
223
  /* We must convert into a "timestamp-formatted integer" ... */
 
224
  int64_t result;
 
225
  temporal.to_int64_t(&result);
 
226
  return result;
275
227
}
276
228
 
277
 
 
278
 
String *Field_timestamp::val_str(String *val_buffer, String *val_ptr)
 
229
String *Field_timestamp::val_str(String *val_buffer, String *)
279
230
{
280
 
  uint32_t temp, temp2;
281
 
  DRIZZLE_TIME time_tmp;
282
 
  THD *thd= table ? table->in_use : current_thd;
 
231
  uint32_t temp;
283
232
  char *to;
284
233
 
285
 
  val_buffer->alloc(field_length+1);
286
 
  to= (char*) val_buffer->ptr();
287
 
  val_buffer->length(field_length);
 
234
  val_buffer->alloc(field_length + 1);
 
235
  to= (char *) val_buffer->ptr();
288
236
 
289
 
  thd->time_zone_used= 1;
290
237
#ifdef WORDS_BIGENDIAN
291
238
  if (table && table->s->db_low_byte_first)
292
 
    temp=uint4korr(ptr);
 
239
    temp= uint4korr(ptr);
293
240
  else
294
241
#endif
295
 
    longget(temp,ptr);
296
 
 
297
 
  if (temp == 0L)
298
 
  {                                   /* Zero time is "000000" */
299
 
    val_ptr->set(STRING_WITH_LEN("0000-00-00 00:00:00"), &my_charset_bin);
300
 
    return val_ptr;
301
 
  }
302
 
  val_buffer->set_charset(&my_charset_bin);     // Safety
303
 
  
304
 
  thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp,(my_time_t)temp);
305
 
 
306
 
  temp= time_tmp.year % 100;
307
 
  if (temp < YY_PART_YEAR - 1)
308
 
  {
309
 
    *to++= '2';
310
 
    *to++= '0';
311
 
  }
312
 
  else
313
 
  {
314
 
    *to++= '1';
315
 
    *to++= '9';
316
 
  }
317
 
  temp2=temp/10; temp=temp-temp2*10;
318
 
  *to++= (char) ('0'+(char) (temp2));
319
 
  *to++= (char) ('0'+(char) (temp));
320
 
  *to++= '-';
321
 
  temp=time_tmp.month;
322
 
  temp2=temp/10; temp=temp-temp2*10;
323
 
  *to++= (char) ('0'+(char) (temp2));
324
 
  *to++= (char) ('0'+(char) (temp));
325
 
  *to++= '-';
326
 
  temp=time_tmp.day;
327
 
  temp2=temp/10; temp=temp-temp2*10;
328
 
  *to++= (char) ('0'+(char) (temp2));
329
 
  *to++= (char) ('0'+(char) (temp));
330
 
  *to++= ' ';
331
 
  temp=time_tmp.hour;
332
 
  temp2=temp/10; temp=temp-temp2*10;
333
 
  *to++= (char) ('0'+(char) (temp2));
334
 
  *to++= (char) ('0'+(char) (temp));
335
 
  *to++= ':';
336
 
  temp=time_tmp.minute;
337
 
  temp2=temp/10; temp=temp-temp2*10;
338
 
  *to++= (char) ('0'+(char) (temp2));
339
 
  *to++= (char) ('0'+(char) (temp));
340
 
  *to++= ':';
341
 
  temp=time_tmp.second;
342
 
  temp2=temp/10; temp=temp-temp2*10;
343
 
  *to++= (char) ('0'+(char) (temp2));
344
 
  *to++= (char) ('0'+(char) (temp));
345
 
  *to= 0;
 
242
    longget(temp, ptr);
 
243
 
 
244
  val_buffer->set_charset(&my_charset_bin);     /* Safety */
 
245
 
 
246
  drizzled::Timestamp temporal;
 
247
  (void) temporal.from_time_t((time_t) temp);
 
248
  size_t to_len;
 
249
 
 
250
  temporal.to_string(to, &to_len);
 
251
  val_buffer->length((uint32_t) to_len);
346
252
  return val_buffer;
347
253
}
348
254
 
349
 
 
350
 
bool Field_timestamp::get_date(DRIZZLE_TIME *ltime, uint32_t fuzzydate)
 
255
bool Field_timestamp::get_date(DRIZZLE_TIME *ltime, uint32_t)
351
256
{
352
 
  long temp;
353
 
  THD *thd= table ? table->in_use : current_thd;
354
 
  thd->time_zone_used= 1;
 
257
  uint32_t temp;
 
258
 
355
259
#ifdef WORDS_BIGENDIAN
356
260
  if (table && table->s->db_low_byte_first)
357
 
    temp=uint4korr(ptr);
 
261
    temp= uint4korr(ptr);
358
262
  else
359
263
#endif
360
 
    longget(temp,ptr);
361
 
  if (temp == 0L)
362
 
  {                                   /* Zero time is "000000" */
363
 
    if (fuzzydate & TIME_NO_ZERO_DATE)
364
 
      return 1;
365
 
    memset(ltime, 0, sizeof(*ltime));
366
 
  }
367
 
  else
368
 
  {
369
 
    thd->variables.time_zone->gmt_sec_to_TIME(ltime, (my_time_t)temp);
370
 
  }
 
264
    longget(temp, ptr);
 
265
  
 
266
  memset(ltime, 0, sizeof(*ltime));
 
267
 
 
268
  drizzled::Timestamp temporal;
 
269
  (void) temporal.from_time_t((time_t) temp);
 
270
 
 
271
  /* @TODO Goodbye the below code when DRIZZLE_TIME is finally gone.. */
 
272
 
 
273
  ltime->time_type= DRIZZLE_TIMESTAMP_DATETIME;
 
274
  ltime->year= temporal.years();
 
275
  ltime->month= temporal.months();
 
276
  ltime->day= temporal.days();
 
277
  ltime->hour= temporal.hours();
 
278
  ltime->minute= temporal.minutes();
 
279
  ltime->second= temporal.seconds();
 
280
 
371
281
  return 0;
372
282
}
373
283
 
376
286
  return Field_timestamp::get_date(ltime,0);
377
287
}
378
288
 
379
 
 
380
 
bool Field_timestamp::send_binary(Protocol *protocol)
381
 
{
382
 
  DRIZZLE_TIME tm;
383
 
  Field_timestamp::get_date(&tm, 0);
384
 
  return protocol->store(&tm);
385
 
}
386
 
 
387
 
 
388
289
int Field_timestamp::cmp(const unsigned char *a_ptr, const unsigned char *b_ptr)
389
290
{
390
291
  int32_t a,b;
404
305
}
405
306
 
406
307
 
407
 
void Field_timestamp::sort_string(unsigned char *to,uint32_t length __attribute__((unused)))
 
308
void Field_timestamp::sort_string(unsigned char *to,uint32_t )
408
309
{
409
310
#ifdef WORDS_BIGENDIAN
410
311
  if (!table || !table->s->db_low_byte_first)
424
325
  }
425
326
}
426
327
 
427
 
 
428
328
void Field_timestamp::sql_type(String &res) const
429
329
{
430
330
  res.set_ascii(STRING_WITH_LEN("timestamp"));
431
331
}
432
332
 
433
 
 
434
333
void Field_timestamp::set_time()
435
334
{
436
 
  THD *thd= table ? table->in_use : current_thd;
437
 
  long tmp= (long) thd->query_start();
 
335
  Session *session= table ? table->in_use : current_session;
 
336
  long tmp= (long) session->query_start();
438
337
  set_notnull();
439
338
  store_timestamp(tmp);
440
339
}
441
340
 
 
341
void Field_timestamp::set_default()
 
342
{
 
343
  if (table->timestamp_field == this &&
 
344
      unireg_check != TIMESTAMP_UN_FIELD)
 
345
    set_time();
 
346
  else
 
347
    Field::set_default();
 
348
}
 
349
 
 
350
long Field_timestamp::get_timestamp(bool *null_value)
 
351
{
 
352
  if ((*null_value= is_null()))
 
353
    return 0;
 
354
#ifdef WORDS_BIGENDIAN
 
355
  if (table && table->s->db_low_byte_first)
 
356
    return sint4korr(ptr);
 
357
#endif
 
358
  long tmp;
 
359
  longget(tmp,ptr);
 
360
  return tmp;
 
361
}
 
362
 
 
363
void Field_timestamp::store_timestamp(time_t timestamp)
 
364
{
 
365
#ifdef WORDS_BIGENDIAN
 
366
  if (table && table->s->db_low_byte_first)
 
367
  {
 
368
    int4store(ptr,timestamp);
 
369
  }
 
370
  else
 
371
#endif
 
372
    longstore(ptr,(uint32_t) timestamp);
 
373
}