~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/field/timestamp.cc

  • Committer: Stewart Smith
  • Date: 2009-05-15 06:57:12 UTC
  • mto: (991.1.5 for-brian)
  • mto: This revision was merged to the branch mainline in revision 1022.
  • Revision ID: stewart@flamingspork.com-20090515065712-bmionylacjmexmmm
Make sql_mode=NO_AUTO_VALUE_ON_ZERO default for Drizzle.

Also fix DEFAULT keyword handling for auto-increment so that it defaults to
NULL and not 0 so that the following is valid and generates two auto-inc
values:

create table t1 (a int auto_increment primary key)
insert into t1 (a) values (default);
insert into t1 (a) values (default);

Important to note that 0 is no longer magic. So this gives you duplicate
primary key error:

insert into t1 (a) values(0);
insert into t1 (a) values(0);

as you've inserted the explicit value of 0 twice.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
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 Sun Microsystems, Inc.
 
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
 
#include "config.h"
22
 
#include <boost/lexical_cast.hpp>
23
 
#include <drizzled/field/epoch.h>
 
21
 
 
22
#include <drizzled/server_includes.h>
 
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
28
 
29
 
#include <math.h>
30
 
 
31
 
#include <sstream>
32
 
 
33
29
#include "drizzled/temporal.h"
34
30
 
35
 
namespace drizzled
36
 
