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
22
#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>
29
#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
33
TIMESTAMP type holds datetime values in range from 1970-01-01 00:00:01 UTC to
34
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
37
Up to one of timestamps columns in the table can be automatically
34
38
set on row update and/or have NOW() as default value.
35
TABLE::timestamp_field points to Field object for such timestamp with
39
TABLE::timestamp_field points to Field object for such timestamp with
36
40
auto-set-on-update. TABLE::time_stamp holds offset in record + 1 for this
37
41
field, and is used by handler code which performs updates required.
39
43
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
44
as defaults for any field. Current limitations (only NOW() and only
45
for one TIMESTAMP field) are because of restricted binary .frm format
42
46
and should go away in the future.
44
48
Also because of this limitation of binary .frm format we use 5 different
45
49
unireg_check values with TIMESTAMP field to distinguish various cases of
46
50
DEFAULT or ON UPDATE values. These values are:
48
52
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
53
auto-set-on-update (or now() as default) in this table before, then this
54
field has NOW() as default and is updated when row changes, else it is
51
55
field which has 0 as default value and is not automatically updated.
52
56
TIMESTAMP_DN_FIELD - field with NOW() as default but not set on update
53
57
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
58
TIMESTAMP_UN_FIELD - field which is set on update automatically but has not
59
NOW() as default (but it may has 0 or some other const timestamp as
56
60
default) (TIMESTAMP ON UPDATE NOW()).
57
TIMESTAMP_DNUN_FIELD - field which has now() as default and is auto-set on
61
TIMESTAMP_DNUN_FIELD - field which has now() as default and is auto-set on
58
62
update. (TIMESTAMP DEFAULT NOW() ON UPDATE NOW())
59
NONE - field which is not auto-set on update with some other than NOW()
63
NONE - field which is not auto-set on update with some other than NOW()
60
64
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
66
Note that TIMESTAMP_OLD_FIELDs are never created explicitly now, they are
67
left only for preserving ability to read old tables. Such fields replaced
68
with their newer analogs in CREATE TABLE and in SHOW CREATE TABLE. This is
69
because we want to prefer NONE unireg_check before TIMESTAMP_OLD_FIELD for
70
"TIMESTAMP DEFAULT 'Const'" field. (Old timestamps allowed such
71
specification too but ignored default value for first timestamp, which of
68
72
course is non-standard.) In most cases user won't notice any change, only
69
73
exception is different behavior of old/new timestamps during ALTER TABLE.
72
75
Field_timestamp::Field_timestamp(unsigned char *ptr_arg,
73
uint32_t len_arg __attribute__((unused)),
74
77
unsigned char *null_ptr_arg, unsigned char null_bit_arg,
75
78
enum utype unireg_check_arg,
76
79
const char *field_name_arg,
78
81
const CHARSET_INFO * const cs)
79
82
:Field_str(ptr_arg, MAX_DATETIME_WIDTH, null_ptr_arg, null_bit_arg,
80
83
unireg_check_arg, field_name_arg, cs)
144
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);
146
const CHARSET_INFO * const )
148
drizzled::Timestamp temporal;
150
if (! temporal.from_string(from, (size_t) len))
152
my_error(ER_INVALID_UNIX_TIMESTAMP_VALUE, MYF(ME_FATALERROR), from);
157
temporal.to_time_t(&tmp);
159
store_timestamp(tmp);
163
int Field_timestamp::store(double from)
165
if (from < 0 || from > 99991231235959.0)
167
/* Convert the double to a string using stringstream */
168
std::stringstream ss;
170
ss.precision(18); /* 18 places should be fine for error display of double input. */
171
ss << from; ss >> tmp;
173
my_error(ER_INVALID_UNIX_TIMESTAMP_VALUE, MYF(ME_FATALERROR), tmp.c_str());
176
return Field_timestamp::store((int64_t) rint(from), false);
179
int Field_timestamp::store(int64_t from, bool)
182
* Try to create a DateTime from the supplied integer. Throw an error
183
* if unable to create a valid DateTime.
185
drizzled::Timestamp temporal;
186
if (! temporal.from_int64_t(from))
188
/* Convert the integer to a string using stringstream */
189
std::stringstream ss;
191
ss << from; ss >> tmp;
193
my_error(ER_INVALID_UNIX_TIMESTAMP_VALUE, MYF(ME_FATALERROR), tmp.c_str());
198
temporal.to_time_t(&tmp);
200
store_timestamp(tmp);
247
204
double Field_timestamp::val_real(void)
252
209
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
213
#ifdef WORDS_BIGENDIAN
260
214
if (table && table->s->db_low_byte_first)
215
temp= uint4korr(ptr);
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;
220
drizzled::Timestamp temporal;
221
(void) temporal.from_time_t((time_t) temp);
223
/* We must convert into a "timestamp-formatted integer" ... */
225
temporal.to_int64_t(&result);
278
String *Field_timestamp::val_str(String *val_buffer, String *val_ptr)
229
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);
234
val_buffer->alloc(field_length + 1);
235
to= (char *) val_buffer->ptr();
289
thd->time_zone_used= 1;
290
237
#ifdef WORDS_BIGENDIAN
291
238
if (table && table->s->db_low_byte_first)
239
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));
244
val_buffer->set_charset(&my_charset_bin); /* Safety */
246
drizzled::Timestamp temporal;
247
(void) temporal.from_time_t((time_t) temp);
250
temporal.to_string(to, &to_len);
251
val_buffer->length((uint32_t) to_len);
346
252
return val_buffer;
350
bool Field_timestamp::get_date(DRIZZLE_TIME *ltime, uint32_t fuzzydate)
255
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
259
#ifdef WORDS_BIGENDIAN
356
260
if (table && table->s->db_low_byte_first)
261
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);
266
memset(ltime, 0, sizeof(*ltime));
268
drizzled::Timestamp temporal;
269
(void) temporal.from_time_t((time_t) temp);
271
/* @TODO Goodbye the below code when DRIZZLE_TIME is finally gone.. */
273
ltime->time_type= DRIZZLE_TIMESTAMP_DATETIME;
274
ltime->year= temporal.years();
275
ltime->month= temporal.months();
276
ltime->day= temporal.days();
277
ltime->hour= temporal.hours();
278
ltime->minute= temporal.minutes();
279
ltime->second= temporal.seconds();
428
328
void Field_timestamp::sql_type(String &res) const
430
330
res.set_ascii(STRING_WITH_LEN("timestamp"));
434
333
void Field_timestamp::set_time()
436
THD *thd= table ? table->in_use : current_thd;
437
long tmp= (long) thd->query_start();
335
Session *session= table ? table->in_use : current_session;
336
long tmp= (long) session->query_start();
439
338
store_timestamp(tmp);
341
void Field_timestamp::set_default()
343
if (table->timestamp_field == this &&
344
unireg_check != TIMESTAMP_UN_FIELD)
347
Field::set_default();
350
long Field_timestamp::get_timestamp(bool *null_value)
352
if ((*null_value= is_null()))
354
#ifdef WORDS_BIGENDIAN
355
if (table && table->s->db_low_byte_first)
356
return sint4korr(ptr);
363
void Field_timestamp::store_timestamp(time_t timestamp)
365
#ifdef WORDS_BIGENDIAN
366
if (table && table->s->db_low_byte_first)
368
int4store(ptr,timestamp);
372
longstore(ptr,(uint32_t) timestamp);