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 "timestamp.h"
28
TIMESTAMP type holds datetime values in range from 1970-01-01 00:00:01 UTC to
29
2038-01-01 00:00:00 UTC stored as number of seconds since Unix
32
Up to one of timestamps columns in the table can be automatically
33
set on row update and/or have NOW() as default value.
34
TABLE::timestamp_field points to Field object for such timestamp with
35
auto-set-on-update. TABLE::time_stamp holds offset in record + 1 for this
36
field, and is used by handler code which performs updates required.
38
Actually SQL-99 says that we should allow niladic functions (like NOW())
39
as defaults for any field. Current limitations (only NOW() and only
40
for one TIMESTAMP field) are because of restricted binary .frm format
41
and should go away in the future.
43
Also because of this limitation of binary .frm format we use 5 different
44
unireg_check values with TIMESTAMP field to distinguish various cases of
45
DEFAULT or ON UPDATE values. These values are:
47
TIMESTAMP_OLD_FIELD - old timestamp, if there was not any fields with
48
auto-set-on-update (or now() as default) in this table before, then this
49
field has NOW() as default and is updated when row changes, else it is
50
field which has 0 as default value and is not automatically updated.
51
TIMESTAMP_DN_FIELD - field with NOW() as default but not set on update
52
automatically (TIMESTAMP DEFAULT NOW())
53
TIMESTAMP_UN_FIELD - field which is set on update automatically but has not
54
NOW() as default (but it may has 0 or some other const timestamp as
55
default) (TIMESTAMP ON UPDATE NOW()).
56
TIMESTAMP_DNUN_FIELD - field which has now() as default and is auto-set on
57
update. (TIMESTAMP DEFAULT NOW() ON UPDATE NOW())
58
NONE - field which is not auto-set on update with some other than NOW()
59
default value (TIMESTAMP DEFAULT 0).
61
Note that TIMESTAMP_OLD_FIELDs are never created explicitly now, they are
62
left only for preserving ability to read old tables. Such fields replaced
63
with their newer analogs in CREATE TABLE and in SHOW CREATE TABLE. This is
64
because we want to prefer NONE unireg_check before TIMESTAMP_OLD_FIELD for
65
"TIMESTAMP DEFAULT 'Const'" field. (Old timestamps allowed such
66
specification too but ignored default value for first timestamp, which of
67
course is non-standard.) In most cases user won't notice any change, only
68
exception is different behavior of old/new timestamps during ALTER TABLE.
71
Field_timestamp::Field_timestamp(uchar *ptr_arg,
72
uint32 len_arg __attribute__((__unused__)),
73
uchar *null_ptr_arg, uchar null_bit_arg,
74
enum utype unireg_check_arg,
75
const char *field_name_arg,
78
:Field_str(ptr_arg, MAX_DATETIME_WIDTH, null_ptr_arg, null_bit_arg,
79
unireg_check_arg, field_name_arg, cs)
81
/* For 4.0 MYD and 4.0 InnoDB compatibility */
82
flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
83
if (!share->timestamp_field && unireg_check != NONE)
85
/* This timestamp has auto-update */
86
share->timestamp_field= this;
87
flags|= TIMESTAMP_FLAG;
88
if (unireg_check != TIMESTAMP_DN_FIELD)
89
flags|= ON_UPDATE_NOW_FLAG;
94
Field_timestamp::Field_timestamp(bool maybe_null_arg,
95
const char *field_name_arg,
97
:Field_str((uchar*) 0, MAX_DATETIME_WIDTH,
98
maybe_null_arg ? (uchar*) "": 0, 0,
99
NONE, field_name_arg, cs)
101
/* For 4.0 MYD and 4.0 InnoDB compatibility */
102
flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
103
if (unireg_check != TIMESTAMP_DN_FIELD)
104
flags|= ON_UPDATE_NOW_FLAG;
109
Get auto-set type for TIMESTAMP field.
111
Returns value indicating during which operations this TIMESTAMP field
112
should be auto-set to current timestamp.
114
timestamp_auto_set_type Field_timestamp::get_auto_set_type() const
116
switch (unireg_check)
118
case TIMESTAMP_DN_FIELD:
119
return TIMESTAMP_AUTO_SET_ON_INSERT;
120
case TIMESTAMP_UN_FIELD:
121
return TIMESTAMP_AUTO_SET_ON_UPDATE;
122
case TIMESTAMP_OLD_FIELD:
124
Although we can have several such columns in legacy tables this
125
function should be called only for first of them (i.e. the one
126
having auto-set property).
128
assert(table->timestamp_field == this);
130
case TIMESTAMP_DNUN_FIELD:
131
return TIMESTAMP_AUTO_SET_ON_BOTH;
134
Normally this function should not be called for TIMESTAMPs without
138
return TIMESTAMP_NO_AUTO_SET;
143
int Field_timestamp::store(const char *from,
145
CHARSET_INFO *cs __attribute__((__unused__)))
150
bool have_smth_to_conv;
151
bool in_dst_time_gap;
152
THD *thd= table ? table->in_use : current_thd;
154
/* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */
155
have_smth_to_conv= (str_to_datetime(from, len, &l_time, 1, &error) >
156
MYSQL_TIMESTAMP_ERROR);
158
if (error || !have_smth_to_conv)
161
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED,
162
from, len, MYSQL_TIMESTAMP_DATETIME, 1);
165
/* Only convert a correct date (not a zero date) */
166
if (have_smth_to_conv && l_time.month)
168
if (!(tmp= TIME_to_timestamp(thd, &l_time, &in_dst_time_gap)))
170
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
171
ER_WARN_DATA_OUT_OF_RANGE,
172
from, len, MYSQL_TIMESTAMP_DATETIME, !error);
175
else if (in_dst_time_gap)
177
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
178
ER_WARN_INVALID_TIMESTAMP,
179
from, len, MYSQL_TIMESTAMP_DATETIME, !error);
183
store_timestamp(tmp);
188
int Field_timestamp::store(double nr)
191
if (nr < 0 || nr > 99991231235959.0)
193
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
194
ER_WARN_DATA_OUT_OF_RANGE,
195
nr, MYSQL_TIMESTAMP_DATETIME);
196
nr= 0; // Avoid overflow on buff
199
error|= Field_timestamp::store((int64_t) rint(nr), false);
204
int Field_timestamp::store(int64_t nr,
205
bool unsigned_val __attribute__((__unused__)))
208
my_time_t timestamp= 0;
210
bool in_dst_time_gap;
211
THD *thd= table ? table->in_use : current_thd;
213
/* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */
214
int64_t tmp= number_to_datetime(nr, &l_time, (thd->variables.sql_mode &
216
MODE_NO_ZERO_IN_DATE, &error);
224
if (!(timestamp= TIME_to_timestamp(thd, &l_time, &in_dst_time_gap)))
226
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
227
ER_WARN_DATA_OUT_OF_RANGE,
228
nr, MYSQL_TIMESTAMP_DATETIME, 1);
233
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
234
ER_WARN_INVALID_TIMESTAMP,
235
nr, MYSQL_TIMESTAMP_DATETIME, 1);
239
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
241
nr, MYSQL_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)
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 * 10000000000LL + time_tmp.month * 100000000LL +
272
time_tmp.day * 1000000L + time_tmp.hour * 10000L +
273
time_tmp.minute * 100 + time_tmp.second;
277
String *Field_timestamp::val_str(String *val_buffer, String *val_ptr)
281
THD *thd= table ? table->in_use : current_thd;
284
val_buffer->alloc(field_length+1);
285
to= (char*) val_buffer->ptr();
286
val_buffer->length(field_length);
288
thd->time_zone_used= 1;
289
#ifdef WORDS_BIGENDIAN
290
if (table && table->s->db_low_byte_first)
297
{ /* Zero time is "000000" */
298
val_ptr->set(STRING_WITH_LEN("0000-00-00 00:00:00"), &my_charset_bin);
301
val_buffer->set_charset(&my_charset_bin); // Safety
303
thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp,(my_time_t)temp);
305
temp= time_tmp.year % 100;
306
if (temp < YY_PART_YEAR - 1)
316
temp2=temp/10; temp=temp-temp2*10;
317
*to++= (char) ('0'+(char) (temp2));
318
*to++= (char) ('0'+(char) (temp));
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));
335
temp=time_tmp.minute;
336
temp2=temp/10; temp=temp-temp2*10;
337
*to++= (char) ('0'+(char) (temp2));
338
*to++= (char) ('0'+(char) (temp));
340
temp=time_tmp.second;
341
temp2=temp/10; temp=temp-temp2*10;
342
*to++= (char) ('0'+(char) (temp2));
343
*to++= (char) ('0'+(char) (temp));
349
bool Field_timestamp::get_date(MYSQL_TIME *ltime, uint fuzzydate)
352
THD *thd= table ? table->in_use : current_thd;
353
thd->time_zone_used= 1;
354
#ifdef WORDS_BIGENDIAN
355
if (table && table->s->db_low_byte_first)
361
{ /* Zero time is "000000" */
362
if (fuzzydate & TIME_NO_ZERO_DATE)
364
bzero((char*) ltime,sizeof(*ltime));
368
thd->variables.time_zone->gmt_sec_to_TIME(ltime, (my_time_t)temp);
373
bool Field_timestamp::get_time(MYSQL_TIME *ltime)
375
return Field_timestamp::get_date(ltime,0);
379
bool Field_timestamp::send_binary(Protocol *protocol)
382
Field_timestamp::get_date(&tm, 0);
383
return protocol->store(&tm);
387
int Field_timestamp::cmp(const uchar *a_ptr, const uchar *b_ptr)
390
#ifdef WORDS_BIGENDIAN
391
if (table && table->s->db_low_byte_first)
402
return ((uint32) a < (uint32) b) ? -1 : ((uint32) a > (uint32) b) ? 1 : 0;
406
void Field_timestamp::sort_string(uchar *to,uint length __attribute__((unused)))
408
#ifdef WORDS_BIGENDIAN
409
if (!table || !table->s->db_low_byte_first)
427
void Field_timestamp::sql_type(String &res) const
429
res.set_ascii(STRING_WITH_LEN("timestamp"));
433
void Field_timestamp::set_time()
435
THD *thd= table ? table->in_use : current_thd;
436
long tmp= (long) thd->query_start();
438
store_timestamp(tmp);