Fix input of ISO "extended" time format for types time and timetz.
authorTom Lane <[email protected]>
Wed, 22 May 2024 22:22:51 +0000 (18:22 -0400)
committerTom Lane <[email protected]>
Wed, 22 May 2024 22:22:51 +0000 (18:22 -0400)
Commit 3e1a373e2 missed teaching DecodeTimeOnly the same "ptype"
manipulations it added to DecodeDateTime.  While likely harmless
at the time, it became a problem after 5b3c59535 added an error check
that ptype must be zero once we exit the parsing loop (that is, there
shouldn't be any unused prefixes).  The consequence was that we'd
reject time or timetz input like T12:34:56 (the "extended" format
per ISO 8601-1:2019), even though that still worked in timestamp
input.

Since this is clearly under-tested code, add test cases covering all
the ISO 8601 time formats.  (Note: although 8601 allows just "Thh",
we have never accepted that, and this patch doesn't change that.
I'm content to leave that as-is because it seems too likely to be
a mistake rather than intended input.  If anyone wants to allow
that, it should be a separate patch anyway, and not back-patched.)

Per bug #18470 from David Perez.  Back-patch to v16 where we
broke it.

Discussion: https://postgr.es/m/18470-34fad4c829106848@postgresql.org

src/backend/utils/adt/datetime.c
src/test/regress/expected/horology.out
src/test/regress/sql/horology.sql

index 5d8d583ddcb7b98d319dd9c698316fcf03d2e5fa..9b36852a5db6dd35b3ee4975865fc4234e7319c4 100644 (file)
@@ -1972,6 +1972,17 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
                break;
 
            case DTK_TIME:
+
+               /*
+                * This might be an ISO time following a "t" field.
+                */
+               if (ptype != 0)
+               {
+                   if (ptype != DTK_TIME)
+                       return DTERR_BAD_FORMAT;
+                   ptype = 0;
+               }
+
                dterr = DecodeTime(field[i], (fmask | DTK_DATE_M),
                                   INTERVAL_FULL_RANGE,
                                   &tmask, tm, fsec);
index e48534ba00b2feb606573f6f41018f9d5bae9f97..31d269b7ba63865b9d9f0a0d41ae3554309a23b0 100644 (file)
@@ -274,6 +274,161 @@ SELECT time with time zone 'J2452271 T040506.789 America/Los_Angeles';
  04:05:06.789-08
 (1 row)
 
+-- Check time formats required by ISO 8601
+SELECT time without time zone '040506.07';
+    time     
+-------------
+ 04:05:06.07
+(1 row)
+
+SELECT time without time zone '04:05:06.07';
+    time     
+-------------
+ 04:05:06.07
+(1 row)
+
+SELECT time without time zone '040506';
+   time   
+----------
+ 04:05:06
+(1 row)
+
+SELECT time without time zone '04:05:06';
+   time   
+----------
+ 04:05:06
+(1 row)
+
+SELECT time without time zone '0405';
+   time   
+----------
+ 04:05:00
+(1 row)
+
+SELECT time without time zone '04:05';
+   time   
+----------
+ 04:05:00
+(1 row)
+
+SELECT time without time zone 'T040506.07';
+    time     
+-------------
+ 04:05:06.07
+(1 row)
+
+SELECT time without time zone 'T04:05:06.07';
+    time     
+-------------
+ 04:05:06.07
+(1 row)
+
+SELECT time without time zone 'T040506';
+   time   
+----------
+ 04:05:06
+(1 row)
+
+SELECT time without time zone 'T04:05:06';
+   time   
+----------
+ 04:05:06
+(1 row)
+
+SELECT time without time zone 'T0405';
+   time   
+----------
+ 04:05:00
+(1 row)
+
+SELECT time without time zone 'T04:05';
+   time   
+----------
+ 04:05:00
+(1 row)
+
+-- 8601 says "Thh" is allowed, but we intentionally reject it as too vague
+SELECT time without time zone 'T04';
+ERROR:  invalid input syntax for type time: "T04"
+LINE 1: SELECT time without time zone 'T04';
+                                      ^
+SELECT time with time zone '040506.07+08';
+     timetz     
+----------------
+ 04:05:06.07+08
+(1 row)
+
+SELECT time with time zone '04:05:06.07+08';
+     timetz     
+----------------
+ 04:05:06.07+08
+(1 row)
+
+SELECT time with time zone '040506+08';
+   timetz    
+-------------
+ 04:05:06+08
+(1 row)
+
+SELECT time with time zone '04:05:06+08';
+   timetz    
+-------------
+ 04:05:06+08
+(1 row)
+
+SELECT time with time zone '0405+08';
+   timetz    
+-------------
+ 04:05:00+08
+(1 row)
+
+SELECT time with time zone '04:05+08';
+   timetz    
+-------------
+ 04:05:00+08
+(1 row)
+
+SELECT time with time zone 'T040506.07+08';
+     timetz     
+----------------
+ 04:05:06.07+08
+(1 row)
+
+SELECT time with time zone 'T04:05:06.07+08';
+     timetz     
+----------------
+ 04:05:06.07+08
+(1 row)
+
+SELECT time with time zone 'T040506+08';
+   timetz    
+-------------
+ 04:05:06+08
+(1 row)
+
+SELECT time with time zone 'T04:05:06+08';
+   timetz    
+-------------
+ 04:05:06+08
+(1 row)
+
+SELECT time with time zone 'T0405+08';
+   timetz    
+-------------
+ 04:05:00+08
+(1 row)
+
+SELECT time with time zone 'T04:05+08';
+   timetz    
+-------------
+ 04:05:00+08
+(1 row)
+
+-- 8601 says "Thh" is allowed, but we intentionally reject it as too vague
+SELECT time with time zone 'T04+08';
+ERROR:  invalid input syntax for type time with time zone: "T04+08"
+LINE 1: SELECT time with time zone 'T04+08';
+                                   ^
 SET DateStyle = 'Postgres, MDY';
 -- Check Julian dates BC
 SELECT date 'J1520447' AS "Confucius' Birthday";
index af70f28e3d991895b410683799b2ecfa3337aca0..8f6c513573d1b096d98506fc4b90bd3f5842142d 100644 (file)
@@ -59,6 +59,35 @@ SELECT time with time zone 'T040506.789 -08';
 SELECT time with time zone 'T040506.789 America/Los_Angeles';
 SELECT time with time zone '2001-12-27 T040506.789 America/Los_Angeles';
 SELECT time with time zone 'J2452271 T040506.789 America/Los_Angeles';
+-- Check time formats required by ISO 8601
+SELECT time without time zone '040506.07';
+SELECT time without time zone '04:05:06.07';
+SELECT time without time zone '040506';
+SELECT time without time zone '04:05:06';
+SELECT time without time zone '0405';
+SELECT time without time zone '04:05';
+SELECT time without time zone 'T040506.07';
+SELECT time without time zone 'T04:05:06.07';
+SELECT time without time zone 'T040506';
+SELECT time without time zone 'T04:05:06';
+SELECT time without time zone 'T0405';
+SELECT time without time zone 'T04:05';
+-- 8601 says "Thh" is allowed, but we intentionally reject it as too vague
+SELECT time without time zone 'T04';
+SELECT time with time zone '040506.07+08';
+SELECT time with time zone '04:05:06.07+08';
+SELECT time with time zone '040506+08';
+SELECT time with time zone '04:05:06+08';
+SELECT time with time zone '0405+08';
+SELECT time with time zone '04:05+08';
+SELECT time with time zone 'T040506.07+08';
+SELECT time with time zone 'T04:05:06.07+08';
+SELECT time with time zone 'T040506+08';
+SELECT time with time zone 'T04:05:06+08';
+SELECT time with time zone 'T0405+08';
+SELECT time with time zone 'T04:05+08';
+-- 8601 says "Thh" is allowed, but we intentionally reject it as too vague
+SELECT time with time zone 'T04+08';
 SET DateStyle = 'Postgres, MDY';
 -- Check Julian dates BC
 SELECT date 'J1520447' AS "Confucius' Birthday";