18
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
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>
33
#include "drizzled/temporal.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
39
TIMESTAMP type holds datetime values in range from 1970-01-01 00:00:01 UTC to
40
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
43
Up to one of timestamps columns in the table can be automatically
34
44
set on row update and/or have NOW() as default value.
35
TABLE::timestamp_field points to Field object for such timestamp with
45
TABLE::timestamp_field points to Field object for such timestamp with
36
46
auto-set-on-update. TABLE::time_stamp holds offset in record + 1 for this
37
47
field, and is used by handler code which performs updates required.
39
49
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
50
as defaults for any field. Current limitations (only NOW() and only
51
for one TIMESTAMP field) are because of restricted binary .frm format
42
52
and should go away in the future.
44
54
Also because of this limitation of binary .frm format we use 5 different
45
55
unireg_check values with TIMESTAMP field to distinguish various cases of
46
56
DEFAULT or ON UPDATE values. These values are:
48
58
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
59
auto-set-on-update (or now() as default) in this table before, then this
60
field has NOW() as default and is updated when row changes, else it is
51
61
field which has 0 as default value and is not automatically updated.
52
62
TIMESTAMP_DN_FIELD - field with NOW() as default but not set on update
53
63
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
64
TIMESTAMP_UN_FIELD - field which is set on update automatically but has not
65
NOW() as default (but it may has 0 or some other const timestamp as
56
66
default) (TIMESTAMP ON UPDATE NOW()).
57
TIMESTAMP_DNUN_FIELD - field which has now() as default and is auto-set on
67
TIMESTAMP_DNUN_FIELD - field which has now() as default and is auto-set on
58
68
update. (TIMESTAMP DEFAULT NOW() ON UPDATE NOW())
59
NONE - field which is not auto-set on update with some other than NOW()
69
NONE - field which is not auto-set on update with some other than NOW()
60
70
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
72
Note that TIMESTAMP_OLD_FIELDs are never created explicitly now, they are
73
left only for preserving ability to read old tables. Such fields replaced
74
with their newer analogs in CREATE TABLE and in SHOW CREATE TABLE. This is
75
because we want to prefer NONE unireg_check before TIMESTAMP_OLD_FIELD for
76
"TIMESTAMP DEFAULT 'Const'" field. (Old timestamps allowed such
77
specification too but ignored default value for first timestamp, which of
68
78
course is non-standard.) In most cases user won't notice any change, only
69
79
exception is different behavior of old/new timestamps during ALTER TABLE.
72
Field_timestamp::Field_timestamp(uchar *ptr_arg,
73
uint32_t len_arg __attribute__((unused)),
74
uchar *null_ptr_arg, uchar null_bit_arg,
81
Field_timestamp::Field_timestamp(unsigned char *ptr_arg,
83
unsigned char *null_ptr_arg,
84
unsigned char null_bit_arg,
75
85
enum utype unireg_check_arg,
76
86
const char *field_name_arg,
78
88
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)
90
DateTime::MAX_STRING_LENGTH - 1 /* no \0 */,
82
96
/* For 4.0 MYD and 4.0 InnoDB compatibility */
83
97
flags|= UNSIGNED_FLAG;
84
if (!share->timestamp_field && unireg_check != NONE)
98
unireg_check= unireg_check_arg;
99
if (! share->timestamp_field && unireg_check != NONE)
86
101
/* This timestamp has auto-update */
87
102
share->timestamp_field= this;
95
109
Field_timestamp::Field_timestamp(bool maybe_null_arg,
96
110
const char *field_name_arg,
97
111
const CHARSET_INFO * const cs)
98
:Field_str((uchar*) 0, MAX_DATETIME_WIDTH,
99
maybe_null_arg ? (uchar*) "": 0, 0,
100
NONE, field_name_arg, cs)
112
:Field_str((unsigned char*) NULL,
113
DateTime::MAX_STRING_LENGTH - 1 /* no \0 */,
114
maybe_null_arg ? (unsigned char*) "": 0,
102
119
/* For 4.0 MYD and 4.0 InnoDB compatibility */
103
120
flags|= UNSIGNED_FLAG;
104
if (unireg_check != TIMESTAMP_DN_FIELD)
105
flags|= ON_UPDATE_NOW_FLAG;
121
if (unireg_check != TIMESTAMP_DN_FIELD)
122
flags|= ON_UPDATE_NOW_FLAG;
110
126
Get auto-set type for TIMESTAMP field.
144
159
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 &
217
MODE_NO_ZERO_IN_DATE, &error);
225
if (!(timestamp= TIME_to_timestamp(thd, &l_time, &in_dst_time_gap)))
227
set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
228
ER_WARN_DATA_OUT_OF_RANGE,
229
nr, DRIZZLE_TIMESTAMP_DATETIME, 1);
234
set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
235
ER_WARN_INVALID_TIMESTAMP,
236
nr, DRIZZLE_TIMESTAMP_DATETIME, 1);
240
set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
241
ER_WARN_DATA_TRUNCATED,
242
nr, DRIZZLE_TIMESTAMP_DATETIME, 1);
244
store_timestamp(timestamp);
161
const CHARSET_INFO * const )
165
ASSERT_COLUMN_MARKED_FOR_WRITE;
167
if (! temporal.from_string(from, (size_t) len))
169
my_error(ER_INVALID_UNIX_TIMESTAMP_VALUE, MYF(ME_FATALERROR), from);
174
temporal.to_time_t(&tmp);
176
store_timestamp(tmp);
180
int Field_timestamp::store(double from)
182
ASSERT_COLUMN_MARKED_FOR_WRITE;
184
if (from < 0 || from > 99991231235959.0)
186
/* Convert the double to a string using stringstream */
187
std::stringstream ss;
189
ss.precision(18); /* 18 places should be fine for error display of double input. */
190
ss << from; ss >> tmp;
192
my_error(ER_INVALID_UNIX_TIMESTAMP_VALUE, MYF(ME_FATALERROR), tmp.c_str());
195
return Field_timestamp::store((int64_t) rint(from), false);
198
int Field_timestamp::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 stringstream */
210
std::stringstream ss;
212
ss << from; ss >> tmp;
214
my_error(ER_INVALID_UNIX_TIMESTAMP_VALUE, MYF(ME_FATALERROR), tmp.c_str());
219
temporal.to_time_t(&tmp);
221
store_timestamp(tmp);
248
225
double Field_timestamp::val_real(void)
253
230
int64_t Field_timestamp::val_int(void)
256
DRIZZLE_TIME time_tmp;
257
THD *thd= table ? table->in_use : current_thd;
259
thd->time_zone_used= 1;
234
ASSERT_COLUMN_MARKED_FOR_READ;
260
236
#ifdef WORDS_BIGENDIAN
261
237
if (table && table->s->db_low_byte_first)
238
temp= uint4korr(ptr);
267
if (temp == 0L) // No time
268
return(0); /* purecov: inspected */
270
thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp, (my_time_t)temp);
272
return time_tmp.year * 10000000000LL + time_tmp.month * 100000000LL +
273
time_tmp.day * 1000000L + time_tmp.hour * 10000L +
274
time_tmp.minute * 100 + time_tmp.second;
244
(void) temporal.from_time_t((time_t) temp);
246
/* We must convert into a "timestamp-formatted integer" ... */
248
temporal.to_int64_t(&result);
278
String *Field_timestamp::val_str(String *val_buffer, String *val_ptr)
252
String *Field_timestamp::val_str(String *val_buffer, String *)
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;
256
int to_len= field_length + 1;
258
val_buffer->alloc(to_len);
259
to= (char *) val_buffer->ptr();
290
261
#ifdef WORDS_BIGENDIAN
291
262
if (table && table->s->db_low_byte_first)
263
temp= uint4korr(ptr);
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));
268
val_buffer->set_charset(&my_charset_bin); /* Safety */
271
(void) temporal.from_time_t((time_t) temp);
274
rlen= temporal.to_string(to, to_len);
275
assert(rlen < to_len);
277
val_buffer->length(rlen);
346
278
return val_buffer;
350
bool Field_timestamp::get_date(DRIZZLE_TIME *ltime, uint fuzzydate)
281
bool Field_timestamp::get_date(DRIZZLE_TIME *ltime, uint32_t)
353
THD *thd= table ? table->in_use : current_thd;
354
thd->time_zone_used= 1;
355
285
#ifdef WORDS_BIGENDIAN
356
286
if (table && table->s->db_low_byte_first)
287
temp= uint4korr(ptr);
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);
292
memset(ltime, 0, sizeof(*ltime));
295
(void) temporal.from_time_t((time_t) temp);
297
/* @TODO Goodbye the below code when DRIZZLE_TIME is finally gone.. */
299
ltime->time_type= DRIZZLE_TIMESTAMP_DATETIME;
300
ltime->year= temporal.years();
301
ltime->month= temporal.months();
302
ltime->day= temporal.days();
303
ltime->hour= temporal.hours();
304
ltime->minute= temporal.minutes();
305
ltime->second= temporal.seconds();
428
354
void Field_timestamp::sql_type(String &res) const
430
356
res.set_ascii(STRING_WITH_LEN("timestamp"));
434
359
void Field_timestamp::set_time()
436
THD *thd= table ? table->in_use : current_thd;
437
long tmp= (long) thd->query_start();
361
Session *session= table ? table->in_use : current_session;
362
long tmp= (long) session->query_start();
439
364
store_timestamp(tmp);
367
void Field_timestamp::set_default()
369
if (table->timestamp_field == this &&
370
unireg_check != TIMESTAMP_UN_FIELD)
373
Field::set_default();
376
long Field_timestamp::get_timestamp(bool *null_value)
378
if ((*null_value= is_null()))
380
#ifdef WORDS_BIGENDIAN
381
if (table && table->s->db_low_byte_first)
382
return sint4korr(ptr);
389
void Field_timestamp::store_timestamp(time_t timestamp)
391
#ifdef WORDS_BIGENDIAN
392
if (table && table->s->db_low_byte_first)
394
int4store(ptr,timestamp);
398
longstore(ptr,(uint32_t) timestamp);
401
} /* namespace drizzled */