mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-02-17 19:30:00 +08:00
Fix bugs with parsing signed hh:mm and hh:mm:ss fields in interval input.
DecodeInterval() failed to honor the "range" parameter (the special SQL syntax for indicating which fields appear in the literal string) if the time was signed. This seems inappropriate, so make it work like the not-signed case. The inconsistency was introduced in my commitf867339c01
, which as noted in its log message was only really focused on making SQL-compliant literals work per spec. Including a sign here is not per spec, but if we're going to allow it then it's reasonable to expect it to work like the not-signed case. Also, remove bogus setting of tmask, which caused subsequent processing to think that what had been given was a timezone and not an hh:mm(:ss) field, thus confusing checks for redundant fields. This seems to be an aboriginal mistake in Lockhart's commit2cf1642461
. Add regression test cases to illustrate the changed behaviors. Back-patch as far as 8.4, where support for spec-compliant interval literals was added. Range problem reported and diagnosed by Amit Kapila, tmask problem by me.
This commit is contained in:
parent
ae47eb112f
commit
bb49e3551b
@ -2874,19 +2874,18 @@ DecodeInterval(char **field, int *ftype, int nf, int range,
|
||||
case DTK_TZ:
|
||||
|
||||
/*
|
||||
* Timezone is a token with a leading sign character and at
|
||||
* Timezone means a token with a leading sign character and at
|
||||
* least one digit; there could be ':', '.', '-' embedded in
|
||||
* it as well.
|
||||
*/
|
||||
Assert(*field[i] == '-' || *field[i] == '+');
|
||||
|
||||
/*
|
||||
* Try for hh:mm or hh:mm:ss. If not, fall through to
|
||||
* DTK_NUMBER case, which can handle signed float numbers and
|
||||
* signed year-month values.
|
||||
* Check for signed hh:mm or hh:mm:ss. If so, process exactly
|
||||
* like DTK_TIME case above, plus handling the sign.
|
||||
*/
|
||||
if (strchr(field[i] + 1, ':') != NULL &&
|
||||
DecodeTime(field[i] + 1, fmask, INTERVAL_FULL_RANGE,
|
||||
DecodeTime(field[i] + 1, fmask, range,
|
||||
&tmask, tm, fsec) == 0)
|
||||
{
|
||||
if (*field[i] == '-')
|
||||
@ -2904,9 +2903,14 @@ DecodeInterval(char **field, int *ftype, int nf, int range,
|
||||
* are reading right to left.
|
||||
*/
|
||||
type = DTK_DAY;
|
||||
tmask = DTK_M(TZ);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise, fall through to DTK_NUMBER case, which can
|
||||
* handle signed float numbers and signed year-month values.
|
||||
*/
|
||||
|
||||
/* FALL THROUGH */
|
||||
|
||||
case DTK_DATE:
|
||||
|
@ -545,6 +545,30 @@ SELECT interval '1 2:03:04' minute to second;
|
||||
1 day 02:03:04
|
||||
(1 row)
|
||||
|
||||
SELECT interval '1 +2:03' minute to second;
|
||||
interval
|
||||
----------------
|
||||
1 day 00:02:03
|
||||
(1 row)
|
||||
|
||||
SELECT interval '1 +2:03:04' minute to second;
|
||||
interval
|
||||
----------------
|
||||
1 day 02:03:04
|
||||
(1 row)
|
||||
|
||||
SELECT interval '1 -2:03' minute to second;
|
||||
interval
|
||||
-----------------
|
||||
1 day -00:02:03
|
||||
(1 row)
|
||||
|
||||
SELECT interval '1 -2:03:04' minute to second;
|
||||
interval
|
||||
-----------------
|
||||
1 day -02:03:04
|
||||
(1 row)
|
||||
|
||||
SELECT interval '123 11' day to hour; -- ok
|
||||
interval
|
||||
-------------------
|
||||
@ -559,6 +583,10 @@ SELECT interval '123 11'; -- not ok, too ambiguous
|
||||
ERROR: invalid input syntax for type interval: "123 11"
|
||||
LINE 1: SELECT interval '123 11';
|
||||
^
|
||||
SELECT interval '123 2:03 -2:04'; -- not ok, redundant hh:mm fields
|
||||
ERROR: invalid input syntax for type interval: "123 2:03 -2:04"
|
||||
LINE 1: SELECT interval '123 2:03 -2:04';
|
||||
^
|
||||
-- test syntaxes for restricted precision
|
||||
SELECT interval(0) '1 day 01:23:45.6789';
|
||||
interval
|
||||
|
@ -165,9 +165,14 @@ SELECT interval '1 2:03:04' hour to second;
|
||||
SELECT interval '1 2' minute to second;
|
||||
SELECT interval '1 2:03' minute to second;
|
||||
SELECT interval '1 2:03:04' minute to second;
|
||||
SELECT interval '1 +2:03' minute to second;
|
||||
SELECT interval '1 +2:03:04' minute to second;
|
||||
SELECT interval '1 -2:03' minute to second;
|
||||
SELECT interval '1 -2:03:04' minute to second;
|
||||
SELECT interval '123 11' day to hour; -- ok
|
||||
SELECT interval '123 11' day; -- not ok
|
||||
SELECT interval '123 11'; -- not ok, too ambiguous
|
||||
SELECT interval '123 2:03 -2:04'; -- not ok, redundant hh:mm fields
|
||||
|
||||
-- test syntaxes for restricted precision
|
||||
SELECT interval(0) '1 day 01:23:45.6789';
|
||||
|
Loading…
Reference in New Issue
Block a user