Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 3152bf7

Browse files
committed
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 commit f867339, 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 commit 2cf1642. 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.
1 parent 95e7505 commit 3152bf7

File tree

3 files changed

+43
-6
lines changed

3 files changed

+43
-6
lines changed

src/backend/utils/adt/datetime.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2873,19 +2873,18 @@ DecodeInterval(char **field, int *ftype, int nf, int range,
28732873
case DTK_TZ:
28742874

28752875
/*
2876-
* Timezone is a token with a leading sign character and at
2876+
* Timezone means a token with a leading sign character and at
28772877
* least one digit; there could be ':', '.', '-' embedded in
28782878
* it as well.
28792879
*/
28802880
Assert(*field[i] == '-' || *field[i] == '+');
28812881

28822882
/*
2883-
* Try for hh:mm or hh:mm:ss. If not, fall through to
2884-
* DTK_NUMBER case, which can handle signed float numbers and
2885-
* signed year-month values.
2883+
* Check for signed hh:mm or hh:mm:ss. If so, process exactly
2884+
* like DTK_TIME case above, plus handling the sign.
28862885
*/
28872886
if (strchr(field[i] + 1, ':') != NULL &&
2888-
DecodeTime(field[i] + 1, fmask, INTERVAL_FULL_RANGE,
2887+
DecodeTime(field[i] + 1, fmask, range,
28892888
&tmask, tm, fsec) == 0)
28902889
{
28912890
if (*field[i] == '-')
@@ -2903,9 +2902,14 @@ DecodeInterval(char **field, int *ftype, int nf, int range,
29032902
* are reading right to left.
29042903
*/
29052904
type = DTK_DAY;
2906-
tmask = DTK_M(TZ);
29072905
break;
29082906
}
2907+
2908+
/*
2909+
* Otherwise, fall through to DTK_NUMBER case, which can
2910+
* handle signed float numbers and signed year-month values.
2911+
*/
2912+
29092913
/* FALL THROUGH */
29102914

29112915
case DTK_DATE:

src/test/regress/expected/interval.out

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,30 @@ SELECT interval '1 2:03:04' minute to second;
545545
1 day 02:03:04
546546
(1 row)
547547

548+
SELECT interval '1 +2:03' minute to second;
549+
interval
550+
----------------
551+
1 day 00:02:03
552+
(1 row)
553+
554+
SELECT interval '1 +2:03:04' minute to second;
555+
interval
556+
----------------
557+
1 day 02:03:04
558+
(1 row)
559+
560+
SELECT interval '1 -2:03' minute to second;
561+
interval
562+
-----------------
563+
1 day -00:02:03
564+
(1 row)
565+
566+
SELECT interval '1 -2:03:04' minute to second;
567+
interval
568+
-----------------
569+
1 day -02:03:04
570+
(1 row)
571+
548572
SELECT interval '123 11' day to hour; -- ok
549573
interval
550574
-------------------
@@ -559,6 +583,10 @@ SELECT interval '123 11'; -- not ok, too ambiguous
559583
ERROR: invalid input syntax for type interval: "123 11"
560584
LINE 1: SELECT interval '123 11';
561585
^
586+
SELECT interval '123 2:03 -2:04'; -- not ok, redundant hh:mm fields
587+
ERROR: invalid input syntax for type interval: "123 2:03 -2:04"
588+
LINE 1: SELECT interval '123 2:03 -2:04';
589+
^
562590
-- test syntaxes for restricted precision
563591
SELECT interval(0) '1 day 01:23:45.6789';
564592
interval

src/test/regress/sql/interval.sql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,14 @@ SELECT interval '1 2:03:04' hour to second;
165165
SELECT interval '1 2' minute to second;
166166
SELECT interval '1 2:03' minute to second;
167167
SELECT interval '1 2:03:04' minute to second;
168+
SELECT interval '1 +2:03' minute to second;
169+
SELECT interval '1 +2:03:04' minute to second;
170+
SELECT interval '1 -2:03' minute to second;
171+
SELECT interval '1 -2:03:04' minute to second;
168172
SELECT interval '123 11' day to hour; -- ok
169173
SELECT interval '123 11' day; -- not ok
170174
SELECT interval '123 11'; -- not ok, too ambiguous
175+
SELECT interval '123 2:03 -2:04'; -- not ok, redundant hh:mm fields
171176

172177
-- test syntaxes for restricted precision
173178
SELECT interval(0) '1 day 01:23:45.6789';

0 commit comments

Comments
 (0)