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
22
#include <drizzled/server_includes.h>
23
#include <drizzled/field/timestamp.h>
26
TIMESTAMP type holds datetime values in range from 1970-01-01 00:00:01 UTC to
27
2038-01-01 00:00:00 UTC stored as number of seconds since Unix
30
Up to one of timestamps columns in the table can be automatically
31
set on row update and/or have NOW() as default value.
32
TABLE::timestamp_field points to Field object for such timestamp with
33
auto-set-on-update. TABLE::time_stamp holds offset in record + 1 for this
34
field, and is used by handler code which performs updates required.
36
Actually SQL-99 says that we should allow niladic functions (like NOW())
37
as defaults for any field. Current limitations (only NOW() and only
38
for one TIMESTAMP field) are because of restricted binary .frm format
39
and should go away in the future.
41
Also because of this limitation of binary .frm format we use 5 different
42
unireg_check values with TIMESTAMP field to distinguish various cases of
43
DEFAULT or ON UPDATE values. These values are:
45
TIMESTAMP_OLD_FIELD - old timestamp, if there was not any fields with
46
auto-set-on-update (or now() as default) in this table before, then this
47
field has NOW() as default and is updated when row changes, else it is
48
field which has 0 as default value and is not automatically updated.
49
TIMESTAMP_DN_FIELD - field with NOW() as default but not set on update
50
automatically (TIMESTAMP DEFAULT NOW())
51
TIMESTAMP_UN_FIELD - field which is set on update automatically but has not
52
NOW() as default (but it may has 0 or some other const timestamp as
53
default) (TIMESTAMP ON UPDATE NOW()).
54
TIMESTAMP_DNUN_FIELD - field which has now() as default and is auto-set on
55
update. (TIMESTAMP DEFAULT NOW() ON UPDATE NOW())
56
NONE - field which is not auto-set on update with some other than NOW()
57
default value (TIMESTAMP DEFAULT 0).
59
Note that TIMESTAMP_OLD_FIELDs are never created explicitly now, they are
60
left only for preserving ability to read old tables. Such fields replaced
61
with their newer analogs in CREATE TABLE and in SHOW CREATE TABLE. This is
62
because we want to prefer NONE unireg_check before TIMESTAMP_OLD_FIELD for
63
"TIMESTAMP DEFAULT 'Const'" field. (Old timestamps allowed such
64
specification too but ignored default value for first timestamp, which of
65
course is non-standard.) In most cases user won't notice any change, only
66
exception is different behavior of old/new timestamps during ALTER TABLE.
69
Field_timestamp::Field_timestamp(unsigned char *ptr_arg,
70
uint32_t len_arg __attribute__((unused)),
71
unsigned char *null_ptr_arg, unsigned char null_bit_arg,
72
enum utype unireg_check_arg,
73
const char *field_name_arg,
75
const CHARSET_INFO * const cs)
76
:Field_str(ptr_arg, MAX_DATETIME_WIDTH, null_ptr_arg, null_bit_arg,
77
unireg_check_arg, field_name_arg, cs)
79
/* For 4.0 MYD and 4.0 InnoDB compatibility */
80
flags|= UNSIGNED_FLAG;
81
if (!share->timestamp_field && unireg_check != NONE)
83
/* This timestamp has auto-update */
84
share->timestamp_field= this;
85
flags|= TIMESTAMP_FLAG;
86
if (unireg_check != TIMESTAMP_DN_FIELD)
87
flags|= ON_UPDATE_NOW_FLAG;
92
Field_timestamp::Field_timestamp(bool maybe_null_arg,
93
const char *field_name_arg,
94
const CHARSET_INFO * const cs)
95
:Field_str((unsigned char*) 0, MAX_DATETIME_WIDTH,
96
maybe_null_arg ? (unsigned char*) "": 0, 0,
97
NONE, field_name_arg, cs)
99
/* For 4.0 MYD and 4.0 InnoDB compatibility */
100
flags|= UNSIGNED_FLAG;
101
if (unireg_check != TIMESTAMP_DN_FIELD)
102
flags|= ON_UPDATE_NOW_FLAG;
107
Get auto-set type for TIMESTAMP field.
109
Returns value indicating during which operations this TIMESTAMP field
110
should be auto-set to current timestamp.
112
timestamp_auto_set_type Field_timestamp::get_auto_set_type() const
114
switch (unireg_check)
116
case TIMESTAMP_DN_FIELD:
117
return TIMESTAMP_AUTO_SET_ON_INSERT;
118
case TIMESTAMP_UN_FIELD:
119
return TIMESTAMP_AUTO_SET_ON_UPDATE;
120
case TIMESTAMP_OLD_FIELD:
122
Although we can have several such columns in legacy tables this
123
function should be called only for first of them (i.e. the one
124
having auto-set property).
126
assert(table->timestamp_field == this);
128
case TIMESTAMP_DNUN_FIELD:
129
return TIMESTAMP_AUTO_SET_ON_BOTH;
132
Normally this function should not be called for TIMESTAMPs without
136
return TIMESTAMP_NO_AUTO_SET;
141
int Field_timestamp::store(const char *from,
143
const CHARSET_INFO * const cs __attribute__((unused)))
148
bool have_smth_to_conv;
149
bool in_dst_time_gap;
150
THD *thd= table ? table->in_use : current_thd;
152
/* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */
153
have_smth_to_conv= (str_to_datetime(from, len, &l_time, 1, &error) >
154
DRIZZLE_TIMESTAMP_ERROR);
156
if (error || !have_smth_to_conv)
159
set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED,
160
from, len, DRIZZLE_TIMESTAMP_DATETIME, 1);
163
/* Only convert a correct date (not a zero date) */
164
if (have_smth_to_conv && l_time.month)
166
if (!(tmp= TIME_to_timestamp(thd, &l_time, &in_dst_time_gap)))
168
set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
169
ER_WARN_DATA_OUT_OF_RANGE,
170
from, len, DRIZZLE_TIMESTAMP_DATETIME, !error);
173
else if (in_dst_time_gap)
175
set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
176
ER_WARN_INVALID_TIMESTAMP,
177
from, len, DRIZZLE_TIMESTAMP_DATETIME, !error);
181
store_timestamp(tmp);
186
int Field_timestamp::store(double nr)
189
if (nr < 0 || nr > 99991231235959.0)
191
set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
192
ER_WARN_DATA_OUT_OF_RANGE,
193
nr, DRIZZLE_TIMESTAMP_DATETIME);
194
nr= 0; // Avoid overflow on buff
197
error|= Field_timestamp::store((int64_t) rint(nr), false);
202
int Field_timestamp::store(int64_t nr,
203
bool unsigned_val __attribute__((unused)))
206
my_time_t timestamp= 0;
208
bool in_dst_time_gap;
209
THD *thd= table ? table->in_use : current_thd;
211
/* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */
212
int64_t tmp= number_to_datetime(nr, &l_time, (thd->variables.sql_mode &
213
MODE_NO_ZERO_DATE), &error);
214
if (tmp == INT64_C(-1))
221
if (!(timestamp= TIME_to_timestamp(thd, &l_time, &in_dst_time_gap)))
223
set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
224
ER_WARN_DATA_OUT_OF_RANGE,
225
nr, DRIZZLE_TIMESTAMP_DATETIME, 1);
230
set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
231
ER_WARN_INVALID_TIMESTAMP,
232
nr, DRIZZLE_TIMESTAMP_DATETIME, 1);
236
set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
237
ER_WARN_DATA_TRUNCATED,
238
nr, DRIZZLE_TIMESTAMP_DATETIME, 1);
240
store_timestamp(timestamp);
244
double Field_timestamp::val_real(void)
246
return (double) Field_timestamp::val_int();
249
int64_t Field_timestamp::val_int(void)
252
DRIZZLE_TIME time_tmp;
253
THD *thd= table ? table->in_use : current_thd;
255
thd->time_zone_used= 1;
256
#ifdef WORDS_BIGENDIAN
257
if (table && table->s->db_low_byte_first)
263
if (temp == 0L) // No time
264
return(0); /* purecov: inspected */
266
thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp, (my_time_t)temp);
268
return time_tmp.year * INT64_C(10000000000) +
269
time_tmp.month * INT64_C(100000000) +
270
time_tmp.day * 1000000 + time_tmp.hour * 10000 +
271
time_tmp.minute * 100 + time_tmp.second;
275
String *Field_timestamp::val_str(String *val_buffer, String *val_ptr)
277
uint32_t temp, temp2;
278
DRIZZLE_TIME time_tmp;
279
THD *thd= table ? table->in_use : current_thd;
282
val_buffer->alloc(field_length+1);
283
to= (char*) val_buffer->ptr();
284
val_buffer->length(field_length);
286
thd->time_zone_used= 1;
287
#ifdef WORDS_BIGENDIAN
288
if (table && table->s->db_low_byte_first)
295
{ /* Zero time is "000000" */
296
val_ptr->set(STRING_WITH_LEN("0000-00-00 00:00:00"), &my_charset_bin);
299
val_buffer->set_charset(&my_charset_bin); // Safety
301
thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp,(my_time_t)temp);
303
temp= time_tmp.year % 100;
304
if (temp < YY_PART_YEAR - 1)
314
temp2=temp/10; temp=temp-temp2*10;
315
*to++= (char) ('0'+(char) (temp2));
316
*to++= (char) ('0'+(char) (temp));
319
temp2=temp/10; temp=temp-temp2*10;
320
*to++= (char) ('0'+(char) (temp2));
321
*to++= (char) ('0'+(char) (temp));
324
temp2=temp/10; temp=temp-temp2*10;
325
*to++= (char) ('0'+(char) (temp2));
326
*to++= (char) ('0'+(char) (temp));
329
temp2=temp/10; temp=temp-temp2*10;
330
*to++= (char) ('0'+(char) (temp2));
331
*to++= (char) ('0'+(char) (temp));
333
temp=time_tmp.minute;
334
temp2=temp/10; temp=temp-temp2*10;
335
*to++= (char) ('0'+(char) (temp2));
336
*to++= (char) ('0'+(char) (temp));
338
temp=time_tmp.second;
339
temp2=temp/10; temp=temp-temp2*10;
340
*to++= (char) ('0'+(char) (temp2));
341
*to++= (char) ('0'+(char) (temp));
347
bool Field_timestamp::get_date(DRIZZLE_TIME *ltime, uint32_t fuzzydate)
350
THD *thd= table ? table->in_use : current_thd;
351
thd->time_zone_used= 1;
352
#ifdef WORDS_BIGENDIAN
353
if (table && table->s->db_low_byte_first)
359
{ /* Zero time is "000000" */
360
if (fuzzydate & TIME_NO_ZERO_DATE)
362
memset(ltime, 0, sizeof(*ltime));
366
thd->variables.time_zone->gmt_sec_to_TIME(ltime, (my_time_t)temp);
371
bool Field_timestamp::get_time(DRIZZLE_TIME *ltime)
373
return Field_timestamp::get_date(ltime,0);
377
bool Field_timestamp::send_binary(Protocol *protocol)
380
Field_timestamp::get_date(&tm, 0);
381
return protocol->store(&tm);
385
int Field_timestamp::cmp(const unsigned char *a_ptr, const unsigned char *b_ptr)
388
#ifdef WORDS_BIGENDIAN
389
if (table && table->s->db_low_byte_first)
400
return ((uint32_t) a < (uint32_t) b) ? -1 : ((uint32_t) a > (uint32_t) b) ? 1 : 0;
404
void Field_timestamp::sort_string(unsigned char *to,uint32_t length __attribute__((unused)))
406
#ifdef WORDS_BIGENDIAN
407
if (!table || !table->s->db_low_byte_first)
425
void Field_timestamp::sql_type(String &res) const
427
res.set_ascii(STRING_WITH_LEN("timestamp"));
431
void Field_timestamp::set_time()
433
THD *thd= table ? table->in_use : current_thd;
434
long tmp= (long) thd->query_start();
436
store_timestamp(tmp);