summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2011-06-06 20:28:15 +0200
committerSergei Golubchik <sergii@pisem.net>2011-06-06 20:28:15 +0200
commit4d128777dde904c5f0adab9b093e854c9c580d41 (patch)
tree36875e84e65be596def46c5d7ce621e60abcbdae /sql
parentc1a92f9caeb368021d5ffbe0df237ded29692c1a (diff)
downloadmariadb-git-4d128777dde904c5f0adab9b093e854c9c580d41.tar.gz
revert a suggested "optimization" that introduced a bug
compilation error in mysys/my_getsystime.c fixed some redundant code removed sec_to_time, time_to_sec, from_unixtime, unix_timestamp, @@timestamp now use decimal, not double for numbers with a fractional part. purge_master_logs_before_date() fixed many bugs in corner cases fixed mysys/my_getsystime.c: compilation failure fixed sql/sql_parse.cc: don't cut corners. it backfires.
Diffstat (limited to 'sql')
-rw-r--r--sql/event_data_objects.cc4
-rw-r--r--sql/event_db_repository.cc10
-rw-r--r--sql/field.cc228
-rw-r--r--sql/field.h78
-rw-r--r--sql/field_conv.cc59
-rw-r--r--sql/filesort.cc2
-rw-r--r--sql/item.cc116
-rw-r--r--sql/item.h1
-rw-r--r--sql/item_cmpfunc.cc404
-rw-r--r--sql/item_cmpfunc.h7
-rw-r--r--sql/item_func.cc30
-rw-r--r--sql/item_sum.cc14
-rw-r--r--sql/item_timefunc.cc175
-rw-r--r--sql/item_timefunc.h37
-rw-r--r--sql/log.cc4
-rw-r--r--sql/my_decimal.cc77
-rw-r--r--sql/my_decimal.h5
-rw-r--r--sql/mysql_priv.h25
-rw-r--r--sql/set_var.cc10
-rw-r--r--sql/sql_parse.cc6
-rw-r--r--sql/sql_show.cc37
-rw-r--r--sql/time.cc151
-rw-r--r--sql/tztime.cc83
-rw-r--r--sql/tztime.h6
-rw-r--r--sql/unireg.h2
25 files changed, 871 insertions, 700 deletions
diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc
index da502b9e639..5ec09e9b0d3 100644
--- a/sql/event_data_objects.cc
+++ b/sql/event_data_objects.cc
@@ -464,7 +464,7 @@ Event_queue_element::load_from_row(THD *thd, TABLE *table)
DBUG_RETURN(TRUE);
starts_null= table->field[ET_FIELD_STARTS]->is_null();
- my_bool not_used= FALSE;
+ uint not_used;
if (!starts_null)
{
table->field[ET_FIELD_STARTS]->get_date(&time, TIME_NO_ZERO_DATE);
@@ -646,7 +646,7 @@ add_interval(MYSQL_TIME *ltime, const Time_zone *time_zone,
if (date_add_interval(ltime, scale, interval))
return 0;
- my_bool not_used;
+ uint not_used;
return time_zone->TIME_to_gmt_sec(ltime, &not_used);
}
diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc
index bf17c94df3e..678a20aaa47 100644
--- a/sql/event_db_repository.cc
+++ b/sql/event_db_repository.cc
@@ -280,7 +280,7 @@ mysql_event_fill_row(THD *thd,
my_tz_OFFSET0->gmt_sec_to_TIME(&time, et->starts);
fields[ET_FIELD_STARTS]->set_notnull();
- fields[ET_FIELD_STARTS]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
+ fields[ET_FIELD_STARTS]->store_time(&time);
}
if (!et->ends_null)
@@ -289,7 +289,7 @@ mysql_event_fill_row(THD *thd,
my_tz_OFFSET0->gmt_sec_to_TIME(&time, et->ends);
fields[ET_FIELD_ENDS]->set_notnull();
- fields[ET_FIELD_ENDS]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
+ fields[ET_FIELD_ENDS]->store_time(&time);
}
}
else if (et->execute_at)
@@ -308,8 +308,7 @@ mysql_event_fill_row(THD *thd,
my_tz_OFFSET0->gmt_sec_to_TIME(&time, et->execute_at);
fields[ET_FIELD_EXECUTE_AT]->set_notnull();
- fields[ET_FIELD_EXECUTE_AT]->
- store_time(&time, MYSQL_TIMESTAMP_DATETIME);
+ fields[ET_FIELD_EXECUTE_AT]->store_time(&time);
}
else
{
@@ -1077,8 +1076,7 @@ update_timing_fields_for_event(THD *thd,
my_tz_OFFSET0->gmt_sec_to_TIME(&time, last_executed);
fields[ET_FIELD_LAST_EXECUTED]->set_notnull();
- fields[ET_FIELD_LAST_EXECUTED]->store_time(&time,
- MYSQL_TIMESTAMP_DATETIME);
+ fields[ET_FIELD_LAST_EXECUTED]->store_time(&time);
}
if (update_status)
{
diff --git a/sql/field.cc b/sql/field.cc
index 87fd7317e9b..ccf8ae14b9a 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -80,7 +80,7 @@ const char field_separator=',';
#define FIELDTYPE_TEAR_FROM (MYSQL_TYPE_BIT + 1)
#define FIELDTYPE_TEAR_TO (MYSQL_TYPE_NEWDECIMAL - 1)
#define FIELDTYPE_NUM (FIELDTYPE_TEAR_FROM + (255 - FIELDTYPE_TEAR_TO))
-inline int field_type2index (enum_field_types field_type)
+static inline int field_type2index (enum_field_types field_type)
{
return (field_type < FIELDTYPE_TEAR_FROM ?
field_type :
@@ -1740,11 +1740,11 @@ bool Field::get_date(MYSQL_TIME *ltime,uint fuzzydate)
Needs to be changed if/when we want to support different time formats.
*/
-int Field::store_time(MYSQL_TIME *ltime, timestamp_type type_arg)
+int Field::store_time_dec(MYSQL_TIME *ltime, uint dec)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
char buff[MAX_DATE_STRING_REP_LENGTH];
- uint length= (uint) my_TIME_to_str(ltime, buff, decimals());
+ uint length= (uint) my_TIME_to_str(ltime, buff, dec);
return store(buff, length, &my_charset_bin);
}
@@ -2734,10 +2734,10 @@ int Field_new_decimal::store_decimal(const my_decimal *decimal_value)
}
-int Field_new_decimal::store_time(MYSQL_TIME *ltime, timestamp_type t_type)
+int Field_new_decimal::store_time_dec(MYSQL_TIME *ltime, uint dec)
{
- my_decimal decimal_value;
- return store_value(date2my_decimal(ltime, &decimal_value));
+ my_decimal decimal_value;
+ return store_value(date2my_decimal(ltime, &decimal_value));
}
@@ -2942,6 +2942,15 @@ Field_new_decimal::unpack(uchar* to, const uchar *from, uint param_data)
return from+len;
}
+int Field_num::store_time_dec(MYSQL_TIME *ltime, uint dec)
+{
+ longlong v= TIME_to_ulonglong(ltime);
+ if (ltime->neg == 0)
+ return store(v, true);
+ return store(-v, false);
+}
+
+
/****************************************************************************
** tiny int
****************************************************************************/
@@ -4187,6 +4196,12 @@ int Field_real::store_decimal(const my_decimal *dm)
return store(dbl);
}
+int Field_real::store_time_dec(MYSQL_TIME *ltime, uint dec)
+{
+ return store(TIME_to_double(ltime));
+}
+
+
double Field_double::val_real(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
@@ -4236,6 +4251,15 @@ my_decimal *Field_real::val_decimal(my_decimal *decimal_value)
}
+bool Field_real::get_date(MYSQL_TIME *ltime,uint fuzzydate)
+{
+ ASSERT_COLUMN_MARKED_FOR_READ;
+ double nr= val_real();
+ return double_to_datetime_with_warn(nr, ltime, fuzzydate,
+ MYSQL_TYPE_SET, field_name);
+}
+
+
String *Field_double::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
@@ -4500,6 +4524,8 @@ int Field_timestamp::store_TIME_with_warning(THD *thd, MYSQL_TIME *l_time,
{
uint conversion_error;
timestamp= TIME_to_timestamp(thd, l_time, &conversion_error);
+ if (timestamp == 0 && l_time->second_part == 0)
+ conversion_error= ER_WARN_DATA_OUT_OF_RANGE;
if (conversion_error)
{
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, conversion_error,
@@ -4516,7 +4542,7 @@ int Field_timestamp::store_TIME_with_warning(THD *thd, MYSQL_TIME *l_time,
return error;
}
-int Field_timestamp::store_time(MYSQL_TIME *ltime,timestamp_type time_type)
+int Field_timestamp::store_time_dec(MYSQL_TIME *ltime, uint dec)
{
THD *thd= table->in_use;
int unused;
@@ -4558,10 +4584,10 @@ int Field_timestamp::store(double nr)
if (nr < 0 || nr > LONGLONG_MAX)
nr= LONGLONG_MAX;
longlong tmp= number_to_datetime((longlong) floor(nr),
+ (nr-floor(nr))*TIME_SECOND_PART_FACTOR,
&l_time, (thd->variables.sql_mode &
MODE_NO_ZERO_DATE) |
MODE_NO_ZERO_IN_DATE, &error);
- l_time.second_part= (ulong)((nr-floor(nr))*TIME_SECOND_PART_FACTOR);
return store_TIME_with_warning(thd, &l_time, &str, error, tmp != -1);
}
@@ -4574,7 +4600,7 @@ int Field_timestamp::store(longlong nr, bool unsigned_val)
THD *thd= table->in_use;
/* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */
- longlong tmp= number_to_datetime(nr, &l_time, (thd->variables.sql_mode &
+ longlong tmp= number_to_datetime(nr, 0, &l_time, (thd->variables.sql_mode &
MODE_NO_ZERO_DATE) |
MODE_NO_ZERO_IN_DATE, &error);
return store_TIME_with_warning(thd, &l_time, &str, error, tmp != LL(-1));
@@ -4873,14 +4899,35 @@ String *Field_timestamp_hires::val_str(String *val_buffer, String *val_ptr)
}
+my_decimal *Field_timestamp_hires::val_decimal(my_decimal *d)
+{
+ MYSQL_TIME ltime;
+ get_date(&ltime, 0);
+ longlong intg= TIME_to_ulonglong(&ltime);
+ return seconds2my_decimal(ltime.neg, intg, ltime.second_part, d);
+}
+
int Field_timestamp_hires::store_decimal(const my_decimal *d)
{
- char buff[DECIMAL_MAX_STR_LENGTH+1];
- String str(buff, sizeof(buff), &my_charset_bin);
- my_decimal2string(E_DEC_FATAL_ERROR, d,
- MAX_DATETIME_COMPRESSED_WIDTH + MAX_DATETIME_PRECISION,
- 6, '0', &str);
- return store(str.ptr(), str.length(), str.charset());
+ ulonglong nr;
+ ulong sec_part;
+ int error;
+ MYSQL_TIME ltime;
+ longlong tmp;
+ THD *thd= table->in_use;
+ Lazy_string_decimal str(d);
+
+ if (my_decimal2seconds(d, &nr, &sec_part))
+ {
+ tmp= -1;
+ error= 2;
+ }
+ else
+ tmp= number_to_datetime(nr, sec_part, &ltime, TIME_NO_ZERO_IN_DATE |
+ (thd->variables.sql_mode &
+ MODE_NO_ZERO_DATE), &error);
+
+ return store_TIME_with_warning(thd, &ltime, &str, error, tmp != -1);
}
int Field_timestamp_hires::set_time()
@@ -5026,13 +5073,14 @@ int Field_temporal::store(double nr)
if (nr < 0 || nr > LONGLONG_MAX)
nr= LONGLONG_MAX;
- longlong tmp= number_to_datetime((longlong) floor(nr), &ltime,
- (TIME_FUZZY_DATE |
+ longlong tmp= number_to_datetime((longlong) floor(nr),
+ ((nr-floor(nr))*TIME_SECOND_PART_FACTOR),
+ &ltime,
+ (TIME_FUZZY_DATE |
(thd->variables.sql_mode &
(MODE_NO_ZERO_IN_DATE |
MODE_NO_ZERO_DATE |
MODE_INVALID_DATES))), &error);
- ltime.second_part= (ulong)((nr-floor(nr))*TIME_SECOND_PART_FACTOR);
return store_TIME_with_warning(&ltime, &str, error, tmp != -1);
}
@@ -5045,7 +5093,7 @@ int Field_temporal::store(longlong nr, bool unsigned_val)
THD *thd= table->in_use;
Lazy_string_num str(nr);
- tmp= number_to_datetime(nr, &ltime, (TIME_FUZZY_DATE |
+ tmp= number_to_datetime(nr, 0, &ltime, (TIME_FUZZY_DATE |
(thd->variables.sql_mode &
(MODE_NO_ZERO_IN_DATE |
MODE_NO_ZERO_DATE |
@@ -5055,7 +5103,7 @@ int Field_temporal::store(longlong nr, bool unsigned_val)
}
-int Field_temporal::store_time(MYSQL_TIME *ltime,timestamp_type time_type)
+int Field_temporal::store_time_dec(MYSQL_TIME *ltime, uint dec)
{
int error = 0, have_smth_to_conv= 1;
MYSQL_TIME l_time= *ltime;
@@ -5064,21 +5112,24 @@ int Field_temporal::store_time(MYSQL_TIME *ltime,timestamp_type time_type)
We don't perform range checking here since values stored in TIME
structure always fit into DATETIME range.
*/
- if (time_type == MYSQL_TIMESTAMP_DATE ||
- time_type == MYSQL_TIMESTAMP_DATETIME)
- {
- have_smth_to_conv= !check_date(&l_time, pack_time(&l_time) != 0,
- (TIME_FUZZY_DATE |
- (current_thd->variables.sql_mode &
- (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
- MODE_INVALID_DATES))), &error);
- }
- else
+ have_smth_to_conv= !check_date(&l_time, pack_time(&l_time) != 0,
+ (TIME_FUZZY_DATE |
+ (current_thd->variables.sql_mode &
+ (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
+ MODE_INVALID_DATES))), &error);
+ return store_TIME_with_warning(&l_time, &str, error, have_smth_to_conv);
+}
+
+my_decimal *Field_temporal::val_decimal(my_decimal *d)
+{
+ MYSQL_TIME ltime;
+ if (get_date(&ltime, TIME_FUZZY_DATE))
{
- error= 1;
- have_smth_to_conv= 0;
+ bzero(&ltime, sizeof(ltime));
+ ltime.time_type= mysql_type_to_time_type(type());
}
- return store_TIME_with_warning(&l_time, &str, error, have_smth_to_conv);
+ longlong intg= TIME_to_ulonglong(&ltime);
+ return seconds2my_decimal(ltime.neg, intg, ltime.second_part, d);
}
/****************************************************************************
@@ -5109,7 +5160,7 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
}
-int Field_time::store_time(MYSQL_TIME *ltime, timestamp_type time_type)
+int Field_time::store_time_dec(MYSQL_TIME *ltime, uint dec)
{
MYSQL_TIME l_time= *ltime;
Lazy_string_time str(ltime);
@@ -5125,7 +5176,12 @@ int Field_time::store(double nr)
MYSQL_TIME ltime;
Lazy_string_double str(nr);
int was_cut;
- int have_smth_to_conv= !number_to_time(nr, &ltime, &was_cut);
+ bool neg= nr < 0;
+ if (neg)
+ nr= -nr;
+ int have_smth_to_conv= !number_to_time(neg, nr,
+ (nr - trunc(nr)) * TIME_SECOND_PART_FACTOR,
+ &ltime, &was_cut);
return store_TIME_with_warning(&ltime, &str, was_cut, have_smth_to_conv);
}
@@ -5136,7 +5192,8 @@ int Field_time::store(longlong nr, bool unsigned_val)
MYSQL_TIME ltime;
Lazy_string_num str(nr);
int was_cut;
- int have_smth_to_conv= !number_to_time((double)nr, &ltime, &was_cut);
+ int have_smth_to_conv= !number_to_time(nr < 0, nr < 0 ? -nr : nr,
+ 0, &ltime, &was_cut);
return store_TIME_with_warning(&ltime, &str, was_cut, have_smth_to_conv);
}
@@ -5248,17 +5305,42 @@ void Field_time::sql_type(String &res) const
res.set_ascii(STRING_WITH_LEN("time"));
}
+static const longlong t_shift= ((TIME_MAX_VALUE_SECONDS+1)*TIME_SECOND_PART_FACTOR);
void Field_time_hires::store_TIME(MYSQL_TIME *ltime)
{
- ulonglong packed= sec_part_shift(pack_time(ltime), dec);
+ ulonglong packed= sec_part_shift(pack_time(ltime), dec) +
+ sec_part_shift(t_shift, dec);
store_bigendian(packed, ptr, Field_time_hires::pack_length());
}
+int Field_time_hires::store_decimal(const my_decimal *d)
+{
+ ulonglong nr;
+ ulong sec_part;
+ Lazy_string_decimal str(d);
+ MYSQL_TIME ltime;
+ int was_cut;
+ bool neg= my_decimal2seconds(d, &nr, &sec_part);
+
+ int have_smth_to_conv= !number_to_time(neg, nr, sec_part, &ltime, &was_cut);
+
+ return store_TIME_with_warning(&ltime, &str, was_cut, have_smth_to_conv);
+}
+
uint32 Field_time_hires::pack_length() const
{
return time_hires_bytes[dec];
}
+longlong Field_time_hires::val_int(void)
+{
+ ASSERT_COLUMN_MARKED_FOR_READ;
+ MYSQL_TIME ltime;
+ Field_time_hires::get_date(&ltime, TIME_TIME_ONLY);
+ longlong val= TIME_to_ulonglong_time(&ltime);
+ return ltime.neg ? -val : val;
+}
+
double Field_time_hires::val_real(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
@@ -5284,20 +5366,18 @@ bool Field_time_hires::get_date(MYSQL_TIME *ltime, uint fuzzydate)
uint32 len= pack_length();
longlong packed= read_bigendian(ptr, len);
- /* sign extension */
- longlong mask= 1LL << (len*8 - 1);
- if (packed & mask)
- packed|= ~(mask-1);
+ if (packed)
+ packed= sec_part_unshift(packed - sec_part_shift(t_shift, dec), dec);
- unpack_time(sec_part_unshift(packed, dec), ltime);
+ unpack_time(packed, ltime);
/*
unpack_time() returns MYSQL_TIMESTAMP_DATETIME.
- To get MYSQL_TIMESTAMP_TIME we few some adjustments
+ To get MYSQL_TIMESTAMP_TIME we few adjustments
*/
ltime->time_type= MYSQL_TIMESTAMP_TIME;
ltime->hour+= (ltime->month*32+ltime->day)*24;
ltime->month= ltime->day= 0;
- return fuzzydate & (TIME_FUZZY_DATE|TIME_TIME_ONLY) ? 0 : 1;
+ return fuzzydate & (TIME_FUZZY_DATE | TIME_TIME_ONLY) ? 0 : 1;
}
@@ -5411,6 +5491,17 @@ int Field_year::store(longlong nr, bool unsigned_val)
}
+int Field_year::store_time_dec(MYSQL_TIME *ltime, uint dec)
+{
+ Lazy_string_time str(ltime);
+ if (Field_year::store(ltime->year, 0))
+ return 1;
+
+ set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED,
+ &str, ltime->time_type, 1);
+ return 0;
+}
+
bool Field_year::send_binary(Protocol *protocol)
{
ASSERT_COLUMN_MARKED_FOR_READ;
@@ -5448,6 +5539,16 @@ String *Field_year::val_str(String *val_buffer,
}
+bool Field_year::get_date(MYSQL_TIME *ltime,uint fuzzydate)
+{
+ int tmp= (int) ptr[0];
+ if (tmp || field_length != 4)
+ tmp+= 1900;
+ return int_to_datetime_with_warn(tmp, ltime, fuzzydate,
+ MYSQL_TYPE_YEAR, field_name);
+}
+
+
void Field_year::sql_type(String &res) const
{
CHARSET_INFO *cs=res.charset();
@@ -5780,12 +5881,27 @@ void Field_datetime_hires::store_TIME(MYSQL_TIME *ltime)
int Field_datetime_hires::store_decimal(const my_decimal *d)
{
- char buff[DECIMAL_MAX_STR_LENGTH+1];
- String str(buff, sizeof(buff), &my_charset_bin);
- my_decimal2string(E_DEC_FATAL_ERROR, d,
- MAX_DATETIME_COMPRESSED_WIDTH + MAX_DATETIME_PRECISION,
- 6, '0', &str);
- return store(str.ptr(), str.length(), str.charset());
+ ulonglong nr;
+ ulong sec_part;
+ int error;
+ MYSQL_TIME ltime;
+ longlong tmp;
+ THD *thd= table->in_use;
+ Lazy_string_decimal str(d);
+
+ if (my_decimal2seconds(d, &nr, &sec_part))
+ {
+ tmp= -1;
+ error= 2;
+ }
+ else
+ tmp= number_to_datetime(nr, sec_part, &ltime, (TIME_FUZZY_DATE |
+ (thd->variables.sql_mode &
+ (MODE_NO_ZERO_IN_DATE |
+ MODE_NO_ZERO_DATE |
+ MODE_INVALID_DATES))), &error);
+
+ return store_TIME_with_warning(&ltime, &str, error, tmp != -1);
}
bool Field_datetime_hires::send_binary(Protocol *protocol)
@@ -9740,7 +9856,7 @@ uint32 Field_blob::max_display_length()
0 otherwise
*/
-bool
+void
Field::set_warning(MYSQL_ERROR::enum_warning_level level, uint code,
int cuted_increment)
{
@@ -9748,15 +9864,13 @@ Field::set_warning(MYSQL_ERROR::enum_warning_level level, uint code,
If this field was created only for type conversion purposes it
will have table == NULL.
*/
- THD *thd= table->in_use;
+ THD *thd= table ? table->in_use : current_thd;
if (thd->count_cuted_fields)
{
thd->cuted_fields+= cuted_increment;
push_warning_printf(thd, level, code, ER(code), field_name,
thd->row_count);
- return 0;
}
- return level >= MYSQL_ERROR::WARN_LEVEL_WARN;
}
@@ -9783,9 +9897,9 @@ void Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level,
timestamp_type ts_type, int cuted_increment)
{
THD *thd= table->in_use;
- if ((thd->really_abort_on_warning() &&
- level >= MYSQL_ERROR::WARN_LEVEL_WARN) ||
- set_warning(level, code, cuted_increment))
+ if (thd->really_abort_on_warning() && level >= MYSQL_ERROR::WARN_LEVEL_WARN)
make_truncated_value_warning(thd, level, str, ts_type, field_name);
+ else
+ set_warning(level, code, cuted_increment);
}
diff --git a/sql/field.h b/sql/field.h
index a976d8b5ce5..e2b922d89b7 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -115,7 +115,9 @@ public:
virtual int store(double nr)=0;
virtual int store(longlong nr, bool unsigned_val)=0;
virtual int store_decimal(const my_decimal *d)=0;
- virtual int store_time(MYSQL_TIME *ltime, timestamp_type t_type);
+ virtual int store_time_dec(MYSQL_TIME *ltime, uint dec);
+ int store_time(MYSQL_TIME *ltime)
+ { return store_time_dec(ltime, TIME_SECOND_PART_DIGITS); }
int store(const char *to, uint length, CHARSET_INFO *cs,
enum_check_fields check_level);
virtual double val_real(void)=0;
@@ -441,7 +443,7 @@ public:
{ return DERIVATION_IMPLICIT; }
virtual void set_derivation(enum Derivation derivation_arg) { }
virtual int set_time() { return 1; }
- bool set_warning(MYSQL_ERROR::enum_warning_level, unsigned int code,
+ void set_warning(MYSQL_ERROR::enum_warning_level, unsigned int code,
int cuted_increment);
void set_datetime_warning(MYSQL_ERROR::enum_warning_level, uint code,
const Lazy_string *str, timestamp_type ts_type,
@@ -529,49 +531,26 @@ private:
{ return 0; }
protected:
- /*
- Helper function to pack()/unpack() int32 values
- */
- static void handle_int32(uchar *to, const uchar *from)
+ uchar *pack_int(uchar *to, const uchar *from, size_t size)
{
- int32 val;
- val = sint4korr(from);
- int4store(to, val);
+ memcpy(to, from, size);
+ return to + size;
}
- /*
- Helper function to pack()/unpack() int64 values
- */
- static void handle_int64(uchar* to, const uchar *from)
+ const uchar *unpack_int(uchar* to, const uchar *from, size_t size)
{
- int64 val;
- val = sint8korr(from);
- int8store(to, val);
+ memcpy(to, from, size);
+ return from + size;
}
uchar *pack_int32(uchar *to, const uchar *from)
- {
- handle_int32(to, from);
- return to + sizeof(int32);
- }
-
+ { return pack_int(to, from, 4); }
const uchar *unpack_int32(uchar* to, const uchar *from)
- {
- handle_int32(to, from);
- return from + sizeof(int32);
- }
-
+ { return unpack_int(to, from, 4); }
uchar *pack_int64(uchar* to, const uchar *from)
- {
- handle_int64(to, from);
- return to + sizeof(int64);
- }
-
+ { return pack_int(to, from, 8); }
const uchar *unpack_int64(uchar* to, const uchar *from)
- {
- handle_int64(to, from);
- return from + sizeof(int64);
- }
+ { return unpack_int(to, from, 8); }
bool field_flags_are_binary()
{
@@ -589,7 +568,7 @@ public:
uchar null_bit_arg, utype unireg_check_arg,
const char *field_name_arg,
uint8 dec_arg, bool zero_arg, bool unsigned_arg);
- Item_result result_type () const { return REAL_RESULT; }
+ enum Item_result result_type () const { return INT_RESULT; }
void prepend_zeros(String *value);
void add_zerofill_and_unsigned(String &res) const;
friend class Create_field;
@@ -600,6 +579,7 @@ public:
int store_decimal(const my_decimal *);
my_decimal *val_decimal(my_decimal *);
uint is_equal(Create_field *new_field);
+ int store_time_dec(MYSQL_TIME *ltime, uint dec);
int check_int(CHARSET_INFO *cs, const char *str, int length,
const char *int_end, int error);
bool get_int(CHARSET_INFO *cs, const char *from, uint len,
@@ -668,7 +648,10 @@ public:
field_name_arg, dec_arg, zero_arg, unsigned_arg),
not_fixed(dec_arg >= NOT_FIXED_DEC)
{}
+ Item_result result_type () const { return REAL_RESULT; }
int store_decimal(const my_decimal *);
+ int store_time_dec(MYSQL_TIME *ltime, uint dec);
+ bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
my_decimal *val_decimal(my_decimal *);
int truncate(double *nr, double max_length);
uint32 max_display_length() { return field_length; }
@@ -742,7 +725,7 @@ public:
int store(const char *to, uint length, CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
- int store_time(MYSQL_TIME *ltime, timestamp_type t_type);
+ int store_time_dec(MYSQL_TIME *ltime, uint dec);
int store_decimal(const my_decimal *);
double val_real(void);
longlong val_int(void);
@@ -775,7 +758,6 @@ public:
unireg_check_arg, field_name_arg,
0, zero_arg,unsigned_arg)
{}
- enum Item_result result_type () const { return INT_RESULT; }
enum_field_types type() const { return MYSQL_TYPE_TINY;}
enum ha_base_keytype key_type() const
{ return unsigned_flag ? HA_KEYTYPE_BINARY : HA_KEYTYPE_INT8; }
@@ -822,7 +804,6 @@ public:
:Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
NONE, field_name_arg, 0, 0, unsigned_arg)
{}
- enum Item_result result_type () const { return INT_RESULT; }
enum_field_types type() const { return MYSQL_TYPE_SHORT;}
enum ha_base_keytype key_type() const
{ return unsigned_flag ? HA_KEYTYPE_USHORT_INT : HA_KEYTYPE_SHORT_INT;}
@@ -867,7 +848,6 @@ public:
unireg_check_arg, field_name_arg,
0, zero_arg,unsigned_arg)
{}
- enum Item_result result_type () const { return INT_RESULT; }
enum_field_types type() const { return MYSQL_TYPE_INT24;}
enum ha_base_keytype key_type() const
{ return unsigned_flag ? HA_KEYTYPE_UINT24 : HA_KEYTYPE_INT24; }
@@ -912,7 +892,6 @@ public:
:Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
NONE, field_name_arg,0,0,unsigned_arg)
{}
- enum Item_result result_type () const { return INT_RESULT; }
enum_field_types type() const { return MYSQL_TYPE_LONG;}
enum ha_base_keytype key_type() const
{ return unsigned_flag ? HA_KEYTYPE_ULONG_INT : HA_KEYTYPE_LONG_INT; }
@@ -958,7 +937,6 @@ public:
:Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
NONE, field_name_arg,0,0,unsigned_arg)
{}
- enum Item_result result_type () const { return INT_RESULT; }
enum_field_types type() const { return MYSQL_TYPE_LONGLONG;}
enum ha_base_keytype key_type() const
{ return unsigned_flag ? HA_KEYTYPE_ULONGLONG : HA_KEYTYPE_LONGLONG; }
@@ -1101,6 +1079,7 @@ public:
class Field_timestamp :public Field_str {
+protected:
int store_TIME_with_warning(THD *, MYSQL_TIME *, const Lazy_string *,
bool, bool);
public:
@@ -1116,7 +1095,7 @@ public:
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
- int store_time(MYSQL_TIME *ltime, timestamp_type type);
+ int store_time_dec(MYSQL_TIME *ltime, uint dec);
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
@@ -1175,6 +1154,7 @@ public:
my_time_t get_timestamp(ulong *sec_part) const;
void store_TIME(my_time_t timestamp, ulong sec_part);
int store_decimal(const my_decimal *d);
+ my_decimal* val_decimal(my_decimal*);
double val_real(void);
String *val_str(String*,String *);
bool send_binary(Protocol *protocol);
@@ -1205,9 +1185,11 @@ public:
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
+ int store_time_dec(MYSQL_TIME *ltime, uint dec);
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
+ bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
bool send_binary(Protocol *protocol);
void sql_type(String &str) const;
};
@@ -1229,7 +1211,8 @@ public:
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
- int store_time(MYSQL_TIME *ltime, timestamp_type type);
+ int store_time_dec(MYSQL_TIME *ltime, uint dec);
+ my_decimal *val_decimal(my_decimal*);
};
class Field_date :public Field_temporal {
@@ -1310,7 +1293,7 @@ public:
{}
enum_field_types type() const { return MYSQL_TYPE_TIME;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_INT24; }
- int store_time(MYSQL_TIME *ltime, timestamp_type type);
+ int store_time_dec(MYSQL_TIME *ltime, uint dec);
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
@@ -1343,7 +1326,8 @@ public:
}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
uint decimals() const { return dec; }
- longlong val_int(void) { return (longlong)floor(val_real()); }
+ int store_decimal(const my_decimal *d);
+ longlong val_int(void);
double val_real(void);
String *val_str(String*,String *);
bool get_date(MYSQL_TIME *ltime, uint fuzzydate);
@@ -1409,9 +1393,9 @@ public:
DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
- int store_decimal(const my_decimal *d);
uint decimals() const { return dec; }
void make_field(Send_field *field);
+ int store_decimal(const my_decimal *d);
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index 2d08cd0694b..6ca48f909a5 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -369,7 +369,7 @@ static void do_field_temporal(Copy_field *copy)
{
MYSQL_TIME ltime;
copy->from_field->get_date(&ltime, TIME_FUZZY_DATE);
- copy->to_field->store_time(&ltime, ltime.time_type);
+ copy->to_field->store_time_dec(&ltime, copy->from_field->decimals());
}
@@ -664,7 +664,25 @@ Copy_field::get_copy_func(Field *to,Field *from)
if (to->result_type() == DECIMAL_RESULT)
return do_field_decimal;
if (to->cmp_type() == TIME_RESULT)
- return do_field_temporal;
+ {
+ if (from->cmp_type() == TIME_RESULT)
+ return do_field_temporal;
+ if (from->result_type() == STRING_RESULT)
+ return do_field_string;
+ if (from->result_type() == INT_RESULT)
+ return do_field_int;
+ if (from->result_type() == DECIMAL_RESULT)
+ return do_field_decimal;
+ return do_field_real;
+ }
+ if (from->cmp_type() == TIME_RESULT)
+ {
+ if (to->result_type() == STRING_RESULT)
+ return do_field_string;
+ if (to->result_type() == INT_RESULT)
+ return do_field_int;
+ return do_field_real;
+ }
// Check if identical fields
if (from->result_type() == STRING_RESULT)
{
@@ -677,15 +695,7 @@ Copy_field::get_copy_func(Field *to,Field *from)
to->type() == MYSQL_TYPE_VARCHAR && !to->has_charset())
return do_field_varbinary_pre50;
- /*
- If we are copying date or datetime's we have to check the dates
- if we don't allow 'all' dates.
- */
- if (to->real_type() != from->real_type() ||
- (((to->table->in_use->variables.sql_mode &
- (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES)) &&
- to->type() == MYSQL_TYPE_DATE) ||
- to->type() == MYSQL_TYPE_DATETIME))
+ if (to->real_type() != from->real_type())
{
if (from->real_type() == MYSQL_TYPE_ENUM ||
from->real_type() == MYSQL_TYPE_SET)
@@ -818,7 +828,22 @@ int field_conv(Field *to,Field *from)
((Field_enum *)(to))->store_type(0);
return 0;
}
- else if ((from->result_type() == STRING_RESULT &&
+ if (from->result_type() == REAL_RESULT)
+ return to->store(from->val_real());
+ if (from->result_type() == DECIMAL_RESULT)
+ {
+ my_decimal buff;
+ return to->store_decimal(from->val_decimal(&buff));
+ }
+ if (from->cmp_type() == TIME_RESULT)
+ {
+ MYSQL_TIME ltime;
+ if (from->get_date(&ltime, TIME_FUZZY_DATE))
+ return to->reset();
+ else
+ return to->store_time_dec(&ltime, from->decimals());
+ }
+ if ((from->result_type() == STRING_RESULT &&
(to->result_type() == STRING_RESULT ||
(from->real_type() != MYSQL_TYPE_ENUM &&
from->real_type() != MYSQL_TYPE_SET))) ||
@@ -835,13 +860,5 @@ int field_conv(Field *to,Field *from)
*/
return to->store(result.c_ptr_quick(),result.length(),from->charset());
}
- else if (from->result_type() == REAL_RESULT)
- return to->store(from->val_real());
- else if (from->result_type() == DECIMAL_RESULT)
- {
- my_decimal buff;
- return to->store_decimal(from->val_decimal(&buff));
- }
- else
- return to->store(from->val_int(), test(from->flags & UNSIGNED_FLAG));
+ return to->store(from->val_int(), test(from->flags & UNSIGNED_FLAG));
}
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 4c096dad4d9..920048d4503 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -844,7 +844,7 @@ static void make_sortkey(register SORTPARAM *param,
case INT_RESULT:
case TIME_RESULT:
{
- longlong value;
+ longlong UNINIT_VAR(value);
if (sort_field->result_type == INT_RESULT)
value= item->val_int_result();
else
diff --git a/sql/item.cc b/sql/item.cc
index 6c74f509915..002621acb5a 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -329,7 +329,7 @@ int Item::save_time_in_field(Field *field)
if (get_time(&ltime))
return set_field_to_null_with_conversions(field, 0);
field->set_notnull();
- return field->store_time(&ltime, MYSQL_TIMESTAMP_TIME);
+ return field->store_time_dec(&ltime, decimals);
}
@@ -339,7 +339,7 @@ int Item::save_date_in_field(Field *field)
if (get_date(&ltime, TIME_FUZZY_DATE))
return set_field_to_null_with_conversions(field, 0);
field->set_notnull();
- return field->store_time(&ltime, MYSQL_TIMESTAMP_DATETIME);
+ return field->store_time_dec(&ltime, decimals);
}
@@ -984,27 +984,59 @@ bool Item::get_date(MYSQL_TIME *ltime,uint fuzzydate)
{
if (field_type() == MYSQL_TYPE_TIME)
fuzzydate|= TIME_TIME_ONLY;
- if (result_type() != INT_RESULT || fuzzydate & TIME_TIME_ONLY)
+
+ Item_result res_type= result_type();
+
+ enum_field_types f_type= MYSQL_TYPE_SET; // a.k.a. use fuzzydate flags
+
+ switch (res_type) {
+ case INT_RESULT:
+ {
+ longlong value= val_int();
+ if (field_type() == MYSQL_TYPE_YEAR)
+ {
+ f_type= MYSQL_TYPE_YEAR;
+ if (value < 70)
+ value+= 2000;
+ else if (value <= 1900)
+ value+= 1900;
+ }
+ if (null_value || int_to_datetime_with_warn(value, ltime, fuzzydate,
+ f_type, field_name_or_null()))
+ goto err;
+ break;
+ }
+ case REAL_RESULT:
+ {
+ double value= val_real();
+ if (null_value || double_to_datetime_with_warn(value, ltime, fuzzydate,
+ f_type, field_name_or_null()))
+ goto err;
+ break;
+ }
+ case DECIMAL_RESULT:
+ {
+ my_decimal value, *res;
+ if (!(res= val_decimal(&value)) ||
+ decimal_to_datetime_with_warn(res, ltime, fuzzydate,
+ f_type, field_name_or_null()))
+ goto err;
+ break;
+ }
+ case STRING_RESULT:
{
char buff[40];
String tmp(buff,sizeof(buff), &my_charset_bin),*res;
if (!(res=val_str(&tmp)) ||
- str_to_datetime_with_warn(res->ptr(), res->length(), ltime,
- fuzzydate) <= MYSQL_TIMESTAMP_ERROR)
+ str_to_datetime_with_warn(res->ptr(), res->length(),
+ ltime, fuzzydate) <= MYSQL_TIMESTAMP_ERROR)
goto err;
+ break;
}
- else
- {
- longlong value= val_int();
- int was_cut;
- if (number_to_datetime(value, ltime, fuzzydate, &was_cut) == LL(-1))
- {
- Lazy_string_num str(value);
- make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- &str, MYSQL_TIMESTAMP_NONE, NullS);
- goto err;
- }
+ default:
+ DBUG_ASSERT(0);
}
+
return 0;
err:
@@ -1012,17 +1044,27 @@ err:
return 1;
}
-/**
- Get time of first argument.
-
- As a extra convenience the time structure is reset on error!
-*/
-
bool Item::get_time(MYSQL_TIME *ltime)
{
return get_date(ltime, TIME_TIME_ONLY | TIME_FUZZY_DATE);
}
+bool Item::get_seconds(ulonglong *sec, ulong *sec_part)
+{
+ if (result_type() == INT_RESULT)
+ { // optimize for an important special case
+ longlong val= val_int();
+ bool neg= val < 0 && !unsigned_flag;
+ *sec= neg ? -val : val;
+ *sec_part= 0;
+ return neg;
+ }
+ my_decimal tmp, *dec= val_decimal(&tmp);
+ if (!dec)
+ return 0;
+ return my_decimal2seconds(dec, sec, sec_part);
+}
+
CHARSET_INFO *Item::default_charset()
{
return current_thd->variables.collation_connection;
@@ -2951,7 +2993,7 @@ int Item_param::save_in_field(Field *field, bool no_conversions)
case DECIMAL_VALUE:
return field->store_decimal(&decimal_value);
case TIME_VALUE:
- field->store_time(&value.time, value.time.time_type);
+ field->store_time_dec(&value.time, decimals);
return 0;
case STRING_VALUE:
case LONG_DATA_VALUE:
@@ -5247,7 +5289,7 @@ void Item_datetime::set(longlong packed)
int Item_datetime::save_in_field(Field *field, bool no_conversions)
{
field->set_notnull();
- return field->store_time(&ltime, ltime.time_type);
+ return field->store_time_dec(&ltime, decimals);
}
longlong Item_datetime::val_int()
@@ -7194,30 +7236,22 @@ longlong Item_cache_int::val_int()
bool Item_cache_int::get_date(MYSQL_TIME *ltime, uint fuzzydate)
{
+ Lazy_string_num str(value);
+
if (!value_cached && !cache_value())
- goto err;
+ {
+ bzero((char*) ltime,sizeof(*ltime));
+ return 1;
+ }
if (cmp_type() == TIME_RESULT)
{
unpack_time(value, ltime);
ltime->time_type= mysql_type_to_time_type(field_type());
+ return 0;
}
- else
- {
- int was_cut;
- if (number_to_datetime(value, ltime, fuzzydate, &was_cut) == -1LL)
- {
- Lazy_string_num str(value);
- make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- &str, MYSQL_TIMESTAMP_NONE, NullS);
- goto err;
- }
- }
- return 0;
-err:
- bzero((char*) ltime,sizeof(*ltime));
- return 1;
+ return Item::get_date(ltime, fuzzydate);
}
int Item_cache_int::save_in_field(Field *field, bool no_conversions)
@@ -7232,7 +7266,7 @@ int Item_cache_int::save_in_field(Field *field, bool no_conversions)
MYSQL_TIME ltime;
unpack_time(value, &ltime);
ltime.time_type= mysql_type_to_time_type(field_type());
- error= field->store_time(&ltime, ltime.time_type);
+ error= field->store_time_dec(&ltime, decimals);
}
else
error= field->store(value, unsigned_flag);
diff --git a/sql/item.h b/sql/item.h
index 16f0857958d..c2b39216e85 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -815,6 +815,7 @@ public:
Item **ref, bool skip_registered);
virtual bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
bool get_time(MYSQL_TIME *ltime);
+ bool get_seconds(ulonglong *sec, ulong *sec_part);
virtual bool get_date_result(MYSQL_TIME *ltime,uint fuzzydate)
{ return get_date(ltime,fuzzydate); }
/*
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index e99835083a6..c244d46133f 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -73,6 +73,30 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems)
}
+/**
+ find an temporal type (item) that others will be converted to
+ for the purpose of comparison.
+
+ this is the type that will be used in warnings like
+ "Incorrect <<TYPE>> value".
+*/
+Item *find_date_time_item(Item **args, uint nargs, uint col)
+{
+ Item *date_arg= 0, **arg, **arg_end;
+ for (arg= args, arg_end= args + nargs; arg != arg_end ; arg++)
+ {
+ Item *item= arg[0]->element_index(col);
+ if (item->cmp_type() != TIME_RESULT)
+ continue;
+ if (item->field_type() == MYSQL_TYPE_DATETIME)
+ return item;
+ if (!date_arg)
+ date_arg= item;
+ }
+ return date_arg;
+}
+
+
/*
Compare row signature of two expressions
@@ -204,7 +228,7 @@ static uint collect_cmp_types(Item **items, uint nitems, bool skip_nulls= FALSE)
{
uint i;
uint found_types;
- Item_result left_result= items[0]->result_type();
+ Item_result left_result= items[0]->cmp_type();
DBUG_ASSERT(nitems > 1);
found_types= 0;
for (i= 1; i < nitems ; i++)
@@ -212,11 +236,11 @@ static uint collect_cmp_types(Item **items, uint nitems, bool skip_nulls= FALSE)
if (skip_nulls && items[i]->type() == Item::NULL_ITEM)
continue; // Skip NULL constant items
if ((left_result == ROW_RESULT ||
- items[i]->result_type() == ROW_RESULT) &&
+ items[i]->cmp_type() == ROW_RESULT) &&
cmp_row_type(items[0], items[i]))
return 0;
found_types|= 1<< (uint)item_cmp_type(left_result,
- items[i]->result_type());
+ items[i]->cmp_type());
}
/*
Even if all right-hand items are NULLs and we are skipping them all, we need
@@ -677,36 +701,6 @@ bool get_mysql_time_from_str(THD *thd, String *str, timestamp_type warn_type,
/**
- @brief Convert date provided in a string to the int representation.
-
- @param[in] thd thread handle
- @param[in] str a string to convert
- @param[in] warn_type type of the timestamp for issuing the warning
- @param[in] warn_name field name for issuing the warning
- @param[out] error_arg could not extract a DATE or DATETIME
-
- @details Convert date provided in the string str to the int
- representation. If the string contains wrong date or doesn't
- contain it at all then a warning is issued. The warn_type and
- the warn_name arguments are used as the name and the type of the
- field when issuing the warning.
-
- @return
- converted value. 0 on error and on zero-dates -- check 'failure'
-*/
-static ulonglong get_date_from_str(THD *thd, String *str,
- timestamp_type warn_type,
- const char *warn_name, bool *error_arg)
-{
- MYSQL_TIME l_time;
- *error_arg= get_mysql_time_from_str(thd, str, warn_type, warn_name, &l_time);
-
- if (*error_arg)
- return 0;
- return pack_time(&l_time);
-}
-
-/**
Prepare the comparator (set the comparison function) for comparing
items *a1 and *a2 in the context of 'type'.
@@ -838,100 +832,28 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
{
longlong UNINIT_VAR(value);
Item *item= **item_arg;
- enum_field_types f_type= warn_item->field_type();
+ enum_field_types f_type= item->cmp_type() == TIME_RESULT ?
+ item->field_type() : warn_item->field_type();
- switch (item->cmp_type()) {
- case TIME_RESULT:
- /* if it's our Item_cache_int, as created below, we simply use the value */
- if (item->result_type() == INT_RESULT)
- {
- value= item->val_int();
- cache_arg= 0;
- }
- else
- {
- MYSQL_TIME buf;
- if (item->get_date_result(&buf, TIME_FUZZY_DATE | TIME_INVALID_DATES))
- DBUG_ASSERT(item->null_value);
- else
- value= pack_time(&buf);
- f_type= item->field_type(); // for Item_cache_int below.
- }
- break;
- case INT_RESULT:
+ if (item->result_type() == INT_RESULT && item->cmp_type() == TIME_RESULT)
+ {
+ /* it's our Item_cache_int, as created below */
value= item->val_int();
-
- if (item->field_type() == MYSQL_TYPE_YEAR)
- {
- Item *real_item= item->real_item();
- if (!(real_item->type() == Item::FIELD_ITEM &&
- ((Item_field *)real_item)->field->type() == MYSQL_TYPE_YEAR &&
- ((Item_field *)real_item)->field->field_length == 4))
- {
- if (value < 70)
- value+= 100;
- if (value <= 1900)
- value+= 1900;
- }
- value*= 13ULL * 32ULL * 24ULL * 60ULL * 60ULL * 1000000ULL;
- }
+ }
+ else
+ {
+ MYSQL_TIME ltime;
+ uint fuzzydate= TIME_FUZZY_DATE | TIME_INVALID_DATES;
+ if (f_type == MYSQL_TYPE_TIME)
+ fuzzydate|= TIME_TIME_ONLY;
+ if (item->get_date(&ltime, fuzzydate))
+ value= 0; /* invalid date */
else
- {
- MYSQL_TIME buf;
- int was_cut;
- longlong res;
-
- if (f_type == MYSQL_TYPE_TIME)
- res= number_to_time((double)value, &buf, &was_cut);
- else
- res= number_to_datetime(value, &buf, TIME_INVALID_DATES|TIME_FUZZY_DATE,
- &was_cut);
- if (res == -1)
- {
- const Lazy_string_num str(value);
- make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, &str,
- mysql_type_to_time_type(f_type),
- warn_item->field_name_or_null());
- value= 0;
- }
- else
- value= pack_time(&buf);
- }
- break;
- case STRING_RESULT:
- case DECIMAL_RESULT:
- case REAL_RESULT:
- {
- char strbuf[MAX_DATETIME_FULL_WIDTH];
- String buf(strbuf, sizeof(strbuf), &my_charset_bin), *str;
- if ((str= item->val_str(&buf)))
- {
- /*
- Convert strings to the integer DATE/DATETIME representation.
- Even if both dates provided in strings we can't compare them directly as
- strings as there is no warranty that they are correct and do not miss
- some insignificant zeros.
- */
- bool error;
- value= (longlong) get_date_from_str(thd, str,
- mysql_type_to_time_type(f_type),
- warn_item->field_name_or_null(),
- &error);
- /*
- If str did not contain a valid date according to the current
- SQL_MODE, get_date_from_str() has already thrown a warning,
- and we don't want to throw NULL on invalid date (see 5.2.6
- "SQL modes" in the manual), so we're done here.
- */
- }
- break;
- }
- case ROW_RESULT:
- DBUG_ASSERT(0);
+ value= pack_time(&ltime);
}
if ((*is_null= item->null_value))
return ~(ulonglong) 0;
- if (cache_arg && item->const_item())
+ if (cache_arg && item->const_item() && item->type() != Item::CACHE_ITEM)
{
/*
cache the packed datetime value in the Item_cache object.
@@ -940,8 +862,8 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
But we create it to have field_type() == MYSQL_TYPE_TIME (or
MYSQL_TIMESTAMP_DATE or MYSQL_TYPE_DATETIME), and thus it will have
cmp_type() == TIME_RESULT.
- As no other item can have this combination of cmp_type() and result_type(),
- it allows us to identify our cache items, see 'case TIME_RESULT:' above.
+ As no other item can have this combination of cmp_type() and
+ result_type(), it allows us to identify our cache items.
*/
Item_cache_int *cache= new Item_cache_int(f_type);
cache->store(item, value);
@@ -2007,18 +1929,7 @@ void Item_func_between::fix_length_and_dec()
strings as.
*/
if (cmp_type == TIME_RESULT)
- {
- for (int i= 0; i < 3; i++)
- {
- if (args[i]->cmp_type() == TIME_RESULT)
- {
- if (args[i]->field_type() != MYSQL_TYPE_TIME ||
- (args[i]->field_type() == MYSQL_TYPE_TIME && compare_as_dates==0))
- compare_as_dates= args[i];
- continue;
- }
- }
- }
+ compare_as_dates= find_date_time_item(args, 3, 0);
/* See the comment about the similar block in Item_bool_func2 */
if (args[0]->real_item()->type() == FIELD_ITEM &&
@@ -2780,16 +2691,17 @@ void Item_func_case::fix_length_and_dec()
if (!(found_types= collect_cmp_types(agg, nagg)))
return;
- for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
+ for (i= 0; i <= (uint)TIME_RESULT; i++)
{
if (found_types & (1 << i) && !cmp_items[i])
{
DBUG_ASSERT((Item_result)i != ROW_RESULT);
+ DBUG_ASSERT((Item_result)i != TIME_RESULT);
if ((Item_result)i == STRING_RESULT &&
agg_arg_charsets(cmp_collation, agg, nagg, MY_COLL_CMP_CONV, 1))
return;
if (!(cmp_items[i]=
- cmp_item::get_comparator((Item_result)i,
+ cmp_item::get_comparator((Item_result)i, 0,
cmp_collation.collation)))
return;
}
@@ -2870,7 +2782,7 @@ void Item_func_case::cleanup()
uint i;
DBUG_ENTER("Item_func_case::cleanup");
Item_func::cleanup();
- for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
+ for (i= 0; i <= (uint)TIME_RESULT; i++)
{
delete cmp_items[i];
cmp_items[i]= 0;
@@ -3300,7 +3212,7 @@ uchar *in_decimal::get_value(Item *item)
}
-cmp_item* cmp_item::get_comparator(Item_result type,
+cmp_item* cmp_item::get_comparator(Item_result type, Item *warn_item,
CHARSET_INFO *cs)
{
switch (type) {
@@ -3315,7 +3227,8 @@ cmp_item* cmp_item::get_comparator(Item_result type,
case DECIMAL_RESULT:
return new cmp_item_decimal;
case TIME_RESULT:
- DBUG_ASSERT(0);
+ DBUG_ASSERT(warn_item);
+ return new cmp_item_datetime(warn_item);
break;
}
return 0; // to satisfy compiler :)
@@ -3379,7 +3292,7 @@ void cmp_item_row::store_value(Item *item)
{
if (!comparators[i])
if (!(comparators[i]=
- cmp_item::get_comparator(item->element_index(i)->result_type(),
+ cmp_item::get_comparator(item->element_index(i)->result_type(), 0,
item->element_index(i)->collation.collation)))
break; // new failed
comparators[i]->store_value(item->element_index(i));
@@ -3580,20 +3493,17 @@ static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y)
(uchar *) y->ptr(),y->length(), 0);
}
-
void Item_func_in::fix_length_and_dec()
{
Item **arg, **arg_end;
bool const_itm= 1;
THD *thd= current_thd;
- bool datetime_found= FALSE;
/* TRUE <=> arguments values will be compared as DATETIMEs. */
- bool compare_as_datetime= FALSE;
Item *date_arg= 0;
uint found_types= 0;
uint type_cnt= 0, i;
Item_result cmp_type= STRING_RESULT;
- left_result_type= args[0]->result_type();
+ left_result_type= args[0]->cmp_type();
if (!(found_types= collect_cmp_types(args, arg_count, true)))
return;
@@ -3605,7 +3515,7 @@ void Item_func_in::fix_length_and_dec()
break;
}
}
- for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
+ for (i= 0; i <= (uint)TIME_RESULT; i++)
{
if (found_types & 1 << i)
{
@@ -3620,16 +3530,12 @@ void Item_func_in::fix_length_and_dec()
agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1))
return;
arg_types_compatible= TRUE;
- }
- if (type_cnt == 1)
- {
- /*
- When comparing rows create the row comparator object beforehand to ease
- the DATETIME comparison detection procedure.
- */
+
if (cmp_type == ROW_RESULT)
{
+ uint cols= args[0]->cols();
cmp_item_row *cmp= 0;
+
if (const_itm && !nulls_in_row())
{
array= new in_row(arg_count-1, 0);
@@ -3641,66 +3547,20 @@ void Item_func_in::fix_length_and_dec()
return;
cmp_items[ROW_RESULT]= cmp;
}
- cmp->n= args[0]->cols();
+ cmp->n= cols;
cmp->alloc_comparators();
- }
- /* All DATE/DATETIME fields/functions has the STRING result type. */
- if (cmp_type == STRING_RESULT || cmp_type == ROW_RESULT)
- {
- uint col, cols= args[0]->cols();
- for (col= 0; col < cols; col++)
+ for (uint col= 0; col < cols; col++)
{
- bool skip_column= FALSE;
- /*
- Check that all items to be compared has the STRING result type and at
- least one of them is a DATE/DATETIME item.
- */
- for (arg= args, arg_end= args + arg_count; arg != arg_end ; arg++)
+ date_arg= find_date_time_item(args, arg_count, col);
+ if (date_arg)
{
- Item *itm= ((cmp_type == STRING_RESULT) ? arg[0] :
- arg[0]->element_index(col));
- if (itm->result_type() != STRING_RESULT)
- {
- skip_column= TRUE;
- break;
- }
- else if (itm->cmp_type() == TIME_RESULT)
- {
- datetime_found= TRUE;
- /*
- Internally all DATE/DATETIME values are converted to the DATETIME
- type. So try to find a DATETIME item to issue correct warnings.
- */
- if (!date_arg)
- date_arg= itm;
- else if (itm->field_type() == MYSQL_TYPE_DATETIME)
- {
- date_arg= itm;
- /* All arguments are already checked to have the STRING result. */
- if (cmp_type == STRING_RESULT)
- break;
- }
- }
- }
- if (skip_column)
- continue;
- if (datetime_found)
- {
- if (cmp_type == ROW_RESULT)
- {
- cmp_item **cmp= 0;
- if (array)
- cmp= ((in_row*)array)->tmp.comparators + col;
- else
- cmp= ((cmp_item_row*)cmp_items[ROW_RESULT])->comparators + col;
- *cmp= new cmp_item_datetime(date_arg);
- /* Reset variables for the next column. */
- date_arg= 0;
- datetime_found= FALSE;
- }
+ cmp_item **cmp= 0;
+ if (array)
+ cmp= ((in_row*)array)->tmp.comparators + col;
else
- compare_as_datetime= TRUE;
+ cmp= ((cmp_item_row*)cmp_items[ROW_RESULT])->comparators + col;
+ *cmp= new cmp_item_datetime(date_arg);
}
}
}
@@ -3711,61 +3571,57 @@ void Item_func_in::fix_length_and_dec()
*/
if (type_cnt == 1 && const_itm && !nulls_in_row())
{
- if (compare_as_datetime)
- array= new in_datetime(date_arg, arg_count - 1);
- else
+ /*
+ IN must compare INT columns and constants as int values (the same
+ way as equality does).
+ So we must check here if the column on the left and all the constant
+ values on the right can be compared as integers and adjust the
+ comparison type accordingly.
+
+ See the comment about the similar block in Item_bool_func2
+ */
+ if (args[0]->real_item()->type() == FIELD_ITEM &&
+ !thd->is_context_analysis_only() && cmp_type != INT_RESULT)
{
- /*
- IN must compare INT columns and constants as int values (the same
- way as equality does).
- So we must check here if the column on the left and all the constant
- values on the right can be compared as integers and adjust the
- comparison type accordingly.
-
- See the comment about the similar block in Item_bool_func2
- */
- if (args[0]->real_item()->type() == FIELD_ITEM &&
- !thd->is_context_analysis_only() && cmp_type != INT_RESULT)
+ Item_field *field_item= (Item_field*) (args[0]->real_item());
+ if (field_item->cmp_type() == INT_RESULT)
{
- Item_field *field_item= (Item_field*) (args[0]->real_item());
- if (field_item->cmp_type() == INT_RESULT)
+ bool all_converted= TRUE;
+ for (arg=args+1, arg_end=args+arg_count; arg != arg_end ; arg++)
{
- bool all_converted= TRUE;
- for (arg=args+1, arg_end=args+arg_count; arg != arg_end ; arg++)
- {
- if (!convert_constant_item (thd, field_item, &arg[0]))
- all_converted= FALSE;
- }
- if (all_converted)
- cmp_type= INT_RESULT;
+ if (!convert_constant_item (thd, field_item, &arg[0]))
+ all_converted= FALSE;
}
+ if (all_converted)
+ cmp_type= INT_RESULT;
}
- switch (cmp_type) {
- case STRING_RESULT:
- array=new in_string(arg_count-1,(qsort2_cmp) srtcmp_in,
- cmp_collation.collation);
- break;
- case INT_RESULT:
- array= new in_longlong(arg_count-1);
- break;
- case REAL_RESULT:
- array= new in_double(arg_count-1);
- break;
- case ROW_RESULT:
- /*
- The row comparator was created at the beginning but only DATETIME
- items comparators were initialized. Call store_value() to setup
- others.
- */
- ((in_row*)array)->tmp.store_value(args[0]);
- break;
- case DECIMAL_RESULT:
- array= new in_decimal(arg_count - 1);
- break;
- case TIME_RESULT:
- DBUG_ASSERT(0);
- break;
- }
+ }
+ switch (cmp_type) {
+ case STRING_RESULT:
+ array=new in_string(arg_count-1,(qsort2_cmp) srtcmp_in,
+ cmp_collation.collation);
+ break;
+ case INT_RESULT:
+ array= new in_longlong(arg_count-1);
+ break;
+ case REAL_RESULT:
+ array= new in_double(arg_count-1);
+ break;
+ case ROW_RESULT:
+ /*
+ The row comparator was created at the beginning but only DATETIME
+ items comparators were initialized. Call store_value() to setup
+ others.
+ */
+ ((in_row*)array)->tmp.store_value(args[0]);
+ break;
+ case DECIMAL_RESULT:
+ array= new in_decimal(arg_count - 1);
+ break;
+ case TIME_RESULT:
+ date_arg= find_date_time_item(args, arg_count, 0);
+ array= new in_datetime(date_arg, arg_count - 1);
+ break;
}
if (array && !(thd->is_fatal_error)) // If not EOM
{
@@ -3786,23 +3642,21 @@ void Item_func_in::fix_length_and_dec()
}
else
{
- if (compare_as_datetime)
- cmp_items[STRING_RESULT]= new cmp_item_datetime(date_arg);
- else
+ for (i= 0; i <= (uint) TIME_RESULT; i++)
{
- for (i= 0; i <= (uint) DECIMAL_RESULT; i++)
+ if (found_types & (1 << i) && !cmp_items[i])
{
- if (found_types & (1 << i) && !cmp_items[i])
- {
- if ((Item_result)i == STRING_RESULT &&
- agg_arg_charsets(cmp_collation, args, arg_count,
- MY_COLL_CMP_CONV, 1))
- return;
- if (!cmp_items[i] && !(cmp_items[i]=
- cmp_item::get_comparator((Item_result)i,
- cmp_collation.collation)))
- return;
- }
+ if ((Item_result)i == STRING_RESULT &&
+ agg_arg_charsets(cmp_collation, args, arg_count,
+ MY_COLL_CMP_CONV, 1))
+ return;
+ if ((Item_result)i == TIME_RESULT)
+ date_arg= find_date_time_item(args, arg_count, 0);
+
+ if (!cmp_items[i] && !(cmp_items[i]=
+ cmp_item::get_comparator((Item_result)i, date_arg,
+ cmp_collation.collation)))
+ return;
}
}
}
@@ -3870,7 +3724,7 @@ longlong Item_func_in::val_int()
have_null= TRUE;
continue;
}
- Item_result cmp_type= item_cmp_type(left_result_type, args[i]->result_type());
+ Item_result cmp_type= item_cmp_type(left_result_type, args[i]->cmp_type());
in_item= cmp_items[(uint)cmp_type];
DBUG_ASSERT(in_item);
if (!(value_added_map & (1 << (uint)cmp_type)))
@@ -5398,7 +5252,7 @@ longlong Item_equal::val_int()
void Item_equal::fix_length_and_dec()
{
Item *item= get_first();
- eval_item= cmp_item::get_comparator(item->result_type(),
+ eval_item= cmp_item::get_comparator(item->result_type(), 0,
item->collation.collation);
}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index d86ae7422c6..6ec070bcc57 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -950,7 +950,8 @@ public:
virtual int cmp(Item *item)= 0;
// for optimized IN with row
virtual int compare(cmp_item *item)= 0;
- static cmp_item* get_comparator(Item_result type, CHARSET_INFO *cs);
+ static cmp_item* get_comparator(Item_result type, Item * warn_item,
+ CHARSET_INFO *cs);
virtual cmp_item *make_same()= 0;
virtual void store_value_by_template(cmp_item *tmpl, Item *item)
{
@@ -1146,7 +1147,7 @@ class Item_func_case :public Item_func
Item_result cmp_type;
DTCollation cmp_collation;
enum_field_types cached_field_type;
- cmp_item *cmp_items[5]; /* For all result types */
+ cmp_item *cmp_items[6]; /* For all result types */
cmp_item *case_item;
public:
Item_func_case(List<Item> &list, Item *first_expr_arg, Item *else_expr_arg)
@@ -1236,7 +1237,7 @@ public:
Item_int_func::cleanup();
delete array;
array= 0;
- for (i= 0; i <= (uint)DECIMAL_RESULT + 1; i++)
+ for (i= 0; i <= (uint)TIME_RESULT; i++)
{
delete cmp_items[i];
cmp_items[i]= 0;
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 5a8e8a4defd..b3eb991b747 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -664,8 +664,8 @@ void Item_num_op::find_num_type(void)
DBUG_ENTER("Item_num_op::find_num_type");
DBUG_PRINT("info", ("name %s", func_name()));
DBUG_ASSERT(arg_count == 2);
- Item_result r0= args[0]->result_type();
- Item_result r1= args[1]->result_type();
+ Item_result r0= args[0]->cast_to_int_type();
+ Item_result r1= args[1]->cast_to_int_type();
if (r0 == REAL_RESULT || r1 == REAL_RESULT ||
r0 == STRING_RESULT || r1 ==STRING_RESULT)
@@ -674,7 +674,8 @@ void Item_num_op::find_num_type(void)
max_length= float_length(decimals);
hybrid_type= REAL_RESULT;
}
- else if (r0 == DECIMAL_RESULT || r1 == DECIMAL_RESULT)
+ else if (r0 == DECIMAL_RESULT || r1 == DECIMAL_RESULT ||
+ r0 == TIME_RESULT || r1 == TIME_RESULT)
{
hybrid_type= DECIMAL_RESULT;
result_precision();
@@ -705,7 +706,7 @@ void Item_func_num1::find_num_type()
{
DBUG_ENTER("Item_func_num1::find_num_type");
DBUG_PRINT("info", ("name %s", func_name()));
- switch (hybrid_type= args[0]->result_type()) {
+ switch (hybrid_type= args[0]->cast_to_int_type()) {
case INT_RESULT:
unsigned_flag= args[0]->unsigned_flag;
break;
@@ -714,9 +715,10 @@ void Item_func_num1::find_num_type()
hybrid_type= REAL_RESULT;
max_length= float_length(decimals);
break;
+ case TIME_RESULT:
+ hybrid_type= DECIMAL_RESULT;
case DECIMAL_RESULT:
break;
- case TIME_RESULT:
case ROW_RESULT:
DBUG_ASSERT(0);
}
@@ -1815,7 +1817,7 @@ void Item_func_int_val::find_num_type()
{
DBUG_ENTER("Item_func_int_val::find_num_type");
DBUG_PRINT("info", ("name %s", func_name()));
- switch(hybrid_type= args[0]->result_type())
+ switch(hybrid_type= args[0]->cast_to_int_type())
{
case STRING_RESULT:
case REAL_RESULT:
@@ -1823,6 +1825,7 @@ void Item_func_int_val::find_num_type()
max_length= float_length(decimals);
break;
case INT_RESULT:
+ case TIME_RESULT:
case DECIMAL_RESULT:
/*
-2 because in most high position can't be used any digit for longlong
@@ -1840,7 +1843,6 @@ void Item_func_int_val::find_num_type()
}
break;
case ROW_RESULT:
- case TIME_RESULT:
DBUG_ASSERT(0);
}
DBUG_PRINT("info", ("Type: %s",
@@ -2240,16 +2242,9 @@ void Item_func_min_max::fix_length_and_dec()
if (args[i]->maybe_null)
maybe_null= 1;
cmp_type= item_cmp_type(cmp_type,args[i]->result_type());
- if (args[i]->cmp_type() == TIME_RESULT)
- {
- if (!compare_as_dates || args[i]->field_type() == MYSQL_TYPE_DATETIME)
- compare_as_dates= args[i];
- }
}
if (cmp_type == STRING_RESULT)
- {
agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV, 1);
- }
else if ((cmp_type == DECIMAL_RESULT) || (cmp_type == INT_RESULT))
max_length= my_decimal_precision_to_length_no_truncation(max_int_part +
decimals, decimals,
@@ -2257,8 +2252,15 @@ void Item_func_min_max::fix_length_and_dec()
else if (cmp_type == REAL_RESULT)
max_length= float_length(decimals);
+ compare_as_dates= find_date_time_item(args, arg_count, 0);
if (compare_as_dates)
+ {
cached_field_type= compare_as_dates->field_type();
+ if (mysql_type_to_time_type(cached_field_type) == MYSQL_TIMESTAMP_DATE)
+ decimals= 0;
+ else
+ set_if_smaller(decimals, TIME_SECOND_PART_DIGITS);
+ }
else
cached_field_type= agg_field_type(args, arg_count);
}
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index d2fd0c4b0eb..e38e1d237b6 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -500,7 +500,7 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table,
field= Field_new_decimal::create_from_item(this);
break;
case ROW_RESULT:
- default:
+ case TIME_RESULT:
// This case should never be choosen
DBUG_ASSERT(0);
return 0;
@@ -624,7 +624,7 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
max_length= item->max_length;
break;
case ROW_RESULT:
- default:
+ case TIME_RESULT:
DBUG_ASSERT(0);
};
setup_hybrid(args[0], NULL);
@@ -761,13 +761,14 @@ void Item_sum_sum::fix_length_and_dec()
DBUG_ENTER("Item_sum_sum::fix_length_and_dec");
maybe_null=null_value=1;
decimals= args[0]->decimals;
- switch (args[0]->result_type()) {
+ switch (args[0]->cast_to_int_type()) {
case REAL_RESULT:
case STRING_RESULT:
hybrid_type= REAL_RESULT;
sum= 0.0;
break;
case INT_RESULT:
+ case TIME_RESULT:
case DECIMAL_RESULT:
{
/* SUM result can't be longer than length(arg) + length(MAX_ROWS) */
@@ -781,7 +782,6 @@ void Item_sum_sum::fix_length_and_dec()
break;
}
case ROW_RESULT:
- default:
DBUG_ASSERT(0);
}
DBUG_PRINT("info", ("Type: %s (%d, %d)",
@@ -970,7 +970,7 @@ void Item_sum_distinct::fix_length_and_dec()
table_field_type= MYSQL_TYPE_NEWDECIMAL;
break;
case ROW_RESULT:
- default:
+ case TIME_RESULT:
DBUG_ASSERT(0);
}
val.traits->fix_length_and_dec(this, args[0]);
@@ -1421,7 +1421,7 @@ void Item_sum_variance::fix_length_and_dec()
break;
}
case ROW_RESULT:
- default:
+ case TIME_RESULT:
DBUG_ASSERT(0);
}
DBUG_PRINT("info", ("Type: REAL_RESULT (%d, %d)", max_length, (int)decimals));
@@ -1832,7 +1832,7 @@ void Item_sum_hybrid::reset_field()
break;
}
case ROW_RESULT:
- default:
+ case TIME_RESULT:
DBUG_ASSERT(0);
}
}
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 18fde7abce3..4174e8083e6 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -46,65 +46,6 @@ static bool make_datetime(MYSQL_TIME *ltime, String *str, uint decimals)
/*
- Convert seconds to MYSQL_TIME value with overflow checking
-
- SYNOPSIS:
- sec_to_time()
- seconds number of seconds
- ltime output MYSQL_TIME value
-
- DESCRIPTION
- If the 'seconds' argument is inside MYSQL_TIME data range, convert it to a
- corresponding value.
- Otherwise, truncate the resulting value to the nearest endpoint, and
- produce a warning message.
-
- RETURN
- 1 if the value was truncated during conversion
- 0 otherwise
-*/
-
-bool Item_func_sec_to_time::sec_to_time(double seconds, MYSQL_TIME *ltime)
-{
- Lazy_string_double str(seconds);
- uint sec;
- const double max_sec_val= TIME_MAX_VALUE_SECONDS +
- TIME_MAX_SECOND_PART/(double)TIME_SECOND_PART_FACTOR;
-
- bzero((char *)ltime, sizeof(*ltime));
-
- ltime->time_type= MYSQL_TIMESTAMP_TIME;
-
- if (seconds < 0)
- {
- ltime->neg= 1;
- if (seconds < -max_sec_val)
- goto overflow;
- seconds= -seconds;
- }
- else if (seconds > max_sec_val)
- goto overflow;
-
- sec= (uint) ((ulonglong) seconds % 3600);
- ltime->hour= (uint) (seconds/3600);
- ltime->minute= sec/60;
- ltime->second= sec % 60;
- ltime->second_part= (ulong)((seconds - floor(seconds))*TIME_SECOND_PART_FACTOR);
-
- return 0;
-
-overflow:
- /* use check_time_range() to set ltime to the max value depending on dec */
- int unused;
- ltime->hour= TIME_MAX_HOUR+1;
- check_time_range(ltime, decimals, &unused);
- make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- &str, MYSQL_TIMESTAMP_TIME, NullS);
- return 1;
-}
-
-
-/*
Date formats corresponding to compound %r and %T conversion specifiers
Note: We should init at least first element of "positions" array
@@ -1225,14 +1166,15 @@ longlong Item_func_unix_timestamp::int_op()
}
-double Item_func_unix_timestamp::real_op()
+my_decimal *Item_func_unix_timestamp::decimal_op(my_decimal* buf)
{
ulong second_part;
my_time_t seconds;
if (get_timestamp_value(&seconds, &second_part))
return 0;
- return seconds + second_part/(double)TIME_SECOND_PART_FACTOR;
+ return seconds2my_decimal(seconds < 0, seconds < 0 ? -seconds : seconds,
+ second_part, buf);
}
@@ -1240,21 +1182,23 @@ longlong Item_func_time_to_sec::int_op()
{
DBUG_ASSERT(fixed == 1);
MYSQL_TIME ltime;
- longlong seconds;
- (void) get_arg0_time(&ltime);
- seconds=ltime.hour*3600L+ltime.minute*60+ltime.second;
+ if (get_arg0_time(&ltime))
+ return 0;
+
+ longlong seconds=ltime.hour*3600L+ltime.minute*60+ltime.second;
return ltime.neg ? -seconds : seconds;
}
-double Item_func_time_to_sec::real_op()
+my_decimal *Item_func_time_to_sec::decimal_op(my_decimal* buf)
{
DBUG_ASSERT(fixed == 1);
MYSQL_TIME ltime;
- double seconds;
- (void) get_arg0_time(&ltime);
- seconds=ltime.hour*3600L+ltime.minute*60+ltime.second+ltime.second_part/1e6;
- return ltime.neg ? -seconds : seconds;
+ if (get_arg0_time(&ltime))
+ return 0;
+
+ longlong seconds= ltime.hour*3600L+ltime.minute*60+ltime.second;
+ return seconds2my_decimal(ltime.neg, seconds, ltime.second_part, buf);
}
@@ -1471,6 +1415,7 @@ void Item_func_curdate::fix_length_and_dec()
ltime.hour= ltime.minute= ltime.second= 0;
ltime.time_type= MYSQL_TIMESTAMP_DATE;
Item_datefunc::fix_length_and_dec();
+ maybe_null= false;
}
/**
@@ -1639,17 +1584,45 @@ bool Item_func_sysdate_local::get_date(MYSQL_TIME *res,
return 0;
}
-
bool Item_func_sec_to_time::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
DBUG_ASSERT(fixed == 1);
- double arg_val= args[0]->val_real();
-
+ bool sign;
+ ulonglong sec;
+ ulong sec_part;
+
+ bzero((char *)ltime, sizeof(*ltime));
+ ltime->time_type= MYSQL_TIMESTAMP_TIME;
+
+ sign= args[0]->get_seconds(&sec, &sec_part);
+
if ((null_value= args[0]->null_value))
return 1;
- sec_to_time(arg_val, ltime);
+ ltime->neg= sign;
+ if (sec > TIME_MAX_VALUE_SECONDS)
+ goto overflow;
+
+ DBUG_ASSERT(sec_part <= TIME_MAX_SECOND_PART);
+ ltime->hour= (uint) (sec/3600);
+ ltime->minute= (uint) (sec % 3600) /60;
+ ltime->second= (uint) sec % 60;
+ ltime->second_part= sec_part;
+
+ return 0;
+
+overflow:
+ /* use check_time_range() to set ltime to the max value depending on dec */
+ int unused;
+ char buf[100];
+ String tmp(buf, sizeof(buf), &my_charset_bin), *err= args[0]->val_str(&tmp);
+
+ ltime->hour= TIME_MAX_HOUR+1;
+ check_time_range(ltime, decimals, &unused);
+ make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ err->ptr(), err->length(),
+ MYSQL_TIMESTAMP_TIME, NullS);
return 0;
}
@@ -1831,7 +1804,6 @@ null_date:
void Item_func_from_unixtime::fix_length_and_dec()
{
thd= current_thd;
- maybe_null= 1;
thd->time_zone_used= 1;
decimals= args[0]->decimals;
Item_temporal_func::fix_length_and_dec();
@@ -1841,13 +1813,21 @@ void Item_func_from_unixtime::fix_length_and_dec()
bool Item_func_from_unixtime::get_date(MYSQL_TIME *ltime,
uint fuzzy_date __attribute__((unused)))
{
- double tmp= args[0]->val_real();
- if (args[0]->null_value || tmp < 0 || tmp > TIMESTAMP_MAX_VALUE)
+ bool sign;
+ ulonglong sec;
+ ulong sec_part;
+
+ bzero((char *)ltime, sizeof(*ltime));
+ ltime->time_type= MYSQL_TIMESTAMP_TIME;
+
+ sign= args[0]->get_seconds(&sec, &sec_part);
+
+ if (args[0]->null_value || sign || sec > TIMESTAMP_MAX_VALUE)
return (null_value= 1);
- thd->variables.time_zone->gmt_sec_to_TIME(ltime, (my_time_t)tmp);
+ thd->variables.time_zone->gmt_sec_to_TIME(ltime, (my_time_t)sec);
- ltime->second_part= (ulong)((tmp - floor(tmp))*TIME_SECOND_PART_FACTOR);
+ ltime->second_part= sec_part;
return (null_value= 0);
}
@@ -1855,7 +1835,6 @@ bool Item_func_from_unixtime::get_date(MYSQL_TIME *ltime,
void Item_func_convert_tz::fix_length_and_dec()
{
- maybe_null= 1;
decimals= args[0]->decimals;
Item_temporal_func::fix_length_and_dec();
}
@@ -1888,7 +1867,7 @@ bool Item_func_convert_tz::get_date(MYSQL_TIME *ltime,
}
{
- my_bool not_used;
+ uint not_used;
my_time_tmp= from_tz->TIME_to_gmt_sec(ltime, &not_used);
ulong sec_part= ltime->second_part;
/* my_time_tmp is guranteed to be in the allowed range */
@@ -1913,7 +1892,6 @@ void Item_func_convert_tz::cleanup()
void Item_date_add_interval::fix_length_and_dec()
{
enum_field_types arg0_field_type;
- maybe_null=1;
/*
The field type for the result of an Item_date function is defined as
@@ -2149,10 +2127,17 @@ bool Item_char_typecast::eq(const Item *item, bool binary_cmp) const
void Item_temporal_typecast::print(String *str, enum_query_type query_type)
{
+ char buf[32];
str->append(STRING_WITH_LEN("cast("));
args[0]->print(str, query_type);
str->append(STRING_WITH_LEN(" as "));
str->append(cast_type());
+ if (decimals)
+ {
+ str->append('(');
+ str->append(llstr(decimals, buf));
+ str->append(')');
+ }
str->append(')');
}
@@ -2300,6 +2285,8 @@ bool Item_time_typecast::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
if (get_arg0_time(ltime))
return 1;
+ if (decimals < TIME_SECOND_PART_DIGITS)
+ ltime->second_part= sec_part_truncate(ltime->second_part, decimals);
/*
MYSQL_TIMESTAMP_TIME value can have non-zero day part,
which we should not lose.
@@ -2325,16 +2312,28 @@ bool Item_datetime_typecast::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
if (get_arg0_date(ltime, fuzzy_date & ~TIME_TIME_ONLY))
return 1;
+ if (decimals < TIME_SECOND_PART_DIGITS)
+ ltime->second_part= sec_part_truncate(ltime->second_part, decimals);
+
+
/*
ltime is valid MYSQL_TYPE_TIME (according to fuzzy_date).
But not every valid TIME value is a valid DATETIME value!
*/
- if (ltime->time_type == MYSQL_TIMESTAMP_TIME && ltime->hour >= 24)
+ if (ltime->time_type == MYSQL_TIMESTAMP_TIME)
{
- Lazy_string_time str(ltime);
- make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- &str, MYSQL_TIMESTAMP_DATETIME, 0);
- return (null_value= 1);
+ if (ltime->neg)
+ {
+ Lazy_string_time str(ltime);
+ make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ &str, MYSQL_TIMESTAMP_DATETIME, 0);
+ return (null_value= 1);
+ }
+
+ uint day= ltime->hour/24;
+ ltime->hour %= 24;
+ ltime->month= day / 31;
+ ltime->day= day % 31;
}
ltime->time_type= MYSQL_TIMESTAMP_DATETIME;
@@ -2384,7 +2383,6 @@ void Item_func_add_time::fix_length_and_dec()
{
enum_field_types arg0_field_type;
decimals= max(args[0]->decimals, args[1]->decimals);
- maybe_null= 1;
/*
The field type for the result of an Item_func_add_time function is defined
@@ -2653,7 +2651,7 @@ longlong Item_func_microsecond::val_int()
{
DBUG_ASSERT(fixed == 1);
MYSQL_TIME ltime;
- if (!get_arg0_time(&ltime))
+ if (!get_arg0_date(&ltime, TIME_FUZZY_DATE))
return ltime.second_part;
return 0;
}
@@ -2938,7 +2936,6 @@ get_date_time_result_type(const char *format, uint length)
void Item_func_str_to_date::fix_length_and_dec()
{
- maybe_null= 1;
cached_field_type= MYSQL_TYPE_DATETIME;
decimals= NOT_FIXED_DEC;
if ((const_item= args[1]->const_item()))
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index d50b0c20716..3b1f69d5383 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -306,12 +306,11 @@ public:
{
if (arg_count)
decimals= args[0]->decimals;
- if (decimals != NOT_FIXED_DEC)
- set_if_smaller(decimals, TIME_SECOND_PART_DIGITS);
+ set_if_smaller(decimals, TIME_SECOND_PART_DIGITS);
max_length=17 + (decimals ? decimals + 1 : 0);
}
- void find_num_type() { hybrid_type= decimals ? REAL_RESULT : INT_RESULT; }
- my_decimal *decimal_op(my_decimal* buf) { DBUG_ASSERT(0); return 0; }
+ void find_num_type() { hybrid_type= decimals ? DECIMAL_RESULT : INT_RESULT; }
+ double real_op() { DBUG_ASSERT(0); return 0; }
String *str_op(String *str) { DBUG_ASSERT(0); return 0; }
};
@@ -338,7 +337,7 @@ public:
return !has_timestamp_args();
}
longlong int_op();
- double real_op();
+ my_decimal *decimal_op(my_decimal* buf);
};
@@ -354,7 +353,7 @@ public:
}
bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
longlong int_op();
- double real_op();
+ my_decimal *decimal_op(my_decimal* buf);
};
@@ -383,6 +382,7 @@ public:
{ MAX_DATETIME_WIDTH, MAX_DATETIME_WIDTH, MAX_DATE_WIDTH,
MAX_DATETIME_WIDTH, MIN_TIME_WIDTH };
+ maybe_null= true;
max_length= max_time_type_width[mysql_type_to_time_type(field_type())+2];
if (decimals)
{
@@ -403,9 +403,6 @@ public:
Item_datefunc() :Item_temporal_func() { }
Item_datefunc(Item *a) :Item_temporal_func(a) { }
enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
- const char *func_name() const { return "date"; }
- bool get_date(MYSQL_TIME *res, uint fuzzy_date)
- { return get_arg0_date(res, fuzzy_date); }
};
@@ -432,6 +429,7 @@ public:
{
store_now_in_TIME(&ltime);
Item_timefunc::fix_length_and_dec();
+ maybe_null= false;
}
bool get_date(MYSQL_TIME *res, uint fuzzy_date);
/*
@@ -504,6 +502,7 @@ public:
{
store_now_in_TIME(&ltime);
Item_temporal_func::fix_length_and_dec();
+ maybe_null= false;
}
bool get_date(MYSQL_TIME *res, uint fuzzy_date);
virtual void store_now_in_TIME(MYSQL_TIME *now_time)=0;
@@ -623,13 +622,12 @@ class Item_func_convert_tz :public Item_temporal_func
class Item_func_sec_to_time :public Item_timefunc
{
- bool sec_to_time(double seconds, MYSQL_TIME *ltime);
+ bool sec_to_time(longlong seconds, ulong sec_part, MYSQL_TIME *ltime);
public:
Item_func_sec_to_time(Item *item) :Item_timefunc(item) {}
bool get_date(MYSQL_TIME *res, uint fuzzy_date);
void fix_length_and_dec()
{
- maybe_null=1;
decimals= args[0]->decimals;
Item_timefunc::fix_length_and_dec();
}
@@ -699,7 +697,6 @@ public:
void print(String *str, enum_query_type query_type);
void fix_length_and_dec()
{
- maybe_null= 1;
if (decimals == NOT_FIXED_DEC)
decimals= args[0]->decimals;
Item_temporal_func::fix_length_and_dec();
@@ -746,12 +743,6 @@ public:
Item_func_makedate(Item *a,Item *b) :Item_temporal_func(a,b) {}
const char *func_name() const { return "makedate"; }
enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
- void fix_length_and_dec()
- {
- /* It returns NULL when the second argument is less or equal to 0 */
- maybe_null= 1;
- Item_temporal_func::fix_length_and_dec();
- }
bool get_date(MYSQL_TIME *ltime, uint fuzzy_date);
};
@@ -782,7 +773,6 @@ public:
{
decimals= max(args[0]->decimals, args[1]->decimals);
Item_timefunc::fix_length_and_dec();
- maybe_null= 1;
}
bool get_date(MYSQL_TIME *ltime, uint fuzzy_date);
};
@@ -792,9 +782,7 @@ class Item_func_maketime :public Item_timefunc
public:
Item_func_maketime(Item *a, Item *b, Item *c)
:Item_timefunc(a, b, c)
- {
- maybe_null= TRUE;
- }
+ {}
const char *func_name() const { return "maketime"; }
bool get_date(MYSQL_TIME *ltime, uint fuzzy_date);
};
@@ -877,9 +865,4 @@ public:
Item_func_last_day(Item *a) :Item_datefunc(a) {}
const char *func_name() const { return "last_day"; }
bool get_date(MYSQL_TIME *res, uint fuzzy_date);
- void fix_length_and_dec()
- {
- maybe_null=1;
- Item_datefunc::fix_length_and_dec();
- }
};
diff --git a/sql/log.cc b/sql/log.cc
index dea93fa1f46..2899fd721e5 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -598,11 +598,11 @@ bool Log_to_csv_event_handler::
/* fill in query_time field */
calc_time_from_sec(&t, query_time, query_time_micro);
- if (table->field[2]->store_time(&t, MYSQL_TIMESTAMP_TIME))
+ if (table->field[2]->store_time(&t))
goto err;
/* lock_time */
calc_time_from_sec(&t, lock_time, lock_time_micro);
- if (table->field[3]->store_time(&t, MYSQL_TIMESTAMP_TIME))
+ if (table->field[3]->store_time(&t))
goto err;
/* rows_sent */
if (table->field[4]->store((longlong) thd->sent_row_count, TRUE))
diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc
index 3aa01880b83..e062867e1c0 100644
--- a/sql/my_decimal.cc
+++ b/sql/my_decimal.cc
@@ -16,6 +16,10 @@
#include "mysql_priv.h"
#include <time.h>
+#define DIG_BASE 1000000000
+#define DIG_PER_DEC1 9
+#define ROUND_UP(X) (((X)+DIG_PER_DEC1-1)/DIG_PER_DEC1)
+
#ifndef MYSQL_CLIENT
/**
@@ -208,20 +212,69 @@ int str2my_decimal(uint mask, const char *from, uint length,
}
+/**
+ converts a decimal into a pair of integers - for integer and fractional parts
+
+ special version, for decimals representing number of seconds.
+ integer part cannot be larger that 1e18 (otherwise it's an overflow).
+ fractional part is microseconds.
+*/
+bool my_decimal2seconds(const my_decimal *d, ulonglong *sec, ulong *microsec)
+{
+ int pos;
+
+ if (d->intg)
+ {
+ pos= (d->intg-1)/DIG_PER_DEC1;
+ *sec= d->buf[pos];
+ if (pos > 0)
+ *sec+= static_cast<longlong>(d->buf[pos-1]) * DIG_BASE;
+ }
+ else
+ {
+ *sec=0;
+ pos= -1;
+ }
+
+ *microsec= d->frac ? static_cast<longlong>(d->buf[pos+1]) / (DIG_BASE/1000000) : 0;
+
+ if (pos > 1)
+ {
+ for (int i=0; i < pos-1; i++)
+ if (d->buf[i])
+ {
+ *sec= LONGLONG_MAX;
+ break;
+ }
+ }
+ return d->sign();
+}
+
+
+/**
+ converts a pair of integers (seconds, microseconds) into a decimal
+*/
+my_decimal *seconds2my_decimal(bool sign,
+ ulonglong sec, ulong microsec, my_decimal *d)
+{
+ d->init();
+ longlong2decimal(sec, d); // cannot fail
+ if (microsec)
+ {
+ d->buf[(d->intg-1) / DIG_PER_DEC1 + 1]= microsec * (DIG_BASE/1000000);
+ d->frac= 6;
+ }
+ ((decimal_t *)d)->sign= sign;
+ return d;
+}
+
+
my_decimal *date2my_decimal(MYSQL_TIME *ltime, my_decimal *dec)
{
- longlong date;
- date = (ltime->year*100L + ltime->month)*100L + ltime->day;
+ longlong date= (ltime->year*100L + ltime->month)*100L + ltime->day;
if (ltime->time_type > MYSQL_TIMESTAMP_DATE)
date= ((date*100L + ltime->hour)*100L+ ltime->minute)*100L + ltime->second;
- if (int2my_decimal(E_DEC_FATAL_ERROR, ltime->neg ? -date : date, FALSE, dec))
- return dec;
- if (ltime->second_part)
- {
- dec->buf[(dec->intg-1) / 9 + 1]= ltime->second_part * 1000;
- dec->frac= 6;
- }
- return dec;
+ return seconds2my_decimal(ltime->neg, date, ltime->second_part, dec);
}
@@ -235,13 +288,9 @@ void my_decimal_trim(ulong *precision, uint *scale)
}
}
-
#ifndef DBUG_OFF
/* routines for debugging print */
-#define DIG_PER_DEC1 9
-#define ROUND_UP(X) (((X)+DIG_PER_DEC1-1)/DIG_PER_DEC1)
-
/* print decimal */
void
print_decimal(const my_decimal *dec)
diff --git a/sql/my_decimal.h b/sql/my_decimal.h
index a5077f397e3..37ce146b281 100644
--- a/sql/my_decimal.h
+++ b/sql/my_decimal.h
@@ -294,6 +294,11 @@ int my_decimal2string(uint mask, const my_decimal *d, uint fixed_prec,
uint fixed_dec, char filler, String *str);
#endif
+bool my_decimal2seconds(const my_decimal *d, ulonglong *sec, ulong *microsec);
+
+my_decimal *seconds2my_decimal(bool sign, ulonglong sec, ulong microsec,
+ my_decimal *d);
+
inline
int my_decimal2int(uint mask, const my_decimal *d, my_bool unsigned_flag,
longlong *l)
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 035f546f37a..f984668e69f 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -781,6 +781,18 @@ mysql_type_to_time_type(enum enum_field_types mysql_type)
#include "sql_profile.h"
#include "sql_partition.h"
+class Lazy_string_decimal: public Lazy_string
+{
+ const my_decimal *d;
+public:
+ Lazy_string_decimal(const my_decimal *d_arg)
+ : Lazy_string(), d(d_arg) {}
+ void copy(String *dst) const {
+ my_decimal2string(E_DEC_FATAL_ERROR, d,
+ 0, 0, ' ', dst);
+ }
+};
+
class user_var_entry;
class Security_context;
enum enum_var_type
@@ -1883,6 +1895,7 @@ void flush_thread_cache();
/* item_func.cc */
extern bool check_reserved_words(LEX_STRING *name);
extern enum_field_types agg_field_type(Item **items, uint nitems);
+Item *find_date_time_item(Item **args, uint nargs, uint col);
/* strfunc.cc */
ulonglong find_set(TYPELIB *lib, const char *x, uint length, CHARSET_INFO *cs,
@@ -2235,6 +2248,18 @@ void make_truncated_value_warning(THD *thd, MYSQL_ERROR::enum_warning_level leve
const Lazy_string *str_val,
timestamp_type time_type,
const char *field_name);
+bool double_to_datetime_with_warn(double value, MYSQL_TIME *ltime,
+ ulong fuzzydate,
+ enum_field_types f_type,
+ const char *name);
+bool decimal_to_datetime_with_warn(const my_decimal *value, MYSQL_TIME *ltime,
+ ulong fuzzydate,
+ enum_field_types f_type,
+ const char *name);
+bool int_to_datetime_with_warn(longlong value, MYSQL_TIME *ltime,
+ ulong fuzzydate,
+ enum_field_types f_type,
+ const char *name);
static inline void make_truncated_value_warning(THD *thd,
MYSQL_ERROR::enum_warning_level level, const char *str_val,
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 376364bab60..d66a72fcf2b 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -2715,15 +2715,19 @@ int set_var_collation_client::update(THD *thd)
bool sys_var_timestamp::check(THD *thd, set_var *var)
{
- double val= var->value->val_real();
- if (val < 0 || val > MY_TIME_T_MAX)
+ ulonglong sec;
+ ulong sec_part;
+ if (var->value->get_seconds(&sec, &sec_part))
+ return TRUE;
+
+ if (sec > TIMESTAMP_MAX_VALUE)
{
my_message(ER_UNKNOWN_ERROR,
"This version of MySQL doesn't support dates later than 2038",
MYF(0));
return TRUE;
}
- var->save_result.ulonglong_value= hrtime_from_time(var->value->val_real());
+ var->save_result.ulonglong_value= hrtime_from_time(sec)+sec_part;
return FALSE;
}
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index c45c4b7dd83..590f705d20e 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2332,11 +2332,7 @@ mysql_execute_command(THD *thd)
goto error;
}
it= new Item_func_unix_timestamp(it);
- /*
- it is OK only emulate fix_fieds, because we need only
- value of constant
- */
- it->quick_fix_field();
+ it->fix_fields(thd, &it);
res = purge_master_logs_before_date(thd, (ulong)it->val_int());
break;
}
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index c5df62c09cf..32a4dc66681 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -3804,21 +3804,21 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
{
thd->variables.time_zone->gmt_sec_to_TIME(&time,
(my_time_t) file->stats.create_time);
- table->field[14]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
+ table->field[14]->store_time(&time);
table->field[14]->set_notnull();
}
if (file->stats.update_time)
{
thd->variables.time_zone->gmt_sec_to_TIME(&time,
(my_time_t) file->stats.update_time);
- table->field[15]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
+ table->field[15]->store_time(&time);
table->field[15]->set_notnull();
}
if (file->stats.check_time)
{
thd->variables.time_zone->gmt_sec_to_TIME(&time,
(my_time_t) file->stats.check_time);
- table->field[16]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
+ table->field[16]->store_time(&time);
table->field[16]->set_notnull();
}
if (file->ha_table_flags() & (ulong) HA_HAS_CHECKSUM)
@@ -4286,10 +4286,10 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
bzero((char *)&time, sizeof(time));
((Field_timestamp *) proc_table->field[12])->get_time(&time);
- table->field[15]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
+ table->field[15]->store_time(&time);
bzero((char *)&time, sizeof(time));
((Field_timestamp *) proc_table->field[13])->get_time(&time);
- table->field[16]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
+ table->field[16]->store_time(&time);
copy_field_as_string(table->field[17], proc_table->field[14]);
copy_field_as_string(table->field[18], proc_table->field[15]);
table->field[19]->store(definer.ptr(), definer.length(), cs);
@@ -4925,21 +4925,21 @@ static void store_schema_partitions_record(THD *thd, TABLE *schema_table,
{
thd->variables.time_zone->gmt_sec_to_TIME(&time,
(my_time_t)stat_info.create_time);
- table->field[18]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
+ table->field[18]->store_time(&time);
table->field[18]->set_notnull();
}
if (stat_info.update_time)
{
thd->variables.time_zone->gmt_sec_to_TIME(&time,
(my_time_t)stat_info.update_time);
- table->field[19]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
+ table->field[19]->store_time(&time);
table->field[19]->set_notnull();
}
if (stat_info.check_time)
{
thd->variables.time_zone->gmt_sec_to_TIME(&time,
(my_time_t)stat_info.check_time);
- table->field[20]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
+ table->field[20]->store_time(&time);
table->field[20]->set_notnull();
}
if (file->ha_table_flags() & (ulong) HA_HAS_CHECKSUM)
@@ -5321,15 +5321,13 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
/* starts & ends . STARTS is always set - see sql_yacc.yy */
et.time_zone->gmt_sec_to_TIME(&time, et.starts);
sch_table->field[ISE_STARTS]->set_notnull();
- sch_table->field[ISE_STARTS]->
- store_time(&time, MYSQL_TIMESTAMP_DATETIME);
+ sch_table->field[ISE_STARTS]->store_time(&time);
if (!et.ends_null)
{
et.time_zone->gmt_sec_to_TIME(&time, et.ends);
sch_table->field[ISE_ENDS]->set_notnull();
- sch_table->field[ISE_ENDS]->
- store_time(&time, MYSQL_TIMESTAMP_DATETIME);
+ sch_table->field[ISE_ENDS]->store_time(&time);
}
}
else
@@ -5339,8 +5337,7 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
et.time_zone->gmt_sec_to_TIME(&time, et.execute_at);
sch_table->field[ISE_EXECUTE_AT]->set_notnull();
- sch_table->field[ISE_EXECUTE_AT]->
- store_time(&time, MYSQL_TIMESTAMP_DATETIME);
+ sch_table->field[ISE_EXECUTE_AT]->store_time(&time);
}
/* status */
@@ -5370,21 +5367,19 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
sch_table->field[ISE_ON_COMPLETION]->
store(STRING_WITH_LEN("PRESERVE"), scs);
- number_to_datetime(et.created, &time, 0, &not_used);
+ number_to_datetime(et.created, 0, &time, 0, &not_used);
DBUG_ASSERT(not_used==0);
- sch_table->field[ISE_CREATED]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
+ sch_table->field[ISE_CREATED]->store_time(&time);
- number_to_datetime(et.modified, &time, 0, &not_used);
+ number_to_datetime(et.modified, 0, &time, 0, &not_used);
DBUG_ASSERT(not_used==0);
- sch_table->field[ISE_LAST_ALTERED]->
- store_time(&time, MYSQL_TIMESTAMP_DATETIME);
+ sch_table->field[ISE_LAST_ALTERED]->store_time(&time);
if (et.last_executed)
{
et.time_zone->gmt_sec_to_TIME(&time, et.last_executed);
sch_table->field[ISE_LAST_EXECUTED]->set_notnull();
- sch_table->field[ISE_LAST_EXECUTED]->
- store_time(&time, MYSQL_TIMESTAMP_DATETIME);
+ sch_table->field[ISE_LAST_EXECUTED]->store_time(&time);
}
sch_table->field[ISE_EVENT_COMMENT]->
diff --git a/sql/time.cc b/sql/time.cc
index ba81fcc86c2..4285e02fb65 100644
--- a/sql/time.cc
+++ b/sql/time.cc
@@ -242,6 +242,109 @@ str_to_datetime_with_warn(const char *str, uint length, MYSQL_TIME *l_time,
}
+/**
+ converts a pair of numbers (integer part, microseconds) to MYSQL_TIME
+
+ @param neg sign of the time value
+ @param nr integer part of the number to convert
+ @param sec_part microsecond part of the number
+ @param ltime converted value will be written here
+ @param fuzzydate conversion flags (TIME_FUZZY_DATE, etc)
+ @param str original number, as a Lazy_string. For the warning
+ @param f_type how to treat the number as. Possible values
+ MYSQL_TYPE_TIME, MYSQL_TYPE_DATE, MYSQL_TYPE_DATETIME
+ or MYSQL_TYPE_SET (which means auto-set to TIME or
+ DATETIME depending on fuzzydate)
+ @param name field name for the warning message; NULL if not a field
+
+ @returns 0 for success, 1 for a failure
+*/
+static bool number_to_time_with_warn(bool neg, ulonglong nr, ulong sec_part,
+ MYSQL_TIME *ltime, ulong fuzzydate,
+ const Lazy_string *str,
+ enum_field_types f_type,
+ const char *name)
+{
+ int was_cut;
+ longlong res;
+
+ if (f_type == MYSQL_TYPE_SET)
+ f_type= fuzzydate & TIME_TIME_ONLY ? MYSQL_TYPE_TIME
+ : MYSQL_TYPE_DATETIME;
+
+ switch (f_type) {
+ case MYSQL_TYPE_YEAR:
+ bzero(ltime, sizeof(*ltime));
+ ltime->year= nr;
+ ltime->time_type= MYSQL_TIMESTAMP_DATE;
+ if (nr > 9999 || (fuzzydate & (TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE)))
+ res= -1;
+ break;
+ case MYSQL_TYPE_TIME:
+ res= number_to_time(neg, nr, sec_part, ltime, &was_cut);
+ break;
+ default:
+ res= number_to_datetime(nr, sec_part, ltime, fuzzydate, &was_cut);
+ break;
+ }
+ if (res >= 0)
+ return 0;
+
+ make_truncated_value_warning(current_thd,
+ MYSQL_ERROR::WARN_LEVEL_WARN, str,
+ mysql_type_to_time_type(f_type),
+ name);
+ return 1;
+}
+
+
+bool double_to_datetime_with_warn(double value, MYSQL_TIME *ltime,
+ ulong fuzzydate,
+ enum_field_types f_type,
+ const char *name)
+{
+ const Lazy_string_double str(value);
+ ulonglong nr;
+ ulong sec_part;
+ bool neg= value < 0;
+
+ if (neg)
+ value= -value;
+
+ nr = value > LONGLONG_MAX ? LONGLONG_MAX
+ : static_cast<ulonglong>(trunc(value));
+ sec_part= (ulong)((value - nr)*TIME_SECOND_PART_FACTOR);
+ return number_to_time_with_warn(neg, nr, sec_part, ltime, fuzzydate,
+ &str, f_type, name);
+}
+
+
+bool decimal_to_datetime_with_warn(const my_decimal *value, MYSQL_TIME *ltime,
+ ulong fuzzydate,
+ enum_field_types f_type,
+ const char *name)
+{
+ const Lazy_string_decimal str(value);
+ ulonglong nr;
+ ulong sec_part;
+ bool neg= my_decimal2seconds(value, &nr, &sec_part);
+ return number_to_time_with_warn(neg, nr, sec_part, ltime, fuzzydate,
+ &str, f_type, name);
+}
+
+
+bool int_to_datetime_with_warn(longlong value, MYSQL_TIME *ltime,
+ ulong fuzzydate,
+ enum_field_types f_type,
+ const char *name)
+{
+ const Lazy_string_num str(value);
+ bool neg= value < 0;
+ return number_to_time_with_warn(neg, neg ? -value : value, 0, ltime,
+ fuzzydate, &str, f_type, name);
+}
+
+
/*
Convert a datetime from broken-down MYSQL_TIME representation to corresponding
TIMESTAMP value.
@@ -263,23 +366,8 @@ str_to_datetime_with_warn(const char *str, uint length, MYSQL_TIME *l_time,
*/
my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, uint *error_code)
{
- my_time_t timestamp;
- my_bool in_dst_time_gap= 0;
-
- *error_code= 0;
thd->time_zone_used= 1;
-
- timestamp= thd->variables.time_zone->TIME_to_gmt_sec(t, &in_dst_time_gap);
- if (timestamp)
- {
- if (in_dst_time_gap)
- *error_code= ER_WARN_INVALID_TIMESTAMP;
- return timestamp;
- }
-
- /* If we are here we have range error. */
- *error_code= ER_WARN_DATA_OUT_OF_RANGE;
- return 0;
+ return thd->variables.time_zone->TIME_to_gmt_sec(t, error_code);
}
@@ -757,6 +845,7 @@ void make_truncated_value_warning(THD *thd, MYSQL_ERROR::enum_warning_level leve
(((((X)->day * 24LL + (X)->hour) * 60LL + \
(X)->minute) * 60LL + (X)->second)*1000000LL + \
(X)->second_part)
+#define GET_PART(X, N) X % N ## LL; X/= N ## LL
bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, INTERVAL interval)
{
@@ -782,7 +871,7 @@ bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, INTERVAL inter
case INTERVAL_DAY:
{
longlong usec, daynr;
- my_bool neg= ltime->neg;
+ my_bool neg= 0;
enum enum_mysql_timestamp_type time_type= ltime->time_type;
if (time_type != MYSQL_TIMESTAMP_TIME)
@@ -790,17 +879,31 @@ bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, INTERVAL inter
usec= COMBINE(ltime) + sign*COMBINE(&interval);
- unpack_time(usec, ltime);
- ltime->time_type= time_type;
+ if (usec < 0)
+ {
+ neg= 1;
+ usec= -usec;
+ }
+
+ ltime->second_part= GET_PART(usec, 1000000);
+ ltime->second= GET_PART(usec, 60);
+ ltime->minute= GET_PART(usec, 60);
ltime->neg^= neg;
if (time_type == MYSQL_TIMESTAMP_TIME)
- break;
+ {
+ if (usec > TIME_MAX_HOUR)
+ goto invalid_date;
+ ltime->hour= usec;
+ ltime->day= 0;
+ return 0;
+ }
if (int_type != INTERVAL_DAY)
ltime->time_type= MYSQL_TIMESTAMP_DATETIME; // Return full date
- daynr= usec/1000000/24/60/60;
+ ltime->hour= GET_PART(usec, 24);
+ daynr= usec;
/* Day number from year 0 to 9999-12-31 */
if ((ulonglong) daynr > MAX_DAY_NUMBER)
@@ -846,13 +949,15 @@ bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, INTERVAL inter
goto null_date;
}
- return 0; // Ok
+ if (ltime->time_type != MYSQL_TIMESTAMP_TIME)
+ return 0; // Ok
invalid_date:
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_DATETIME_FUNCTION_OVERFLOW,
ER(ER_DATETIME_FUNCTION_OVERFLOW),
- "datetime");
+ ltime->time_type == MYSQL_TIMESTAMP_TIME ?
+ "time" : "datetime");
null_date:
return 1;
}
diff --git a/sql/tztime.cc b/sql/tztime.cc
index 7ebb8eb392a..9921f9db0d4 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -815,9 +815,11 @@ sec_since_epoch(int year, int mon, int mday, int hour, int min ,int sec)
TIME_to_gmt_sec()
t - pointer to structure for broken down represenatation
sp - pointer to struct with time zone description
- in_dst_time_gap - pointer to bool which is set to true if datetime
- value passed doesn't really exist (i.e. falls into
- spring time-gap) and is not touched otherwise.
+ error_code - 0, if the conversion was successful;
+ ER_WARN_DATA_OUT_OF_RANGE, if t contains datetime value
+ which is out of TIMESTAMP range;
+ ER_WARN_INVALID_TIMESTAMP, if t represents value which
+ doesn't exists (falls into the spring time-gap).
DESCRIPTION
This is mktime analog for MySQL. It is essentially different
@@ -880,8 +882,7 @@ sec_since_epoch(int year, int mon, int mday, int hour, int min ,int sec)
0 in case of error.
*/
static my_time_t
-TIME_to_gmt_sec(const MYSQL_TIME *t, const TIME_ZONE_INFO *sp,
- my_bool *in_dst_time_gap)
+TIME_to_gmt_sec(const MYSQL_TIME *t, const TIME_ZONE_INFO *sp, uint *error_code)
{
my_time_t local_t;
uint saved_seconds;
@@ -891,8 +892,12 @@ TIME_to_gmt_sec(const MYSQL_TIME *t, const TIME_ZONE_INFO *sp,
DBUG_ENTER("TIME_to_gmt_sec");
if (!validate_timestamp_range(t))
+ {
+ *error_code= ER_WARN_DATA_OUT_OF_RANGE;
DBUG_RETURN(0);
+ }
+ *error_code= 0;
/* We need this for correct leap seconds handling */
if (t->second < SECS_PER_MIN)
@@ -936,6 +941,7 @@ TIME_to_gmt_sec(const MYSQL_TIME *t, const TIME_ZONE_INFO *sp,
This means that source time can't be represented as my_time_t due to
limited my_time_t range.
*/
+ *error_code= ER_WARN_DATA_OUT_OF_RANGE;
DBUG_RETURN(0);
}
@@ -952,6 +958,7 @@ TIME_to_gmt_sec(const MYSQL_TIME *t, const TIME_ZONE_INFO *sp,
if (local_t > (my_time_t) (TIMESTAMP_MAX_VALUE - shift * SECS_PER_DAY +
sp->revtis[i].rt_offset - saved_seconds))
{
+ *error_code= ER_WARN_DATA_OUT_OF_RANGE;
DBUG_RETURN(0); /* my_time_t overflow */
}
local_t+= shift * SECS_PER_DAY;
@@ -965,7 +972,7 @@ TIME_to_gmt_sec(const MYSQL_TIME *t, const TIME_ZONE_INFO *sp,
Now we are returning my_time_t value corresponding to the
beginning of the gap.
*/
- *in_dst_time_gap= 1;
+ *error_code= ER_WARN_INVALID_TIMESTAMP;
local_t= sp->revts[i] - sp->revtis[i].rt_offset + saved_seconds;
}
else
@@ -1007,8 +1014,7 @@ class Time_zone_system : public Time_zone
{
public:
Time_zone_system() {} /* Remove gcc warning */
- virtual my_time_t TIME_to_gmt_sec(const MYSQL_TIME *t,
- my_bool *in_dst_time_gap) const;
+ virtual my_time_t TIME_to_gmt_sec(const MYSQL_TIME *t, uint *error_code) const;
virtual void gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const;
virtual const String * get_name() const;
};
@@ -1022,9 +1028,11 @@ public:
TIME_to_gmt_sec()
t - pointer to MYSQL_TIME structure with local time in
broken-down representation.
- in_dst_time_gap - pointer to bool which is set to true if datetime
- value passed doesn't really exist (i.e. falls into
- spring time-gap) and is not touched otherwise.
+ error_code - 0, if the conversion was successful;
+ ER_WARN_DATA_OUT_OF_RANGE, if t contains datetime value
+ which is out of TIMESTAMP range;
+ ER_WARN_INVALID_TIMESTAMP, if t represents value which
+ doesn't exists (falls into the spring time-gap).
DESCRIPTION
This method uses system function (localtime_r()) for conversion
@@ -1040,10 +1048,10 @@ public:
Corresponding my_time_t value or 0 in case of error
*/
my_time_t
-Time_zone_system::TIME_to_gmt_sec(const MYSQL_TIME *t, my_bool *in_dst_time_gap) const
+Time_zone_system::TIME_to_gmt_sec(const MYSQL_TIME *t, uint *error_code) const
{
long not_used;
- return my_system_gmt_sec(t, &not_used, in_dst_time_gap);
+ return my_system_gmt_sec(t, &not_used, error_code);
}
@@ -1103,7 +1111,7 @@ class Time_zone_utc : public Time_zone
public:
Time_zone_utc() {} /* Remove gcc warning */
virtual my_time_t TIME_to_gmt_sec(const MYSQL_TIME *t,
- my_bool *in_dst_time_gap) const;
+ uint *error_code) const;
virtual void gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const;
virtual const String * get_name() const;
};
@@ -1112,14 +1120,6 @@ public:
/*
Convert UTC time from MYSQL_TIME representation to its my_time_t representation.
- SYNOPSIS
- TIME_to_gmt_sec()
- t - pointer to MYSQL_TIME structure with local time
- in broken-down representation.
- in_dst_time_gap - pointer to bool which is set to true if datetime
- value passed doesn't really exist (i.e. falls into
- spring time-gap) and is not touched otherwise.
-
DESCRIPTION
Since Time_zone_utc is used only internally for my_time_t -> TIME
conversions, this function of Time_zone interface is not implemented for
@@ -1129,10 +1129,11 @@ public:
0
*/
my_time_t
-Time_zone_utc::TIME_to_gmt_sec(const MYSQL_TIME *t, my_bool *in_dst_time_gap) const
+Time_zone_utc::TIME_to_gmt_sec(const MYSQL_TIME *t, uint *error_code) const
{
/* Should be never called */
DBUG_ASSERT(0);
+ *error_code= ER_WARN_DATA_OUT_OF_RANGE;
return 0;
}
@@ -1192,8 +1193,7 @@ class Time_zone_db : public Time_zone
{
public:
Time_zone_db(TIME_ZONE_INFO *tz_info_arg, const String * tz_name_arg);
- virtual my_time_t TIME_to_gmt_sec(const MYSQL_TIME *t,
- my_bool *in_dst_time_gap) const;
+ virtual my_time_t TIME_to_gmt_sec(const MYSQL_TIME *t, uint *error_code) const;
virtual void gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const;
virtual const String * get_name() const;
private:
@@ -1230,9 +1230,11 @@ Time_zone_db::Time_zone_db(TIME_ZONE_INFO *tz_info_arg,
TIME_to_gmt_sec()
t - pointer to MYSQL_TIME structure with local time
in broken-down representation.
- in_dst_time_gap - pointer to bool which is set to true if datetime
- value passed doesn't really exist (i.e. falls into
- spring time-gap) and is not touched otherwise.
+ error_code - 0, if the conversion was successful;
+ ER_WARN_DATA_OUT_OF_RANGE, if t contains datetime value
+ which is out of TIMESTAMP range;
+ ER_WARN_INVALID_TIMESTAMP, if t represents value which
+ doesn't exists (falls into the spring time-gap).
DESCRIPTION
Please see ::TIME_to_gmt_sec for function description and
@@ -1242,9 +1244,9 @@ Time_zone_db::Time_zone_db(TIME_ZONE_INFO *tz_info_arg,
Corresponding my_time_t value or 0 in case of error
*/
my_time_t
-Time_zone_db::TIME_to_gmt_sec(const MYSQL_TIME *t, my_bool *in_dst_time_gap) const
+Time_zone_db::TIME_to_gmt_sec(const MYSQL_TIME *t, uint *error_code) const
{
- return ::TIME_to_gmt_sec(t, tz_info, in_dst_time_gap);
+ return ::TIME_to_gmt_sec(t, tz_info, error_code);
}
@@ -1290,7 +1292,7 @@ class Time_zone_offset : public Time_zone
public:
Time_zone_offset(long tz_offset_arg);
virtual my_time_t TIME_to_gmt_sec(const MYSQL_TIME *t,
- my_bool *in_dst_time_gap) const;
+ uint *error_code) const;
virtual void gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const;
virtual const String * get_name() const;
/*
@@ -1332,17 +1334,17 @@ Time_zone_offset::Time_zone_offset(long tz_offset_arg):
TIME_to_gmt_sec()
t - pointer to MYSQL_TIME structure with local time
in broken-down representation.
- in_dst_time_gap - pointer to bool which should be set to true if
- datetime value passed doesn't really exist
- (i.e. falls into spring time-gap) and is not
- touched otherwise.
- It is not really used in this class.
+ error_code - 0, if the conversion was successful;
+ ER_WARN_DATA_OUT_OF_RANGE, if t contains datetime value
+ which is out of TIMESTAMP range;
+ ER_WARN_INVALID_TIMESTAMP, if t represents value which
+ doesn't exists (falls into the spring time-gap).
RETURN VALUE
Corresponding my_time_t value or 0 in case of error
*/
my_time_t
-Time_zone_offset::TIME_to_gmt_sec(const MYSQL_TIME *t, my_bool *in_dst_time_gap) const
+Time_zone_offset::TIME_to_gmt_sec(const MYSQL_TIME *t, uint *error_code) const
{
my_time_t local_t;
int shift= 0;
@@ -1352,7 +1354,11 @@ Time_zone_offset::TIME_to_gmt_sec(const MYSQL_TIME *t, my_bool *in_dst_time_gap)
us to make all validation checks here.
*/
if (!validate_timestamp_range(t))
+ {
+ *error_code= ER_WARN_DATA_OUT_OF_RANGE;
return 0;
+ }
+ *error_code= 0;
/*
Do a temporary shift of the boundary dates to avoid
@@ -1376,6 +1382,7 @@ Time_zone_offset::TIME_to_gmt_sec(const MYSQL_TIME *t, my_bool *in_dst_time_gap)
return local_t;
/* range error*/
+ *error_code= ER_WARN_DATA_OUT_OF_RANGE;
return 0;
}
@@ -2733,7 +2740,7 @@ main(int argc, char **argv)
for (time_tmp.second=0; time_tmp.second<60; time_tmp.second+=25)
{
long not_used;
- my_bool not_used_2;
+ uint not_used_2;
t= (time_t)my_system_gmt_sec(&time_tmp, &not_used, &not_used_2);
t1= (time_t)TIME_to_gmt_sec(&time_tmp, &tz_info, &not_used_2);
if (t != t1)
diff --git a/sql/tztime.h b/sql/tztime.h
index 9bf103519c4..306f76dfece 100644
--- a/sql/tztime.h
+++ b/sql/tztime.h
@@ -33,11 +33,11 @@ public:
/**
Converts local time in broken down MYSQL_TIME representation to
my_time_t (UTC seconds since Epoch) represenation.
- Returns 0 in case of error. Sets in_dst_time_gap to true if date provided
- falls into spring time-gap (or lefts it untouched otherwise).
+ Returns 0 in case of error. May set error_code to ER_WARN_DATA_OUT_OF_RANGE
+ or ER_WARN_INVALID_TIMESTAMP, see TIME_to_timestamp())
*/
virtual my_time_t TIME_to_gmt_sec(const MYSQL_TIME *t,
- my_bool *in_dst_time_gap) const = 0;
+ uint *error_code) const = 0;
/**
Converts time in my_time_t representation to local time in
broken down MYSQL_TIME representation.
diff --git a/sql/unireg.h b/sql/unireg.h
index 50facf51d02..4f3a376ccf9 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -72,7 +72,7 @@
#define MAX_BIT_FIELD_LENGTH 64 /* Max length in bits for bit fields */
#define MAX_DATE_WIDTH 10 /* YYYY-MM-DD */
-#define MIN_TIME_WIDTH 9 /* HHH:MM:SS */
+#define MIN_TIME_WIDTH 10 /* -HHH:MM:SS */
#define MAX_TIME_WIDTH 16 /* -DDDDDD HH:MM:SS */
#define MAX_TIME_FULL_WIDTH 23 /* -DDDDDD HH:MM:SS.###### */
#define MAX_DATETIME_FULL_WIDTH 29 /* YYYY-MM-DD HH:MM:SS.###### AM */