18
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22
#include <drizzled/server_includes.h>
23
#include <drizzled/field/timestamp.h>
22
#include <boost/lexical_cast.hpp>
23
#include <drizzled/field/epoch.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>
30
#if defined(CMATH_NAMESPACE)
31
using namespace CMATH_NAMESPACE;
33
#include "drizzled/temporal.h"
35
TIMESTAMP type holds datetime values in range from 1970-01-01 00:00:01 UTC to
36
2038-01-01 00:00:00 UTC stored as number of seconds since Unix
42
TIMESTAMP type holds datetime values in range from 1970-01-01 00:00:01 UTC to
43
2038-01-01 00:00:00 UTC stored as number of seconds since Unix
39
Up to one of timestamps columns in the table can be automatically
46
Up to one of timestamps columns in the table can be automatically
40
47
set on row update and/or have NOW() as default value.
41
TABLE::timestamp_field points to Field object for such timestamp with
48
TABLE::timestamp_field points to Field object for such timestamp with
42
49
auto-set-on-update. TABLE::time_stamp holds offset in record + 1 for this
43
50
field, and is used by handler code which performs updates required.
45
52
Actually SQL-99 says that we should allow niladic functions (like NOW())
46
as defaults for any field. Current limitations (only NOW() and only
47
for one TIMESTAMP field) are because of restricted binary .frm format
53
as defaults for any field. Current limitations (only NOW() and only
54
for one TIMESTAMP field) are because of restricted binary .frm format
48
55
and should go away in the future.
50
57
Also because of this limitation of binary .frm format we use 5 different
51
58
unireg_check values with TIMESTAMP field to distinguish various cases of
52
59
DEFAULT or ON UPDATE values. These values are:
54
61
TIMESTAMP_OLD_FIELD - old timestamp, if there was not any fields with
55
auto-set-on-update (or now() as default) in this table before, then this
56
field has NOW() as default and is updated when row changes, else it is
62
auto-set-on-update (or now() as default) in this table before, then this
63
field has NOW() as default and is updated when row changes, else it is
57
64
field which has 0 as default value and is not automatically updated.
58
65
TIMESTAMP_DN_FIELD - field with NOW() as default but not set on update
59
66
automatically (TIMESTAMP DEFAULT NOW())
60
TIMESTAMP_UN_FIELD - field which is set on update automatically but has not
61
NOW() as default (but it may has 0 or some other const timestamp as
67
TIMESTAMP_UN_FIELD - field which is set on update automatically but has not
68
NOW() as default (but it may has 0 or some other const timestamp as
62
69
default) (TIMESTAMP ON UPDATE NOW()).
63
TIMESTAMP_DNUN_FIELD - field which has now() as default and is auto-set on
70
TIMESTAMP_DNUN_FIELD - field which has now() as default and is auto-set on
64
71
update. (TIMESTAMP DEFAULT NOW() ON UPDATE NOW())
65
NONE - field which is not auto-set on update with some other than NOW()
72
NONE - field which is not auto-set on update with some other than NOW()
66
73
default value (TIMESTAMP DEFAULT 0).
68
Note that TIMESTAMP_OLD_FIELDs are never created explicitly now, they are
69
left only for preserving ability to read old tables. Such fields replaced
70
with their newer analogs in CREATE TABLE and in SHOW CREATE TABLE. This is
71
because we want to prefer NONE unireg_check before TIMESTAMP_OLD_FIELD for
72
"TIMESTAMP DEFAULT 'Const'" field. (Old timestamps allowed such
73
specification too but ignored default value for first timestamp, which of
75
Note that TIMESTAMP_OLD_FIELDs are never created explicitly now, they are
76
left only for preserving ability to read old tables. Such fields replaced
77
with their newer analogs in CREATE TABLE and in SHOW CREATE TABLE. This is
78
because we want to prefer NONE unireg_check before TIMESTAMP_OLD_FIELD for
79
"TIMESTAMP DEFAULT 'Const'" field. (Old timestamps allowed such
80
specification too but ignored default value for first timestamp, which of
74
81
course is non-standard.) In most cases user won't notice any change, only
75
82
exception is different behavior of old/new timestamps during ALTER TABLE.
78
Field_timestamp::Field_timestamp(unsigned char *ptr_arg,
79
uint32_t len_arg __attribute__((unused)),
80
unsigned char *null_ptr_arg, unsigned char null_bit_arg,
81
enum utype unireg_check_arg,
82
const char *field_name_arg,
84
const CHARSET_INFO * const cs)
85
:Field_str(ptr_arg, MAX_DATETIME_WIDTH, null_ptr_arg, null_bit_arg,
86
unireg_check_arg, field_name_arg, cs)
84
Epoch::Epoch(unsigned char *ptr_arg,
86
unsigned char *null_ptr_arg,
87
unsigned char null_bit_arg,
88
enum utype unireg_check_arg,
89
const char *field_name_arg,
90
drizzled::TableShare *share,
91
const drizzled::CHARSET_INFO * const cs) :
93
DateTime::MAX_STRING_LENGTH - 1 /* no \0 */,
88
/* For 4.0 MYD and 4.0 InnoDB compatibility */
89
flags|= UNSIGNED_FLAG;
90
if (!share->timestamp_field && unireg_check != NONE)
99
unireg_check= unireg_check_arg;
100
if (! share->getTimestampField() && unireg_check != NONE)
92
102
/* This timestamp has auto-update */
93
share->timestamp_field= this;
94
flags|= TIMESTAMP_FLAG;
103
share->setTimestampField(this);
104
flags|= FUNCTION_DEFAULT_FLAG;
95
105
if (unireg_check != TIMESTAMP_DN_FIELD)
96
106
flags|= ON_UPDATE_NOW_FLAG;
101
Field_timestamp::Field_timestamp(bool maybe_null_arg,
102
const char *field_name_arg,
103
const CHARSET_INFO * const cs)
104
:Field_str((unsigned char*) 0, MAX_DATETIME_WIDTH,
105
maybe_null_arg ? (unsigned char*) "": 0, 0,
106
NONE, field_name_arg, cs)
110
Epoch::Epoch(bool maybe_null_arg,
111
const char *field_name_arg,
112
const CHARSET_INFO * const cs) :
113
Field_str((unsigned char*) NULL,
114
DateTime::MAX_STRING_LENGTH - 1 /* no \0 */,
115
maybe_null_arg ? (unsigned char*) "": 0,
108
/* For 4.0 MYD and 4.0 InnoDB compatibility */
109
flags|= UNSIGNED_FLAG;
110
if (unireg_check != TIMESTAMP_DN_FIELD)
111
flags|= ON_UPDATE_NOW_FLAG;
120
if (unireg_check != TIMESTAMP_DN_FIELD)
121
flags|= ON_UPDATE_NOW_FLAG;
116
125
Get auto-set type for TIMESTAMP field.
118
127
Returns value indicating during which operations this TIMESTAMP field
119
128
should be auto-set to current timestamp.
121
timestamp_auto_set_type Field_timestamp::get_auto_set_type() const
130
timestamp_auto_set_type Epoch::get_auto_set_type() const
123
132
switch (unireg_check)
150
int Field_timestamp::store(const char *from,
152
const CHARSET_INFO * const cs __attribute__((unused)))
157
bool have_smth_to_conv;
158
bool in_dst_time_gap;
159
Session *session= table ? table->in_use : current_session;
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);
165
if (error || !have_smth_to_conv)
168
set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED,
169
from, len, DRIZZLE_TIMESTAMP_DATETIME, 1);
172
/* Only convert a correct date (not a zero date) */
173
if (have_smth_to_conv && l_time.month)
175
if (!(tmp= TIME_to_timestamp(session, &l_time, &in_dst_time_gap)))
177
set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
178
ER_WARN_DATA_OUT_OF_RANGE,
179
from, len, DRIZZLE_TIMESTAMP_DATETIME, !error);
182
else if (in_dst_time_gap)
184
set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
185
ER_WARN_INVALID_TIMESTAMP,
186
from, len, DRIZZLE_TIMESTAMP_DATETIME, !error);
190
store_timestamp(tmp);
195
int Field_timestamp::store(double nr)
198
if (nr < 0 || nr > 99991231235959.0)
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
206
error|= Field_timestamp::store((int64_t) rint(nr), false);
211
int Field_timestamp::store(int64_t nr,
212
bool unsigned_val __attribute__((unused)))
215
my_time_t timestamp= 0;
217
bool in_dst_time_gap;
218
Session *session= table ? table->in_use : current_session;
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))
230
if (!(timestamp= TIME_to_timestamp(session, &l_time, &in_dst_time_gap)))
232
set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
233
ER_WARN_DATA_OUT_OF_RANGE,
234
nr, DRIZZLE_TIMESTAMP_DATETIME, 1);
239
set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
240
ER_WARN_INVALID_TIMESTAMP,
241
nr, DRIZZLE_TIMESTAMP_DATETIME, 1);
245
set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
246
ER_WARN_DATA_TRUNCATED,
247
nr, DRIZZLE_TIMESTAMP_DATETIME, 1);
249
store_timestamp(timestamp);
253
double Field_timestamp::val_real(void)
255
return (double) Field_timestamp::val_int();
258
int64_t Field_timestamp::val_int(void)
261
DRIZZLE_TIME time_tmp;
262
Session *session= table ? table->in_use : current_session;
264
#ifdef WORDS_BIGENDIAN
265
if (table && table->s->db_low_byte_first)
271
if (temp == 0L) // No time
272
return(0); /* purecov: inspected */
274
session->variables.time_zone->gmt_sec_to_TIME(&time_tmp, (my_time_t)temp);
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;
283
String *Field_timestamp::val_str(String *val_buffer, String *val_ptr)
285
uint32_t temp, temp2;
286
DRIZZLE_TIME time_tmp;
287
Session *session= table ? table->in_use : current_session;
158
int Epoch::store(const char *from,
160
const CHARSET_INFO * const )
164
ASSERT_COLUMN_MARKED_FOR_WRITE;
166
if (not temporal.from_string(from, (size_t) len))
168
my_error(ER_INVALID_UNIX_TIMESTAMP_VALUE, MYF(ME_FATALERROR), from);
173
temporal.to_time_t(tmp);
179
int Epoch::store(double from)
181
ASSERT_COLUMN_MARKED_FOR_WRITE;
183
if (from < 0 || from > 99991231235959.0)
185
/* Convert the double to a string using stringstream */
186
std::stringstream ss;
188
ss.precision(18); /* 18 places should be fine for error display of double input. */
192
my_error(ER_INVALID_UNIX_TIMESTAMP_VALUE, MYF(ME_FATALERROR), tmp.c_str());
195
return Epoch::store((int64_t) rint(from), false);
198
int Epoch::store(int64_t from, bool)
200
ASSERT_COLUMN_MARKED_FOR_WRITE;
203
* Try to create a DateTime from the supplied integer. Throw an error
204
* if unable to create a valid DateTime.
207
if (! temporal.from_int64_t(from))
209
/* Convert the integer to a string using boost::lexical_cast */
210
std::string tmp(boost::lexical_cast<std::string>(from));
212
my_error(ER_INVALID_UNIX_TIMESTAMP_VALUE, MYF(ME_FATALERROR), tmp.c_str());
217
temporal.to_time_t(tmp);
224
double Epoch::val_real(void)
226
return (double) Epoch::val_int();
229
int64_t Epoch::val_int(void)
233
ASSERT_COLUMN_MARKED_FOR_READ;
238
(void) temporal.from_time_t((time_t) temp);
240
/* We must convert into a "timestamp-formatted integer" ... */
242
temporal.to_int64_t(&result);
246
String *Epoch::val_str(String *val_buffer, String *)
290
val_buffer->alloc(field_length+1);
291
to= (char*) val_buffer->ptr();
292
val_buffer->length(field_length);
294
#ifdef WORDS_BIGENDIAN
295
if (table && table->s->db_low_byte_first)
302
{ /* Zero time is "000000" */
303
val_ptr->set(STRING_WITH_LEN("0000-00-00 00:00:00"), &my_charset_bin);
306
val_buffer->set_charset(&my_charset_bin); // Safety
308
session->variables.time_zone->gmt_sec_to_TIME(&time_tmp,(my_time_t)temp);
310
temp= time_tmp.year % 100;
311
if (temp < YY_PART_YEAR - 1)
321
temp2=temp/10; temp=temp-temp2*10;
322
*to++= (char) ('0'+(char) (temp2));
323
*to++= (char) ('0'+(char) (temp));
326
temp2=temp/10; temp=temp-temp2*10;
327
*to++= (char) ('0'+(char) (temp2));
328
*to++= (char) ('0'+(char) (temp));
331
temp2=temp/10; temp=temp-temp2*10;
332
*to++= (char) ('0'+(char) (temp2));
333
*to++= (char) ('0'+(char) (temp));
336
temp2=temp/10; temp=temp-temp2*10;
337
*to++= (char) ('0'+(char) (temp2));
338
*to++= (char) ('0'+(char) (temp));
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));
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));
250
int to_len= field_length + 1;
252
val_buffer->alloc(to_len);
253
to= (char *) val_buffer->ptr();
257
val_buffer->set_charset(&my_charset_bin); /* Safety */
260
(void) temporal.from_time_t((time_t) temp);
263
rlen= temporal.to_string(to, to_len);
264
assert(rlen < to_len);
266
val_buffer->length(rlen);
350
267
return val_buffer;
354
bool Field_timestamp::get_date(DRIZZLE_TIME *ltime, uint32_t fuzzydate)
270
bool Epoch::get_date(DRIZZLE_TIME *ltime, uint32_t)
357
Session *session= table ? table->in_use : current_session;
358
#ifdef WORDS_BIGENDIAN
359
if (table && table->s->db_low_byte_first)
365
{ /* Zero time is "000000" */
366
if (fuzzydate & TIME_NO_ZERO_DATE)
368
memset(ltime, 0, sizeof(*ltime));
372
session->variables.time_zone->gmt_sec_to_TIME(ltime, (my_time_t)temp);
276
memset(ltime, 0, sizeof(*ltime));
279
(void) temporal.from_time_t((time_t) temp);
281
/* @TODO Goodbye the below code when DRIZZLE_TIME is finally gone.. */
283
ltime->time_type= DRIZZLE_TIMESTAMP_DATETIME;
284
ltime->year= temporal.years();
285
ltime->month= temporal.months();
286
ltime->day= temporal.days();
287
ltime->hour= temporal.hours();
288
ltime->minute= temporal.minutes();
289
ltime->second= temporal.seconds();
377
bool Field_timestamp::get_time(DRIZZLE_TIME *ltime)
379
return Field_timestamp::get_date(ltime,0);
383
bool Field_timestamp::send_binary(Protocol *protocol)
386
Field_timestamp::get_date(&tm, 0);
387
return protocol->store(&tm);
391
int Field_timestamp::cmp(const unsigned char *a_ptr, const unsigned char *b_ptr)
394
#ifdef WORDS_BIGENDIAN
395
if (table && table->s->db_low_byte_first)
406
return ((uint32_t) a < (uint32_t) b) ? -1 : ((uint32_t) a > (uint32_t) b) ? 1 : 0;
410
void Field_timestamp::sort_string(unsigned char *to,uint32_t length __attribute__((unused)))
412
#ifdef WORDS_BIGENDIAN
413
if (!table || !table->s->db_low_byte_first)
294
bool Epoch::get_time(DRIZZLE_TIME *ltime)
296
return Epoch::get_date(ltime,0);
299
int Epoch::cmp(const unsigned char *a_ptr, const unsigned char *b_ptr)
303
unpack_num(a, a_ptr);
304
unpack_num(b, b_ptr);
306
return (a < b) ? -1 : (a > b) ? 1 : 0;
310
void Epoch::sort_string(unsigned char *to,uint32_t )
312
#ifdef WORDS_BIGENDIAN
313
if (!getTable() || !getTable()->getShare()->db_low_byte_first)
431
void Field_timestamp::sql_type(String &res) const
338
void Epoch::sql_type(String &res) const
433
340
res.set_ascii(STRING_WITH_LEN("timestamp"));
437
void Field_timestamp::set_time()
343
void Epoch::set_time()
439
Session *session= table ? table->in_use : current_session;
440
long tmp= (long) session->query_start();
345
Session *session= getTable() ? getTable()->in_use : current_session;
346
time_t tmp= session->query_start();
442
store_timestamp(tmp);
446
void Field_timestamp::set_default()
351
void Epoch::set_default()
448
if (table->timestamp_field == this &&
353
if (getTable()->timestamp_field == this &&
449
354
unireg_check != TIMESTAMP_UN_FIELD)
452
360
Field::set_default();
455
long Field_timestamp::get_timestamp(bool *null_value)
364
long Epoch::get_timestamp(bool *null_value)
457
366
if ((*null_value= is_null()))
459
#ifdef WORDS_BIGENDIAN
460
if (table && table->s->db_low_byte_first)
461
return sint4korr(ptr);
370
return unpack_num(tmp);
469
void Field_timestamp::store_timestamp(my_time_t timestamp)
373
size_t Epoch::max_string_length()
471
#ifdef WORDS_BIGENDIAN
472
if (table && table->s->db_low_byte_first)
474
int4store(ptr,timestamp);
478
longstore(ptr,(uint32_t) timestamp);
375
return sizeof(uint64_t);
378
} /* namespace field */
379
} /* namespace drizzled */