Make jsonpath .string() be immutable for datetimes.

Discussion of commit ed055d249 revealed that we don't actually
want jsonpath's .string() method to depend on DateStyle, nor
TimeZone either, because the non-"_tz" jsonpath functions are
supposed to be immutable.  Potentially we could allow a TimeZone
dependency in the "_tz" variants, but it seems better to just
uniformly define this method as returning the same string that
jsonb text output would do.  That's easier to implement too,
saving a couple dozen lines.

Patch by me, per complaint from Peter Eisentraut.  Back-patch
to v17 where this feature came in (in 66ea94e8e).  Also
back-patch ed055d249 to provide test cases.

Discussion: https://postgr.es/m/5e8879d0-a3c8-4be2-950f-d83aa2af953a@eisentraut.org
This commit is contained in:
Tom Lane 2024-09-12 14:30:29 -04:00
parent 4eada203a5
commit cb599b9ddf
4 changed files with 44 additions and 92 deletions

View File

@ -18017,16 +18017,15 @@ ERROR: jsonpath member accessor can only be applied to an object
</para> </para>
<para> <para>
String value converted from a JSON boolean, number, string, or String value converted from a JSON boolean, number, string, or
datetime (the output format for datetimes is determined by datetime
the <xref linkend="guc-datestyle"/> parameter)
</para> </para>
<para> <para>
<literal>jsonb_path_query_array('[1.23, "xyz", false]', '$[*].string()')</literal> <literal>jsonb_path_query_array('[1.23, "xyz", false]', '$[*].string()')</literal>
<returnvalue>["1.23", "xyz", "false"]</returnvalue> <returnvalue>["1.23", "xyz", "false"]</returnvalue>
</para> </para>
<para> <para>
<literal>jsonb_path_query('"2023-08-15"', '$.datetime().string()')</literal> <literal>jsonb_path_query('"2023-08-15 12:34:56"', '$.timestamp().string()')</literal>
<returnvalue>"2023-08-15"</returnvalue> <returnvalue>"2023-08-15T12:34:56"</returnvalue>
</para></entry> </para></entry>
</row> </row>

View File

@ -72,6 +72,7 @@
#include "utils/datetime.h" #include "utils/datetime.h"
#include "utils/float.h" #include "utils/float.h"
#include "utils/formatting.h" #include "utils/formatting.h"
#include "utils/json.h"
#include "utils/jsonpath.h" #include "utils/jsonpath.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/memutils.h" #include "utils/memutils.h"
@ -1629,32 +1630,13 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
break; break;
case jbvDatetime: case jbvDatetime:
{ {
switch (jb->val.datetime.typid) char buf[MAXDATELEN + 1];
{
case DATEOID: JsonEncodeDateTime(buf,
tmp = DatumGetCString(DirectFunctionCall1(date_out, jb->val.datetime.value,
jb->val.datetime.value)); jb->val.datetime.typid,
break; &jb->val.datetime.tz);
case TIMEOID: tmp = pstrdup(buf);
tmp = DatumGetCString(DirectFunctionCall1(time_out,
jb->val.datetime.value));
break;
case TIMETZOID:
tmp = DatumGetCString(DirectFunctionCall1(timetz_out,
jb->val.datetime.value));
break;
case TIMESTAMPOID:
tmp = DatumGetCString(DirectFunctionCall1(timestamp_out,
jb->val.datetime.value));
break;
case TIMESTAMPTZOID:
tmp = DatumGetCString(DirectFunctionCall1(timestamptz_out,
jb->val.datetime.value));
break;
default:
elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
jb->val.datetime.typid);
}
} }
break; break;
case jbvNull: case jbvNull:

View File

