mirror of
https://github.com/postgres/postgres.git
synced 2025-04-25 21:42:33 +03:00
This introduces the SQL/JSON functions for querying JSON data using jsonpath expressions. The functions are: JSON_EXISTS() JSON_QUERY() JSON_VALUE() All of these functions only operate on jsonb. The workaround for now is to cast the argument to jsonb. JSON_EXISTS() tests if the jsonpath expression applied to the jsonb value yields any values. JSON_VALUE() must return a single value, and an error occurs if it tries to return multiple values. JSON_QUERY() must return a json object or array, and there are various WRAPPER options for handling scalar or multi-value results. Both these functions have options for handling EMPTY and ERROR conditions. Nikita Glukhov Reviewers have included (in no particular order) Andres Freund, Alexander Korotkov, Pavel Stehule, Andrew Alsup, Erik Rijkers, Zihong Yu, Himanshu Upadhyaya, Daniel Gustafsson, Justin Pryzby. Discussion: https://postgr.es/m/cd0bb935-0158-78a7-08b5-904886deac4b@postgrespro.ru
1019 lines
29 KiB
Plaintext
1019 lines
29 KiB
Plaintext
-- JSON_EXISTS
|
|
SELECT JSON_EXISTS(NULL::jsonb, '$');
|
|
json_exists
|
|
-------------
|
|
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '[]', '$');
|
|
json_exists
|
|
-------------
|
|
t
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(JSON_OBJECT(RETURNING jsonb), '$');
|
|
json_exists
|
|
-------------
|
|
t
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '1', '$');
|
|
json_exists
|
|
-------------
|
|
t
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb 'null', '$');
|
|
json_exists
|
|
-------------
|
|
t
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '[]', '$');
|
|
json_exists
|
|
-------------
|
|
t
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '1', '$.a');
|
|
json_exists
|
|
-------------
|
|
f
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '1', 'strict $.a');
|
|
json_exists
|
|
-------------
|
|
f
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '1', 'strict $.a' ERROR ON ERROR);
|
|
ERROR: jsonpath member accessor can only be applied to an object
|
|
SELECT JSON_EXISTS(jsonb 'null', '$.a');
|
|
json_exists
|
|
-------------
|
|
f
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '[]', '$.a');
|
|
json_exists
|
|
-------------
|
|
f
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '[1, "aaa", {"a": 1}]', 'strict $.a');
|
|
json_exists
|
|
-------------
|
|
f
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '[1, "aaa", {"a": 1}]', 'lax $.a');
|
|
json_exists
|
|
-------------
|
|
t
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '{}', '$.a');
|
|
json_exists
|
|
-------------
|
|
f
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '{"b": 1, "a": 2}', '$.a');
|
|
json_exists
|
|
-------------
|
|
t
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '1', '$.a.b');
|
|
json_exists
|
|
-------------
|
|
f
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '{"a": {"b": 1}}', '$.a.b');
|
|
json_exists
|
|
-------------
|
|
t
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '{"a": 1, "b": 2}', '$.a.b');
|
|
json_exists
|
|
-------------
|
|
f
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '{"a": 1, "b": 2}', '$.* ? (@ > $x)' PASSING 1 AS x);
|
|
json_exists
|
|
-------------
|
|
t
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '{"a": 1, "b": 2}', '$.* ? (@ > $x)' PASSING '1' AS x);
|
|
json_exists
|
|
-------------
|
|
f
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '{"a": 1, "b": 2}', '$.* ? (@ > $x && @ < $y)' PASSING 0 AS x, 2 AS y);
|
|
json_exists
|
|
-------------
|
|
t
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '{"a": 1, "b": 2}', '$.* ? (@ > $x && @ < $y)' PASSING 0 AS x, 1 AS y);
|
|
json_exists
|
|
-------------
|
|
f
|
|
(1 row)
|
|
|
|
-- extension: boolean expressions
|
|
SELECT JSON_EXISTS(jsonb '1', '$ > 2');
|
|
json_exists
|
|
-------------
|
|
t
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '1', '$.a > 2' ERROR ON ERROR);
|
|
json_exists
|
|
-------------
|
|
t
|
|
(1 row)
|
|
|
|
-- extension: RETURNING clause
|
|
SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING bool);
|
|
json_exists
|
|
-------------
|
|
t
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '1', '$[1]' RETURNING bool);
|
|
json_exists
|
|
-------------
|
|
f
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING int);
|
|
json_exists
|
|
-------------
|
|
1
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '1', '$[1]' RETURNING int);
|
|
json_exists
|
|
-------------
|
|
0
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING text);
|
|
json_exists
|
|
-------------
|
|
true
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '1', '$[1]' RETURNING text);
|
|
json_exists
|
|
-------------
|
|
false
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '1', 'strict $[1]' RETURNING text FALSE ON ERROR);
|
|
json_exists
|
|
-------------
|
|
false
|
|
(1 row)
|
|
|
|
SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING jsonb);
|
|
ERROR: cannot cast type boolean to jsonb
|
|
LINE 1: SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING jsonb);
|
|
^
|
|
SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING float4);
|
|
ERROR: cannot cast type boolean to real
|
|
LINE 1: SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING float4);
|
|
^
|
|
-- JSON_VALUE
|
|
SELECT JSON_VALUE(NULL::jsonb, '$');
|
|
json_value
|
|
------------
|
|
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb 'null', '$');
|
|
json_value
|
|
------------
|
|
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb 'null', '$' RETURNING int);
|
|
json_value
|
|
------------
|
|
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb 'true', '$');
|
|
json_value
|
|
------------
|
|
true
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb 'true', '$' RETURNING bool);
|
|
json_value
|
|
------------
|
|
t
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '123', '$');
|
|
json_value
|
|
------------
|
|
123
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '123', '$' RETURNING int) + 234;
|
|
?column?
|
|
----------
|
|
357
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '123', '$' RETURNING text);
|
|
json_value
|
|
------------
|
|
123
|
|
(1 row)
|
|
|
|
/* jsonb bytea ??? */
|
|
SELECT JSON_VALUE(jsonb '123', '$' RETURNING bytea ERROR ON ERROR);
|
|
ERROR: SQL/JSON item cannot be cast to target type
|
|
SELECT JSON_VALUE(jsonb '1.23', '$');
|
|
json_value
|
|
------------
|
|
1.23
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '1.23', '$' RETURNING int);
|
|
json_value
|
|
------------
|
|
1
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '"1.23"', '$' RETURNING numeric);
|
|
json_value
|
|
------------
|
|
1.23
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '"1.23"', '$' RETURNING int ERROR ON ERROR);
|
|
ERROR: invalid input syntax for type integer: "1.23"
|
|
SELECT JSON_VALUE(jsonb '"aaa"', '$');
|
|
json_value
|
|
------------
|
|
aaa
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING text);
|
|
json_value
|
|
------------
|
|
aaa
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING char(5));
|
|
json_value
|
|
------------
|
|
aaa
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING char(2));
|
|
json_value
|
|
------------
|
|
aa
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING json);
|
|
json_value
|
|
------------
|
|
"aaa"
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING jsonb);
|
|
json_value
|
|
------------
|
|
"aaa"
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING json ERROR ON ERROR);
|
|
json_value
|
|
------------
|
|
"aaa"
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING jsonb ERROR ON ERROR);
|
|
json_value
|
|
------------
|
|
"aaa"
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '"\"aaa\""', '$' RETURNING json);
|
|
json_value
|
|
------------
|
|
"\"aaa\""
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '"\"aaa\""', '$' RETURNING jsonb);
|
|
json_value
|
|
------------
|
|
"\"aaa\""
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING int);
|
|
json_value
|
|
------------
|
|
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING int ERROR ON ERROR);
|
|
ERROR: invalid input syntax for type integer: "aaa"
|
|
SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING int DEFAULT 111 ON ERROR);
|
|
json_value
|
|
------------
|
|
111
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '"123"', '$' RETURNING int) + 234;
|
|
?column?
|
|
----------
|
|
357
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '"2017-02-20"', '$' RETURNING date) + 9;
|
|
?column?
|
|
------------
|
|
03-01-2017
|
|
(1 row)
|
|
|
|
-- Test NULL checks execution in domain types
|
|
CREATE DOMAIN sqljsonb_int_not_null AS int NOT NULL;
|
|
SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null);
|
|
ERROR: domain sqljsonb_int_not_null does not allow null values
|
|
SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null NULL ON ERROR);
|
|
ERROR: domain sqljsonb_int_not_null does not allow null values
|
|
SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null DEFAULT NULL ON ERROR);
|
|
ERROR: domain sqljsonb_int_not_null does not allow null values
|
|
SELECT JSON_VALUE(jsonb '[]', '$');
|
|
json_value
|
|
------------
|
|
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '[]', '$' ERROR ON ERROR);
|
|
ERROR: JSON path expression in JSON_VALUE should return singleton scalar item
|
|
SELECT JSON_VALUE(jsonb '{}', '$');
|
|
json_value
|
|
------------
|
|
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '{}', '$' ERROR ON ERROR);
|
|
ERROR: JSON path expression in JSON_VALUE should return singleton scalar item
|
|
SELECT JSON_VALUE(jsonb '1', '$.a');
|
|
json_value
|
|
------------
|
|
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '1', 'strict $.a' ERROR ON ERROR);
|
|
ERROR: jsonpath member accessor can only be applied to an object
|
|
SELECT JSON_VALUE(jsonb '1', 'strict $.a' DEFAULT 'error' ON ERROR);
|
|
json_value
|
|
------------
|
|
error
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '1', 'lax $.a' ERROR ON ERROR);
|
|
json_value
|
|
------------
|
|
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '1', 'lax $.a' ERROR ON EMPTY ERROR ON ERROR);
|
|
ERROR: no SQL/JSON item
|
|
SELECT JSON_VALUE(jsonb '1', 'strict $.a' DEFAULT 2 ON ERROR);
|
|
json_value
|
|
------------
|
|
2
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '1', 'lax $.a' DEFAULT 2 ON ERROR);
|
|
json_value
|
|
------------
|
|
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '1', 'lax $.a' DEFAULT '2' ON ERROR);
|
|
json_value
|
|
------------
|
|
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '1', 'lax $.a' NULL ON EMPTY DEFAULT '2' ON ERROR);
|
|
json_value
|
|
------------
|
|
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '1', 'lax $.a' DEFAULT '2' ON EMPTY DEFAULT '3' ON ERROR);
|
|
json_value
|
|
------------
|
|
2
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '1', 'lax $.a' ERROR ON EMPTY DEFAULT '3' ON ERROR);
|
|
json_value
|
|
------------
|
|
3
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '[1,2]', '$[*]' ERROR ON ERROR);
|
|
ERROR: JSON path expression in JSON_VALUE should return singleton scalar item
|
|
SELECT JSON_VALUE(jsonb '[1,2]', '$[*]' DEFAULT '0' ON ERROR);
|
|
json_value
|
|
------------
|
|
0
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '[" "]', '$[*]' RETURNING int ERROR ON ERROR);
|
|
ERROR: invalid input syntax for type integer: " "
|
|
SELECT JSON_VALUE(jsonb '[" "]', '$[*]' RETURNING int DEFAULT 2 + 3 ON ERROR);
|
|
json_value
|
|
------------
|
|
5
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb '["1"]', '$[*]' RETURNING int DEFAULT 2 + 3 ON ERROR);
|
|
json_value
|
|
------------
|
|
1
|
|
(1 row)
|
|
|
|
SELECT
|
|
x,
|
|
JSON_VALUE(
|
|
jsonb '{"a": 1, "b": 2}',
|
|
'$.* ? (@ > $x)' PASSING x AS x
|
|
RETURNING int
|
|
DEFAULT -1 ON EMPTY
|
|
DEFAULT -2 ON ERROR
|
|
) y
|
|
FROM
|
|
generate_series(0, 2) x;
|
|
x | y
|
|
---+----
|
|
0 | -2
|
|
1 | 2
|
|
2 | -1
|
|
(3 rows)
|
|
|
|
SELECT JSON_VALUE(jsonb 'null', '$a' PASSING point ' (1, 2 )' AS a);
|
|
json_value
|
|
------------
|
|
(1,2)
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb 'null', '$a' PASSING point ' (1, 2 )' AS a RETURNING point);
|
|
json_value
|
|
------------
|
|
(1,2)
|
|
(1 row)
|
|
|
|
-- Test timestamptz passing and output
|
|
SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts);
|
|
json_value
|
|
------------------------------
|
|
Tue Feb 20 18:34:56 2018 PST
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING timestamptz);
|
|
json_value
|
|
------------------------------
|
|
Tue Feb 20 18:34:56 2018 PST
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING timestamp);
|
|
json_value
|
|
--------------------------
|
|
Tue Feb 20 18:34:56 2018
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING json);
|
|
json_value
|
|
-----------------------------
|
|
"2018-02-21T02:34:56+00:00"
|
|
(1 row)
|
|
|
|
SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING jsonb);
|
|
json_value
|
|
-----------------------------
|
|
"2018-02-21T02:34:56+00:00"
|
|
(1 row)
|
|
|
|
-- JSON_QUERY
|
|
SELECT
|
|
JSON_QUERY(js, '$'),
|
|
JSON_QUERY(js, '$' WITHOUT WRAPPER),
|
|
JSON_QUERY(js, '$' WITH CONDITIONAL WRAPPER),
|
|
JSON_QUERY(js, '$' WITH UNCONDITIONAL ARRAY WRAPPER),
|
|
JSON_QUERY(js, '$' WITH ARRAY WRAPPER)
|
|
FROM
|
|
(VALUES
|
|
(jsonb 'null'),
|
|
('12.3'),
|
|
('true'),
|
|
('"aaa"'),
|
|
('[1, null, "2"]'),
|
|
('{"a": 1, "b": [2]}')
|
|
) foo(js);
|
|
json_query | json_query | json_query | json_query | json_query
|
|
--------------------+--------------------+--------------------+----------------------+----------------------
|
|
null | null | [null] | [null] | [null]
|
|
12.3 | 12.3 | [12.3] | [12.3] | [12.3]
|
|
true | true | [true] | [true] | [true]
|
|
"aaa" | "aaa" | ["aaa"] | ["aaa"] | ["aaa"]
|
|
[1, null, "2"] | [1, null, "2"] | [1, null, "2"] | [[1, null, "2"]] | [[1, null, "2"]]
|
|
{"a": 1, "b": [2]} | {"a": 1, "b": [2]} | {"a": 1, "b": [2]} | [{"a": 1, "b": [2]}] | [{"a": 1, "b": [2]}]
|
|
(6 rows)
|
|
|
|
SELECT
|
|
JSON_QUERY(js, 'strict $[*]') AS "unspec",
|
|
JSON_QUERY(js, 'strict $[*]' WITHOUT WRAPPER) AS "without",
|
|
JSON_QUERY(js, 'strict $[*]' WITH CONDITIONAL WRAPPER) AS "with cond",
|
|
JSON_QUERY(js, 'strict $[*]' WITH UNCONDITIONAL ARRAY WRAPPER) AS "with uncond",
|
|
JSON_QUERY(js, 'strict $[*]' WITH ARRAY WRAPPER) AS "with"
|
|
FROM
|
|
(VALUES
|
|
(jsonb '1'),
|
|
('[]'),
|
|
('[null]'),
|
|
('[12.3]'),
|
|
('[true]'),
|
|
('["aaa"]'),
|
|
('[[1, 2, 3]]'),
|
|
('[{"a": 1, "b": [2]}]'),
|
|
('[1, "2", null, [3]]')
|
|
) foo(js);
|
|
unspec | without | with cond | with uncond | with
|
|
--------------------+--------------------+---------------------+----------------------+----------------------
|
|
| | | |
|
|
| | | |
|
|
null | null | [null] | [null] | [null]
|
|
12.3 | 12.3 | [12.3] | [12.3] | [12.3]
|
|
true | true | [true] | [true] | [true]
|
|
"aaa" | "aaa" | ["aaa"] | ["aaa"] | ["aaa"]
|
|
[1, 2, 3] | [1, 2, 3] | [1, 2, 3] | [[1, 2, 3]] | [[1, 2, 3]]
|
|
{"a": 1, "b": [2]} | {"a": 1, "b": [2]} | {"a": 1, "b": [2]} | [{"a": 1, "b": [2]}] | [{"a": 1, "b": [2]}]
|
|
| | [1, "2", null, [3]] | [1, "2", null, [3]] | [1, "2", null, [3]]
|
|
(9 rows)
|
|
|
|
SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text);
|
|
json_query
|
|
------------
|
|
"aaa"
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text KEEP QUOTES);
|
|
json_query
|
|
------------
|
|
"aaa"
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text KEEP QUOTES ON SCALAR STRING);
|
|
json_query
|
|
------------
|
|
"aaa"
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text OMIT QUOTES);
|
|
json_query
|
|
------------
|
|
aaa
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text OMIT QUOTES ON SCALAR STRING);
|
|
json_query
|
|
------------
|
|
aaa
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '"aaa"', '$' OMIT QUOTES ERROR ON ERROR);
|
|
ERROR: invalid input syntax for type json
|
|
DETAIL: Token "aaa" is invalid.
|
|
CONTEXT: JSON data, line 1: aaa
|
|
SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING json OMIT QUOTES ERROR ON ERROR);
|
|
ERROR: invalid input syntax for type json
|
|
DETAIL: Token "aaa" is invalid.
|
|
CONTEXT: JSON data, line 1: aaa
|
|
SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING bytea FORMAT JSON OMIT QUOTES ERROR ON ERROR);
|
|
json_query
|
|
------------
|
|
\x616161
|
|
(1 row)
|
|
|
|
-- QUOTES behavior should not be specified when WITH WRAPPER used:
|
|
-- Should fail
|
|
SELECT JSON_QUERY(jsonb '[1]', '$' WITH WRAPPER OMIT QUOTES);
|
|
ERROR: SQL/JSON QUOTES behavior must not be specified when WITH WRAPPER is used
|
|
LINE 1: SELECT JSON_QUERY(jsonb '[1]', '$' WITH WRAPPER OMIT QUOTES)...
|
|
^
|
|
SELECT JSON_QUERY(jsonb '[1]', '$' WITH WRAPPER KEEP QUOTES);
|
|
ERROR: SQL/JSON QUOTES behavior must not be specified when WITH WRAPPER is used
|
|
LINE 1: SELECT JSON_QUERY(jsonb '[1]', '$' WITH WRAPPER KEEP QUOTES)...
|
|
^
|
|
SELECT JSON_QUERY(jsonb '[1]', '$' WITH CONDITIONAL WRAPPER KEEP QUOTES);
|
|
ERROR: SQL/JSON QUOTES behavior must not be specified when WITH WRAPPER is used
|
|
LINE 1: ...N_QUERY(jsonb '[1]', '$' WITH CONDITIONAL WRAPPER KEEP QUOTE...
|
|
^
|
|
SELECT JSON_QUERY(jsonb '[1]', '$' WITH CONDITIONAL WRAPPER OMIT QUOTES);
|
|
ERROR: SQL/JSON QUOTES behavior must not be specified when WITH WRAPPER is used
|
|
LINE 1: ...N_QUERY(jsonb '[1]', '$' WITH CONDITIONAL WRAPPER OMIT QUOTE...
|
|
^
|
|
-- Should succeed
|
|
SELECT JSON_QUERY(jsonb '[1]', '$' WITHOUT WRAPPER OMIT QUOTES);
|
|
json_query
|
|
------------
|
|
[1]
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[1]', '$' WITHOUT WRAPPER KEEP QUOTES);
|
|
json_query
|
|
------------
|
|
[1]
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[]', '$[*]');
|
|
json_query
|
|
------------
|
|
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[]', '$[*]' NULL ON EMPTY);
|
|
json_query
|
|
------------
|
|
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[]', '$[*]' EMPTY ON EMPTY);
|
|
json_query
|
|
------------
|
|
[]
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[]', '$[*]' EMPTY ARRAY ON EMPTY);
|
|
json_query
|
|
------------
|
|
[]
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[]', '$[*]' EMPTY OBJECT ON EMPTY);
|
|
json_query
|
|
------------
|
|
{}
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY);
|
|
json_query
|
|
------------
|
|
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[]', '$[*]' DEFAULT '"empty"' ON EMPTY);
|
|
json_query
|
|
------------
|
|
"empty"
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY NULL ON ERROR);
|
|
json_query
|
|
------------
|
|
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY EMPTY ARRAY ON ERROR);
|
|
json_query
|
|
------------
|
|
[]
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY EMPTY OBJECT ON ERROR);
|
|
json_query
|
|
------------
|
|
{}
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY ERROR ON ERROR);
|
|
ERROR: no SQL/JSON item
|
|
SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON ERROR);
|
|
json_query
|
|
------------
|
|
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' ERROR ON ERROR);
|
|
ERROR: JSON path expression in JSON_QUERY should return singleton item without wrapper
|
|
HINT: use WITH WRAPPER clause to wrap SQL/JSON item sequence into array
|
|
SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' DEFAULT '"empty"' ON ERROR);
|
|
json_query
|
|
------------
|
|
"empty"
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING json);
|
|
json_query
|
|
------------
|
|
[1, 2]
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING json FORMAT JSON);
|
|
json_query
|
|
------------
|
|
[1, 2]
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING jsonb);
|
|
json_query
|
|
------------
|
|
[1, 2]
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING jsonb FORMAT JSON);
|
|
json_query
|
|
------------
|
|
[1, 2]
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING text);
|
|
json_query
|
|
------------
|
|
[1, 2]
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING char(10));
|
|
json_query
|
|
------------
|
|
[1, 2]
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING char(3));
|
|
json_query
|
|
------------
|
|
[1,
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING text FORMAT JSON);
|
|
json_query
|
|
------------
|
|
[1, 2]
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING bytea);
|
|
json_query
|
|
----------------
|
|
\x5b312c20325d
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING bytea FORMAT JSON);
|
|
json_query
|
|
----------------
|
|
\x5b312c20325d
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' RETURNING bytea EMPTY OBJECT ON ERROR);
|
|
json_query
|
|
------------
|
|
\x7b7d
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' RETURNING bytea FORMAT JSON EMPTY OBJECT ON ERROR);
|
|
json_query
|
|
------------
|
|
\x7b7d
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' RETURNING json EMPTY OBJECT ON ERROR);
|
|
json_query
|
|
------------
|
|
{}
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' RETURNING jsonb EMPTY OBJECT ON ERROR);
|
|
json_query
|
|
------------
|
|
{}
|
|
(1 row)
|
|
|
|
SELECT
|
|
x, y,
|
|
JSON_QUERY(
|
|
jsonb '[1,2,3,4,5,null]',
|
|
'$[*] ? (@ >= $x && @ <= $y)'
|
|
PASSING x AS x, y AS y
|
|
WITH CONDITIONAL WRAPPER
|
|
EMPTY ARRAY ON EMPTY
|
|
) list
|
|
FROM
|
|
generate_series(0, 4) x,
|
|
generate_series(0, 4) y;
|
|
x | y | list
|
|
---+---+--------------
|
|
0 | 0 | []
|
|
0 | 1 | [1]
|
|
0 | 2 | [1, 2]
|
|
0 | 3 | [1, 2, 3]
|
|
0 | 4 | [1, 2, 3, 4]
|
|
1 | 0 | []
|
|
1 | 1 | [1]
|
|
1 | 2 | [1, 2]
|
|
1 | 3 | [1, 2, 3]
|
|
1 | 4 | [1, 2, 3, 4]
|
|
2 | 0 | []
|
|
2 | 1 | []
|
|
2 | 2 | [2]
|
|
2 | 3 | [2, 3]
|
|
2 | 4 | [2, 3, 4]
|
|
3 | 0 | []
|
|
3 | 1 | []
|
|
3 | 2 | []
|
|
3 | 3 | [3]
|
|
3 | 4 | [3, 4]
|
|
4 | 0 | []
|
|
4 | 1 | []
|
|
4 | 2 | []
|
|
4 | 3 | []
|
|
4 | 4 | [4]
|
|
(25 rows)
|
|
|
|
-- Extension: record types returning
|
|
CREATE TYPE sqljsonb_rec AS (a int, t text, js json, jb jsonb, jsa json[]);
|
|
CREATE TYPE sqljsonb_reca AS (reca sqljsonb_rec[]);
|
|
SELECT JSON_QUERY(jsonb '[{"a": 1, "b": "foo", "t": "aaa", "js": [1, "2", {}], "jb": {"x": [1, "2", {}]}}, {"a": 2}]', '$[0]' RETURNING sqljsonb_rec);
|
|
json_query
|
|
-----------------------------------------------------
|
|
(1,aaa,"[1, ""2"", {}]","{""x"": [1, ""2"", {}]}",)
|
|
(1 row)
|
|
|
|
SELECT * FROM unnest((JSON_QUERY(jsonb '{"jsa": [{"a": 1, "b": ["foo"]}, {"a": 2, "c": {}}, 123]}', '$' RETURNING sqljsonb_rec)).jsa);
|
|
unnest
|
|
------------------------
|
|
{"a": 1, "b": ["foo"]}
|
|
{"a": 2, "c": {}}
|
|
123
|
|
(3 rows)
|
|
|
|
SELECT * FROM unnest((JSON_QUERY(jsonb '{"reca": [{"a": 1, "t": ["foo", []]}, {"a": 2, "jb": [{}, true]}]}', '$' RETURNING sqljsonb_reca)).reca);
|
|
a | t | js | jb | jsa
|
|
---+-------------+----+------------+-----
|
|
1 | ["foo", []] | | |
|
|
2 | | | [{}, true] |
|
|
(2 rows)
|
|
|
|
-- Extension: array types returning
|
|
SELECT JSON_QUERY(jsonb '[1,2,null,"3"]', '$[*]' RETURNING int[] WITH WRAPPER);
|
|
json_query
|
|
--------------
|
|
{1,2,NULL,3}
|
|
(1 row)
|
|
|
|
SELECT * FROM unnest(JSON_QUERY(jsonb '[{"a": 1, "t": ["foo", []]}, {"a": 2, "jb": [{}, true]}]', '$' RETURNING sqljsonb_rec[]));
|
|
a | t | js | jb | jsa
|
|
---+-------------+----+------------+-----
|
|
1 | ["foo", []] | | |
|
|
2 | | | [{}, true] |
|
|
(2 rows)
|
|
|
|
-- Extension: domain types returning
|
|
SELECT JSON_QUERY(jsonb '{"a": 1}', '$.a' RETURNING sqljsonb_int_not_null);
|
|
json_query
|
|
------------
|
|
1
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb '{"a": 1}', '$.b' RETURNING sqljsonb_int_not_null);
|
|
ERROR: domain sqljsonb_int_not_null does not allow null values
|
|
-- Test timestamptz passing and output
|
|
SELECT JSON_QUERY(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts);
|
|
json_query
|
|
-----------------------------
|
|
"2018-02-21T02:34:56+00:00"
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING json);
|
|
json_query
|
|
-----------------------------
|
|
"2018-02-21T02:34:56+00:00"
|
|
(1 row)
|
|
|
|
SELECT JSON_QUERY(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING jsonb);
|
|
json_query
|
|
-----------------------------
|
|
"2018-02-21T02:34:56+00:00"
|
|
(1 row)
|
|
|
|
-- Test constraints
|
|
CREATE TABLE test_jsonb_constraints (
|
|
js text,
|
|
i int,
|
|
x jsonb DEFAULT JSON_QUERY(jsonb '[1,2]', '$[*]' WITH WRAPPER)
|
|
CONSTRAINT test_jsonb_constraint1
|
|
CHECK (js IS JSON)
|
|
CONSTRAINT test_jsonb_constraint2
|
|
CHECK (JSON_EXISTS(js::jsonb, '$.a' PASSING i + 5 AS int, i::text AS txt, array[1,2,3] as arr))
|
|
CONSTRAINT test_jsonb_constraint3
|
|
CHECK (JSON_VALUE(js::jsonb, '$.a' RETURNING int DEFAULT ('12' || i)::int ON EMPTY ERROR ON ERROR) > i)
|
|
CONSTRAINT test_jsonb_constraint4
|
|
CHECK (JSON_QUERY(js::jsonb, '$.a' WITH CONDITIONAL WRAPPER EMPTY OBJECT ON ERROR) < jsonb '[10]')
|
|
CONSTRAINT test_jsonb_constraint5
|
|
CHECK (JSON_QUERY(js::jsonb, '$.a' RETURNING char(5) OMIT QUOTES EMPTY ARRAY ON EMPTY) > 'a' COLLATE "C")
|
|
CONSTRAINT test_jsonb_constraint6
|
|
CHECK (JSON_EXISTS(js::jsonb, 'strict $.a' RETURNING int TRUE ON ERROR) < 2)
|
|
);
|
|
\d test_jsonb_constraints
|
|
Table "public.test_jsonb_constraints"
|
|
Column | Type | Collation | Nullable | Default
|
|
--------+---------+-----------+----------+--------------------------------------------------------------------------------
|
|
js | text | | |
|
|
i | integer | | |
|
|
x | jsonb | | | JSON_QUERY('[1, 2]'::jsonb, '$[*]' RETURNING jsonb WITH UNCONDITIONAL WRAPPER)
|
|
Check constraints:
|
|
"test_jsonb_constraint1" CHECK (js IS JSON)
|
|
"test_jsonb_constraint2" CHECK (JSON_EXISTS(js::jsonb, '$."a"' PASSING i + 5 AS int, i::text AS txt, ARRAY[1, 2, 3] AS arr))
|
|
"test_jsonb_constraint3" CHECK (JSON_VALUE(js::jsonb, '$."a"' RETURNING integer DEFAULT ('12'::text || i)::integer ON EMPTY ERROR ON ERROR) > i)
|
|
"test_jsonb_constraint4" CHECK (JSON_QUERY(js::jsonb, '$."a"' RETURNING jsonb WITH CONDITIONAL WRAPPER EMPTY OBJECT ON ERROR) < '[10]'::jsonb)
|
|
"test_jsonb_constraint5" CHECK (JSON_QUERY(js::jsonb, '$."a"' RETURNING character(5) OMIT QUOTES EMPTY ARRAY ON EMPTY) > ('a'::bpchar COLLATE "C"))
|
|
"test_jsonb_constraint6" CHECK (JSON_EXISTS(js::jsonb, 'strict $."a"' RETURNING integer TRUE ON ERROR) < 2)
|
|
|
|
SELECT check_clause
|
|
FROM information_schema.check_constraints
|
|
WHERE constraint_name LIKE 'test_jsonb_constraint%';
|
|
check_clause
|
|
--------------------------------------------------------------------------------------------------------------------------
|
|
((js IS JSON))
|
|
(JSON_EXISTS((js)::jsonb, '$."a"' PASSING (i + 5) AS int, (i)::text AS txt, ARRAY[1, 2, 3] AS arr))
|
|
((JSON_VALUE((js)::jsonb, '$."a"' RETURNING integer DEFAULT (('12'::text || i))::integer ON EMPTY ERROR ON ERROR) > i))
|
|
((JSON_QUERY((js)::jsonb, '$."a"' RETURNING jsonb WITH CONDITIONAL WRAPPER EMPTY OBJECT ON ERROR) < '[10]'::jsonb))
|
|
((JSON_QUERY((js)::jsonb, '$."a"' RETURNING character(5) OMIT QUOTES EMPTY ARRAY ON EMPTY) > ('a'::bpchar COLLATE "C")))
|
|
((JSON_EXISTS((js)::jsonb, 'strict $."a"' RETURNING integer TRUE ON ERROR) < 2))
|
|
(6 rows)
|
|
|
|
SELECT pg_get_expr(adbin, adrelid) FROM pg_attrdef WHERE adrelid = 'test_jsonb_constraints'::regclass;
|
|
pg_get_expr
|
|
--------------------------------------------------------------------------------
|
|
JSON_QUERY('[1, 2]'::jsonb, '$[*]' RETURNING jsonb WITH UNCONDITIONAL WRAPPER)
|
|
(1 row)
|
|
|
|
INSERT INTO test_jsonb_constraints VALUES ('', 1);
|
|
ERROR: new row for relation "test_jsonb_constraints" violates check constraint "test_jsonb_constraint1"
|
|
DETAIL: Failing row contains (, 1, [1, 2]).
|
|
INSERT INTO test_jsonb_constraints VALUES ('1', 1);
|
|
ERROR: new row for relation "test_jsonb_constraints" violates check constraint "test_jsonb_constraint2"
|
|
DETAIL: Failing row contains (1, 1, [1, 2]).
|
|
INSERT INTO test_jsonb_constraints VALUES ('[]');
|
|
ERROR: new row for relation "test_jsonb_constraints" violates check constraint "test_jsonb_constraint2"
|
|
DETAIL: Failing row contains ([], null, [1, 2]).
|
|
INSERT INTO test_jsonb_constraints VALUES ('{"b": 1}', 1);
|
|
ERROR: new row for relation "test_jsonb_constraints" violates check constraint "test_jsonb_constraint2"
|
|
DETAIL: Failing row contains ({"b": 1}, 1, [1, 2]).
|
|
INSERT INTO test_jsonb_constraints VALUES ('{"a": 1}', 1);
|
|
ERROR: new row for relation "test_jsonb_constraints" violates check constraint "test_jsonb_constraint3"
|
|
DETAIL: Failing row contains ({"a": 1}, 1, [1, 2]).
|
|
INSERT INTO test_jsonb_constraints VALUES ('{"a": 7}', 1);
|
|
ERROR: new row for relation "test_jsonb_constraints" violates check constraint "test_jsonb_constraint5"
|
|
DETAIL: Failing row contains ({"a": 7}, 1, [1, 2]).
|
|
INSERT INTO test_jsonb_constraints VALUES ('{"a": 10}', 1);
|
|
ERROR: new row for relation "test_jsonb_constraints" violates check constraint "test_jsonb_constraint4"
|
|
DETAIL: Failing row contains ({"a": 10}, 1, [1, 2]).
|
|
DROP TABLE test_jsonb_constraints;
|
|
-- Test mutabilily od query functions
|
|
CREATE TABLE test_jsonb_mutability(js jsonb);
|
|
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$'));
|
|
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a[0]'));
|
|
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime()'));
|
|
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@ < $.datetime())'));
|
|
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime() < $.datetime())'));
|
|
ERROR: functions in index expression must be marked IMMUTABLE
|
|
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime() < $.datetime("HH:MI TZH"))'));
|
|
ERROR: functions in index expression must be marked IMMUTABLE
|
|
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime("HH:MI TZH") < $.datetime("HH:MI TZH"))'));
|
|
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime("HH:MI") < $.datetime("YY-MM-DD HH:MI"))'));
|
|
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime("HH:MI TZH") < $.datetime("YY-MM-DD HH:MI"))'));
|
|
ERROR: functions in index expression must be marked IMMUTABLE
|
|
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime("HH:MI TZH") < $x' PASSING '12:34'::timetz AS x));
|
|
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime("HH:MI TZH") < $y' PASSING '12:34'::timetz AS x));
|
|
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime() < $x' PASSING '12:34'::timetz AS x));
|
|
ERROR: functions in index expression must be marked IMMUTABLE
|
|
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime() < $x' PASSING '1234'::int AS x));
|
|
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime() ? (@ == $x)' PASSING '12:34'::time AS x));
|
|
ERROR: functions in index expression must be marked IMMUTABLE
|
|
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime("YY-MM-DD") ? (@ == $x)' PASSING '2020-07-14'::date AS x));
|
|
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$[1, $.a ? (@.datetime() == $x)]' PASSING '12:34'::time AS x));
|
|
ERROR: functions in index expression must be marked IMMUTABLE
|
|
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$[1, 0 to $.a ? (@.datetime() == $x)]' PASSING '12:34'::time AS x));
|
|
ERROR: functions in index expression must be marked IMMUTABLE
|
|
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$[1, $.a ? (@.datetime("HH:MI") == $x)]' PASSING '12:34'::time AS x));
|
|
DROP TABLE test_jsonb_mutability;
|