Accept fractional seconds in jsonpath's datetime() method.
authorTom Lane <[email protected]>
Mon, 12 Jun 2023 14:54:28 +0000 (10:54 -0400)
committerTom Lane <[email protected]>
Mon, 12 Jun 2023 14:54:44 +0000 (10:54 -0400)
Commit 927d9abb6 purported to make datetime() accept any string
that could be output for a datetime value by to_jsonb().  But it
overlooked the possibility of fractional seconds being present,
so that cases as simple as to_jsonb(now()) would defeat it.

Fix by adding formats that include ".US" to the list in
executeDateTimeMethod().  (Note that while this is nominally
microseconds, it'll do the right thing for fractions with
fewer than six digits.)

In passing, re-order the list to restore the datatype ordering
specified in its comment.  The violation accidentally did not
break anything; but the next edit might be less lucky, so add
more comments.

Per report from Tim Field.  Back-patch to v13 where datetime()
was added, like the previous patch.

Discussion: https://postgr.es/m/014A028B-5CE6-4FDF-AC24-426CA6FC9CEE@mohiohio.com

src/backend/utils/adt/jsonpath_exec.c
src/test/regress/expected/jsonb_jsonpath.out
src/test/regress/sql/jsonb_jsonpath.sql

index 41430bab7ed22fd7ec72161ea2f7c4659d8b895a..2d0599b4aaae3fc8899725edf4c602986812b220 100644 (file)
@@ -1840,20 +1840,29 @@ executeDateTimeMethod(JsonPathExecContext *cxt, JsonPathItem *jsp,
         * According to SQL/JSON standard enumerate ISO formats for: date,
         * timetz, time, timestamptz, timestamp.
         *
-        * We also support ISO 8601 for timestamps, because to_json[b]()
-        * functions use this format.
+        * We also support ISO 8601 format (with "T") for timestamps, because
+        * to_json[b]() functions use this format.
         */
        static const char *fmt_str[] =
        {
-           "yyyy-mm-dd",
+           "yyyy-mm-dd",       /* date */
+           "HH24:MI:SS.USTZH:TZM", /* timetz */
+           "HH24:MI:SS.USTZH",
            "HH24:MI:SSTZH:TZM",
            "HH24:MI:SSTZH",
+           "HH24:MI:SS.US",    /* time without tz */
            "HH24:MI:SS",
+           "yyyy-mm-dd HH24:MI:SS.USTZH:TZM",  /* timestamptz */
+           "yyyy-mm-dd HH24:MI:SS.USTZH",
            "yyyy-mm-dd HH24:MI:SSTZH:TZM",
            "yyyy-mm-dd HH24:MI:SSTZH",
-           "yyyy-mm-dd HH24:MI:SS",
+           "yyyy-mm-dd\"T\"HH24:MI:SS.USTZH:TZM",
+           "yyyy-mm-dd\"T\"HH24:MI:SS.USTZH",
            "yyyy-mm-dd\"T\"HH24:MI:SSTZH:TZM",
            "yyyy-mm-dd\"T\"HH24:MI:SSTZH",
+           "yyyy-mm-dd HH24:MI:SS.US", /* timestamp without tz */
+           "yyyy-mm-dd HH24:MI:SS",
+           "yyyy-mm-dd\"T\"HH24:MI:SS.US",
            "yyyy-mm-dd\"T\"HH24:MI:SS"
        };
 
index 328a6b391990f3520634c54e812d73ea239aa564..6659bc9091ac04373bf3ce28b16d13bf6c036670 100644 (file)
@@ -1920,6 +1920,21 @@ select jsonb_path_query('"2017-03-10T12:34:56+3:10"', '$.datetime()');
 select jsonb_path_query('"2017-03-10t12:34:56+3:10"', '$.datetime()');
 ERROR:  datetime format is not recognized: "2017-03-10t12:34:56+3:10"
 HINT:  Use a datetime template argument to specify the input data format.
+select jsonb_path_query('"2017-03-10 12:34:56.789+3:10"', '$.datetime()');
+        jsonb_path_query         
+---------------------------------
+ "2017-03-10T12:34:56.789+03:10"
+(1 row)
+
+select jsonb_path_query('"2017-03-10T12:34:56.789+3:10"', '$.datetime()');
+        jsonb_path_query         
+---------------------------------
+ "2017-03-10T12:34:56.789+03:10"
+(1 row)
+
+select jsonb_path_query('"2017-03-10t12:34:56.789+3:10"', '$.datetime()');
+ERROR:  datetime format is not recognized: "2017-03-10t12:34:56.789+3:10"
+HINT:  Use a datetime template argument to specify the input data format.
 select jsonb_path_query('"12:34:56"', '$.datetime().type()');
      jsonb_path_query     
 --------------------------
index bd025077d520d0286dce3f968a9d89f3a55c5424..e0ce509264a9a8c5f16b3cb6254e9a2bd288fe2c 100644 (file)
@@ -414,6 +414,9 @@ select jsonb_path_query('"2017-03-10 12:34:56+3:10"', '$.datetime().type()');
 select jsonb_path_query('"2017-03-10 12:34:56+3:10"', '$.datetime()');
 select jsonb_path_query('"2017-03-10T12:34:56+3:10"', '$.datetime()');
 select jsonb_path_query('"2017-03-10t12:34:56+3:10"', '$.datetime()');
+select jsonb_path_query('"2017-03-10 12:34:56.789+3:10"', '$.datetime()');
+select jsonb_path_query('"2017-03-10T12:34:56.789+3:10"', '$.datetime()');
+select jsonb_path_query('"2017-03-10t12:34:56.789+3:10"', '$.datetime()');
 select jsonb_path_query('"12:34:56"', '$.datetime().type()');
 select jsonb_path_query('"12:34:56"', '$.datetime()');
 select jsonb_path_query('"12:34:56+3"', '$.datetime().type()');