18
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22
#include <boost/lexical_cast.hpp>
23
#include <drizzled/field/datetime.h>
24
#include <drizzled/error.h>
25
#include <drizzled/table.h>
26
#include <drizzled/temporal.h>
27
#include <drizzled/session.h>
21
#ifdef USE_PRAGMA_IMPLEMENTATION
22
#pragma implementation // gcc: Class implementation
38
27
/****************************************************************************
40
29
** In string context: YYYY-MM-DD HH:MM:DD
41
30
** In number context: YYYYMMDDHHMMDD
31
** Stored as a 8 byte unsigned int. Should sometimes be change to a 6 byte int.
42
32
****************************************************************************/
44
34
int Field_datetime::store(const char *from,
46
const CHARSET_INFO * const )
48
ASSERT_COLUMN_MARKED_FOR_WRITE;
50
* Try to create a DateTime from the supplied string. Throw an error
51
* if unable to create a valid DateTime.
54
if (! temporal.from_string(from, (size_t) len))
56
my_error(ER_INVALID_DATETIME_VALUE, MYF(ME_FATALERROR), from);
59
/* Create the stored integer format. @TODO This should go away. Should be up to engine... */
61
temporal.to_int64_t(&int_value);
63
#ifdef WORDS_BIGENDIAN
64
if (getTable() && getTable()->isDatabaseLowByteFirst())
66
int8store(ptr, int_value);
70
int64_tstore(ptr, int_value);
74
int Field_datetime::store(double from)
76
ASSERT_COLUMN_MARKED_FOR_WRITE;
77
if (from < 0.0 || from > 99991231235959.0)
79
/* Convert the double to a string using boost::lexical_cast */
80
std::string tmp(boost::lexical_cast<std::string>(from));
82
my_error(ER_INVALID_DATETIME_VALUE, MYF(ME_FATALERROR), tmp.c_str());
85
return Field_datetime::store((int64_t) rint(from), false);
88
int Field_datetime::store(int64_t from, bool)
90
ASSERT_COLUMN_MARKED_FOR_WRITE;
92
* Try to create a DateTime from the supplied integer. Throw an error
93
* if unable to create a valid DateTime.
96
if (! temporal.from_int64_t(from))
98
/* Convert the integer to a string using boost::lexical_cast */
99
std::string tmp(boost::lexical_cast<std::string>(from));
101
my_error(ER_INVALID_DATETIME_VALUE, MYF(ME_FATALERROR), tmp.c_str());
106
* Because "from" may be a silly MySQL-like "datetime number" (like, oh, 101)
107
* we must here get the value of the DateTime as its *real* int64_t, after
108
* the conversion above has been done...yuck. God, save us.
111
temporal.to_int64_t(&int_value);
113
#ifdef WORDS_BIGENDIAN
114
if (getTable() && getTable()->isDatabaseLowByteFirst())
116
int8store(ptr, int_value);
120
int64_tstore(ptr, int_value);
124
int Field_datetime::store_time(type::Time <ime, type::timestamp_t)
128
temporal.set_years(ltime.year);
129
temporal.set_months(ltime.month);
130
temporal.set_days(ltime.day);
131
temporal.set_hours(ltime.hour);
132
temporal.set_minutes(ltime.minute);
133
temporal.set_seconds(ltime.second);
135
if (! temporal.is_valid())
137
char tmp_string[type::Time::MAX_STRING_LENGTH];
138
size_t tmp_string_len;
140
tmp_string_len= temporal.to_string(tmp_string, type::Time::MAX_STRING_LENGTH);
141
assert(tmp_string_len < type::Time::MAX_STRING_LENGTH);
142
my_error(ER_INVALID_DATETIME_VALUE, MYF(ME_FATALERROR), tmp_string);
147
temporal.to_int64_t(&int_value);
149
#ifdef WORDS_BIGENDIAN
150
if (getTable() && getTable()->isDatabaseLowByteFirst())
152
int8store(ptr, int_value);
156
int64_tstore(ptr, int_value);
161
double Field_datetime::val_real(void) const
36
CHARSET_INFO *cs __attribute__((__unused__)))
41
enum enum_mysql_timestamp_type func_res;
42
THD *thd= table ? table->in_use : current_thd;
44
func_res= str_to_datetime(from, len, &time_tmp,
46
(thd->variables.sql_mode &
47
(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
48
MODE_INVALID_DATES))),
50
if ((int) func_res > (int) MYSQL_TIMESTAMP_ERROR)
51
tmp= TIME_to_uint64_t_datetime(&time_tmp);
53
error= 1; // Fix if invalid zero date
56
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
57
ER_WARN_DATA_OUT_OF_RANGE,
58
from, len, MYSQL_TIMESTAMP_DATETIME, 1);
60
#ifdef WORDS_BIGENDIAN
61
if (table && table->s->db_low_byte_first)
67
int64_tstore(ptr,tmp);
72
int Field_datetime::store(double nr)
75
if (nr < 0.0 || nr > 99991231235959.0)
77
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
78
ER_WARN_DATA_OUT_OF_RANGE,
79
nr, MYSQL_TIMESTAMP_DATETIME);
83
error|= Field_datetime::store((int64_t) rint(nr), false);
88
int Field_datetime::store(int64_t nr,
89
bool unsigned_val __attribute__((__unused__)))
93
int64_t initial_nr= nr;
94
THD *thd= table ? table->in_use : current_thd;
96
nr= number_to_datetime(nr, ¬_used, (TIME_FUZZY_DATE |
97
(thd->variables.sql_mode &
98
(MODE_NO_ZERO_IN_DATE |
100
MODE_INVALID_DATES))), &error);
109
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
110
error == 2 ? ER_WARN_DATA_OUT_OF_RANGE :
111
WARN_DATA_TRUNCATED, initial_nr,
112
MYSQL_TIMESTAMP_DATETIME, 1);
114
#ifdef WORDS_BIGENDIAN
115
if (table && table->s->db_low_byte_first)
121
int64_tstore(ptr,nr);
126
int Field_datetime::store_time(MYSQL_TIME *ltime,timestamp_type time_type)
131
We don't perform range checking here since values stored in TIME
132
structure always fit into DATETIME range.
134
if (time_type == MYSQL_TIMESTAMP_DATE ||
135
time_type == MYSQL_TIMESTAMP_DATETIME)
137
tmp=((ltime->year*10000L+ltime->month*100+ltime->day)*1000000LL+
138
(ltime->hour*10000L+ltime->minute*100+ltime->second));
139
if (check_date(ltime, tmp != 0,
141
(current_thd->variables.sql_mode &
142
(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
143
MODE_INVALID_DATES))), &error))
145
char buff[MAX_DATE_STRING_REP_LENGTH];
146
String str(buff, sizeof(buff), &my_charset_latin1);
147
make_datetime((DATE_TIME_FORMAT *) 0, ltime, &str);
148
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED,
149
str.ptr(), str.length(), MYSQL_TIMESTAMP_DATETIME,1);
156
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
158
#ifdef WORDS_BIGENDIAN
159
if (table && table->s->db_low_byte_first)
165
int64_tstore(ptr,tmp);
169
bool Field_datetime::send_binary(Protocol *protocol)
172
Field_datetime::get_date(&tm, TIME_FUZZY_DATE);
173
return protocol->store(&tm);
177
double Field_datetime::val_real(void)
163
179
return (double) Field_datetime::val_int();
166
int64_t Field_datetime::val_int(void) const
182
int64_t Field_datetime::val_int(void)
170
ASSERT_COLUMN_MARKED_FOR_READ;
172
185
#ifdef WORDS_BIGENDIAN
173
if (getTable() && getTable()->isDatabaseLowByteFirst())
186
if (table && table->s->db_low_byte_first)
174
187
j=sint8korr(ptr);
182
String *Field_datetime::val_str(String *val_buffer, String *) const
195
String *Field_datetime::val_str(String *val_buffer,
196
String *val_ptr __attribute__((unused)))
184
val_buffer->alloc(DateTime::MAX_STRING_LENGTH);
185
val_buffer->length(DateTime::MAX_STRING_LENGTH);
188
ASSERT_COLUMN_MARKED_FOR_READ;
198
val_buffer->alloc(field_length);
199
val_buffer->length(field_length);
190
205
#ifdef WORDS_BIGENDIAN
191
if (getTable() && getTable()->isDatabaseLowByteFirst())
206
if (table && table->s->db_low_byte_first)
192
207
tmp=sint8korr(ptr);
195
210
int64_tget(tmp,ptr);
199
/* TODO: add an assert that this succeeds
200
* currently fails due to bug in allowing
201
* ALTER TABLE to add a datetime column that's
202
* not null without a default value.
204
dt.from_int64_t(tmp, false); /* NOTE: this does *NOT* attempt convertion
205
from formats such as 20090101 as
206
the stored value has already been
211
rlen= dt.to_string((char*)val_buffer->ptr(), DateTime::MAX_STRING_LENGTH);
212
assert((rlen+1) < DateTime::MAX_STRING_LENGTH);
214
val_buffer->length(rlen);
213
Avoid problem with slow int64_t arithmetic and sprintf
216
part1=(long) (tmp/1000000LL);
217
part2=(long) (tmp - (uint64_t) part1*1000000LL);
219
pos=(char*) val_buffer->ptr() + MAX_DATETIME_WIDTH;
221
*pos--= (char) ('0'+(char) (part2%10)); part2/=10;
222
*pos--= (char) ('0'+(char) (part2%10)); part3= (int) (part2 / 10);
224
*pos--= (char) ('0'+(char) (part3%10)); part3/=10;
225
*pos--= (char) ('0'+(char) (part3%10)); part3/=10;
227
*pos--= (char) ('0'+(char) (part3%10)); part3/=10;
228
*pos--= (char) ('0'+(char) part3);
230
*pos--= (char) ('0'+(char) (part1%10)); part1/=10;
231
*pos--= (char) ('0'+(char) (part1%10)); part1/=10;
233
*pos--= (char) ('0'+(char) (part1%10)); part1/=10;
234
*pos--= (char) ('0'+(char) (part1%10)); part3= (int) (part1/10);
236
*pos--= (char) ('0'+(char) (part3%10)); part3/=10;
237
*pos--= (char) ('0'+(char) (part3%10)); part3/=10;
238
*pos--= (char) ('0'+(char) (part3%10)); part3/=10;
239
*pos=(char) ('0'+(char) part3);
216
240
return val_buffer;
219
bool Field_datetime::get_date(type::Time <ime, uint32_t fuzzydate) const
243
bool Field_datetime::get_date(MYSQL_TIME *ltime, uint fuzzydate)
221
245
int64_t tmp=Field_datetime::val_int();
222
uint32_t part1,part2;
223
part1=(uint32_t) (tmp/INT64_C(1000000));
224
part2=(uint32_t) (tmp - (uint64_t) part1*INT64_C(1000000));
226
ltime.time_type= type::DRIZZLE_TIMESTAMP_DATETIME;
228
ltime.second_part= 0;
229
ltime.second= (int) (part2%100);
230
ltime.minute= (int) (part2/100%100);
231
ltime.hour= (int) (part2/10000);
232
ltime.day= (int) (part1%100);
233
ltime.month= (int) (part1/100%100);
234
ltime.year= (int) (part1/10000);
236
return (!(fuzzydate & TIME_FUZZY_DATE) && (!ltime.month || !ltime.day)) ? 1 : 0;
247
part1=(uint32) (tmp/1000000LL);
248
part2=(uint32) (tmp - (uint64_t) part1*1000000LL);
250
ltime->time_type= MYSQL_TIMESTAMP_DATETIME;
252
ltime->second_part= 0;
253
ltime->second= (int) (part2%100);
254
ltime->minute= (int) (part2/100%100);
255
ltime->hour= (int) (part2/10000);
256
ltime->day= (int) (part1%100);
257
ltime->month= (int) (part1/100%100);
258
ltime->year= (int) (part1/10000);
259
return (!(fuzzydate & TIME_FUZZY_DATE) && (!ltime->month || !ltime->day)) ? 1 : 0;
239
bool Field_datetime::get_time(type::Time <ime) const
262
bool Field_datetime::get_time(MYSQL_TIME *ltime)
241
264
return Field_datetime::get_date(ltime,0);
244
int Field_datetime::cmp(const unsigned char *a_ptr, const unsigned char *b_ptr)
267
int Field_datetime::cmp(const uchar *a_ptr, const uchar *b_ptr)
247
270
#ifdef WORDS_BIGENDIAN
248
if (getTable() && getTable()->isDatabaseLowByteFirst())
271
if (table && table->s->db_low_byte_first)
250
273
a=sint8korr(a_ptr);
251
274
b=sint8korr(b_ptr);