{
37
 
 
38
 
namespace field
39
 
{
40
31
 
41
32
/**
42
33
  TIMESTAMP type holds datetime values in range from 1970-01-01 00:00:01 UTC to
81
72
  course is non-standard.) In most cases user won't notice any change, only
82
73
  exception is different behavior of old/new timestamps during ALTER TABLE.
83
74
 */
84
 
  Epoch::Epoch(unsigned char *ptr_arg,
85
 
               unsigned char *null_ptr_arg,
86
 
               unsigned char null_bit_arg,
87
 
               enum utype unireg_check_arg,
88
 
               const char *field_name_arg,
89
 
               drizzled::TableShare *share) :
90
 
  Field_str(ptr_arg,
91
 
            MicroTimestamp::MAX_STRING_LENGTH - 1, /* no \0 */
92
 
            null_ptr_arg,
93
 
            null_bit_arg,
94
 
            field_name_arg,
95
 
            &my_charset_bin)
 
75
Field_timestamp::Field_timestamp(unsigned char *ptr_arg,
 
76
                                 uint32_t ,
 
77
                                 unsigned char *null_ptr_arg, unsigned char null_bit_arg,
 
78
                                 enum utype unireg_check_arg,
 
79
                                 const char *field_name_arg,
 
80
                                 TableShare *share,
 
81
                                 const CHARSET_INFO * const cs)
 
82
  :Field_str(ptr_arg, MAX_DATETIME_WIDTH, null_ptr_arg, null_bit_arg,
 
83
             unireg_check_arg, field_name_arg, cs)
96
84
{
97
 
  unireg_check= unireg_check_arg;
98
 
  if (! share->getTimestampField() && unireg_check != NONE)
 
85
  /* For 4.0 MYD and 4.0 InnoDB compatibility */
 
86
  flags|= UNSIGNED_FLAG;
 
87
  if (!share->timestamp_field && unireg_check != NONE)
99
88
  {
100
89
    /* This timestamp has auto-update */
101
 
    share->setTimestampField(this);
102
 
    flags|= FUNCTION_DEFAULT_FLAG;
 
90
    share->timestamp_field= this;
 
91
    flags|= TIMESTAMP_FLAG;
103
92
    if (unireg_check != TIMESTAMP_DN_FIELD)
104
93
      flags|= ON_UPDATE_NOW_FLAG;
105
94
  }
106
95
}
107
96
 
108
 
Epoch::Epoch(bool maybe_null_arg,
109
 
             const char *field_name_arg) :
110
 
  Field_str((unsigned char*) NULL,
111
 
            MicroTimestamp::MAX_STRING_LENGTH - 1, /* no \0 */
112
 
            maybe_null_arg ? (unsigned char*) "": 0,
113
 
            0,
114
 
            field_name_arg,
115
 
            &my_charset_bin)
 
97
Field_timestamp::Field_timestamp(bool maybe_null_arg,
 
98
                                 const char *field_name_arg,
 
99
                                 const CHARSET_INFO * const cs)
 
100
  :Field_str((unsigned char*) 0, MAX_DATETIME_WIDTH,
 
101
             maybe_null_arg ? (unsigned char*) "": 0, 0,
 
102
             NONE, field_name_arg, cs)
116
103
{
117
 
  if (unireg_check != TIMESTAMP_DN_FIELD)
118
 
    flags|= ON_UPDATE_NOW_FLAG;
 
104
  /* For 4.0 MYD and 4.0 InnoDB compatibility */
 
105
  flags|= UNSIGNED_FLAG;
 
106
    if (unireg_check != TIMESTAMP_DN_FIELD)
 
107
      flags|= ON_UPDATE_NOW_FLAG;
119
108
}
120
109
 
121
110
/**
124
113
  Returns value indicating during which operations this TIMESTAMP field
125
114
  should be auto-set to current timestamp.
126
115
*/
127
 
timestamp_auto_set_type Epoch::get_auto_set_type() const
 
116
timestamp_auto_set_type Field_timestamp::get_auto_set_type() const
128
117
{
129
118
  switch (unireg_check)
130
119
  {
138
127
      function should be called only for first of them (i.e. the one
139
128
      having auto-set property).
140
129
    */
141
 
    assert(getTable()->timestamp_field == this);
 
130
    assert(table->timestamp_field == this);
142
131
    /* Fall-through */
143
132
  case TIMESTAMP_DNUN_FIELD:
144
133
    return TIMESTAMP_AUTO_SET_ON_BOTH;
152
141
  }
153
142
}
154
143
 
155
 
int Epoch::store(const char *from,
156
 
                 uint32_t len,
157
 
                 const CHARSET_INFO * const )
 
144
int Field_timestamp::store(const char *from,
 
145
                           uint32_t len,
 
146
                           const CHARSET_INFO * const )
158
147
{
159
 
  Timestamp temporal;
160
 
 
161
 
  ASSERT_COLUMN_MARKED_FOR_WRITE;
162
 
 
163
 
  if (not temporal.from_string(from, (size_t) len))
 
148
  drizzled::Timestamp temporal;
 
149
 
 
150
  if (! temporal.from_string(from, (size_t) len))
164
151
  {
165
 
    my_error(ER_INVALID_TIMESTAMP_VALUE, MYF(ME_FATALERROR), from);
 
152
    my_error(ER_INVALID_UNIX_TIMESTAMP_VALUE, MYF(ME_FATALERROR), from);
166
153
    return 1;
167
154
  }
168
155
 
169
156
  time_t tmp;
170
 
  temporal.to_time_t(tmp);
 
157
  temporal.to_time_t(&tmp);
171
158
 
172
 
  uint64_t time_tmp= tmp;
173
 
  pack_num(time_tmp);
 
159
  store_timestamp(tmp);
174
160
  return 0;
175
161
}
176
162
 
177
 
int Epoch::store(double from)
 
163
int Field_timestamp::store(double from)
178
164
{
179
 
  ASSERT_COLUMN_MARKED_FOR_WRITE;
180
 
 
181
 
  uint64_t from_tmp= (uint64_t)from;
182
 
 
183
 
  Timestamp temporal;
184
 
  if (not temporal.from_int64_t(from_tmp))
 
165
  if (from < 0 || from > 99991231235959.0)
185
166
  {
186
 
    /* Convert the integer to a string using boost::lexical_cast */
187
 
    std::string tmp(boost::lexical_cast<std::string>(from));
 
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;
188
172
 
189
 
    my_error(ER_INVALID_TIMESTAMP_VALUE, MYF(ME_FATALERROR), tmp.c_str());
 
173
    my_error(ER_INVALID_UNIX_TIMESTAMP_VALUE, MYF(ME_FATALERROR), tmp.c_str());
190
174
    return 2;
191
175
  }
192
 
 
193
 
  time_t tmp;
194
 
  temporal.to_time_t(tmp);
195
 
 
196
 
  uint64_t tmp_micro= tmp;
197
 
  pack_num(tmp_micro);
198
 
 
199
 
  return 0;
200
 
}
201
 
 
202
 
int Epoch::store_decimal(const type::Decimal *value)
203
 
{
204
 
  double tmp;
205
 
  value->convert(tmp);
206
 
 
207
 
  return store(tmp);
208
 
}
209
 
 
210
 
int Epoch::store(int64_t from, bool)
211
 
{
212
 
  ASSERT_COLUMN_MARKED_FOR_WRITE;
213
 
 
 
176
  return Field_timestamp::store((int64_t) rint(from), false);
 
177
}
 
178
 
 
179
int Field_timestamp::store(int64_t from, bool)
 
180
{
214
181
  /* 
215
182
   * Try to create a DateTime from the supplied integer.  Throw an error
216
183
   * if unable to create a valid DateTime.  
217
184
   */
218
 
  Timestamp temporal;
219
 
  if (not temporal.from_int64_t(from))
 
185
  drizzled::Timestamp temporal;
 
186
  if (! temporal.from_int64_t(from))
220
187
  {
221
 
    /* Convert the integer to a string using boost::lexical_cast */
222
 
    std::string tmp(boost::lexical_cast<std::string>(from));
 
188
    /* Convert the integer to a string using stringstream */
 
189
    std::stringstream ss;
 
190
    std::string tmp;
 
191
    ss << from; ss >> tmp;
223
192
 
224
 
    my_error(ER_INVALID_TIMESTAMP_VALUE, MYF(ME_FATALERROR), tmp.c_str());
 
193
    my_error(ER_INVALID_UNIX_TIMESTAMP_VALUE, MYF(ME_FATALERROR), tmp.c_str());
225
194
    return 2;
226
195
  }
227
196
 
228
197
  time_t tmp;
229
 
  temporal.to_time_t(tmp);
230
 
 
231
 
  uint64_t tmp64= tmp;
232
 
  pack_num(tmp64);
233
 
 
 
198
  temporal.to_time_t(&tmp);
 
199
 
 
200
  store_timestamp(tmp);
234
201
  return 0;
235
202
}
236
203
 
237
 
double Epoch::val_real(void)
 
204
double Field_timestamp::val_real(void)
238
205
{
239
 
  return (double) Epoch::val_int();
 
206
  return (double) Field_timestamp::val_int();
240
207
}
241
208
 
242
 
int64_t Epoch::val_int(void)
 
209
int64_t Field_timestamp::val_int(void)
243
210
{
244
 
  uint64_t temp;
245
 
 
246
 
  ASSERT_COLUMN_MARKED_FOR_READ;
247
 
 
248
 
  unpack_num(temp);
249
 
 
250
 
  Timestamp temporal;
 
211
  uint32_t temp;
 
212
 
 
213
#ifdef WORDS_BIGENDIAN
 
214
  if (table && table->s->db_low_byte_first)
 
215
    temp= uint4korr(ptr);
 
216
  else
 
217
#endif
 
218
    longget(temp, ptr);
 
219
 
 
220
  drizzled::Timestamp temporal;
251
221
  (void) temporal.from_time_t((time_t) temp);
252
222
 
253
223
  /* We must convert into a "timestamp-formatted integer" ... */
256
226
  return result;
257
227
}
258
228
 
259
 
String *Epoch::val_str(String *val_buffer, String *)
 
229
String *Field_timestamp::val_str(String *val_buffer, String *)
260
230
{
261
 
  uint64_t temp= 0;
 
231
  uint32_t temp;
262
232
  char *to;
263
 
  int to_len= field_length + 1;
264
233
 
265
 
  val_buffer->alloc(to_len);
 
234
  val_buffer->alloc(field_length + 1);
266
235
  to= (char *) val_buffer->ptr();
267
236
 
268
 
  unpack_num(temp);
 
237
#ifdef WORDS_BIGENDIAN
 
238
  if (table && table->s->db_low_byte_first)
 
239
    temp= uint4korr(ptr);
 
240
  else
 
241
#endif
 
242
    longget(temp, ptr);
269
243
 
270
244
  val_buffer->set_charset(&my_charset_bin);     /* Safety */
271
245
 
272
 
  Timestamp temporal;
 
246
  drizzled::Timestamp temporal;
273
247
  (void) temporal.from_time_t((time_t) temp);
274
 
 
275
 
  int rlen;
276
 
  rlen= temporal.to_string(to, to_len);
277
 
  assert(rlen < to_len);
278
 
 
279
 
  val_buffer->length(rlen);
 
248
  size_t to_len;
 
249
 
 
250
  temporal.to_string(to, &to_len);
 
251
  val_buffer->length((uint32_t) to_len);
280
252
  return val_buffer;
281
253
}
282
254
 
283
 
bool Epoch::get_date(type::Time &ltime, uint32_t)
 
255
bool Field_timestamp::get_date(DRIZZLE_TIME *ltime, uint32_t)
284
256
{
285
 
  uint64_t temp;
286
 
  type::Time::epoch_t time_temp;
 
257
  uint32_t temp;
287
258
 
288
 
  unpack_num(temp);
289
 
  time_temp= temp;
 
259
#ifdef WORDS_BIGENDIAN
 
260
  if (table && table->s->db_low_byte_first)
 
261
    temp= uint4korr(ptr);
 
262
  else
 
263
#endif
 
264
    longget(temp, ptr);
290
265
  
291
 
  ltime.reset();
292
 
 
293
 
  ltime.store(time_temp);
 
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();
294
280
 
295
281
  return 0;
296
282
}
297
283
 
298
 
bool Epoch::get_time(type::Time &ltime)
299
 
{
300
 
  return Epoch::get_date(ltime, 0);
301
 
}
302
 
 
303
 
int Epoch::cmp(const unsigned char *a_ptr, const unsigned char *b_ptr)
304
 
{
305
 
  uint64_t a,b;
306
 
 
307
 
  unpack_num(a, a_ptr);
308
 
  unpack_num(b, b_ptr);
309
 
 
310
 
  return (a < b) ? -1 : (a > b) ? 1 : 0;
311
 
}
312
 
 
313
 
 
314
 
void Epoch::sort_string(unsigned char *to,uint32_t )
315
 
{
316
 
#ifdef WORDS_BIGENDIAN
317
 
  if (!getTable() || !getTable()->getShare()->db_low_byte_first)
 
284
bool Field_timestamp::get_time(DRIZZLE_TIME *ltime)
 
285
{
 
286
  return Field_timestamp::get_date(ltime,0);
 
287
}
 
288
 
 
289
int Field_timestamp::cmp(const unsigned char *a_ptr, const unsigned char *b_ptr)
 
290
{
 
291
  int32_t a,b;
 
292
#ifdef WORDS_BIGENDIAN
 
293
  if (table && table->s->db_low_byte_first)
 
294
  {
 
295
    a=sint4korr(a_ptr);
 
296
    b=sint4korr(b_ptr);
 
297
  }
 
298
  else
 
299
#endif
 
300
  {
 
301
  longget(a,a_ptr);
 
302
  longget(b,b_ptr);
 
303
  }
 
304
  return ((uint32_t) a < (uint32_t) b) ? -1 : ((uint32_t) a > (uint32_t) b) ? 1 : 0;
 
305
}
 
306
 
 
307
 
 
308
void Field_timestamp::sort_string(unsigned char *to,uint32_t )
 
309
{
 
310
#ifdef WORDS_BIGENDIAN
 
311
  if (!table || !table->s->db_low_byte_first)
318
312
  {
319
313
    to[0] = ptr[0];
320
314
    to[1] = ptr[1];
321
315
    to[2] = ptr[2];
322
316
    to[3] = ptr[3];
323
 
    to[4] = ptr[4];
324
 
    to[5] = ptr[5];
325
 
    to[6] = ptr[6];
326
 
    to[7] = ptr[7];
327
317
  }
328
318
  else
329
319
#endif
330
320
  {
331
 
    to[0] = ptr[7];
332
 
    to[1] = ptr[6];
333
 
    to[2] = ptr[5];
334
 
    to[3] = ptr[4];
335
 
    to[4] = ptr[3];
336
 
    to[5] = ptr[2];
337
 
    to[6] = ptr[1];
338
 
    to[7] = ptr[0];
 
321
    to[0] = ptr[3];
 
322
    to[1] = ptr[2];
 
323
    to[2] = ptr[1];
 
324
    to[3] = ptr[0];
339
325
  }
340
326
}
341
327
 
342
 
void Epoch::sql_type(String &res) const
 
328
void Field_timestamp::sql_type(String &res) const
343
329
{
344
330
  res.set_ascii(STRING_WITH_LEN("timestamp"));
345
331
}
346
332
 
347
 
void Epoch::set_time()
 
333
void Field_timestamp::set_time()
348
334
{
349
 
  Session *session= getTable() ? getTable()->in_use : current_session;
350
 
  time_t tmp= session->getCurrentTimestampEpoch();
351
 
 
 
335
  Session *session= table ? table->in_use : current_session;
 
336
  long tmp= (long) session->query_start();
352
337
  set_notnull();
353
 
  pack_num(static_cast<uint32_t>(tmp));
 
338
  store_timestamp(tmp);
354
339
}
355
340
 
356
 
void Epoch::set_default()
 
341
void Field_timestamp::set_default()
357
342
{
358
 
  if (getTable()->timestamp_field == this &&
 
343
  if (table->timestamp_field == this &&
359
344
      unireg_check != TIMESTAMP_UN_FIELD)
360
 
  {
361
345
    set_time();
362
 
  }
363
346
  else
364
 
  {
365
347
    Field::set_default();
366
 
  }
367
348
}
368
349
 
369
 
long Epoch::get_timestamp(bool *null_value)
 
350
long Field_timestamp::get_timestamp(bool *null_value)
370
351
{
371
352
  if ((*null_value= is_null()))
372
353
    return 0;
373
 
 
374
 
  uint64_t tmp;
375
 
  return unpack_num(tmp);
 
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;
376
361
}
377
362
 
378
 
size_t Epoch::max_string_length()
 
363
void Field_timestamp::store_timestamp(time_t timestamp)
379
364
{
380
 
  return sizeof(uint64_t);
 
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);
381
373
}
382
 
 
383
 
} /* namespace field */
384
 
} /* namespace drizzled */