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:
Andrew Dunstan 2015-10-07 17:41:45 -04:00
parent 32e53593f9
commit f844f0ef18
8 changed files with 171 additions and 1067 deletions

View File

@ -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)

View File

@ -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)

View 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)

View 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)

View File

@ -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

View File

@ -117,6 +117,7 @@ test: xmlmap
test: functional_deps
test: advisory_lock
test: json
test: json_encoding
test: equivclass
test: plancache
test: limit

View File

@ -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;

View 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;