diff --git a/src/test/regress/expected/json.out b/src/test/regress/expected/json.out index 2a82aef6ba9..bdedf3a7010 100644 --- a/src/test/regress/expected/json.out +++ b/src/test/regress/expected/json.out @@ -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) - diff --git a/src/test/regress/expected/json_1.out b/src/test/regress/expected/json_1.out deleted file mode 100644 index e43118360ad..00000000000 --- a/src/test/regress/expected/json_1.out +++ /dev/null @@ -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) - diff --git a/src/test/regress/expected/json_encoding.out b/src/test/regress/expected/json_encoding.out new file mode 100644 index 00000000000..fbdb8dd6d05 --- /dev/null +++ b/src/test/regress/expected/json_encoding.out @@ -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) + diff --git a/src/test/regress/expected/json_encoding_1.out b/src/test/regress/expected/json_encoding_1.out new file mode 100644 index 00000000000..61272b145b4 --- /dev/null +++ b/src/test/regress/expected/json_encoding_1.out @@ -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) + diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index f42e5cf6676..4c6ce9702c5 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -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 diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule index d26924401a8..57fc93d3cda 100644 --- a/src/test/regress/serial_schedule +++ b/src/test/regress/serial_schedule @@ -117,6 +117,7 @@ test: xmlmap test: functional_deps test: advisory_lock test: json +test: json_encoding test: equivclass test: plancache test: limit diff --git a/src/test/regress/sql/json.sql b/src/test/regress/sql/json.sql index 73993adcfef..7a8c7b138a5 100644 --- a/src/test/regress/sql/json.sql +++ b/src/test/regress/sql/json.sql @@ -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; diff --git a/src/test/regress/sql/json_encoding.sql b/src/test/regress/sql/json_encoding.sql new file mode 100644 index 00000000000..f3842611197 --- /dev/null +++ b/src/test/regress/sql/json_encoding.sql @@ -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;