1
/* - mode: c++ c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2008 MySQL
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.
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.
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
21
#ifdef USE_PRAGMA_IMPLEMENTATION
22
#pragma implementation // gcc: Class implementation
25
#include <drizzled/server_includes.h>
26
#include <drizzled/field/timestamp.h>
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
Up to one of timestamps columns in the table can be automatically
34
set on row update and/or have NOW() as default value.
35
TABLE::timestamp_field points to Field object for such timestamp with
36
auto-set-on-update. TABLE::time_stamp holds offset in record + 1 for this
37
field, and is used by handler code which performs updates required.
39
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
42
and should go away in the future.
44
Also because of this limitation of binary .frm format we use 5 different
45
unireg_check values with TIMESTAMP field to distinguish various cases of
46
DEFAULT or ON UPDATE values. These values are:
48
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
51
field which has 0 as default value and is not automatically updated.
52
TIMESTAMP_DN_FIELD - field with NOW() as default but not set on update
53
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
56
default) (TIMESTAMP ON UPDATE NOW()).
57
TIMESTAMP_DNUN_FIELD - field which has now() as default and is auto-set on
58
update. (TIMESTAMP DEFAULT NOW() ON UPDATE NOW())
59
NONE - field which is not auto-set on update with some other than NOW()
60
default value (TIMESTAMP DEFAULT 0).
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
68
course is non-standard.) In most cases user won't notice any change, only
69
exception is different behavior of old/new timestamps during ALTER TABLE.
72
Field_timestamp::Field_timestamp(unsigned char *ptr_arg,
73
uint32_t len_arg __attribute__((unused)),
74
unsigned char *null_ptr_arg, unsigned char null_bit_arg,
75
enum utype unireg_check_arg,
76
const char *field_name_arg,
78
const CHARSET_INFO * const cs)
79
:Field_str(ptr_arg, MAX_DATETIME_WIDTH, null_ptr_arg, null_bit_arg,
80
unireg_check_arg, field_name_arg, cs)
82
/* For 4.0 MYD and 4.0 InnoDB compatibility */
83
flags|= UNSIGNED_FLAG;
84
if (!share->timestamp_field && unireg_check != NONE)
86
/* This timestamp has auto-update */
87
share->timestamp_field= this;
88
flags|= TIMESTAMP_FLAG;
89
if (unireg_check != TIMESTAMP_DN_FIELD)
90
flags|= ON_UPDATE_NOW_FLAG;
95
Field_timestamp::Field_timestamp(bool maybe_null_arg,
96
const char *field_name_arg,
97
const CHARSET_INFO * const cs)
98
:Field_str((unsigned char*) 0, MAX_DATETIME_WIDTH,
99
maybe_null_arg ? (unsigned char*) "": 0, 0,
100
NONE, field_name_arg, cs)
102
/* For 4.0 MYD and 4.0 InnoDB compatibility */
103
flags|= UNSIGNED_FLAG;
104
if (unireg_check != TIMESTAMP_DN_FIELD)
105
flags|= ON_UPDATE_NOW_FLAG;
110
Get auto-set type for TIMESTAMP field.
112
Returns value indicating during which operations this TIMESTAMP field
113
should be auto-set to current timestamp.
115
timestamp_auto_set_type Field_timestamp::get_auto_set_type() const
117
switch (unireg_check)
119
case TIMESTAMP_DN_FIELD:
120
return TIMESTAMP_AUTO_SET_ON_INSERT;
121
case TIMESTAMP_UN_FIELD:
122
return TIMESTAMP_AUTO_SET_ON_UPDATE;
123
case TIMESTAMP_OLD_FIELD:
125
Although we can have several such columns in legacy tables this
126
function should be called only for first of them (i.e. the one
127
having auto-set property).
129
assert(table->timestamp_field == this);
131
case TIMESTAMP_DNUN_FIELD:
132
return TIMESTAMP_AUTO_SET_ON_BOTH;
135
Normally this function should not be called for TIMESTAMPs without
139
return TIMESTAMP_NO_AUTO_SET;
144
int Field_timestamp::store(const char *from,
146
const CHARSET_INFO * const cs __attribute__((unused)))
151
bool have_smth_to_conv;
152
bool in_dst_time_gap;
153
THD *thd= table ? table->in_use : current_thd;
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);
159
if (error || !have_smth_to_conv)
162
set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED,
163
from, len, DRIZZLE_TIMESTAMP_DATETIME, 1);
166
/* Only convert a correct date (not a zero date) */
167
if (have_smth_to_conv && l_time.month)
169
if (!(tmp= TIME_to_timestamp(thd, &l_time, &in_dst_time_gap)))
171
set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
172
ER_WARN_DATA_OUT_OF_RANGE,
173
from, len, DRIZZLE_TIMESTAMP_DATETIME, !error);
176
else if (in_dst_time_gap)
178
set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
179
ER_WARN_INVALID_TIMESTAMP,
180
from, len, DRIZZLE_TIMESTAMP_DATETIME, !error);
184
store_timestamp(tmp);
189
int Field_timestamp::store(double nr)
192
if (nr < 0 || nr > 99991231235959.0)
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
200
error|= Field_timestamp::store((int64_t) rint(nr), false);
205
int Field_timestamp::store(int64_t nr,
206
bool unsigned_val __attribute__((unused)))
209
my_time_t timestamp= 0;
211
bool in_dst_time_gap;
212
THD *thd= table ? table->in_use : current_thd;
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))
224
if (!(timestamp= TIME_to_timestamp(thd, &l_time, &in_dst_time_gap)))
226
set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
227
ER_WARN_DATA_OUT_OF_RANGE,
228
nr, DRIZZLE_TIMESTAMP_DATETIME, 1);
233
set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
234
ER_WARN_INVALID_TIMESTAMP,
235
nr, DRIZZLE_TIMESTAMP_DATETIME, 1);
239
set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
240
ER_WARN_DATA_TRUNCATED,
241
nr, DRIZZLE_TIMESTAMP_DATETIME, 1);
243
store_timestamp(timestamp);
247
double Field_timestamp::val_real(void)
249
return (double) Field_timestamp::val_int();
252
int64_t Field_timestamp::val_int(void)
255
DRIZZLE_TIME time_tmp;
256
THD *thd= table ? table->in_use : current_thd;
258
thd->time_zone_used= 1;
259
#ifdef WORDS_BIGENDIAN
260
if (table && table->s->db_low_byte_first)
266
if (temp == 0L) // No time
267
return(0); /* purecov: inspected */
269
thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp, (my_time_t)temp);
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;
278
String *Field_timestamp::val_str(String *val_buffer, String *val_ptr)
280
uint32_t temp, temp2;
281
DRIZZLE_TIME time_tmp;
282
THD *thd= table ? table->in_use : current_thd;
285
val_buffer->alloc(field_length+1);
286
to= (char*) val_buffer->ptr();
287
val_buffer->length(field_length);
289
thd->time_zone_used= 1;
290
#ifdef WORDS_BIGENDIAN
291
if (table && table->s->db_low_byte_first)
298
{ /* Zero time is "000000" */
299
val_ptr->set(STRING_WITH_LEN("0000-00-00 00:00:00"), &my_charset_bin);
302
val_buffer->set_charset(&my_charset_bin); // Safety
304
thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp,(my_time_t)temp);
306
temp= time_tmp.year % 100;
307
if (temp < YY_PART_YEAR - 1)
317
temp2=temp/10; temp=temp-temp2*10;
318
*to++= (char) ('0'+(char) (temp2));
319
*to++= (char) ('0'+(char) (temp));
322
temp2=temp/10; temp=temp-temp2*10;
323
*to++= (char) ('0'+(char) (temp2));
324
*to++= (char) ('0'+(char) (temp));
327
temp2=temp/10; temp=temp-temp2*10;
328
*to++= (char) ('0'+(char) (temp2));
329
*to++= (char) ('0'+(char) (temp));
332
temp2=temp/10; temp=temp-temp2*10;
333
*to++= (char) ('0'+(char) (temp2));
334
*to++= (char) ('0'+(char) (temp));
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));
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));
350
bool Field_timestamp::get_date(DRIZZLE_TIME *ltime, uint32_t fuzzydate)
353
THD *thd= table ? table->in_use : current_thd;
354
thd->time_zone_used= 1;
355
#ifdef WORDS_BIGENDIAN
356
if (table && table->s->db_low_byte_first)
362
{ /* Zero time is "000000" */
363
if (fuzzydate & TIME_NO_ZERO_DATE)
365
memset(ltime, 0, sizeof(*ltime));
369
thd->variables.time_zone->gmt_sec_to_TIME(ltime, (my_time_t)temp);
374
bool Field_timestamp::get_time(DRIZZLE_TIME *ltime)
376
return Field_timestamp::get_date(ltime,0);
380
bool Field_timestamp::send_binary(Protocol *protocol)
383
Field_timestamp::get_date(&tm, 0);
384
return protocol->store(&tm);
388
int Field_timestamp::cmp(const unsigned char *a_ptr, const unsigned char *b_ptr)
391
#ifdef WORDS_BIGENDIAN
392
if (table && table->s->db_low_byte_first)
403
return ((uint32_t) a < (uint32_t) b) ? -1 : ((uint32_t) a > (uint32_t) b) ? 1 : 0;
407
void Field_timestamp::sort_string(unsigned char *to,uint32_t length __attribute__((unused)))
409
#ifdef WORDS_BIGENDIAN
410
if (!table || !table->s->db_low_byte_first)
428
void Field_timestamp::sql_type(String &res) const
430
res.set_ascii(STRING_WITH_LEN("timestamp"));
434
void Field_timestamp::set_time()
436
THD *thd= table ? table->in_use : current_thd;
437
long tmp= (long) thd->query_start();
439
store_timestamp(tmp);