mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-02-11 19:20:40 +08:00
Factor out encoding specific tests for json
This lets us remove the large alternative results files for the main json and jsonb tests, which makes modifying those tests simpler for committers and patch submitters. Backpatch to 9.4 for jsonb and 9.3 for json.
This commit is contained in:
parent
32e53593f9
commit
f844f0ef18
@ -42,36 +42,7 @@ LINE 1: SELECT '"\v"'::json;
|
||||
^
|
||||
DETAIL: Escape sequence "\v" is invalid.
|
||||
CONTEXT: JSON data, line 1: "\v...
|
||||
SELECT '"\u"'::json; -- ERROR, incomplete escape
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '"\u"'::json;
|
||||
^
|
||||
DETAIL: "\u" must be followed by four hexadecimal digits.
|
||||
CONTEXT: JSON data, line 1: "\u"
|
||||
SELECT '"\u00"'::json; -- ERROR, incomplete escape
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '"\u00"'::json;
|
||||
^
|
||||
DETAIL: "\u" must be followed by four hexadecimal digits.
|
||||
CONTEXT: JSON data, line 1: "\u00"
|
||||
SELECT '"\u000g"'::json; -- ERROR, g is not a hex digit
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '"\u000g"'::json;
|
||||
^
|
||||
DETAIL: "\u" must be followed by four hexadecimal digits.
|
||||
CONTEXT: JSON data, line 1: "\u000g...
|
||||
SELECT '"\u0000"'::json; -- OK, legal escape
|
||||
json
|
||||
----------
|
||||
"\u0000"
|
||||
(1 row)
|
||||
|
||||
SELECT '"\uaBcD"'::json; -- OK, uppercase and lower case both OK
|
||||
json
|
||||
----------
|
||||
"\uaBcD"
|
||||
(1 row)
|
||||
|
||||
-- see json_encoding test for input with unicode escapes
|
||||
-- Numbers.
|
||||
SELECT '1'::json; -- OK
|
||||
json
|
||||
@ -936,45 +907,3 @@ select * from json_populate_recordset(row('def',99,null)::jpop,'[{"a":[100,200,3
|
||||
ERROR: cannot call json_populate_recordset on a nested object
|
||||
select * from json_populate_recordset(row('def',99,null)::jpop,'[{"c":[100,200,300],"x":43.2},{"a":{"z":true},"b":3,"c":"2012-01-20 10:42:53"}]') q;
|
||||
ERROR: cannot call json_populate_recordset on a nested object
|
||||
-- handling of unicode surrogate pairs
|
||||
select json '{ "a": "\ud83d\ude04\ud83d\udc36" }' -> 'a' as correct_in_utf8;
|
||||
correct_in_utf8
|
||||
----------------------------
|
||||
"\ud83d\ude04\ud83d\udc36"
|
||||
(1 row)
|
||||
|
||||
select json '{ "a": "\ud83d\ud83d" }' -> 'a'; -- 2 high surrogates in a row
|
||||
ERROR: invalid input syntax for type json
|
||||
DETAIL: Unicode high surrogate must not follow a high surrogate.
|
||||
CONTEXT: JSON data, line 1: { "a":...
|
||||
select json '{ "a": "\ude04\ud83d" }' -> 'a'; -- surrogates in wrong order
|
||||
ERROR: invalid input syntax for type json
|
||||
DETAIL: Unicode low surrogate must follow a high surrogate.
|
||||
CONTEXT: JSON data, line 1: { "a":...
|
||||
select json '{ "a": "\ud83dX" }' -> 'a'; -- orphan high surrogate
|
||||
ERROR: invalid input syntax for type json
|
||||
DETAIL: Unicode low surrogate must follow a high surrogate.
|
||||
CONTEXT: JSON data, line 1: { "a":...
|
||||
select json '{ "a": "\ude04X" }' -> 'a'; -- orphan low surrogate
|
||||
ERROR: invalid input syntax for type json
|
||||
DETAIL: Unicode low surrogate must follow a high surrogate.
|
||||
CONTEXT: JSON data, line 1: { "a":...
|
||||
--handling of simple unicode escapes
|
||||
select json '{ "a": "the Copyright \u00a9 sign" }' ->> 'a' as correct_in_utf8;
|
||||
correct_in_utf8
|
||||
----------------------
|
||||
the Copyright © sign
|
||||
(1 row)
|
||||
|
||||
select json '{ "a": "dollar \u0024 character" }' ->> 'a' as correct_everywhere;
|
||||
correct_everywhere
|
||||
--------------------
|
||||
dollar $ character
|
||||
(1 row)
|
||||
|
||||
select json '{ "a": "null \u0000 escape" }' ->> 'a' as not_unescaped;
|
||||
not_unescaped
|
||||
--------------------
|
||||
null \u0000 escape
|
||||
(1 row)
|
||||
|
||||
|
@ -1,976 +0,0 @@
|
||||
-- Strings.
|
||||
SELECT '""'::json; -- OK.
|
||||
json
|
||||
------
|
||||
""
|
||||
(1 row)
|
||||
|
||||
SELECT $$''$$::json; -- ERROR, single quotes are not allowed
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT $$''$$::json;
|
||||
^
|
||||
DETAIL: Token "'" is invalid.
|
||||
CONTEXT: JSON data, line 1: '...
|
||||
SELECT '"abc"'::json; -- OK
|
||||
json
|
||||
-------
|
||||
"abc"
|
||||
(1 row)
|
||||
|
||||
SELECT '"abc'::json; -- ERROR, quotes not closed
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '"abc'::json;
|
||||
^
|
||||
DETAIL: Token ""abc" is invalid.
|
||||
CONTEXT: JSON data, line 1: "abc
|
||||
SELECT '"abc
|
||||
def"'::json; -- ERROR, unescaped newline in string constant
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '"abc
|
||||
^
|
||||
DETAIL: Character with value 0x0a must be escaped.
|
||||
CONTEXT: JSON data, line 1: "abc
|
||||
SELECT '"\n\"\\"'::json; -- OK, legal escapes
|
||||
json
|
||||
----------
|
||||
"\n\"\\"
|
||||
(1 row)
|
||||
|
||||
SELECT '"\v"'::json; -- ERROR, not a valid JSON escape
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '"\v"'::json;
|
||||
^
|
||||
DETAIL: Escape sequence "\v" is invalid.
|
||||
CONTEXT: JSON data, line 1: "\v...
|
||||
SELECT '"\u"'::json; -- ERROR, incomplete escape
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '"\u"'::json;
|
||||
^
|
||||
DETAIL: "\u" must be followed by four hexadecimal digits.
|
||||
CONTEXT: JSON data, line 1: "\u"
|
||||
SELECT '"\u00"'::json; -- ERROR, incomplete escape
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '"\u00"'::json;
|
||||
^
|
||||
DETAIL: "\u" must be followed by four hexadecimal digits.
|
||||
CONTEXT: JSON data, line 1: "\u00"
|
||||
SELECT '"\u000g"'::json; -- ERROR, g is not a hex digit
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '"\u000g"'::json;
|
||||
^
|
||||
DETAIL: "\u" must be followed by four hexadecimal digits.
|
||||
CONTEXT: JSON data, line 1: "\u000g...
|
||||
SELECT '"\u0000"'::json; -- OK, legal escape
|
||||
json
|
||||
----------
|
||||
"\u0000"
|
||||
(1 row)
|
||||
|
||||
SELECT '"\uaBcD"'::json; -- OK, uppercase and lower case both OK
|
||||
json
|
||||
----------
|
||||
"\uaBcD"
|
||||
(1 row)
|
||||
|
||||
-- Numbers.
|
||||
SELECT '1'::json; -- OK
|
||||
json
|
||||
------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
SELECT '0'::json; -- OK
|
||||
json
|
||||
------
|
||||
0
|
||||
(1 row)
|
||||
|
||||
SELECT '01'::json; -- ERROR, not valid according to JSON spec
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '01'::json;
|
||||
^
|
||||
DETAIL: Token "01" is invalid.
|
||||
CONTEXT: JSON data, line 1: 01
|
||||
SELECT '0.1'::json; -- OK
|
||||
json
|
||||
------
|
||||
0.1
|
||||
(1 row)
|
||||
|
||||
SELECT '9223372036854775808'::json; -- OK, even though it's too large for int8
|
||||
json
|
||||
---------------------
|
||||
9223372036854775808
|
||||
(1 row)
|
||||
|
||||
SELECT '1e100'::json; -- OK
|
||||
json
|
||||
-------
|
||||
1e100
|
||||
(1 row)
|
||||
|
||||
SELECT '1.3e100'::json; -- OK
|
||||
json
|
||||
---------
|
||||
1.3e100
|
||||
(1 row)
|
||||
|
||||
SELECT '1f2'::json; -- ERROR
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '1f2'::json;
|
||||
^
|
||||
DETAIL: Token "1f2" is invalid.
|
||||
CONTEXT: JSON data, line 1: 1f2
|
||||
SELECT '0.x1'::json; -- ERROR
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '0.x1'::json;
|
||||
^
|
||||
DETAIL: Token "0.x1" is invalid.
|
||||
CONTEXT: JSON data, line 1: 0.x1
|
||||
SELECT '1.3ex100'::json; -- ERROR
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '1.3ex100'::json;
|
||||
^
|
||||
DETAIL: Token "1.3ex100" is invalid.
|
||||
CONTEXT: JSON data, line 1: 1.3ex100
|
||||
-- Arrays.
|
||||
SELECT '[]'::json; -- OK
|
||||
json
|
||||
------
|
||||
[]
|
||||
(1 row)
|
||||
|
||||
SELECT '[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]'::json; -- OK
|
||||
json
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
|
||||
(1 row)
|
||||
|
||||
SELECT '[1,2]'::json; -- OK
|
||||
json
|
||||
-------
|
||||
[1,2]
|
||||
(1 row)
|
||||
|
||||
SELECT '[1,2,]'::json; -- ERROR, trailing comma
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '[1,2,]'::json;
|
||||
^
|
||||
DETAIL: Expected JSON value, but found "]".
|
||||
CONTEXT: JSON data, line 1: [1,2,]
|
||||
SELECT '[1,2'::json; -- ERROR, no closing bracket
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '[1,2'::json;
|
||||
^
|
||||
DETAIL: The input string ended unexpectedly.
|
||||
CONTEXT: JSON data, line 1: [1,2
|
||||
SELECT '[1,[2]'::json; -- ERROR, no closing bracket
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '[1,[2]'::json;
|
||||
^
|
||||
DETAIL: The input string ended unexpectedly.
|
||||
CONTEXT: JSON data, line 1: [1,[2]
|
||||
-- Objects.
|
||||
SELECT '{}'::json; -- OK
|
||||
json
|
||||
------
|
||||
{}
|
||||
(1 row)
|
||||
|
||||
SELECT '{"abc"}'::json; -- ERROR, no value
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '{"abc"}'::json;
|
||||
^
|
||||
DETAIL: Expected ":", but found "}".
|
||||
CONTEXT: JSON data, line 1: {"abc"}
|
||||
SELECT '{"abc":1}'::json; -- OK
|
||||
json
|
||||
-----------
|
||||
{"abc":1}
|
||||
(1 row)
|
||||
|
||||
SELECT '{1:"abc"}'::json; -- ERROR, keys must be strings
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '{1:"abc"}'::json;
|
||||
^
|
||||
DETAIL: Expected string or "}", but found "1".
|
||||
CONTEXT: JSON data, line 1: {1...
|
||||
SELECT '{"abc",1}'::json; -- ERROR, wrong separator
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '{"abc",1}'::json;
|
||||
^
|
||||
DETAIL: Expected ":", but found ",".
|
||||
CONTEXT: JSON data, line 1: {"abc",...
|
||||
SELECT '{"abc"=1}'::json; -- ERROR, totally wrong separator
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '{"abc"=1}'::json;
|
||||
^
|
||||
DETAIL: Token "=" is invalid.
|
||||
CONTEXT: JSON data, line 1: {"abc"=...
|
||||
SELECT '{"abc"::1}'::json; -- ERROR, another wrong separator
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '{"abc"::1}'::json;
|
||||
^
|
||||
DETAIL: Expected JSON value, but found ":".
|
||||
CONTEXT: JSON data, line 1: {"abc"::...
|
||||
SELECT '{"abc":1,"def":2,"ghi":[3,4],"hij":{"klm":5,"nop":[6]}}'::json; -- OK
|
||||
json
|
||||
---------------------------------------------------------
|
||||
{"abc":1,"def":2,"ghi":[3,4],"hij":{"klm":5,"nop":[6]}}
|
||||
(1 row)
|
||||
|
||||
SELECT '{"abc":1:2}'::json; -- ERROR, colon in wrong spot
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '{"abc":1:2}'::json;
|
||||
^
|
||||
DETAIL: Expected "," or "}", but found ":".
|
||||
CONTEXT: JSON data, line 1: {"abc":1:...
|
||||
SELECT '{"abc":1,3}'::json; -- ERROR, no value
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '{"abc":1,3}'::json;
|
||||
^
|
||||
DETAIL: Expected string, but found "3".
|
||||
CONTEXT: JSON data, line 1: {"abc":1,3...
|
||||
-- Recursion.
|
||||
SET max_stack_depth = '100kB';
|
||||
SELECT repeat('[', 10000)::json;
|
||||
ERROR: stack depth limit exceeded
|
||||
HINT: Increase the configuration parameter "max_stack_depth" (currently 100kB), after ensuring the platform's stack depth limit is adequate.
|
||||
SELECT repeat('{"a":', 10000)::json;
|
||||
ERROR: stack depth limit exceeded
|
||||
HINT: Increase the configuration parameter "max_stack_depth" (currently 100kB), after ensuring the platform's stack depth limit is adequate.
|
||||
RESET max_stack_depth;
|
||||
-- Miscellaneous stuff.
|
||||
SELECT 'true'::json; -- OK
|
||||
json
|
||||
------
|
||||
true
|
||||
(1 row)
|
||||
|
||||
SELECT 'false'::json; -- OK
|
||||
json
|
||||
-------
|
||||
false
|
||||
(1 row)
|
||||
|
||||
SELECT 'null'::json; -- OK
|
||||
json
|
||||
------
|
||||
null
|
||||
(1 row)
|
||||
|
||||
SELECT ' true '::json; -- OK, even with extra whitespace
|
||||
json
|
||||
--------
|
||||
true
|
||||
(1 row)
|
||||
|
||||
SELECT 'true false'::json; -- ERROR, too many values
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT 'true false'::json;
|
||||
^
|
||||
DETAIL: Expected end of input, but found "false".
|
||||
CONTEXT: JSON data, line 1: true false
|
||||
SELECT 'true, false'::json; -- ERROR, too many values
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT 'true, false'::json;
|
||||
^
|
||||
DETAIL: Expected end of input, but found ",".
|
||||
CONTEXT: JSON data, line 1: true,...
|
||||
SELECT 'truf'::json; -- ERROR, not a keyword
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT 'truf'::json;
|
||||
^
|
||||
DETAIL: Token "truf" is invalid.
|
||||
CONTEXT: JSON data, line 1: truf
|
||||
SELECT 'trues'::json; -- ERROR, not a keyword
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT 'trues'::json;
|
||||
^
|
||||
DETAIL: Token "trues" is invalid.
|
||||
CONTEXT: JSON data, line 1: trues
|
||||
SELECT ''::json; -- ERROR, no value
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT ''::json;
|
||||
^
|
||||
DETAIL: The input string ended unexpectedly.
|
||||
CONTEXT: JSON data, line 1:
|
||||
SELECT ' '::json; -- ERROR, no value
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT ' '::json;
|
||||
^
|
||||
DETAIL: The input string ended unexpectedly.
|
||||
CONTEXT: JSON data, line 1:
|
||||
--constructors
|
||||
-- array_to_json
|
||||
SELECT array_to_json(array(select 1 as a));
|
||||
array_to_json
|
||||
---------------
|
||||
[1]
|
||||
(1 row)
|
||||
|
||||
SELECT array_to_json(array_agg(q),false) from (select x as b, x * 2 as c from generate_series(1,3) x) q;
|
||||
array_to_json
|
||||
---------------------------------------------
|
||||
[{"b":1,"c":2},{"b":2,"c":4},{"b":3,"c":6}]
|
||||
(1 row)
|
||||
|
||||
SELECT array_to_json(array_agg(q),true) from (select x as b, x * 2 as c from generate_series(1,3) x) q;
|
||||
array_to_json
|
||||
-----------------
|
||||
[{"b":1,"c":2},+
|
||||
{"b":2,"c":4},+
|
||||
{"b":3,"c":6}]
|
||||
(1 row)
|
||||
|
||||
SELECT array_to_json(array_agg(q),false)
|
||||
FROM ( SELECT $$a$$ || x AS b, y AS c,
|
||||
ARRAY[ROW(x.*,ARRAY[1,2,3]),
|
||||
ROW(y.*,ARRAY[4,5,6])] AS z
|
||||
FROM generate_series(1,2) x,
|
||||
generate_series(4,5) y) q;
|
||||
array_to_json
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
[{"b":"a1","c":4,"z":[{"f1":1,"f2":[1,2,3]},{"f1":4,"f2":[4,5,6]}]},{"b":"a1","c":5,"z":[{"f1":1,"f2":[1,2,3]},{"f1":5,"f2":[4,5,6]}]},{"b":"a2","c":4,"z":[{"f1":2,"f2":[1,2,3]},{"f1":4,"f2":[4,5,6]}]},{"b":"a2","c":5,"z":[{"f1":2,"f2":[1,2,3]},{"f1":5,"f2":[4,5,6]}]}]
|
||||
(1 row)
|
||||
|
||||
SELECT array_to_json(array_agg(x),false) from generate_series(5,10) x;
|
||||
array_to_json
|
||||
----------------
|
||||
[5,6,7,8,9,10]
|
||||
(1 row)
|
||||
|
||||
SELECT array_to_json('{{1,5},{99,100}}'::int[]);
|
||||
array_to_json
|
||||
------------------
|
||||
[[1,5],[99,100]]
|
||||
(1 row)
|
||||
|
||||
-- row_to_json
|
||||
SELECT row_to_json(row(1,'foo'));
|
||||
row_to_json
|
||||
---------------------
|
||||
{"f1":1,"f2":"foo"}
|
||||
(1 row)
|
||||
|
||||
SELECT row_to_json(q)
|
||||
FROM (SELECT $$a$$ || x AS b,
|
||||
y AS c,
|
||||
ARRAY[ROW(x.*,ARRAY[1,2,3]),
|
||||
ROW(y.*,ARRAY[4,5,6])] AS z
|
||||
FROM generate_series(1,2) x,
|
||||
generate_series(4,5) y) q;
|
||||
row_to_json
|
||||
--------------------------------------------------------------------
|
||||
{"b":"a1","c":4,"z":[{"f1":1,"f2":[1,2,3]},{"f1":4,"f2":[4,5,6]}]}
|
||||
{"b":"a1","c":5,"z":[{"f1":1,"f2":[1,2,3]},{"f1":5,"f2":[4,5,6]}]}
|
||||
{"b":"a2","c":4,"z":[{"f1":2,"f2":[1,2,3]},{"f1":4,"f2":[4,5,6]}]}
|
||||
{"b":"a2","c":5,"z":[{"f1":2,"f2":[1,2,3]},{"f1":5,"f2":[4,5,6]}]}
|
||||
(4 rows)
|
||||
|
||||
SELECT row_to_json(q,true)
|
||||
FROM (SELECT $$a$$ || x AS b,
|
||||
y AS c,
|
||||
ARRAY[ROW(x.*,ARRAY[1,2,3]),
|
||||
ROW(y.*,ARRAY[4,5,6])] AS z
|
||||
FROM generate_series(1,2) x,
|
||||
generate_series(4,5) y) q;
|
||||
row_to_json
|
||||
-----------------------------------------------------
|
||||
{"b":"a1", +
|
||||
"c":4, +
|
||||
"z":[{"f1":1,"f2":[1,2,3]},{"f1":4,"f2":[4,5,6]}]}
|
||||
{"b":"a1", +
|
||||
"c":5, +
|
||||
"z":[{"f1":1,"f2":[1,2,3]},{"f1":5,"f2":[4,5,6]}]}
|
||||
{"b":"a2", +
|
||||
"c":4, +
|
||||
"z":[{"f1":2,"f2":[1,2,3]},{"f1":4,"f2":[4,5,6]}]}
|
||||
{"b":"a2", +
|
||||
"c":5, +
|
||||
"z":[{"f1":2,"f2":[1,2,3]},{"f1":5,"f2":[4,5,6]}]}
|
||||
(4 rows)
|
||||
|
||||
CREATE TEMP TABLE rows AS
|
||||
SELECT x, 'txt' || x as y
|
||||
FROM generate_series(1,3) AS x;
|
||||
SELECT row_to_json(q,true)
|
||||
FROM rows q;
|
||||
row_to_json
|
||||
--------------
|
||||
{"x":1, +
|
||||
"y":"txt1"}
|
||||
{"x":2, +
|
||||
"y":"txt2"}
|
||||
{"x":3, +
|
||||
"y":"txt3"}
|
||||
(3 rows)
|
||||
|
||||
SELECT row_to_json(row((select array_agg(x) as d from generate_series(5,10) x)),false);
|
||||
row_to_json
|
||||
-----------------------
|
||||
{"f1":[5,6,7,8,9,10]}
|
||||
(1 row)
|
||||
|
||||
--json_agg
|
||||
SELECT json_agg(q)
|
||||
FROM ( SELECT $$a$$ || x AS b, y AS c,
|
||||
ARRAY[ROW(x.*,ARRAY[1,2,3]),
|
||||
ROW(y.*,ARRAY[4,5,6])] AS z
|
||||
FROM generate_series(1,2) x,
|
||||
generate_series(4,5) y) q;
|
||||
json_agg
|
||||
-----------------------------------------------------------------------
|
||||
[{"b":"a1","c":4,"z":[{"f1":1,"f2":[1,2,3]},{"f1":4,"f2":[4,5,6]}]}, +
|
||||
{"b":"a1","c":5,"z":[{"f1":1,"f2":[1,2,3]},{"f1":5,"f2":[4,5,6]}]}, +
|
||||
{"b":"a2","c":4,"z":[{"f1":2,"f2":[1,2,3]},{"f1":4,"f2":[4,5,6]}]}, +
|
||||
{"b":"a2","c":5,"z":[{"f1":2,"f2":[1,2,3]},{"f1":5,"f2":[4,5,6]}]}]
|
||||
(1 row)
|
||||
|
||||
SELECT json_agg(q)
|
||||
FROM rows q;
|
||||
json_agg
|
||||
-----------------------
|
||||
[{"x":1,"y":"txt1"}, +
|
||||
{"x":2,"y":"txt2"}, +
|
||||
{"x":3,"y":"txt3"}]
|
||||
(1 row)
|
||||
|
||||
-- non-numeric output
|
||||
SELECT row_to_json(q)
|
||||
FROM (SELECT 'NaN'::float8 AS "float8field") q;
|
||||
row_to_json
|
||||
-----------------------
|
||||
{"float8field":"NaN"}
|
||||
(1 row)
|
||||
|
||||
SELECT row_to_json(q)
|
||||
FROM (SELECT 'Infinity'::float8 AS "float8field") q;
|
||||
row_to_json
|
||||
----------------------------
|
||||
{"float8field":"Infinity"}
|
||||
(1 row)
|
||||
|
||||
SELECT row_to_json(q)
|
||||
FROM (SELECT '-Infinity'::float8 AS "float8field") q;
|
||||
row_to_json
|
||||
-----------------------------
|
||||
{"float8field":"-Infinity"}
|
||||
(1 row)
|
||||
|
||||
-- json input
|
||||
SELECT row_to_json(q)
|
||||
FROM (SELECT '{"a":1,"b": [2,3,4,"d","e","f"],"c":{"p":1,"q":2}}'::json AS "jsonfield") q;
|
||||
row_to_json
|
||||
------------------------------------------------------------------
|
||||
{"jsonfield":{"a":1,"b": [2,3,4,"d","e","f"],"c":{"p":1,"q":2}}}
|
||||
(1 row)
|
||||
|
||||
-- json extraction functions
|
||||
CREATE TEMP TABLE test_json (
|
||||
json_type text,
|
||||
test_json json
|
||||
);
|
||||
INSERT INTO test_json VALUES
|
||||
('scalar','"a scalar"'),
|
||||
('array','["zero", "one","two",null,"four","five"]'),
|
||||
('object','{"field1":"val1","field2":"val2","field3":null}');
|
||||
SELECT test_json -> 'x'
|
||||
FROM test_json
|
||||
WHERE json_type = 'scalar';
|
||||
ERROR: cannot extract element from a scalar
|
||||
SELECT test_json -> 'x'
|
||||
FROM test_json
|
||||
WHERE json_type = 'array';
|
||||
ERROR: cannot extract field from a non-object
|
||||
SELECT test_json -> 'x'
|
||||
FROM test_json
|
||||
WHERE json_type = 'object';
|
||||
?column?
|
||||
----------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT test_json->'field2'
|
||||
FROM test_json
|
||||
WHERE json_type = 'object';
|
||||
?column?
|
||||
----------
|
||||
"val2"
|
||||
(1 row)
|
||||
|
||||
SELECT test_json->>'field2'
|
||||
FROM test_json
|
||||
WHERE json_type = 'object';
|
||||
?column?
|
||||
----------
|
||||
val2
|
||||
(1 row)
|
||||
|
||||
SELECT test_json -> 2
|
||||
FROM test_json
|
||||
WHERE json_type = 'scalar';
|
||||
ERROR: cannot extract element from a scalar
|
||||
SELECT test_json -> 2
|
||||
FROM test_json
|
||||
WHERE json_type = 'array';
|
||||
?column?
|
||||
----------
|
||||
"two"
|
||||
(1 row)
|
||||
|
||||
SELECT test_json -> 2
|
||||
FROM test_json
|
||||
WHERE json_type = 'object';
|
||||
ERROR: cannot extract array element from a non-array
|
||||
SELECT test_json->>2
|
||||
FROM test_json
|
||||
WHERE json_type = 'array';
|
||||
?column?
|
||||
----------
|
||||
two
|
||||
(1 row)
|
||||
|
||||
SELECT json_object_keys(test_json)
|
||||
FROM test_json
|
||||
WHERE json_type = 'scalar';
|
||||
ERROR: cannot call json_object_keys on a scalar
|
||||
SELECT json_object_keys(test_json)
|
||||
FROM test_json
|
||||
WHERE json_type = 'array';
|
||||
ERROR: cannot call json_object_keys on an array
|
||||
SELECT json_object_keys(test_json)
|
||||
FROM test_json
|
||||
WHERE json_type = 'object';
|
||||
json_object_keys
|
||||
------------------
|
||||
field1
|
||||
field2
|
||||
field3
|
||||
(3 rows)
|
||||
|
||||
-- nulls
|
||||
select (test_json->'field3') is null as expect_false
|
||||
from test_json
|
||||
where json_type = 'object';
|
||||
expect_false
|
||||
--------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
select (test_json->>'field3') is null as expect_true
|
||||
from test_json
|
||||
where json_type = 'object';
|
||||
expect_true
|
||||
-------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
select (test_json->3) is null as expect_false
|
||||
from test_json
|
||||
where json_type = 'array';
|
||||
expect_false
|
||||
--------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
select (test_json->>3) is null as expect_true
|
||||
from test_json
|
||||
where json_type = 'array';
|
||||
expect_true
|
||||
-------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
-- array length
|
||||
SELECT json_array_length('[1,2,3,{"f1":1,"f2":[5,6]},4]');
|
||||
json_array_length
|
||||
-------------------
|
||||
5
|
||||
(1 row)
|
||||
|
||||
SELECT json_array_length('[]');
|
||||
json_array_length
|
||||
-------------------
|
||||
0
|
||||
(1 row)
|
||||
|
||||
SELECT json_array_length('{"f1":1,"f2":[5,6]}');
|
||||
ERROR: cannot get array length of a non-array
|
||||
SELECT json_array_length('4');
|
||||
ERROR: cannot get array length of a scalar
|
||||
-- each
|
||||
select json_each('{"f1":[1,2,3],"f2":{"f3":1},"f4":null}');
|
||||
json_each
|
||||
-------------------
|
||||
(f1,"[1,2,3]")
|
||||
(f2,"{""f3"":1}")
|
||||
(f4,null)
|
||||
(3 rows)
|
||||
|
||||
select * from json_each('{"f1":[1,2,3],"f2":{"f3":1},"f4":null,"f5":99,"f6":"stringy"}') q;
|
||||
key | value
|
||||
-----+-----------
|
||||
f1 | [1,2,3]
|
||||
f2 | {"f3":1}
|
||||
f4 | null
|
||||
f5 | 99
|
||||
f6 | "stringy"
|
||||
(5 rows)
|
||||
|
||||
select json_each_text('{"f1":[1,2,3],"f2":{"f3":1},"f4":null,"f5":"null"}');
|
||||
json_each_text
|
||||
-------------------
|
||||
(f1,"[1,2,3]")
|
||||
(f2,"{""f3"":1}")
|
||||
(f4,)
|
||||
(f5,null)
|
||||
(4 rows)
|
||||
|
||||
select * from json_each_text('{"f1":[1,2,3],"f2":{"f3":1},"f4":null,"f5":99,"f6":"stringy"}') q;
|
||||
key | value
|
||||
-----+----------
|
||||
f1 | [1,2,3]
|
||||
f2 | {"f3":1}
|
||||
f4 |
|
||||
f5 | 99
|
||||
f6 | stringy
|
||||
(5 rows)
|
||||
|
||||
-- extract_path, extract_path_as_text
|
||||
select json_extract_path('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f4','f6');
|
||||
json_extract_path
|
||||
-------------------
|
||||
"stringy"
|
||||
(1 row)
|
||||
|
||||
select json_extract_path('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f2');
|
||||
json_extract_path
|
||||
-------------------
|
||||
{"f3":1}
|
||||
(1 row)
|
||||
|
||||
select json_extract_path('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',0::text);
|
||||
json_extract_path
|
||||
-------------------
|
||||
"f3"
|
||||
(1 row)
|
||||
|
||||
select json_extract_path('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',1::text);
|
||||
json_extract_path
|
||||
-------------------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
select json_extract_path_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f4','f6');
|
||||
json_extract_path_text
|
||||
------------------------
|
||||
stringy
|
||||
(1 row)
|
||||
|
||||
select json_extract_path_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f2');
|
||||
json_extract_path_text
|
||||
------------------------
|
||||
{"f3":1}
|
||||
(1 row)
|
||||
|
||||
select json_extract_path_text('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',0::text);
|
||||
json_extract_path_text
|
||||
------------------------
|
||||
f3
|
||||
(1 row)
|
||||
|
||||
select json_extract_path_text('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',1::text);
|
||||
json_extract_path_text
|
||||
------------------------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
-- extract_path nulls
|
||||
select json_extract_path('{"f2":{"f3":1},"f4":{"f5":null,"f6":"stringy"}}','f4','f5') is null as expect_false;
|
||||
expect_false
|
||||
--------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
select json_extract_path_text('{"f2":{"f3":1},"f4":{"f5":null,"f6":"stringy"}}','f4','f5') is null as expect_true;
|
||||
expect_true
|
||||
-------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
select json_extract_path('{"f2":{"f3":1},"f4":[0,1,2,null]}','f4','3') is null as expect_false;
|
||||
expect_false
|
||||
--------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
select json_extract_path_text('{"f2":{"f3":1},"f4":[0,1,2,null]}','f4','3') is null as expect_true;
|
||||
expect_true
|
||||
-------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
-- extract_path operators
|
||||
select '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::json#>array['f4','f6'];
|
||||
?column?
|
||||
-----------
|
||||
"stringy"
|
||||
(1 row)
|
||||
|
||||
select '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::json#>array['f2'];
|
||||
?column?
|
||||
----------
|
||||
{"f3":1}
|
||||
(1 row)
|
||||
|
||||
select '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::json#>array['f2','0'];
|
||||
?column?
|
||||
----------
|
||||
"f3"
|
||||
(1 row)
|
||||
|
||||
select '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::json#>array['f2','1'];
|
||||
?column?
|
||||
----------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
select '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::json#>>array['f4','f6'];
|
||||
?column?
|
||||
----------
|
||||
stringy
|
||||
(1 row)
|
||||
|
||||
select '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::json#>>array['f2'];
|
||||
?column?
|
||||
----------
|
||||
{"f3":1}
|
||||
(1 row)
|
||||
|
||||
select '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::json#>>array['f2','0'];
|
||||
?column?
|
||||
----------
|
||||
f3
|
||||
(1 row)
|
||||
|
||||
select '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::json#>>array['f2','1'];
|
||||
?column?
|
||||
----------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
-- same using array literals
|
||||
select '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::json#>'{f4,f6}';
|
||||
?column?
|
||||
-----------
|
||||
"stringy"
|
||||
(1 row)
|
||||
|
||||
select '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::json#>'{f2}';
|
||||
?column?
|
||||
----------
|
||||
{"f3":1}
|
||||
(1 row)
|
||||
|
||||
select '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::json#>'{f2,0}';
|
||||
?column?
|
||||
----------
|
||||
"f3"
|
||||
(1 row)
|
||||
|
||||
select '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::json#>'{f2,1}';
|
||||
?column?
|
||||
----------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
select '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::json#>>'{f4,f6}';
|
||||
?column?
|
||||
----------
|
||||
stringy
|
||||
(1 row)
|
||||
|
||||
select '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::json#>>'{f2}';
|
||||
?column?
|
||||
----------
|
||||
{"f3":1}
|
||||
(1 row)
|
||||
|
||||
select '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::json#>>'{f2,0}';
|
||||
?column?
|
||||
----------
|
||||
f3
|
||||
(1 row)
|
||||
|
||||
select '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::json#>>'{f2,1}';
|
||||
?column?
|
||||
----------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
-- array_elements
|
||||
select json_array_elements('[1,true,[1,[2,3]],null,{"f1":1,"f2":[7,8,9]},false]');
|
||||
json_array_elements
|
||||
-----------------------
|
||||
1
|
||||
true
|
||||
[1,[2,3]]
|
||||
null
|
||||
{"f1":1,"f2":[7,8,9]}
|
||||
false
|
||||
(6 rows)
|
||||
|
||||
select * from json_array_elements('[1,true,[1,[2,3]],null,{"f1":1,"f2":[7,8,9]},false]') q;
|
||||
value
|
||||
-----------------------
|
||||
1
|
||||
true
|
||||
[1,[2,3]]
|
||||
null
|
||||
{"f1":1,"f2":[7,8,9]}
|
||||
false
|
||||
(6 rows)
|
||||
|
||||
-- populate_record
|
||||
create type jpop as (a text, b int, c timestamp);
|
||||
select * from json_populate_record(null::jpop,'{"a":"blurfl","x":43.2}') q;
|
||||
a | b | c
|
||||
--------+---+---
|
||||
blurfl | |
|
||||
(1 row)
|
||||
|
||||
select * from json_populate_record(row('x',3,'2012-12-31 15:30:56')::jpop,'{"a":"blurfl","x":43.2}') q;
|
||||
a | b | c
|
||||
--------+---+--------------------------
|
||||
blurfl | 3 | Mon Dec 31 15:30:56 2012
|
||||
(1 row)
|
||||
|
||||
select * from json_populate_record(null::jpop,'{"a":"blurfl","x":43.2}', true) q;
|
||||
a | b | c
|
||||
--------+---+---
|
||||
blurfl | |
|
||||
(1 row)
|
||||
|
||||
select * from json_populate_record(row('x',3,'2012-12-31 15:30:56')::jpop,'{"a":"blurfl","x":43.2}', true) q;
|
||||
a | b | c
|
||||
--------+---+--------------------------
|
||||
blurfl | 3 | Mon Dec 31 15:30:56 2012
|
||||
(1 row)
|
||||
|
||||
select * from json_populate_record(null::jpop,'{"a":[100,200,false],"x":43.2}', true) q;
|
||||
a | b | c
|
||||
-----------------+---+---
|
||||
[100,200,false] | |
|
||||
(1 row)
|
||||
|
||||
select * from json_populate_record(row('x',3,'2012-12-31 15:30:56')::jpop,'{"a":[100,200,false],"x":43.2}', true) q;
|
||||
a | b | c
|
||||
-----------------+---+--------------------------
|
||||
[100,200,false] | 3 | Mon Dec 31 15:30:56 2012
|
||||
(1 row)
|
||||
|
||||
select * from json_populate_record(row('x',3,'2012-12-31 15:30:56')::jpop,'{"c":[100,200,false],"x":43.2}', true) q;
|
||||
ERROR: invalid input syntax for type timestamp: "[100,200,false]"
|
||||
-- populate_recordset
|
||||
select * from json_populate_recordset(null::jpop,'[{"a":"blurfl","x":43.2},{"b":3,"c":"2012-01-20 10:42:53"}]',false) q;
|
||||
a | b | c
|
||||
--------+---+--------------------------
|
||||
blurfl | |
|
||||
| 3 | Fri Jan 20 10:42:53 2012
|
||||
(2 rows)
|
||||
|
||||
select * from json_populate_recordset(row('def',99,null)::jpop,'[{"a":"blurfl","x":43.2},{"b":3,"c":"2012-01-20 10:42:53"}]',false) q;
|
||||
a | b | c
|
||||
--------+----+--------------------------
|
||||
blurfl | 99 |
|
||||
def | 3 | Fri Jan 20 10:42:53 2012
|
||||
(2 rows)
|
||||
|
||||
select * from json_populate_recordset(null::jpop,'[{"a":"blurfl","x":43.2},{"b":3,"c":"2012-01-20 10:42:53"}]',true) q;
|
||||
a | b | c
|
||||
--------+---+--------------------------
|
||||
blurfl | |
|
||||
| 3 | Fri Jan 20 10:42:53 2012
|
||||
(2 rows)
|
||||
|
||||
select * from json_populate_recordset(row('def',99,null)::jpop,'[{"a":"blurfl","x":43.2},{"b":3,"c":"2012-01-20 10:42:53"}]',true) q;
|
||||
a | b | c
|
||||
--------+----+--------------------------
|
||||
blurfl | 99 |
|
||||
def | 3 | Fri Jan 20 10:42:53 2012
|
||||
(2 rows)
|
||||
|
||||
select * from json_populate_recordset(row('def',99,null)::jpop,'[{"a":[100,200,300],"x":43.2},{"a":{"z":true},"b":3,"c":"2012-01-20 10:42:53"}]',true) q;
|
||||
a | b | c
|
||||
---------------+----+--------------------------
|
||||
[100,200,300] | 99 |
|
||||
{"z":true} | 3 | Fri Jan 20 10:42:53 2012
|
||||
(2 rows)
|
||||
|
||||
select * from json_populate_recordset(row('def',99,null)::jpop,'[{"c":[100,200,300],"x":43.2},{"a":{"z":true},"b":3,"c":"2012-01-20 10:42:53"}]',true) q;
|
||||
ERROR: invalid input syntax for type timestamp: "[100,200,300]"
|
||||
create type jpop2 as (a int, b json, c int, d int);
|
||||
select * from json_populate_recordset(null::jpop2, '[{"a":2,"c":3,"b":{"z":4},"d":6}]',true) q;
|
||||
a | b | c | d
|
||||
---+---------+---+---
|
||||
2 | {"z":4} | 3 | 6
|
||||
(1 row)
|
||||
|
||||
-- using the default use_json_as_text argument
|
||||
select * from json_populate_recordset(null::jpop,'[{"a":"blurfl","x":43.2},{"b":3,"c":"2012-01-20 10:42:53"}]') q;
|
||||
a | b | c
|
||||
--------+---+--------------------------
|
||||
blurfl | |
|
||||
| 3 | Fri Jan 20 10:42:53 2012
|
||||
(2 rows)
|
||||
|
||||
select * from json_populate_recordset(row('def',99,null)::jpop,'[{"a":"blurfl","x":43.2},{"b":3,"c":"2012-01-20 10:42:53"}]') q;
|
||||
a | b | c
|
||||
--------+----+--------------------------
|
||||
blurfl | 99 |
|
||||
def | 3 | Fri Jan 20 10:42:53 2012
|
||||
(2 rows)
|
||||
|
||||
select * from json_populate_recordset(row('def',99,null)::jpop,'[{"a":[100,200,300],"x":43.2},{"a":{"z":true},"b":3,"c":"2012-01-20 10:42:53"}]') q;
|
||||
ERROR: cannot call json_populate_recordset on a nested object
|
||||
select * from json_populate_recordset(row('def',99,null)::jpop,'[{"c":[100,200,300],"x":43.2},{"a":{"z":true},"b":3,"c":"2012-01-20 10:42:53"}]') q;
|
||||
ERROR: cannot call json_populate_recordset on a nested object
|
||||
-- handling of unicode surrogate pairs
|
||||
select json '{ "a": "\ud83d\ude04\ud83d\udc36" }' -> 'a' as correct_in_utf8;
|
||||
ERROR: invalid input syntax for type json
|
||||
DETAIL: Unicode escape values cannot be used for code point values above 007F when the server encoding is not UTF8.
|
||||
CONTEXT: JSON data, line 1: { "a":...
|
||||
select json '{ "a": "\ud83d\ud83d" }' -> 'a'; -- 2 high surrogates in a row
|
||||
ERROR: invalid input syntax for type json
|
||||
DETAIL: Unicode high surrogate must not follow a high surrogate.
|
||||
CONTEXT: JSON data, line 1: { "a":...
|
||||
select json '{ "a": "\ude04\ud83d" }' -> 'a'; -- surrogates in wrong order
|
||||
ERROR: invalid input syntax for type json
|
||||
DETAIL: Unicode low surrogate must follow a high surrogate.
|
||||
CONTEXT: JSON data, line 1: { "a":...
|
||||
select json '{ "a": "\ud83dX" }' -> 'a'; -- orphan high surrogate
|
||||
ERROR: invalid input syntax for type json
|
||||
DETAIL: Unicode low surrogate must follow a high surrogate.
|
||||
CONTEXT: JSON data, line 1: { "a":...
|
||||
select json '{ "a": "\ude04X" }' -> 'a'; -- orphan low surrogate
|
||||
ERROR: invalid input syntax for type json
|
||||
DETAIL: Unicode low surrogate must follow a high surrogate.
|
||||
CONTEXT: JSON data, line 1: { "a":...
|
||||
--handling of simple unicode escapes
|
||||
select json '{ "a": "the Copyright \u00a9 sign" }' ->> 'a' as correct_in_utf8;
|
||||
ERROR: invalid input syntax for type json
|
||||
DETAIL: Unicode escape values cannot be used for code point values above 007F when the server encoding is not UTF8.
|
||||
CONTEXT: JSON data, line 1: { "a":...
|
||||
select json '{ "a": "dollar \u0024 character" }' ->> 'a' as correct_everywhere;
|
||||
correct_everywhere
|
||||
--------------------
|
||||
dollar $ character
|
||||
(1 row)
|
||||
|
||||
select json '{ "a": "null \u0000 escape" }' ->> 'a' as not_unescaped;
|
||||
not_unescaped
|
||||
--------------------
|
||||
null \u0000 escape
|
||||
(1 row)
|
||||
|
74
src/test/regress/expected/json_encoding.out
Normal file
74
src/test/regress/expected/json_encoding.out
Normal file
@ -0,0 +1,74 @@
|
||||
-- encoding-sensitive tests for json
|
||||
-- basic unicode input
|
||||
SELECT '"\u"'::json; -- ERROR, incomplete escape
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '"\u"'::json;
|
||||
^
|
||||
DETAIL: "\u" must be followed by four hexadecimal digits.
|
||||
CONTEXT: JSON data, line 1: "\u"
|
||||
SELECT '"\u00"'::json; -- ERROR, incomplete escape
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '"\u00"'::json;
|
||||
^
|
||||
DETAIL: "\u" must be followed by four hexadecimal digits.
|
||||
CONTEXT: JSON data, line 1: "\u00"
|
||||
SELECT '"\u000g"'::json; -- ERROR, g is not a hex digit
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '"\u000g"'::json;
|
||||
^
|
||||
DETAIL: "\u" must be followed by four hexadecimal digits.
|
||||
CONTEXT: JSON data, line 1: "\u000g...
|
||||
SELECT '"\u0000"'::json; -- OK, legal escape
|
||||
json
|
||||
----------
|
||||
"\u0000"
|
||||
(1 row)
|
||||
|
||||
SELECT '"\uaBcD"'::json; -- OK, uppercase and lower case both OK
|
||||
json
|
||||
----------
|
||||
"\uaBcD"
|
||||
(1 row)
|
||||
|
||||
-- handling of unicode surrogate pairs
|
||||
select json '{ "a": "\ud83d\ude04\ud83d\udc36" }' -> 'a' as correct_in_utf8;
|
||||
correct_in_utf8
|
||||
----------------------------
|
||||
"\ud83d\ude04\ud83d\udc36"
|
||||
(1 row)
|
||||
|
||||
select json '{ "a": "\ud83d\ud83d" }' -> 'a'; -- 2 high surrogates in a row
|
||||
ERROR: invalid input syntax for type json
|
||||
DETAIL: Unicode high surrogate must not follow a high surrogate.
|
||||
CONTEXT: JSON data, line 1: { "a":...
|
||||
select json '{ "a": "\ude04\ud83d" }' -> 'a'; -- surrogates in wrong order
|
||||
ERROR: invalid input syntax for type json
|
||||
DETAIL: Unicode low surrogate must follow a high surrogate.
|
||||
CONTEXT: JSON data, line 1: { "a":...
|
||||
select json '{ "a": "\ud83dX" }' -> 'a'; -- orphan high surrogate
|
||||
ERROR: invalid input syntax for type json
|
||||
DETAIL: Unicode low surrogate must follow a high surrogate.
|
||||
CONTEXT: JSON data, line 1: { "a":...
|
||||
select json '{ "a": "\ude04X" }' -> 'a'; -- orphan low surrogate
|
||||
ERROR: invalid input syntax for type json
|
||||
DETAIL: Unicode low surrogate must follow a high surrogate.
|
||||
CONTEXT: JSON data, line 1: { "a":...
|
||||
--handling of simple unicode escapes
|
||||
select json '{ "a": "the Copyright \u00a9 sign" }' ->> 'a' as correct_in_utf8;
|
||||
correct_in_utf8
|
||||
----------------------
|
||||
the Copyright © sign
|
||||
(1 row)
|
||||
|
||||
select json '{ "a": "dollar \u0024 character" }' ->> 'a' as correct_everywhere;
|
||||
correct_everywhere
|
||||
--------------------
|
||||
dollar $ character
|
||||
(1 row)
|
||||
|
||||
select json '{ "a": "null \u0000 escape" }' ->> 'a' as not_escaped;
|
||||
not_escaped
|
||||
--------------------
|
||||
null \u0000 escape
|
||||
(1 row)
|
||||
|
70
src/test/regress/expected/json_encoding_1.out
Normal file
70
src/test/regress/expected/json_encoding_1.out
Normal file
@ -0,0 +1,70 @@
|
||||
-- encoding-sensitive tests for json
|
||||
-- basic unicode input
|
||||
SELECT '"\u"'::json; -- ERROR, incomplete escape
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '"\u"'::json;
|
||||
^
|
||||
DETAIL: "\u" must be followed by four hexadecimal digits.
|
||||
CONTEXT: JSON data, line 1: "\u"
|
||||
SELECT '"\u00"'::json; -- ERROR, incomplete escape
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '"\u00"'::json;
|
||||
^
|
||||
DETAIL: "\u" must be followed by four hexadecimal digits.
|
||||
CONTEXT: JSON data, line 1: "\u00"
|
||||
SELECT '"\u000g"'::json; -- ERROR, g is not a hex digit
|
||||
ERROR: invalid input syntax for type json
|
||||
LINE 1: SELECT '"\u000g"'::json;
|
||||
^
|
||||
DETAIL: "\u" must be followed by four hexadecimal digits.
|
||||
CONTEXT: JSON data, line 1: "\u000g...
|
||||
SELECT '"\u0000"'::json; -- OK, legal escape
|
||||
json
|
||||
----------
|
||||
"\u0000"
|
||||
(1 row)
|
||||
|
||||
SELECT '"\uaBcD"'::json; -- OK, uppercase and lower case both OK
|
||||
json
|
||||
----------
|
||||
"\uaBcD"
|
||||
(1 row)
|
||||
|
||||
-- handling of unicode surrogate pairs
|
||||
select json '{ "a": "\ud83d\ude04\ud83d\udc36" }' -> 'a' as correct_in_utf8;
|
||||
ERROR: invalid input syntax for type json
|
||||
DETAIL: Unicode escape values cannot be used for code point values above 007F when the server encoding is not UTF8.
|
||||
CONTEXT: JSON data, line 1: { "a":...
|
||||
select json '{ "a": "\ud83d\ud83d" }' -> 'a'; -- 2 high surrogates in a row
|
||||
ERROR: invalid input syntax for type json
|
||||
DETAIL: Unicode high surrogate must not follow a high surrogate.
|
||||
CONTEXT: JSON data, line 1: { "a":...
|
||||
select json '{ "a": "\ude04\ud83d" }' -> 'a'; -- surrogates in wrong order
|
||||
ERROR: invalid input syntax for type json
|
||||
DETAIL: Unicode low surrogate must follow a high surrogate.
|
||||
CONTEXT: JSON data, line 1: { "a":...
|
||||
select json '{ "a": "\ud83dX" }' -> 'a'; -- orphan high surrogate
|
||||
ERROR: invalid input syntax for type json
|
||||
DETAIL: Unicode low surrogate must follow a high surrogate.
|
||||
CONTEXT: JSON data, line 1: { "a":...
|
||||
select json '{ "a": "\ude04X" }' -> 'a'; -- orphan low surrogate
|
||||
ERROR: invalid input syntax for type json
|
||||
DETAIL: Unicode low surrogate must follow a high surrogate.
|
||||
CONTEXT: JSON data, line 1: { "a":...
|
||||
--handling of simple unicode escapes
|
||||
select json '{ "a": "the Copyright \u00a9 sign" }' ->> 'a' as correct_in_utf8;
|
||||
ERROR: invalid input syntax for type json
|
||||
DETAIL: Unicode escape values cannot be used for code point values above 007F when the server encoding is not UTF8.
|
||||
CONTEXT: JSON data, line 1: { "a":...
|
||||
select json '{ "a": "dollar \u0024 character" }' ->> 'a' as correct_everywhere;
|
||||
correct_everywhere
|
||||
--------------------
|
||||
dollar $ character
|
||||
(1 row)
|
||||
|
||||
select json '{ "a": "null \u0000 escape" }' ->> 'a' as not_escaped;
|
||||
not_escaped
|
||||
--------------------
|
||||
null \u0000 escape
|
||||
(1 row)
|
||||
|
@ -98,7 +98,7 @@ test: event_trigger
|
||||
# ----------
|
||||
# Another group of parallel tests
|
||||
# ----------
|
||||
test: select_views portals_p2 foreign_key cluster dependency guc bitmapops combocid tsearch tsdicts foreign_data window xmlmap functional_deps advisory_lock json equivclass
|
||||
test: select_views portals_p2 foreign_key cluster dependency guc bitmapops combocid tsearch tsdicts foreign_data window xmlmap functional_deps advisory_lock json json_encoding equivclass
|
||||
|
||||
# ----------
|
||||
# Another group of parallel tests
|
||||
|
@ -117,6 +117,7 @@ test: xmlmap
|
||||
test: functional_deps
|
||||
test: advisory_lock
|
||||
test: json
|
||||
test: json_encoding
|
||||
test: equivclass
|
||||
test: plancache
|
||||
test: limit
|
||||
|
@ -7,11 +7,7 @@ SELECT '"abc
|
||||
def"'::json; -- ERROR, unescaped newline in string constant
|
||||
SELECT '"\n\"\\"'::json; -- OK, legal escapes
|
||||
SELECT '"\v"'::json; -- ERROR, not a valid JSON escape
|
||||
SELECT '"\u"'::json; -- ERROR, incomplete escape
|
||||
SELECT '"\u00"'::json; -- ERROR, incomplete escape
|
||||
SELECT '"\u000g"'::json; -- ERROR, g is not a hex digit
|
||||
SELECT '"\u0000"'::json; -- OK, legal escape
|
||||
SELECT '"\uaBcD"'::json; -- OK, uppercase and lower case both OK
|
||||
-- see json_encoding test for input with unicode escapes
|
||||
|
||||
-- Numbers.
|
||||
SELECT '1'::json; -- OK
|
||||
@ -306,16 +302,3 @@ select * from json_populate_recordset(row('def',99,null)::jpop,'[{"a":"blurfl","
|
||||
select * from json_populate_recordset(row('def',99,null)::jpop,'[{"a":[100,200,300],"x":43.2},{"a":{"z":true},"b":3,"c":"2012-01-20 10:42:53"}]') q;
|
||||
select * from json_populate_recordset(row('def',99,null)::jpop,'[{"c":[100,200,300],"x":43.2},{"a":{"z":true},"b":3,"c":"2012-01-20 10:42:53"}]') q;
|
||||
|
||||
-- handling of unicode surrogate pairs
|
||||
|
||||
select json '{ "a": "\ud83d\ude04\ud83d\udc36" }' -> 'a' as correct_in_utf8;
|
||||
select json '{ "a": "\ud83d\ud83d" }' -> 'a'; -- 2 high surrogates in a row
|
||||
select json '{ "a": "\ude04\ud83d" }' -> 'a'; -- surrogates in wrong order
|
||||
select json '{ "a": "\ud83dX" }' -> 'a'; -- orphan high surrogate
|
||||
select json '{ "a": "\ude04X" }' -> 'a'; -- orphan low surrogate
|
||||
|
||||
--handling of simple unicode escapes
|
||||
|
||||
select json '{ "a": "the Copyright \u00a9 sign" }' ->> 'a' as correct_in_utf8;
|
||||
select json '{ "a": "dollar \u0024 character" }' ->> 'a' as correct_everywhere;
|
||||
select json '{ "a": "null \u0000 escape" }' ->> 'a' as not_unescaped;
|
||||
|
23
src/test/regress/sql/json_encoding.sql
Normal file
23
src/test/regress/sql/json_encoding.sql
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
-- encoding-sensitive tests for json
|
||||
|
||||
-- basic unicode input
|
||||
SELECT '"\u"'::json; -- ERROR, incomplete escape
|
||||
SELECT '"\u00"'::json; -- ERROR, incomplete escape
|
||||
SELECT '"\u000g"'::json; -- ERROR, g is not a hex digit
|
||||
SELECT '"\u0000"'::json; -- OK, legal escape
|
||||
SELECT '"\uaBcD"'::json; -- OK, uppercase and lower case both OK
|
||||
|
||||
-- handling of unicode surrogate pairs
|
||||
|
||||
select json '{ "a": "\ud83d\ude04\ud83d\udc36" }' -> 'a' as correct_in_utf8;
|
||||
select json '{ "a": "\ud83d\ud83d" }' -> 'a'; -- 2 high surrogates in a row
|
||||
select json '{ "a": "\ude04\ud83d" }' -> 'a'; -- surrogates in wrong order
|
||||
select json '{ "a": "\ud83dX" }' -> 'a'; -- orphan high surrogate
|
||||
select json '{ "a": "\ude04X" }' -> 'a'; -- orphan low surrogate
|
||||
|
||||
--handling of simple unicode escapes
|
||||
|
||||
select json '{ "a": "the Copyright \u00a9 sign" }' ->> 'a' as correct_in_utf8;
|
||||
select json '{ "a": "dollar \u0024 character" }' ->> 'a' as correct_everywhere;
|
||||
select json '{ "a": "null \u0000 escape" }' ->> 'a' as not_escaped;
|
Loading…
Reference in New Issue
Block a user