summaryrefslogtreecommitdiff
path: root/sql-common
diff options
context:
space:
mode:
Diffstat (limited to 'sql-common')
-rw-r--r--sql-common/my_time.c104
1 files changed, 69 insertions, 35 deletions
diff --git a/sql-common/my_time.c b/sql-common/my_time.c
index 249ed48713a..e2f1b8c4e1c 100644
--- a/sql-common/my_time.c
+++ b/sql-common/my_time.c
@@ -63,9 +63,7 @@ uint calc_days_in_year(uint year)
static const ulonglong C_KNOWN_FLAGS= C_TIME_NO_ZERO_IN_DATE |
C_TIME_NO_ZERO_DATE |
- C_TIME_INVALID_DATES |
- C_TIME_TIME_ONLY |
- C_TIME_DATETIME_ONLY;
+ C_TIME_INVALID_DATES;
#define C_FLAGS_OK(flags) (((flags) & ~C_KNOWN_FLAGS) == 0)
@@ -161,7 +159,8 @@ static int get_punct(const char **str, const char *end)
return 1;
}
-static int get_date_time_separator(uint *number_of_fields, ulonglong flags,
+static int get_date_time_separator(uint *number_of_fields,
+ my_bool punct_is_date_time_separator,
const char **str, const char *end)
{
const char *s= *str;
@@ -180,11 +179,11 @@ static int get_date_time_separator(uint *number_of_fields, ulonglong flags,
but
cast("11:11:11.12.12.12" as time) should give 11:11:11.12
that is, a punctuation character can be accepted as a date/time separator
- only if TIME_DATETIME_ONLY (see str_to_time) is not set.
+ only if "punct_is_date_time_separator" is set.
*/
if (my_ispunct(&my_charset_latin1, *s))
{
- if (flags & C_TIME_DATETIME_ONLY)
+ if (!punct_is_date_time_separator)
{
/* see above, returning 1 is not enough, we need hard abort here */
*number_of_fields= 0;
@@ -414,6 +413,9 @@ str_to_DDhhmmssff_internal(my_bool neg, const char *str, size_t length,
TIME_NO_ZERO_IN_DATE Don't allow partial dates
TIME_NO_ZERO_DATE Don't allow 0000-00-00 date
TIME_INVALID_DATES Allow 2000-02-31
+ punct_is_date_time_separator
+ Allow punctuation as a date/time separator,
+ or return a hard error.
status Conversion status
@@ -448,7 +450,9 @@ str_to_DDhhmmssff_internal(my_bool neg, const char *str, size_t length,
static my_bool
str_to_datetime_or_date_body(const char *str, size_t length, MYSQL_TIME *l_time,
- ulonglong flags, MYSQL_TIME_STATUS *status)
+ ulonglong flags,
+ my_bool punct_is_date_time_separator,
+ MYSQL_TIME_STATUS *status)
{
const char *end=str+length, *pos;
uint number_of_fields= 0, digits, year_length, not_zero_date;
@@ -503,7 +507,8 @@ str_to_datetime_or_date_body(const char *str, size_t length, MYSQL_TIME *l_time,
|| get_number(&l_time->month, &number_of_fields, &str, end)
|| get_punct(&str, end)
|| get_number(&l_time->day, &number_of_fields, &str, end)
- || get_date_time_separator(&number_of_fields, flags, &str, end)
+ || get_date_time_separator(&number_of_fields,
+ punct_is_date_time_separator, &str, end)
|| get_number(&l_time->hour, &number_of_fields, &str, end)
|| get_punct(&str, end)
|| get_number(&l_time->minute, &number_of_fields, &str, end)
@@ -587,6 +592,7 @@ err:
TRUE on error
*/
+static
my_bool str_to_datetime_or_date_or_time_body(const char *str, size_t length,
MYSQL_TIME *l_time,
ulonglong fuzzydate,
@@ -599,9 +605,7 @@ my_bool str_to_datetime_or_date_or_time_body(const char *str, size_t length,
if (is_datetime_body_candidate(str, length))
{ /* Probably full timestamp */
(void) str_to_datetime_or_date_body(str, length, l_time,
- (fuzzydate & ~C_TIME_TIME_ONLY) |
- C_TIME_DATETIME_ONLY,
- status);
+ fuzzydate, FALSE, status);
if (l_time->time_type >= MYSQL_TIMESTAMP_ERROR)
return l_time->time_type == MYSQL_TIMESTAMP_ERROR;
my_time_status_init(status);
@@ -616,6 +620,12 @@ my_bool str_to_datetime_or_date_or_time_body(const char *str, size_t length,
}
+/*
+ Convert a string with INTERVAL DAY TO SECOND to MYSQL_TIME.
+ Input format: [-][DD ]hh:mm:ss.ffffff
+
+ If the input string appears to be a DATETIME, error is returned.
+*/
my_bool str_to_DDhhmmssff(const char *str, size_t length, MYSQL_TIME *ltime,
ulong max_hour, MYSQL_TIME_STATUS *status)
{
@@ -634,7 +644,7 @@ my_bool str_to_DDhhmmssff(const char *str, size_t length, MYSQL_TIME *ltime,
if (is_datetime_body_candidate(str, length))
{
(void) str_to_datetime_or_date_body(str, length, ltime,
- C_TIME_DATETIME_ONLY, status);
+ 0, FALSE, status);
if (ltime->time_type > MYSQL_TIMESTAMP_ERROR)
{
status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
@@ -650,7 +660,7 @@ my_bool str_to_DDhhmmssff(const char *str, size_t length, MYSQL_TIME *ltime,
will scan only '2001'.
*/
if (str_to_DDhhmmssff_internal(neg, str, length, ltime, max_hour,
- status, &endptr) ||
+ status, &endptr) ||
(endptr < str + length && endptr[0] == '-'))
return TRUE;
status->warnings|= warn;
@@ -658,10 +668,13 @@ my_bool str_to_DDhhmmssff(const char *str, size_t length, MYSQL_TIME *ltime,
}
-my_bool str_to_time(const char *str, size_t length, MYSQL_TIME *l_time,
- ulonglong fuzzydate, MYSQL_TIME_STATUS *status)
+my_bool
+str_to_datetime_or_date_or_time(const char *str, size_t length,
+ MYSQL_TIME *l_time,
+ ulonglong fuzzydate,
+ MYSQL_TIME_STATUS *status)
{
- my_bool neg;
+ my_bool neg, rc;
int warn;
DBUG_ASSERT(C_FLAGS_OK(fuzzydate));
my_time_status_init(status);
@@ -674,18 +687,23 @@ my_bool str_to_time(const char *str, size_t length, MYSQL_TIME *l_time,
QQ: Perhaps we should modify xxx_body() to return endptr.
If endptr points to '-', return an error.
*/
- if (str_to_datetime_or_date_or_time_body(str, length, l_time,
- fuzzydate, status))
- return TRUE;
+ rc= str_to_datetime_or_date_or_time_body(str, length, l_time,
+ fuzzydate, status);
status->warnings|= warn;
- l_time->neg= neg;
+ if (rc)
+ return rc;
+ if ((l_time->neg= neg) && l_time->time_type != MYSQL_TIMESTAMP_TIME)
+ {
+ status->warnings|= MYSQL_TIME_WARN_OUT_OF_RANGE;
+ return TRUE;
+ }
return FALSE;
}
my_bool
-str_to_datetime(const char *str, size_t length, MYSQL_TIME *l_time,
- ulonglong flags, MYSQL_TIME_STATUS *status)
+str_to_datetime_or_date(const char *str, size_t length, MYSQL_TIME *l_time,
+ ulonglong flags, MYSQL_TIME_STATUS *status)
{
my_bool neg, rc;
int warn;
@@ -696,13 +714,11 @@ str_to_datetime(const char *str, size_t length, MYSQL_TIME *l_time,
status->warnings= warn;
return TRUE;
}
- rc= (flags & C_TIME_TIME_ONLY) ?
- str_to_datetime_or_date_or_time_body(str, length, l_time, flags, status) :
- str_to_datetime_or_date_body(str, length, l_time, flags, status);
+ rc= str_to_datetime_or_date_body(str, length, l_time, flags, TRUE, status);
status->warnings|= warn;
if (rc)
return rc;
- if ((l_time->neg= neg) && l_time->time_type != MYSQL_TIMESTAMP_TIME)
+ if ((l_time->neg= neg))
{
status->warnings|= MYSQL_TIME_WARN_OUT_OF_RANGE;
return TRUE;
@@ -711,6 +727,27 @@ str_to_datetime(const char *str, size_t length, MYSQL_TIME *l_time,
}
+
+/**
+ Convert a string to INTERVAL DAY TO SECOND.
+ Input format: [DD ]hh:mm:ss.ffffff
+
+ Datetime or date formats are not understood.
+
+ Optional leading spaces and signs must be scanned by the caller.
+ "str" should point to the first digit.
+
+ @param neg - set the value to be negative
+ @param str - the input string
+ @param length - length of "str"
+ @param[OUT] l_time - write the result here
+ @param max_hour - if the result hour value appears to be greater than
+ max_hour, then cut to result to 'max_hour:59:59.999999'
+ @param err_hour - if the hour appears to be greater than err_hour,
+ return an error (without cut)
+ @param status
+ @param endptr
+*/
static my_bool
str_to_DDhhmmssff_internal(my_bool neg, const char *str, size_t length,
MYSQL_TIME *l_time, ulong max_hour,
@@ -1428,7 +1465,7 @@ int my_timeval_to_str(const struct timeval *tm, char *to, uint dec)
representation and form value of DATETIME type as side-effect.
SYNOPSIS
- number_to_datetime()
+ number_to_datetime_or_date()
nr - datetime value as number
time_res - pointer for structure for broken-down representation
flags - flags to use in validating date, as in str_to_datetime()
@@ -1449,8 +1486,9 @@ int my_timeval_to_str(const struct timeval *tm, char *to, uint dec)
Datetime value in YYYYMMDDHHMMSS format.
*/
-longlong number_to_datetime(longlong nr, ulong sec_part, MYSQL_TIME *time_res,
- ulonglong flags, int *was_cut)
+longlong number_to_datetime_or_date(longlong nr, ulong sec_part,
+ MYSQL_TIME *time_res,
+ ulonglong flags, int *was_cut)
{
long part1,part2;
DBUG_ASSERT(C_FLAGS_OK(flags));
@@ -1554,13 +1592,9 @@ longlong number_to_datetime(longlong nr, ulong sec_part, MYSQL_TIME *time_res,
0 time value is valid, but was possibly truncated
-1 time value is invalid
*/
-int number_to_time(my_bool neg, ulonglong nr, ulong sec_part,
- MYSQL_TIME *ltime, int *was_cut)
+int number_to_time_only(my_bool neg, ulonglong nr, ulong sec_part,
+ MYSQL_TIME *ltime, int *was_cut)
{
- if (nr > 9999999 && nr <= 99991231235959ULL && neg == 0)
- return number_to_datetime(nr, sec_part, ltime,
- C_TIME_INVALID_DATES, was_cut) < 0 ? -1 : 0;
-
*was_cut= 0;
ltime->year= ltime->month= ltime->day= 0;
ltime->time_type= MYSQL_TIMESTAMP_TIME;