@ -2653,8 +2653,8 @@ ERROR: cannot convert value from timestamptz to timestamp without time zone usa
HINT: Use *_tz() function for time zone support. HINT: Use *_tz() function for time zone support.
select jsonb_path_query_tz('"2023-08-15 12:34:56 +5:30"', '$.timestamp().string()'); -- should work select jsonb_path_query_tz('"2023-08-15 12:34:56 +5:30"', '$.timestamp().string()'); -- should work
jsonb_path_query_tz jsonb_path_query_tz
---------------------------- -----------------------
"Tue Aug 15 00:04:56 2023" "2023-08-15T00:04:56"
(1 row) (1 row)
select jsonb_path_query('"2023-08-15 12:34:56"', '$.timestamp_tz().string()'); select jsonb_path_query('"2023-08-15 12:34:56"', '$.timestamp_tz().string()');
@ -2662,63 +2662,20 @@ ERROR: cannot convert value from timestamp to timestamptz without time zone usa
HINT: Use *_tz() function for time zone support. HINT: Use *_tz() function for time zone support.
select jsonb_path_query_tz('"2023-08-15 12:34:56"', '$.timestamp_tz().string()'); -- should work select jsonb_path_query_tz('"2023-08-15 12:34:56"', '$.timestamp_tz().string()'); -- should work
jsonb_path_query_tz jsonb_path_query_tz
-------------------------------- -----------------------------
"Tue Aug 15 12:34:56 2023 PDT" "2023-08-15T12:34:56-07:00"
(1 row) (1 row)
select jsonb_path_query('"2023-08-15 12:34:56 +5:30"', '$.timestamp_tz().string()'); select jsonb_path_query('"2023-08-15 12:34:56 +5:30"', '$.timestamp_tz().string()');
jsonb_path_query jsonb_path_query
-------------------------------- -----------------------------
"Tue Aug 15 00:04:56 2023 PDT" "2023-08-15T12:34:56+05:30"
(1 row)
select jsonb_path_query('"2023-08-15 12:34:56"', '$.timestamp().string()');
jsonb_path_query
----------------------------
"Tue Aug 15 12:34:56 2023"
(1 row)
select jsonb_path_query('"12:34:56 +5:30"', '$.time_tz().string()');
jsonb_path_query
------------------
"12:34:56+05:30"
(1 row)
select jsonb_path_query_tz('"12:34:56"', '$.time_tz().string()');
jsonb_path_query_tz
---------------------
"12:34:56-07"
(1 row)
select jsonb_path_query('"12:34:56"', '$.time().string()');
jsonb_path_query
------------------
"12:34:56"
(1 row)
select jsonb_path_query('"2023-08-15"', '$.date().string()');
jsonb_path_query
------------------
"08-15-2023"
(1 row)
set datestyle = 'ISO';
select jsonb_path_query_tz('"2023-08-15 12:34:56"', '$.timestamp_tz().string()');
jsonb_path_query_tz
--------------------------
"2023-08-15 12:34:56-07"
(1 row)
select jsonb_path_query('"2023-08-15 12:34:56 +5:30"', '$.timestamp_tz().string()');
jsonb_path_query
--------------------------
"2023-08-15 00:04:56-07"
(1 row) (1 row)
select jsonb_path_query('"2023-08-15 12:34:56"', '$.timestamp().string()'); select jsonb_path_query('"2023-08-15 12:34:56"', '$.timestamp().string()');
jsonb_path_query jsonb_path_query
----------------------- -----------------------
"2023-08-15 12:34:56" "2023-08-15T12:34:56"
(1 row) (1 row)
select jsonb_path_query('"12:34:56 +5:30"', '$.time_tz().string()'); select jsonb_path_query('"12:34:56 +5:30"', '$.time_tz().string()');
@ -2730,7 +2687,7 @@ select jsonb_path_query('"12:34:56 +5:30"', '$.time_tz().string()');
select jsonb_path_query_tz('"12:34:56"', '$.time_tz().string()'); select jsonb_path_query_tz('"12:34:56"', '$.time_tz().string()');
jsonb_path_query_tz jsonb_path_query_tz
--------------------- ---------------------
"12:34:56-07" "12:34:56-07:00"
(1 row) (1 row)
select jsonb_path_query('"12:34:56"', '$.time().string()'); select jsonb_path_query('"12:34:56"', '$.time().string()');
@ -2745,7 +2702,23 @@ select jsonb_path_query('"2023-08-15"', '$.date().string()');
"2023-08-15" "2023-08-15"
(1 row) (1 row)
reset datestyle; -- .string() does not react to timezone or datestyle
begin;
set local timezone = 'UTC';
set local datestyle = 'German';
select jsonb_path_query('"2023-08-15 12:34:56 +5:30"', '$.timestamp_tz().string()');
jsonb_path_query
-----------------------------
"2023-08-15T12:34:56+05:30"
(1 row)
select jsonb_path_query('"2023-08-15 12:34:56"', '$.timestamp().string()');
jsonb_path_query
-----------------------
"2023-08-15T12:34:56"
(1 row)
rollback;
-- Test .time() -- Test .time()
select jsonb_path_query('null', '$.time()'); select jsonb_path_query('null', '$.time()');
ERROR: jsonpath item method .time() can only be applied to a string ERROR: jsonpath item method .time() can only be applied to a string

View File

@ -611,15 +611,13 @@ select jsonb_path_query_tz('"12:34:56"', '$.time_tz().string()');
select jsonb_path_query('"12:34:56"', '$.time().string()'); select jsonb_path_query('"12:34:56"', '$.time().string()');
select jsonb_path_query('"2023-08-15"', '$.date().string()'); select jsonb_path_query('"2023-08-15"', '$.date().string()');
set datestyle = 'ISO'; -- .string() does not react to timezone or datestyle
select jsonb_path_query_tz('"2023-08-15 12:34:56"', '$.timestamp_tz().string()'); begin;
set local timezone = 'UTC';
set local datestyle = 'German';
select jsonb_path_query('"2023-08-15 12:34:56 +5:30"', '$.timestamp_tz().string()'); select jsonb_path_query('"2023-08-15 12:34:56 +5:30"', '$.timestamp_tz().string()');
select jsonb_path_query('"2023-08-15 12:34:56"', '$.timestamp().string()'); select jsonb_path_query('"2023-08-15 12:34:56"', '$.timestamp().string()');
select jsonb_path_query('"12:34:56 +5:30"', '$.time_tz().string()'); rollback;
select jsonb_path_query_tz('"12:34:56"', '$.time_tz().string()');
select jsonb_path_query('"12:34:56"', '$.time().string()');
select jsonb_path_query('"2023-08-15"', '$.date().string()');
reset datestyle;
-- Test .time() -- Test .time()
select jsonb_path_query('null', '$.time()'); select jsonb_path_query('null', '$.time()');