1
/* -*- mode: c++ c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2008 Sun Microsystems
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>
24
#include <drizzled/error.h>
25
#include <drizzled/tztime.h>
26
#include <drizzled/table.h>
27
#include <drizzled/session.h>
30
#if defined(CMATH_NAMESPACE)
31
using namespace CMATH_NAMESPACE;
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
39
Up to one of timestamps columns in the table can be automatically
40
set on row update and/or have NOW() as default value.
41
TABLE::timestamp_field points to Field object for such timestamp with
42
auto-set-on-update. TABLE::time_stamp holds offset in record + 1 for this
43
field, and is used by handler code which performs updates required.
45
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
48
and should go away in the future.
50
Also because of this limitation of binary .frm format we use 5 different
51
unireg_check values with TIMESTAMP field to distinguish various cases of
52
DEFAULT or ON UPDATE values. These values are:
54
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
57
field which has 0 as default value and is not automatically updated.
58
TIMESTAMP_DN_FIELD - field with NOW() as default but not set on update
59
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
62
default) (TIMESTAMP ON UPDATE NOW()).
63
TIMESTAMP_DNUN_FIELD - field which has now() as default and is auto-set on
64
update. (TIMESTAMP DEFAULT NOW() ON UPDATE NOW())
65
NONE - field which is not auto-set on update with some other than NOW()
66
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
74
course is non-standard.) In most cases user won't notice any change, only
75
exception is different behavior of old/new timestamps during ALTER TABLE.
78
Field_timestamp::Field_timestamp(unsigned char *ptr_arg,
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)
88
/* For 4.0 MYD and 4.0 InnoDB compatibility */
89
flags|= UNSIGNED_FLAG;
90
if (!share->timestamp_field && unireg_check != NONE)
92
/* This timestamp has auto-update */
93
share->timestamp_field= this;
94
flags|= TIMESTAMP_FLAG;
95
if (unireg_check != TIMESTAMP_DN_FIELD)
96
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)
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;
116
Get auto-set type for TIMESTAMP field.
118
Returns value indicating during which operations this TIMESTAMP field
119
should be auto-set to current timestamp.
121
timestamp_auto_set_type Field_timestamp::get_auto_set_type() const
123
switch (unireg_check)
125
case TIMESTAMP_DN_FIELD:
126
return TIMESTAMP_AUTO_SET_ON_INSERT;
127
case TIMESTAMP_UN_FIELD:
128
return TIMESTAMP_AUTO_SET_ON_UPDATE;
129
case TIMESTAMP_OLD_FIELD:
131
Although we can have several such columns in legacy tables this
132
function should be called only for first of them (i.e. the one
133
having auto-set property).
135
assert(table->timestamp_field == this);
137
case TIMESTAMP_DNUN_FIELD:
138
return TIMESTAMP_AUTO_SET_ON_BOTH;
141
Normally this function should not be called for TIMESTAMPs without
145
return TIMESTAMP_NO_AUTO_SET;
150
int Field_timestamp::store(const char *from,
152
const CHARSET_INFO * const )
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,
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, (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;
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,(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));
354
bool Field_timestamp::get_date(DRIZZLE_TIME *ltime, uint32_t fuzzydate)
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, (time_t)temp);
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 )
412
#ifdef WORDS_BIGENDIAN
413
if (!table || !table->s->db_low_byte_first)
431
void Field_timestamp::sql_type(String &res) const
433
res.set_ascii(STRING_WITH_LEN("timestamp"));
437
void Field_timestamp::set_time()
439
Session *session= table ? table->in_use : current_session;
440
long tmp= (long) session->query_start();
442
store_timestamp(tmp);
446
void Field_timestamp::set_default()
448
if (table->timestamp_field == this &&
449
unireg_check != TIMESTAMP_UN_FIELD)
452
Field::set_default();
455
long Field_timestamp::get_timestamp(bool *null_value)
457
if ((*null_value= is_null()))
459
#ifdef WORDS_BIGENDIAN
460
if (table && table->s->db_low_byte_first)
461
return sint4korr(ptr);
469
void Field_timestamp::store_timestamp(time_t timestamp)
471
#ifdef WORDS_BIGENDIAN
472
if (table && table->s->db_low_byte_first)
474
int4store(ptr,timestamp);
478
longstore(ptr,(uint32_t) timestamp);