summaryrefslogtreecommitdiff
path: root/sql/time.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/time.cc')
-rw-r--r--sql/time.cc149
1 files changed, 102 insertions, 47 deletions
diff --git a/sql/time.cc b/sql/time.cc
index 60cf4631b6f..7b59bc91e1f 100644
--- a/sql/time.cc
+++ b/sql/time.cc
@@ -241,32 +241,92 @@ str_to_datetime_with_warn(const char *str, uint length, MYSQL_TIME *l_time,
}
-bool double_to_datetime_with_warn(double value, MYSQL_TIME *ltime,
- ulong fuzzydate)
+/**
+ 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 field_name field name or NULL if not a field. For the warning
+
+ @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,
+ const char *field_name)
{
- if (double_to_datetime(value, ltime, fuzzydate))
+ int was_cut;
+ longlong res;
+ enum_field_types f_type;
+
+ if (fuzzydate & TIME_TIME_ONLY)
{
- char buff[40];
- uint length= my_sprintf(buff, (buff, "%-30.21g", value));
- make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- buff, length, MYSQL_TIMESTAMP_DATETIME,
- NullS);
- return 1;
+ f_type= MYSQL_TYPE_TIME;
+ res= number_to_time(neg, nr, sec_part, ltime, &was_cut);
}
- return 0;
+ else
+ {
+ f_type= MYSQL_TYPE_DATETIME;
+ res= number_to_datetime(nr, sec_part, ltime, fuzzydate, &was_cut);
+ }
+
+ if ((was_cut && !(fuzzydate & TIME_FUZZY_DATE)) || res < 0)
+ {
+ make_truncated_value_warning(current_thd,
+ MYSQL_ERROR::WARN_LEVEL_WARN, str,
+ res < 0 ? MYSQL_TIMESTAMP_ERROR
+ : mysql_type_to_time_type(f_type),
+ field_name);
+ }
+ return res < 0;
}
-bool decimal_to_datetime_with_warn(decimal_t *value, MYSQL_TIME *ltime,
- ulong fuzzydate)
+
+bool double_to_datetime_with_warn(double value, MYSQL_TIME *ltime,
+ ulong fuzzydate, const char *field_name)
{
- char buff[40];
- int length= sizeof(buff);
+ 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,
+ field_name);
+}
+
- decimal2string(value, buff, &length, 0, 0, 0);
- return (str_to_datetime_with_warn(buff, length, ltime, fuzzydate) <=
- MYSQL_TIMESTAMP_ERROR);
+bool decimal_to_datetime_with_warn(const my_decimal *value, MYSQL_TIME *ltime,
+ ulong fuzzydate, const char *field_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,
+ field_name);
}
+
+bool int_to_datetime_with_warn(longlong value, MYSQL_TIME *ltime,
+ ulong fuzzydate, const char *field_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, field_name);
+}
+
+
/*
Convert a datetime from broken-down MYSQL_TIME representation to
corresponding TIMESTAMP value.
@@ -288,25 +348,8 @@ bool decimal_to_datetime_with_warn(decimal_t *value, MYSQL_TIME *ltime,
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);
-
- /* In case of error, timestamp == 0 and in_dst_time_gap is != 0 */
- if (timestamp || ! in_dst_time_gap)
- {
- 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);
}
@@ -697,11 +740,6 @@ KNOWN_DATE_TIME_FORMAT known_date_time_formats[6]=
};
-/*
- Return format string according format name.
- If name is unknown, result is NULL
-*/
-
const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
timestamp_type type)
{
@@ -812,6 +850,7 @@ void make_truncated_value_warning(THD *thd,
(((((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)
@@ -838,7 +877,7 @@ bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type,
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)
@@ -846,17 +885,31 @@ bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type,
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)
@@ -902,13 +955,15 @@ bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type,
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;
}