]> granicus.if.org Git - postgresql/commitdiff
Factor out encoding specific tests for json
authorAndrew Dunstan <andrew@dunslane.net>
Wed, 7 Oct 2015 21:41:45 +0000 (17:41 -0400)
committerAndrew Dunstan <andrew@dunslane.net>
Thu, 8 Oct 2015 02:18:27 +0000 (22:18 -0400)
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.

src/test/regress/expected/json.out
src/test/regress/expected/json_1.out [deleted file]
src/test/regress/expected/json_encoding.out [new file with mode: 0644]
src/test/regress/expected/json_encoding_1.out [new file with mode: 0644]
src/test/regress/expected/jsonb.out
src/test/regress/expected/jsonb_1.out [deleted file]
src/test/regress/parallel_schedule
src/test/regress/serial_schedule
src/test/regress/sql/json.sql
src/test/regress/sql/json_encoding.sql [new file with mode: 0644]
src/test/regress/sql/jsonb.sql

index 5d33de00b1e681ab179f86b08a4cf9057a9ded2f..42a7c7109f46b9612979064802989c213f7ae5cf 100644 (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 
@@ -1419,88 +1390,6 @@ select * from json_populate_recordset(row('def',99,null)::jpop,'[{"a":[100,200,3
  {"z":true}    |  3 | Fri Jan 20 10:42:53 2012
 (2 rows)
 
--- 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" }' as correct_in_utf8;
-            correct_in_utf8            
----------------------------------------
- { "a":  "the Copyright \u00a9 sign" }
-(1 row)
-
-select json '{ "a":  "dollar \u0024 character" }' as correct_everywhere;
-         correct_everywhere          
--------------------------------------
- { "a":  "dollar \u0024 character" }
-(1 row)
-
-select json '{ "a":  "dollar \\u0024 character" }' as not_an_escape;
-            not_an_escape             
---------------------------------------
- { "a":  "dollar \\u0024 character" }
-(1 row)
-
-select json '{ "a":  "null \u0000 escape" }' as not_unescaped;
-         not_unescaped          
---------------------------------
- { "a":  "null \u0000 escape" }
-(1 row)
-
-select json '{ "a":  "null \\u0000 escape" }' as not_an_escape;
-          not_an_escape          
----------------------------------
- { "a":  "null \\u0000 escape" }
-(1 row)
-
-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":  "dollar \\u0024 character" }' ->> 'a' as not_an_escape;
-      not_an_escape      
--------------------------
- dollar \u0024 character
-(1 row)
-
-select json '{ "a":  "null \u0000 escape" }' ->> 'a' as fails;
-ERROR:  unsupported Unicode escape sequence
-DETAIL:  \u0000 cannot be converted to text.
-CONTEXT:  JSON data, line 1: { "a":...
-select json '{ "a":  "null \\u0000 escape" }' ->> 'a' as not_an_escape;
-   not_an_escape    
---------------------
- null \u0000 escape
-(1 row)
-
 --json_typeof() function
 select value, json_typeof(value)
   from (values (json '123.4'),
diff --git a/src/test/regress/expected/json_1.out b/src/test/regress/expected/json_1.out
deleted file mode 100644 (file)
index a6e092c..0000000
+++ /dev/null
@@ -1,1726 +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)
-
--- to_json, timestamps
-select to_json(timestamp '2014-05-28 12:22:35.614298');
-           to_json            
-------------------------------
- "2014-05-28T12:22:35.614298"
-(1 row)
-
-BEGIN;
-SET LOCAL TIME ZONE 10.5;
-select to_json(timestamptz '2014-05-28 12:22:35.614298-04');
-              to_json               
-------------------------------------
- "2014-05-29T02:52:35.614298+10:30"
-(1 row)
-
-SET LOCAL TIME ZONE -8;
-select to_json(timestamptz '2014-05-28 12:22:35.614298-04');
-              to_json               
-------------------------------------
- "2014-05-28T08:22:35.614298-08:00"
-(1 row)
-
-COMMIT;
-select to_json(date '2014-05-28');
-   to_json    
---------------
- "2014-05-28"
-(1 row)
-
-select to_json(date 'Infinity');
-  to_json   
-------------
- "infinity"
-(1 row)
-
-select to_json(timestamp 'Infinity');
-  to_json   
-------------
- "infinity"
-(1 row)
-
-select to_json(timestamptz 'Infinity');
-  to_json   
-------------
- "infinity"
-(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 ORDER BY x, y)
-  FROM rows q;
-       json_agg        
------------------------
- [{"x":1,"y":"txt1"}, +
-  {"x":2,"y":"txt2"}, +
-  {"x":3,"y":"txt3"}]
-(1 row)
-
-UPDATE rows SET x = NULL WHERE x = 1;
-SELECT json_agg(q ORDER BY x NULLS FIRST, y)
-  FROM rows q;
-         json_agg         
---------------------------
- [{"x":null,"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", [1,2,3],{"f1":9}]'),
-('object','{"field1":"val1","field2":"val2","field3":null, "field4": 4, "field5": [1,2,3], "field6": {"f1":9}}');
-SELECT test_json -> 'x'
-FROM test_json
-WHERE json_type = 'scalar';
- ?column? 
-----------
-(1 row)
-
-SELECT test_json -> 'x'
-FROM test_json
-WHERE json_type = 'array';
- ?column? 
-----------
-(1 row)
-
-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';
- ?column? 
-----------
-(1 row)
-
-SELECT test_json -> 2
-FROM test_json
-WHERE json_type = 'array';
- ?column? 
-----------
- "two"
-(1 row)
-
-SELECT test_json -> -1
-FROM test_json
-WHERE json_type = 'array';
- ?column? 
-----------
- {"f1":9}
-(1 row)
-
-SELECT test_json -> 2
-FROM test_json
-WHERE json_type = 'object';
- ?column? 
-----------
-(1 row)
-
-SELECT test_json->>2
-FROM test_json
-WHERE json_type = 'array';
- ?column? 
-----------
- two
-(1 row)
-
-SELECT test_json ->> 6 FROM test_json WHERE json_type = 'array';
- ?column? 
-----------
- [1,2,3]
-(1 row)
-
-SELECT test_json ->> 7 FROM test_json WHERE json_type = 'array';
- ?column? 
-----------
- {"f1":9}
-(1 row)
-
-SELECT test_json ->> 'field4' FROM test_json WHERE json_type = 'object';
- ?column? 
-----------
- 4
-(1 row)
-
-SELECT test_json ->> 'field5' FROM test_json WHERE json_type = 'object';
- ?column? 
-----------
- [1,2,3]
-(1 row)
-
-SELECT test_json ->> 'field6' FROM test_json WHERE json_type = 'object';
- ?column? 
-----------
- {"f1":9}
-(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
- field4
- field5
- field6
-(6 rows)
-
--- test extending object_keys resultset - initial resultset size is 256
-select count(*) from
-    (select json_object_keys(json_object(array_agg(g)))
-     from (select unnest(array['f'||n,n::text])as g
-           from generate_series(1,300) as n) x ) y;
- count 
--------
-   300
-(1 row)
-
--- 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)
-
--- corner cases
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::json -> null::text;
- ?column? 
-----------
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::json -> null::int;
- ?column? 
-----------
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::json -> 1;
- ?column? 
-----------
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::json -> -1;
- ?column? 
-----------
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::json -> 'z';
- ?column? 
-----------
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::json -> '';
- ?column? 
-----------
-(1 row)
-
-select '[{"b": "c"}, {"b": "cc"}]'::json -> 1;
-  ?column?   
--------------
- {"b": "cc"}
-(1 row)
-
-select '[{"b": "c"}, {"b": "cc"}]'::json -> 3;
- ?column? 
-----------
-(1 row)
-
-select '[{"b": "c"}, {"b": "cc"}]'::json -> 'z';
- ?column? 
-----------
-(1 row)
-
-select '{"a": "c", "b": null}'::json -> 'b';
- ?column? 
-----------
- null
-(1 row)
-
-select '"foo"'::json -> 1;
- ?column? 
-----------
-(1 row)
-
-select '"foo"'::json -> 'z';
- ?column? 
-----------
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::json ->> null::text;
- ?column? 
-----------
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::json ->> null::int;
- ?column? 
-----------
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::json ->> 1;
- ?column? 
-----------
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::json ->> 'z';
- ?column? 
-----------
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::json ->> '';
- ?column? 
-----------
-(1 row)
-
-select '[{"b": "c"}, {"b": "cc"}]'::json ->> 1;
-  ?column?   
--------------
- {"b": "cc"}
-(1 row)
-
-select '[{"b": "c"}, {"b": "cc"}]'::json ->> 3;
- ?column? 
-----------
-(1 row)
-
-select '[{"b": "c"}, {"b": "cc"}]'::json ->> 'z';
- ?column? 
-----------
-(1 row)
-
-select '{"a": "c", "b": null}'::json ->> 'b';
- ?column? 
-----------
-(1 row)
-
-select '"foo"'::json ->> 1;
- ?column? 
-----------
-(1 row)
-
-select '"foo"'::json ->> 'z';
- ?column? 
-----------
-(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)
-
--- corner cases for same
-select '{"a": {"b":{"c": "foo"}}}'::json #> '{}';
-         ?column?          
----------------------------
- {"a": {"b":{"c": "foo"}}}
-(1 row)
-
-select '[1,2,3]'::json #> '{}';
- ?column? 
-----------
- [1,2,3]
-(1 row)
-
-select '"foo"'::json #> '{}';
- ?column? 
-----------
- "foo"
-(1 row)
-
-select '42'::json #> '{}';
- ?column? 
-----------
- 42
-(1 row)
-
-select 'null'::json #> '{}';
- ?column? 
-----------
- null
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::json #> array['a'];
-      ?column?      
---------------------
- {"b":{"c": "foo"}}
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::json #> array['a', null];
- ?column? 
-----------
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::json #> array['a', ''];
- ?column? 
-----------
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::json #> array['a','b'];
-   ?column?   
---------------
- {"c": "foo"}
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::json #> array['a','b','c'];
- ?column? 
-----------
- "foo"
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::json #> array['a','b','c','d'];
- ?column? 
-----------
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::json #> array['a','z','c'];
- ?column? 
-----------
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::json #> array['a','1','b'];
- ?column? 
-----------
- "cc"
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::json #> array['a','z','b'];
- ?column? 
-----------
-(1 row)
-
-select '[{"b": "c"}, {"b": "cc"}]'::json #> array['1','b'];
- ?column? 
-----------
- "cc"
-(1 row)
-
-select '[{"b": "c"}, {"b": "cc"}]'::json #> array['z','b'];
- ?column? 
-----------
-(1 row)
-
-select '[{"b": "c"}, {"b": null}]'::json #> array['1','b'];
- ?column? 
-----------
- null
-(1 row)
-
-select '"foo"'::json #> array['z'];
- ?column? 
-----------
-(1 row)
-
-select '42'::json #> array['f2'];
- ?column? 
-----------
-(1 row)
-
-select '42'::json #> array['0'];
- ?column? 
-----------
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::json #>> '{}';
-         ?column?          
----------------------------
- {"a": {"b":{"c": "foo"}}}
-(1 row)
-
-select '[1,2,3]'::json #>> '{}';
- ?column? 
-----------
- [1,2,3]
-(1 row)
-
-select '"foo"'::json #>> '{}';
- ?column? 
-----------
- foo
-(1 row)
-
-select '42'::json #>> '{}';
- ?column? 
-----------
- 42
-(1 row)
-
-select 'null'::json #>> '{}';
- ?column? 
-----------
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::json #>> array['a'];
-      ?column?      
---------------------
- {"b":{"c": "foo"}}
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::json #>> array['a', null];
- ?column? 
-----------
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::json #>> array['a', ''];
- ?column? 
-----------
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::json #>> array['a','b'];
-   ?column?   
---------------
- {"c": "foo"}
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::json #>> array['a','b','c'];
- ?column? 
-----------
- foo
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::json #>> array['a','b','c','d'];
- ?column? 
-----------
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::json #>> array['a','z','c'];
- ?column? 
-----------
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::json #>> array['a','1','b'];
- ?column? 
-----------
- cc
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::json #>> array['a','z','b'];
- ?column? 
-----------
-(1 row)
-
-select '[{"b": "c"}, {"b": "cc"}]'::json #>> array['1','b'];
- ?column? 
-----------
- cc
-(1 row)
-
-select '[{"b": "c"}, {"b": "cc"}]'::json #>> array['z','b'];
- ?column? 
-----------
-(1 row)
-
-select '[{"b": "c"}, {"b": null}]'::json #>> array['1','b'];
- ?column? 
-----------
-(1 row)
-
-select '"foo"'::json #>> array['z'];
- ?column? 
-----------
-(1 row)
-
-select '42'::json #>> array['f2'];
- ?column? 
-----------
-(1 row)
-
-select '42'::json #>> array['0'];
- ?column? 
-----------
-(1 row)
-
--- array_elements
-select json_array_elements('[1,true,[1,[2,3]],null,{"f1":1,"f2":[7,8,9]},false,"stringy"]');
-  json_array_elements  
------------------------
- 1
- true
- [1,[2,3]]
- null
- {"f1":1,"f2":[7,8,9]}
- false
- "stringy"
-(7 rows)
-
-select * from json_array_elements('[1,true,[1,[2,3]],null,{"f1":1,"f2":[7,8,9]},false,"stringy"]') q;
-         value         
------------------------
- 1
- true
- [1,[2,3]]
- null
- {"f1":1,"f2":[7,8,9]}
- false
- "stringy"
-(7 rows)
-
-select json_array_elements_text('[1,true,[1,[2,3]],null,{"f1":1,"f2":[7,8,9]},false,"stringy"]');
- json_array_elements_text 
---------------------------
- 1
- true
- [1,[2,3]]
- {"f1":1,"f2":[7,8,9]}
- false
- stringy
-(7 rows)
-
-select * from json_array_elements_text('[1,true,[1,[2,3]],null,{"f1":1,"f2":[7,8,9]},false,"stringy"]') q;
-         value         
------------------------
- 1
- true
- [1,[2,3]]
- {"f1":1,"f2":[7,8,9]}
- false
- stringy
-(7 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}') 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":[100,200,false],"x":43.2}') 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}') 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}') 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"}]') 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(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;
-       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"}]') 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}]') q;
- a |    b    | c | d 
----+---------+---+---
- 2 | {"z":4} | 3 | 6
-(1 row)
-
-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;
-       a       | b  |            c             
----------------+----+--------------------------
- [100,200,300] | 99 | 
- {"z":true}    |  3 | Fri Jan 20 10:42:53 2012
-(2 rows)
-
--- handling of unicode surrogate pairs
-select json '{ "a":  "\ud83d\ude04\ud83d\udc36" }' -> 'a' as correct_in_utf8;
-ERROR:  unsupported Unicode escape sequence
-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" }' as correct_in_utf8;
-            correct_in_utf8            
----------------------------------------
- { "a":  "the Copyright \u00a9 sign" }
-(1 row)
-
-select json '{ "a":  "dollar \u0024 character" }' as correct_everywhere;
-         correct_everywhere          
--------------------------------------
- { "a":  "dollar \u0024 character" }
-(1 row)
-
-select json '{ "a":  "dollar \\u0024 character" }' as not_an_escape;
-            not_an_escape             
---------------------------------------
- { "a":  "dollar \\u0024 character" }
-(1 row)
-
-select json '{ "a":  "null \u0000 escape" }' as not_unescaped;
-         not_unescaped          
---------------------------------
- { "a":  "null \u0000 escape" }
-(1 row)
-
-select json '{ "a":  "null \\u0000 escape" }' as not_an_escape;
-          not_an_escape          
----------------------------------
- { "a":  "null \\u0000 escape" }
-(1 row)
-
-select json '{ "a":  "the Copyright \u00a9 sign" }' ->> 'a' as correct_in_utf8;
-ERROR:  unsupported Unicode escape sequence
-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":  "dollar \\u0024 character" }' ->> 'a' as not_an_escape;
-      not_an_escape      
--------------------------
- dollar \u0024 character
-(1 row)
-
-select json '{ "a":  "null \u0000 escape" }' ->> 'a' as fails;
-ERROR:  unsupported Unicode escape sequence
-DETAIL:  \u0000 cannot be converted to text.
-CONTEXT:  JSON data, line 1: { "a":...
-select json '{ "a":  "null \\u0000 escape" }' ->> 'a' as not_an_escape;
-   not_an_escape    
---------------------
- null \u0000 escape
-(1 row)
-
---json_typeof() function
-select value, json_typeof(value)
-  from (values (json '123.4'),
-               (json '-1'),
-               (json '"foo"'),
-               (json 'true'),
-               (json 'false'),
-               (json 'null'),
-               (json '[1, 2, 3]'),
-               (json '[]'),
-               (json '{"x":"foo", "y":123}'),
-               (json '{}'),
-               (NULL::json))
-      as data(value);
-        value         | json_typeof 
-----------------------+-------------
- 123.4                | number
- -1                   | number
- "foo"                | string
- true                 | boolean
- false                | boolean
- null                 | null
- [1, 2, 3]            | array
- []                   | array
- {"x":"foo", "y":123} | object
- {}                   | object
-                      | 
-(11 rows)
-
--- json_build_array, json_build_object, json_object_agg
-SELECT json_build_array('a',1,'b',1.2,'c',true,'d',null,'e',json '{"x": 3, "y": [1,2,3]}');
-                           json_build_array                            
------------------------------------------------------------------------
- ["a", 1, "b", 1.2, "c", true, "d", null, "e", {"x": 3, "y": [1,2,3]}]
-(1 row)
-
-SELECT json_build_object('a',1,'b',1.2,'c',true,'d',null,'e',json '{"x": 3, "y": [1,2,3]}');
-                             json_build_object                              
-----------------------------------------------------------------------------
- {"a" : 1, "b" : 1.2, "c" : true, "d" : null, "e" : {"x": 3, "y": [1,2,3]}}
-(1 row)
-
-SELECT json_build_object(
-       'a', json_build_object('b',false,'c',99),
-       'd', json_build_object('e',array[9,8,7]::int[],
-           'f', (select row_to_json(r) from ( select relkind, oid::regclass as name from pg_class where relname = 'pg_class') r)));
-                                        json_build_object                                        
--------------------------------------------------------------------------------------------------
- {"a" : {"b" : false, "c" : 99}, "d" : {"e" : [9,8,7], "f" : {"relkind":"r","name":"pg_class"}}}
-(1 row)
-
--- empty objects/arrays
-SELECT json_build_array();
- json_build_array 
-------------------
- []
-(1 row)
-
-SELECT json_build_object();
- json_build_object 
--------------------
- {}
-(1 row)
-
--- make sure keys are quoted
-SELECT json_build_object(1,2);
- json_build_object 
--------------------
- {"1" : 2}
-(1 row)
-
--- keys must be scalar and not null
-SELECT json_build_object(null,2);
-ERROR:  argument 1 cannot be null
-HINT:  Object keys should be text.
-SELECT json_build_object(r,2) FROM (SELECT 1 AS a, 2 AS b) r;
-ERROR:  key value must be scalar, not array, composite, or json
-SELECT json_build_object(json '{"a":1,"b":2}', 3);
-ERROR:  key value must be scalar, not array, composite, or json
-SELECT json_build_object('{1,2,3}'::int[], 3);
-ERROR:  key value must be scalar, not array, composite, or json
-CREATE TEMP TABLE foo (serial_num int, name text, type text);
-INSERT INTO foo VALUES (847001,'t15','GE1043');
-INSERT INTO foo VALUES (847002,'t16','GE1043');
-INSERT INTO foo VALUES (847003,'sub-alpha','GESS90');
-SELECT json_build_object('turbines',json_object_agg(serial_num,json_build_object('name',name,'type',type)))
-FROM foo;
-                                                                            json_build_object                                                                            
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- {"turbines" : { "847001" : {"name" : "t15", "type" : "GE1043"}, "847002" : {"name" : "t16", "type" : "GE1043"}, "847003" : {"name" : "sub-alpha", "type" : "GESS90"} }}
-(1 row)
-
-SELECT json_object_agg(name, type) FROM foo;
-                        json_object_agg                         
-----------------------------------------------------------------
- { "t15" : "GE1043", "t16" : "GE1043", "sub-alpha" : "GESS90" }
-(1 row)
-
-INSERT INTO foo VALUES (999999, NULL, 'bar');
-SELECT json_object_agg(name, type) FROM foo;
-ERROR:  field name must not be null
--- json_object
--- one dimension
-SELECT json_object('{a,1,b,2,3,NULL,"d e f","a b c"}');
-                      json_object                      
--------------------------------------------------------
- {"a" : "1", "b" : "2", "3" : null, "d e f" : "a b c"}
-(1 row)
-
--- same but with two dimensions
-SELECT json_object('{{a,1},{b,2},{3,NULL},{"d e f","a b c"}}');
-                      json_object                      
--------------------------------------------------------
- {"a" : "1", "b" : "2", "3" : null, "d e f" : "a b c"}
-(1 row)
-
--- odd number error
-SELECT json_object('{a,b,c}');
-ERROR:  array must have even number of elements
--- one column error
-SELECT json_object('{{a},{b}}');
-ERROR:  array must have two columns
--- too many columns error
-SELECT json_object('{{a,b,c},{b,c,d}}');
-ERROR:  array must have two columns
--- too many dimensions error
-SELECT json_object('{{{a,b},{c,d}},{{b,c},{d,e}}}');
-ERROR:  wrong number of array subscripts
---two argument form of json_object
-select json_object('{a,b,c,"d e f"}','{1,2,3,"a b c"}');
-                     json_object                      
-------------------------------------------------------
- {"a" : "1", "b" : "2", "c" : "3", "d e f" : "a b c"}
-(1 row)
-
--- too many dimensions
-SELECT json_object('{{a,1},{b,2},{3,NULL},{"d e f","a b c"}}', '{{a,1},{b,2},{3,NULL},{"d e f","a b c"}}');
-ERROR:  wrong number of array subscripts
--- mismatched dimensions
-select json_object('{a,b,c,"d e f",g}','{1,2,3,"a b c"}');
-ERROR:  mismatched array dimensions
-select json_object('{a,b,c,"d e f"}','{1,2,3,"a b c",g}');
-ERROR:  mismatched array dimensions
--- null key error
-select json_object('{a,b,NULL,"d e f"}','{1,2,3,"a b c"}');
-ERROR:  null value not allowed for object key
--- empty key is allowed
-select json_object('{a,b,"","d e f"}','{1,2,3,"a b c"}');
-                     json_object                     
------------------------------------------------------
- {"a" : "1", "b" : "2", "" : "3", "d e f" : "a b c"}
-(1 row)
-
--- json_to_record and json_to_recordset
-select * from json_to_record('{"a":1,"b":"foo","c":"bar"}')
-    as x(a int, b text, d text);
- a |  b  | d 
----+-----+---
- 1 | foo | 
-(1 row)
-
-select * from json_to_recordset('[{"a":1,"b":"foo","d":false},{"a":2,"b":"bar","c":true}]')
-    as x(a int, b text, c boolean);
- a |  b  | c 
----+-----+---
- 1 | foo | 
- 2 | bar | t
-(2 rows)
-
-select * from json_to_recordset('[{"a":1,"b":{"d":"foo"},"c":true},{"a":2,"c":false,"b":{"d":"bar"}}]')
-    as x(a int, b json, c boolean);
- a |      b      | c 
----+-------------+---
- 1 | {"d":"foo"} | t
- 2 | {"d":"bar"} | f
-(2 rows)
-
--- json_strip_nulls
-select json_strip_nulls(null);
- json_strip_nulls 
-------------------
-(1 row)
-
-select json_strip_nulls('1');
- json_strip_nulls 
-------------------
- 1
-(1 row)
-
-select json_strip_nulls('"a string"');
- json_strip_nulls 
-------------------
- "a string"
-(1 row)
-
-select json_strip_nulls('null');
- json_strip_nulls 
-------------------
- null
-(1 row)
-
-select json_strip_nulls('[1,2,null,3,4]');
- json_strip_nulls 
-------------------
- [1,2,null,3,4]
-(1 row)
-
-select json_strip_nulls('{"a":1,"b":null,"c":[2,null,3],"d":{"e":4,"f":null}}');
-          json_strip_nulls          
-------------------------------------
- {"a":1,"c":[2,null,3],"d":{"e":4}}
-(1 row)
-
-select json_strip_nulls('[1,{"a":1,"b":null,"c":2},3]');
-  json_strip_nulls   
----------------------
- [1,{"a":1,"c":2},3]
-(1 row)
-
--- an empty object is not null and should not be stripped
-select json_strip_nulls('{"a": {"b": null, "c": null}, "d": {} }');
- json_strip_nulls 
-------------------
- {"a":{},"d":{}}
-(1 row)
-
diff --git a/src/test/regress/expected/json_encoding.out b/src/test/regress/expected/json_encoding.out
new file mode 100644 (file)
index 0000000..d8d34f4
--- /dev/null
@@ -0,0 +1,247 @@
+-- encoding-sensitive tests for json and jsonb
+-- first 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" }' as correct_in_utf8;
+            correct_in_utf8            
+---------------------------------------
+ { "a":  "the Copyright \u00a9 sign" }
+(1 row)
+
+select json '{ "a":  "dollar \u0024 character" }' as correct_everywhere;
+         correct_everywhere          
+-------------------------------------
+ { "a":  "dollar \u0024 character" }
+(1 row)
+
+select json '{ "a":  "dollar \\u0024 character" }' as not_an_escape;
+            not_an_escape             
+--------------------------------------
+ { "a":  "dollar \\u0024 character" }
+(1 row)
+
+select json '{ "a":  "null \u0000 escape" }' as not_unescaped;
+         not_unescaped          
+--------------------------------
+ { "a":  "null \u0000 escape" }
+(1 row)
+
+select json '{ "a":  "null \\u0000 escape" }' as not_an_escape;
+          not_an_escape          
+---------------------------------
+ { "a":  "null \\u0000 escape" }
+(1 row)
+
+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":  "dollar \\u0024 character" }' ->> 'a' as not_an_escape;
+      not_an_escape      
+-------------------------
+ dollar \u0024 character
+(1 row)
+
+select json '{ "a":  "null \u0000 escape" }' ->> 'a' as fails;
+ERROR:  unsupported Unicode escape sequence
+DETAIL:  \u0000 cannot be converted to text.
+CONTEXT:  JSON data, line 1: { "a":...
+select json '{ "a":  "null \\u0000 escape" }' ->> 'a' as not_an_escape;
+   not_an_escape    
+--------------------
+ null \u0000 escape
+(1 row)
+
+-- then jsonb
+-- basic unicode input
+SELECT '"\u"'::jsonb;                  -- ERROR, incomplete escape
+ERROR:  invalid input syntax for type json
+LINE 1: SELECT '"\u"'::jsonb;
+               ^
+DETAIL:  "\u" must be followed by four hexadecimal digits.
+CONTEXT:  JSON data, line 1: "\u"
+SELECT '"\u00"'::jsonb;                        -- ERROR, incomplete escape
+ERROR:  invalid input syntax for type json
+LINE 1: SELECT '"\u00"'::jsonb;
+               ^
+DETAIL:  "\u" must be followed by four hexadecimal digits.
+CONTEXT:  JSON data, line 1: "\u00"
+SELECT '"\u000g"'::jsonb;              -- ERROR, g is not a hex digit
+ERROR:  invalid input syntax for type json
+LINE 1: SELECT '"\u000g"'::jsonb;
+               ^
+DETAIL:  "\u" must be followed by four hexadecimal digits.
+CONTEXT:  JSON data, line 1: "\u000g...
+SELECT '"\u0045"'::jsonb;              -- OK, legal escape
+ jsonb 
+-------
+ "E"
+(1 row)
+
+SELECT '"\u0000"'::jsonb;              -- ERROR, we don't support U+0000
+ERROR:  unsupported Unicode escape sequence
+LINE 1: SELECT '"\u0000"'::jsonb;
+               ^
+DETAIL:  \u0000 cannot be converted to text.
+CONTEXT:  JSON data, line 1: ...
+-- use octet_length here so we don't get an odd unicode char in the
+-- output
+SELECT octet_length('"\uaBcD"'::jsonb::text); -- OK, uppercase and lower case both OK
+ octet_length 
+--------------
+            5
+(1 row)
+
+-- handling of unicode surrogate pairs
+SELECT octet_length((jsonb '{ "a":  "\ud83d\ude04\ud83d\udc36" }' -> 'a')::text) AS correct_in_utf8;
+ correct_in_utf8 
+-----------------
+              10
+(1 row)
+
+SELECT jsonb '{ "a":  "\ud83d\ud83d" }' -> 'a'; -- 2 high surrogates in a row
+ERROR:  invalid input syntax for type json
+LINE 1: SELECT jsonb '{ "a":  "\ud83d\ud83d" }' -> 'a';
+                     ^
+DETAIL:  Unicode high surrogate must not follow a high surrogate.
+CONTEXT:  JSON data, line 1: { "a":...
+SELECT jsonb '{ "a":  "\ude04\ud83d" }' -> 'a'; -- surrogates in wrong order
+ERROR:  invalid input syntax for type json
+LINE 1: SELECT jsonb '{ "a":  "\ude04\ud83d" }' -> 'a';
+                     ^
+DETAIL:  Unicode low surrogate must follow a high surrogate.
+CONTEXT:  JSON data, line 1: { "a":...
+SELECT jsonb '{ "a":  "\ud83dX" }' -> 'a'; -- orphan high surrogate
+ERROR:  invalid input syntax for type json
+LINE 1: SELECT jsonb '{ "a":  "\ud83dX" }' -> 'a';
+                     ^
+DETAIL:  Unicode low surrogate must follow a high surrogate.
+CONTEXT:  JSON data, line 1: { "a":...
+SELECT jsonb '{ "a":  "\ude04X" }' -> 'a'; -- orphan low surrogate
+ERROR:  invalid input syntax for type json
+LINE 1: SELECT jsonb '{ "a":  "\ude04X" }' -> 'a';
+                     ^
+DETAIL:  Unicode low surrogate must follow a high surrogate.
+CONTEXT:  JSON data, line 1: { "a":...
+-- handling of simple unicode escapes
+SELECT jsonb '{ "a":  "the Copyright \u00a9 sign" }' as correct_in_utf8;
+        correct_in_utf8        
+-------------------------------
+ {"a": "the Copyright © sign"}
+(1 row)
+
+SELECT jsonb '{ "a":  "dollar \u0024 character" }' as correct_everywhere;
+     correct_everywhere      
+-----------------------------
+ {"a": "dollar $ character"}
+(1 row)
+
+SELECT jsonb '{ "a":  "dollar \\u0024 character" }' as not_an_escape;
+           not_an_escape           
+-----------------------------------
+ {"a": "dollar \\u0024 character"}
+(1 row)
+
+SELECT jsonb '{ "a":  "null \u0000 escape" }' as fails;
+ERROR:  unsupported Unicode escape sequence
+LINE 1: SELECT jsonb '{ "a":  "null \u0000 escape" }' as fails;
+                     ^
+DETAIL:  \u0000 cannot be converted to text.
+CONTEXT:  JSON data, line 1: { "a":...
+SELECT jsonb '{ "a":  "null \\u0000 escape" }' as not_an_escape;
+        not_an_escape         
+------------------------------
+ {"a": "null \\u0000 escape"}
+(1 row)
+
+SELECT jsonb '{ "a":  "the Copyright \u00a9 sign" }' ->> 'a' as correct_in_utf8;
+   correct_in_utf8    
+----------------------
+ the Copyright © sign
+(1 row)
+
+SELECT jsonb '{ "a":  "dollar \u0024 character" }' ->> 'a' as correct_everywhere;
+ correct_everywhere 
+--------------------
+ dollar $ character
+(1 row)
+
+SELECT jsonb '{ "a":  "dollar \\u0024 character" }' ->> 'a' as not_an_escape;
+      not_an_escape      
+-------------------------
+ dollar \u0024 character
+(1 row)
+
+SELECT jsonb '{ "a":  "null \u0000 escape" }' ->> 'a' as fails;
+ERROR:  unsupported Unicode escape sequence
+LINE 1: SELECT jsonb '{ "a":  "null \u0000 escape" }' ->> 'a' as fai...
+                     ^
+DETAIL:  \u0000 cannot be converted to text.
+CONTEXT:  JSON data, line 1: { "a":...
+SELECT jsonb '{ "a":  "null \\u0000 escape" }' ->> 'a' as not_an_escape;
+   not_an_escape    
+--------------------
+ 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 (file)
index 0000000..79ed78e
--- /dev/null
@@ -0,0 +1,243 @@
+-- encoding-sensitive tests for json and jsonb
+-- first 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:  unsupported Unicode escape sequence
+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" }' as correct_in_utf8;
+            correct_in_utf8            
+---------------------------------------
+ { "a":  "the Copyright \u00a9 sign" }
+(1 row)
+
+select json '{ "a":  "dollar \u0024 character" }' as correct_everywhere;
+         correct_everywhere          
+-------------------------------------
+ { "a":  "dollar \u0024 character" }
+(1 row)
+
+select json '{ "a":  "dollar \\u0024 character" }' as not_an_escape;
+            not_an_escape             
+--------------------------------------
+ { "a":  "dollar \\u0024 character" }
+(1 row)
+
+select json '{ "a":  "null \u0000 escape" }' as not_unescaped;
+         not_unescaped          
+--------------------------------
+ { "a":  "null \u0000 escape" }
+(1 row)
+
+select json '{ "a":  "null \\u0000 escape" }' as not_an_escape;
+          not_an_escape          
+---------------------------------
+ { "a":  "null \\u0000 escape" }
+(1 row)
+
+select json '{ "a":  "the Copyright \u00a9 sign" }' ->> 'a' as correct_in_utf8;
+ERROR:  unsupported Unicode escape sequence
+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":  "dollar \\u0024 character" }' ->> 'a' as not_an_escape;
+      not_an_escape      
+-------------------------
+ dollar \u0024 character
+(1 row)
+
+select json '{ "a":  "null \u0000 escape" }' ->> 'a' as fails;
+ERROR:  unsupported Unicode escape sequence
+DETAIL:  \u0000 cannot be converted to text.
+CONTEXT:  JSON data, line 1: { "a":...
+select json '{ "a":  "null \\u0000 escape" }' ->> 'a' as not_an_escape;
+   not_an_escape    
+--------------------
+ null \u0000 escape
+(1 row)
+
+-- then jsonb
+-- basic unicode input
+SELECT '"\u"'::jsonb;                  -- ERROR, incomplete escape
+ERROR:  invalid input syntax for type json
+LINE 1: SELECT '"\u"'::jsonb;
+               ^
+DETAIL:  "\u" must be followed by four hexadecimal digits.
+CONTEXT:  JSON data, line 1: "\u"
+SELECT '"\u00"'::jsonb;                        -- ERROR, incomplete escape
+ERROR:  invalid input syntax for type json
+LINE 1: SELECT '"\u00"'::jsonb;
+               ^
+DETAIL:  "\u" must be followed by four hexadecimal digits.
+CONTEXT:  JSON data, line 1: "\u00"
+SELECT '"\u000g"'::jsonb;              -- ERROR, g is not a hex digit
+ERROR:  invalid input syntax for type json
+LINE 1: SELECT '"\u000g"'::jsonb;
+               ^
+DETAIL:  "\u" must be followed by four hexadecimal digits.
+CONTEXT:  JSON data, line 1: "\u000g...
+SELECT '"\u0045"'::jsonb;              -- OK, legal escape
+ jsonb 
+-------
+ "E"
+(1 row)
+
+SELECT '"\u0000"'::jsonb;              -- ERROR, we don't support U+0000
+ERROR:  unsupported Unicode escape sequence
+LINE 1: SELECT '"\u0000"'::jsonb;
+               ^
+DETAIL:  \u0000 cannot be converted to text.
+CONTEXT:  JSON data, line 1: ...
+-- use octet_length here so we don't get an odd unicode char in the
+-- output
+SELECT octet_length('"\uaBcD"'::jsonb::text); -- OK, uppercase and lower case both OK
+ERROR:  unsupported Unicode escape sequence
+LINE 1: SELECT octet_length('"\uaBcD"'::jsonb::text);
+                            ^
+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: ...
+-- handling of unicode surrogate pairs
+SELECT octet_length((jsonb '{ "a":  "\ud83d\ude04\ud83d\udc36" }' -> 'a')::text) AS correct_in_utf8;
+ERROR:  unsupported Unicode escape sequence
+LINE 1: SELECT octet_length((jsonb '{ "a":  "\ud83d\ude04\ud83d\udc3...
+                                   ^
+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 jsonb '{ "a":  "\ud83d\ud83d" }' -> 'a'; -- 2 high surrogates in a row
+ERROR:  invalid input syntax for type json
+LINE 1: SELECT jsonb '{ "a":  "\ud83d\ud83d" }' -> 'a';
+                     ^
+DETAIL:  Unicode high surrogate must not follow a high surrogate.
+CONTEXT:  JSON data, line 1: { "a":...
+SELECT jsonb '{ "a":  "\ude04\ud83d" }' -> 'a'; -- surrogates in wrong order
+ERROR:  invalid input syntax for type json
+LINE 1: SELECT jsonb '{ "a":  "\ude04\ud83d" }' -> 'a';
+                     ^
+DETAIL:  Unicode low surrogate must follow a high surrogate.
+CONTEXT:  JSON data, line 1: { "a":...
+SELECT jsonb '{ "a":  "\ud83dX" }' -> 'a'; -- orphan high surrogate
+ERROR:  invalid input syntax for type json
+LINE 1: SELECT jsonb '{ "a":  "\ud83dX" }' -> 'a';
+                     ^
+DETAIL:  Unicode low surrogate must follow a high surrogate.
+CONTEXT:  JSON data, line 1: { "a":...
+SELECT jsonb '{ "a":  "\ude04X" }' -> 'a'; -- orphan low surrogate
+ERROR:  invalid input syntax for type json
+LINE 1: SELECT jsonb '{ "a":  "\ude04X" }' -> 'a';
+                     ^
+DETAIL:  Unicode low surrogate must follow a high surrogate.
+CONTEXT:  JSON data, line 1: { "a":...
+-- handling of simple unicode escapes
+SELECT jsonb '{ "a":  "the Copyright \u00a9 sign" }' as correct_in_utf8;
+ERROR:  unsupported Unicode escape sequence
+LINE 1: SELECT jsonb '{ "a":  "the Copyright \u00a9 sign" }' as corr...
+                     ^
+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 jsonb '{ "a":  "dollar \u0024 character" }' as correct_everywhere;
+     correct_everywhere      
+-----------------------------
+ {"a": "dollar $ character"}
+(1 row)
+
+SELECT jsonb '{ "a":  "dollar \\u0024 character" }' as not_an_escape;
+           not_an_escape           
+-----------------------------------
+ {"a": "dollar \\u0024 character"}
+(1 row)
+
+SELECT jsonb '{ "a":  "null \u0000 escape" }' as fails;
+ERROR:  unsupported Unicode escape sequence
+LINE 1: SELECT jsonb '{ "a":  "null \u0000 escape" }' as fails;
+                     ^
+DETAIL:  \u0000 cannot be converted to text.
+CONTEXT:  JSON data, line 1: { "a":...
+SELECT jsonb '{ "a":  "null \\u0000 escape" }' as not_an_escape;
+        not_an_escape         
+------------------------------
+ {"a": "null \\u0000 escape"}
+(1 row)
+
+SELECT jsonb '{ "a":  "the Copyright \u00a9 sign" }' ->> 'a' as correct_in_utf8;
+ERROR:  unsupported Unicode escape sequence
+LINE 1: SELECT jsonb '{ "a":  "the Copyright \u00a9 sign" }' ->> 'a'...
+                     ^
+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 jsonb '{ "a":  "dollar \u0024 character" }' ->> 'a' as correct_everywhere;
+ correct_everywhere 
+--------------------
+ dollar $ character
+(1 row)
+
+SELECT jsonb '{ "a":  "dollar \\u0024 character" }' ->> 'a' as not_an_escape;
+      not_an_escape      
+-------------------------
+ dollar \u0024 character
+(1 row)
+
+SELECT jsonb '{ "a":  "null \u0000 escape" }' ->> 'a' as fails;
+ERROR:  unsupported Unicode escape sequence
+LINE 1: SELECT jsonb '{ "a":  "null \u0000 escape" }' ->> 'a' as fai...
+                     ^
+DETAIL:  \u0000 cannot be converted to text.
+CONTEXT:  JSON data, line 1: { "a":...
+SELECT jsonb '{ "a":  "null \\u0000 escape" }' ->> 'a' as not_an_escape;
+   not_an_escape    
+--------------------
+ null \u0000 escape
+(1 row)
+
index c4e87707bd76327e7818a64bbd92f418baee683f..07091a9bfb4c3d38ebdf29bc8f9401606e8376a8 100644 (file)
@@ -42,44 +42,7 @@ LINE 1: SELECT '"\v"'::jsonb;
                ^
 DETAIL:  Escape sequence "\v" is invalid.
 CONTEXT:  JSON data, line 1: "\v...
-SELECT '"\u"'::jsonb;                  -- ERROR, incomplete escape
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT '"\u"'::jsonb;
-               ^
-DETAIL:  "\u" must be followed by four hexadecimal digits.
-CONTEXT:  JSON data, line 1: "\u"
-SELECT '"\u00"'::jsonb;                        -- ERROR, incomplete escape
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT '"\u00"'::jsonb;
-               ^
-DETAIL:  "\u" must be followed by four hexadecimal digits.
-CONTEXT:  JSON data, line 1: "\u00"
-SELECT '"\u000g"'::jsonb;              -- ERROR, g is not a hex digit
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT '"\u000g"'::jsonb;
-               ^
-DETAIL:  "\u" must be followed by four hexadecimal digits.
-CONTEXT:  JSON data, line 1: "\u000g...
-SELECT '"\u0045"'::jsonb;              -- OK, legal escape
- jsonb 
--------
- "E"
-(1 row)
-
-SELECT '"\u0000"'::jsonb;              -- ERROR, we don't support U+0000
-ERROR:  unsupported Unicode escape sequence
-LINE 1: SELECT '"\u0000"'::jsonb;
-               ^
-DETAIL:  \u0000 cannot be converted to text.
-CONTEXT:  JSON data, line 1: ...
--- use octet_length here so we don't get an odd unicode char in the
--- output
-SELECT octet_length('"\uaBcD"'::jsonb::text); -- OK, uppercase and lower case both OK
- octet_length 
---------------
-            5
-(1 row)
-
+-- see json_encoding test for input with unicode escapes
 -- Numbers.
 SELECT '1'::jsonb;                             -- OK
  jsonb 
@@ -1981,98 +1944,6 @@ SELECT * FROM jsonb_populate_recordset(row('def',99,NULL)::jbpop,'[{"a":[100,200
  {"z": true}     |  3 | Fri Jan 20 10:42:53 2012
 (2 rows)
 
--- handling of unicode surrogate pairs
-SELECT octet_length((jsonb '{ "a":  "\ud83d\ude04\ud83d\udc36" }' -> 'a')::text) AS correct_in_utf8;
- correct_in_utf8 
------------------
-              10
-(1 row)
-
-SELECT jsonb '{ "a":  "\ud83d\ud83d" }' -> 'a'; -- 2 high surrogates in a row
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT jsonb '{ "a":  "\ud83d\ud83d" }' -> 'a';
-                     ^
-DETAIL:  Unicode high surrogate must not follow a high surrogate.
-CONTEXT:  JSON data, line 1: { "a":...
-SELECT jsonb '{ "a":  "\ude04\ud83d" }' -> 'a'; -- surrogates in wrong order
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT jsonb '{ "a":  "\ude04\ud83d" }' -> 'a';
-                     ^
-DETAIL:  Unicode low surrogate must follow a high surrogate.
-CONTEXT:  JSON data, line 1: { "a":...
-SELECT jsonb '{ "a":  "\ud83dX" }' -> 'a'; -- orphan high surrogate
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT jsonb '{ "a":  "\ud83dX" }' -> 'a';
-                     ^
-DETAIL:  Unicode low surrogate must follow a high surrogate.
-CONTEXT:  JSON data, line 1: { "a":...
-SELECT jsonb '{ "a":  "\ude04X" }' -> 'a'; -- orphan low surrogate
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT jsonb '{ "a":  "\ude04X" }' -> 'a';
-                     ^
-DETAIL:  Unicode low surrogate must follow a high surrogate.
-CONTEXT:  JSON data, line 1: { "a":...
--- handling of simple unicode escapes
-SELECT jsonb '{ "a":  "the Copyright \u00a9 sign" }' as correct_in_utf8;
-        correct_in_utf8        
--------------------------------
- {"a": "the Copyright © sign"}
-(1 row)
-
-SELECT jsonb '{ "a":  "dollar \u0024 character" }' as correct_everywhere;
-     correct_everywhere      
------------------------------
- {"a": "dollar $ character"}
-(1 row)
-
-SELECT jsonb '{ "a":  "dollar \\u0024 character" }' as not_an_escape;
-           not_an_escape           
------------------------------------
- {"a": "dollar \\u0024 character"}
-(1 row)
-
-SELECT jsonb '{ "a":  "null \u0000 escape" }' as fails;
-ERROR:  unsupported Unicode escape sequence
-LINE 1: SELECT jsonb '{ "a":  "null \u0000 escape" }' as fails;
-                     ^
-DETAIL:  \u0000 cannot be converted to text.
-CONTEXT:  JSON data, line 1: { "a":...
-SELECT jsonb '{ "a":  "null \\u0000 escape" }' as not_an_escape;
-        not_an_escape         
-------------------------------
- {"a": "null \\u0000 escape"}
-(1 row)
-
-SELECT jsonb '{ "a":  "the Copyright \u00a9 sign" }' ->> 'a' as correct_in_utf8;
-   correct_in_utf8    
-----------------------
- the Copyright © sign
-(1 row)
-
-SELECT jsonb '{ "a":  "dollar \u0024 character" }' ->> 'a' as correct_everywhere;
- correct_everywhere 
---------------------
- dollar $ character
-(1 row)
-
-SELECT jsonb '{ "a":  "dollar \\u0024 character" }' ->> 'a' as not_an_escape;
-      not_an_escape      
--------------------------
- dollar \u0024 character
-(1 row)
-
-SELECT jsonb '{ "a":  "null \u0000 escape" }' ->> 'a' as fails;
-ERROR:  unsupported Unicode escape sequence
-LINE 1: SELECT jsonb '{ "a":  "null \u0000 escape" }' ->> 'a' as fai...
-                     ^
-DETAIL:  \u0000 cannot be converted to text.
-CONTEXT:  JSON data, line 1: { "a":...
-SELECT jsonb '{ "a":  "null \\u0000 escape" }' ->> 'a' as not_an_escape;
-   not_an_escape    
---------------------
- null \u0000 escape
-(1 row)
-
 -- jsonb_to_record and jsonb_to_recordset
 select * from jsonb_to_record('{"a":1,"b":"foo","c":"bar"}')
     as x(a int, b text, d text);
diff --git a/src/test/regress/expected/jsonb_1.out b/src/test/regress/expected/jsonb_1.out
deleted file mode 100644 (file)
index deb87dd..0000000
+++ /dev/null
@@ -1,3336 +0,0 @@
--- Strings.
-SELECT '""'::jsonb;                            -- OK.
- jsonb 
--------
- ""
-(1 row)
-
-SELECT $$''$$::jsonb;                  -- ERROR, single quotes are not allowed
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT $$''$$::jsonb;
-               ^
-DETAIL:  Token "'" is invalid.
-CONTEXT:  JSON data, line 1: '...
-SELECT '"abc"'::jsonb;                 -- OK
- jsonb 
--------
- "abc"
-(1 row)
-
-SELECT '"abc'::jsonb;                  -- ERROR, quotes not closed
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT '"abc'::jsonb;
-               ^
-DETAIL:  Token ""abc" is invalid.
-CONTEXT:  JSON data, line 1: "abc
-SELECT '"abc
-def"'::jsonb;                                  -- 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\"\\"'::jsonb;              -- OK, legal escapes
-  jsonb   
-----------
- "\n\"\\"
-(1 row)
-
-SELECT '"\v"'::jsonb;                  -- ERROR, not a valid JSON escape
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT '"\v"'::jsonb;
-               ^
-DETAIL:  Escape sequence "\v" is invalid.
-CONTEXT:  JSON data, line 1: "\v...
-SELECT '"\u"'::jsonb;                  -- ERROR, incomplete escape
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT '"\u"'::jsonb;
-               ^
-DETAIL:  "\u" must be followed by four hexadecimal digits.
-CONTEXT:  JSON data, line 1: "\u"
-SELECT '"\u00"'::jsonb;                        -- ERROR, incomplete escape
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT '"\u00"'::jsonb;
-               ^
-DETAIL:  "\u" must be followed by four hexadecimal digits.
-CONTEXT:  JSON data, line 1: "\u00"
-SELECT '"\u000g"'::jsonb;              -- ERROR, g is not a hex digit
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT '"\u000g"'::jsonb;
-               ^
-DETAIL:  "\u" must be followed by four hexadecimal digits.
-CONTEXT:  JSON data, line 1: "\u000g...
-SELECT '"\u0045"'::jsonb;              -- OK, legal escape
- jsonb 
--------
- "E"
-(1 row)
-
-SELECT '"\u0000"'::jsonb;              -- ERROR, we don't support U+0000
-ERROR:  unsupported Unicode escape sequence
-LINE 1: SELECT '"\u0000"'::jsonb;
-               ^
-DETAIL:  \u0000 cannot be converted to text.
-CONTEXT:  JSON data, line 1: ...
--- use octet_length here so we don't get an odd unicode char in the
--- output
-SELECT octet_length('"\uaBcD"'::jsonb::text); -- OK, uppercase and lower case both OK
-ERROR:  unsupported Unicode escape sequence
-LINE 1: SELECT octet_length('"\uaBcD"'::jsonb::text);
-                            ^
-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: ...
--- Numbers.
-SELECT '1'::jsonb;                             -- OK
- jsonb 
--------
- 1
-(1 row)
-
-SELECT '0'::jsonb;                             -- OK
- jsonb 
--------
- 0
-(1 row)
-
-SELECT '01'::jsonb;                            -- ERROR, not valid according to JSON spec
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT '01'::jsonb;
-               ^
-DETAIL:  Token "01" is invalid.
-CONTEXT:  JSON data, line 1: 01
-SELECT '0.1'::jsonb;                           -- OK
- jsonb 
--------
- 0.1
-(1 row)
-
-SELECT '9223372036854775808'::jsonb;   -- OK, even though it's too large for int8
-        jsonb        
----------------------
- 9223372036854775808
-(1 row)
-
-SELECT '1e100'::jsonb;                 -- OK
-                                                 jsonb                                                 
--------------------------------------------------------------------------------------------------------
- 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-(1 row)
-
-SELECT '1.3e100'::jsonb;                       -- OK
-                                                 jsonb                                                 
--------------------------------------------------------------------------------------------------------
- 13000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-(1 row)
-
-SELECT '1f2'::jsonb;                           -- ERROR
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT '1f2'::jsonb;
-               ^
-DETAIL:  Token "1f2" is invalid.
-CONTEXT:  JSON data, line 1: 1f2
-SELECT '0.x1'::jsonb;                  -- ERROR
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT '0.x1'::jsonb;
-               ^
-DETAIL:  Token "0.x1" is invalid.
-CONTEXT:  JSON data, line 1: 0.x1
-SELECT '1.3ex100'::jsonb;              -- ERROR
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT '1.3ex100'::jsonb;
-               ^
-DETAIL:  Token "1.3ex100" is invalid.
-CONTEXT:  JSON data, line 1: 1.3ex100
--- Arrays.
-SELECT '[]'::jsonb;                            -- OK
- jsonb 
--------
- []
-(1 row)
-
-SELECT '[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]'::jsonb;  -- OK
-                                                                                                  jsonb                                                                                                   
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
-(1 row)
-
-SELECT '[1,2]'::jsonb;                 -- OK
- jsonb  
---------
- [1, 2]
-(1 row)
-
-SELECT '[1,2,]'::jsonb;                        -- ERROR, trailing comma
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT '[1,2,]'::jsonb;
-               ^
-DETAIL:  Expected JSON value, but found "]".
-CONTEXT:  JSON data, line 1: [1,2,]
-SELECT '[1,2'::jsonb;                  -- ERROR, no closing bracket
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT '[1,2'::jsonb;
-               ^
-DETAIL:  The input string ended unexpectedly.
-CONTEXT:  JSON data, line 1: [1,2
-SELECT '[1,[2]'::jsonb;                        -- ERROR, no closing bracket
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT '[1,[2]'::jsonb;
-               ^
-DETAIL:  The input string ended unexpectedly.
-CONTEXT:  JSON data, line 1: [1,[2]
--- Objects.
-SELECT '{}'::jsonb;                            -- OK
- jsonb 
--------
- {}
-(1 row)
-
-SELECT '{"abc"}'::jsonb;                       -- ERROR, no value
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT '{"abc"}'::jsonb;
-               ^
-DETAIL:  Expected ":", but found "}".
-CONTEXT:  JSON data, line 1: {"abc"}
-SELECT '{"abc":1}'::jsonb;             -- OK
-   jsonb    
-------------
- {"abc": 1}
-(1 row)
-
-SELECT '{1:"abc"}'::jsonb;             -- ERROR, keys must be strings
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT '{1:"abc"}'::jsonb;
-               ^
-DETAIL:  Expected string or "}", but found "1".
-CONTEXT:  JSON data, line 1: {1...
-SELECT '{"abc",1}'::jsonb;             -- ERROR, wrong separator
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT '{"abc",1}'::jsonb;
-               ^
-DETAIL:  Expected ":", but found ",".
-CONTEXT:  JSON data, line 1: {"abc",...
-SELECT '{"abc"=1}'::jsonb;             -- ERROR, totally wrong separator
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT '{"abc"=1}'::jsonb;
-               ^
-DETAIL:  Token "=" is invalid.
-CONTEXT:  JSON data, line 1: {"abc"=...
-SELECT '{"abc"::1}'::jsonb;            -- ERROR, another wrong separator
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT '{"abc"::1}'::jsonb;
-               ^
-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]}}'::jsonb; -- OK
-                               jsonb                                
---------------------------------------------------------------------
- {"abc": 1, "def": 2, "ghi": [3, 4], "hij": {"klm": 5, "nop": [6]}}
-(1 row)
-
-SELECT '{"abc":1:2}'::jsonb;           -- ERROR, colon in wrong spot
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT '{"abc":1:2}'::jsonb;
-               ^
-DETAIL:  Expected "," or "}", but found ":".
-CONTEXT:  JSON data, line 1: {"abc":1:...
-SELECT '{"abc":1,3}'::jsonb;           -- ERROR, no value
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT '{"abc":1,3}'::jsonb;
-               ^
-DETAIL:  Expected string, but found "3".
-CONTEXT:  JSON data, line 1: {"abc":1,3...
--- Recursion.
-SET max_stack_depth = '100kB';
-SELECT repeat('[', 10000)::jsonb;
-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)::jsonb;
-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'::jsonb;                  -- OK
- jsonb 
--------
- true
-(1 row)
-
-SELECT 'false'::jsonb;                 -- OK
- jsonb 
--------
- false
-(1 row)
-
-SELECT 'null'::jsonb;                  -- OK
- jsonb 
--------
- null
-(1 row)
-
-SELECT ' true '::jsonb;                        -- OK, even with extra whitespace
- jsonb 
--------
- true
-(1 row)
-
-SELECT 'true false'::jsonb;            -- ERROR, too many values
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT 'true false'::jsonb;
-               ^
-DETAIL:  Expected end of input, but found "false".
-CONTEXT:  JSON data, line 1: true false
-SELECT 'true, false'::jsonb;           -- ERROR, too many values
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT 'true, false'::jsonb;
-               ^
-DETAIL:  Expected end of input, but found ",".
-CONTEXT:  JSON data, line 1: true,...
-SELECT 'truf'::jsonb;                  -- ERROR, not a keyword
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT 'truf'::jsonb;
-               ^
-DETAIL:  Token "truf" is invalid.
-CONTEXT:  JSON data, line 1: truf
-SELECT 'trues'::jsonb;                 -- ERROR, not a keyword
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT 'trues'::jsonb;
-               ^
-DETAIL:  Token "trues" is invalid.
-CONTEXT:  JSON data, line 1: trues
-SELECT ''::jsonb;                              -- ERROR, no value
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT ''::jsonb;
-               ^
-DETAIL:  The input string ended unexpectedly.
-CONTEXT:  JSON data, line 1: 
-SELECT '    '::jsonb;                  -- ERROR, no value
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT '    '::jsonb;
-               ^
-DETAIL:  The input string ended unexpectedly.
-CONTEXT:  JSON data, line 1:     
--- make sure jsonb is passed through json generators without being escaped
-SELECT array_to_json(ARRAY [jsonb '{"a":1}', jsonb '{"b":[2,3]}']);
-      array_to_json       
---------------------------
- [{"a": 1},{"b": [2, 3]}]
-(1 row)
-
--- to_jsonb, timestamps
-select to_jsonb(timestamp '2014-05-28 12:22:35.614298');
-           to_jsonb           
-------------------------------
- "2014-05-28T12:22:35.614298"
-(1 row)
-
-BEGIN;
-SET LOCAL TIME ZONE 10.5;
-select to_jsonb(timestamptz '2014-05-28 12:22:35.614298-04');
-              to_jsonb              
-------------------------------------
- "2014-05-29T02:52:35.614298+10:30"
-(1 row)
-
-SET LOCAL TIME ZONE -8;
-select to_jsonb(timestamptz '2014-05-28 12:22:35.614298-04');
-              to_jsonb              
-------------------------------------
- "2014-05-28T08:22:35.614298-08:00"
-(1 row)
-
-COMMIT;
-select to_jsonb(date '2014-05-28');
-   to_jsonb   
---------------
- "2014-05-28"
-(1 row)
-
-select to_jsonb(date 'Infinity');
-  to_jsonb  
-------------
- "infinity"
-(1 row)
-
-select to_jsonb(timestamp 'Infinity');
-  to_jsonb  
-------------
- "infinity"
-(1 row)
-
-select to_jsonb(timestamptz 'Infinity');
-  to_jsonb  
-------------
- "infinity"
-(1 row)
-
---jsonb_agg
-CREATE TEMP TABLE rows AS
-SELECT x, 'txt' || x as y
-FROM generate_series(1,3) AS x;
-SELECT jsonb_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;
-                                                                                                                                                                    jsonb_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 jsonb_agg(q ORDER BY x, y)
-  FROM rows q;
-                               jsonb_agg                               
------------------------------------------------------------------------
- [{"x": 1, "y": "txt1"}, {"x": 2, "y": "txt2"}, {"x": 3, "y": "txt3"}]
-(1 row)
-
-UPDATE rows SET x = NULL WHERE x = 1;
-SELECT jsonb_agg(q ORDER BY x NULLS FIRST, y)
-  FROM rows q;
-                                jsonb_agg                                 
---------------------------------------------------------------------------
- [{"x": null, "y": "txt1"}, {"x": 2, "y": "txt2"}, {"x": 3, "y": "txt3"}]
-(1 row)
-
--- jsonb extraction functions
-CREATE TEMP TABLE test_jsonb (
-       json_type text,
-       test_json jsonb
-);
-INSERT INTO test_jsonb VALUES
-('scalar','"a scalar"'),
-('array','["zero", "one","two",null,"four","five", [1,2,3],{"f1":9}]'),
-('object','{"field1":"val1","field2":"val2","field3":null, "field4": 4, "field5": [1,2,3], "field6": {"f1":9}}');
-SELECT test_json -> 'x' FROM test_jsonb WHERE json_type = 'scalar';
- ?column? 
-----------
-(1 row)
-
-SELECT test_json -> 'x' FROM test_jsonb WHERE json_type = 'array';
- ?column? 
-----------
-(1 row)
-
-SELECT test_json -> 'x' FROM test_jsonb WHERE json_type = 'object';
- ?column? 
-----------
-(1 row)
-
-SELECT test_json -> 'field2' FROM test_jsonb WHERE json_type = 'object';
- ?column? 
-----------
- "val2"
-(1 row)
-
-SELECT test_json ->> 'field2' FROM test_jsonb WHERE json_type = 'scalar';
- ?column? 
-----------
-(1 row)
-
-SELECT test_json ->> 'field2' FROM test_jsonb WHERE json_type = 'array';
- ?column? 
-----------
-(1 row)
-
-SELECT test_json ->> 'field2' FROM test_jsonb WHERE json_type = 'object';
- ?column? 
-----------
- val2
-(1 row)
-
-SELECT test_json -> 2 FROM test_jsonb WHERE json_type = 'scalar';
- ?column? 
-----------
-(1 row)
-
-SELECT test_json -> 2 FROM test_jsonb WHERE json_type = 'array';
- ?column? 
-----------
- "two"
-(1 row)
-
-SELECT test_json -> 9 FROM test_jsonb WHERE json_type = 'array';
- ?column? 
-----------
-(1 row)
-
-SELECT test_json -> 2 FROM test_jsonb WHERE json_type = 'object';
- ?column? 
-----------
-(1 row)
-
-SELECT test_json ->> 6 FROM test_jsonb WHERE json_type = 'array';
- ?column?  
------------
- [1, 2, 3]
-(1 row)
-
-SELECT test_json ->> 7 FROM test_jsonb WHERE json_type = 'array';
- ?column?  
------------
- {"f1": 9}
-(1 row)
-
-SELECT test_json ->> 'field4' FROM test_jsonb WHERE json_type = 'object';
- ?column? 
-----------
- 4
-(1 row)
-
-SELECT test_json ->> 'field5' FROM test_jsonb WHERE json_type = 'object';
- ?column?  
------------
- [1, 2, 3]
-(1 row)
-
-SELECT test_json ->> 'field6' FROM test_jsonb WHERE json_type = 'object';
- ?column?  
------------
- {"f1": 9}
-(1 row)
-
-SELECT test_json ->> 2 FROM test_jsonb WHERE json_type = 'scalar';
- ?column? 
-----------
-(1 row)
-
-SELECT test_json ->> 2 FROM test_jsonb WHERE json_type = 'array';
- ?column? 
-----------
- two
-(1 row)
-
-SELECT test_json ->> 2 FROM test_jsonb WHERE json_type = 'object';
- ?column? 
-----------
-(1 row)
-
-SELECT jsonb_object_keys(test_json) FROM test_jsonb WHERE json_type = 'scalar';
-ERROR:  cannot call jsonb_object_keys on a scalar
-SELECT jsonb_object_keys(test_json) FROM test_jsonb WHERE json_type = 'array';
-ERROR:  cannot call jsonb_object_keys on an array
-SELECT jsonb_object_keys(test_json) FROM test_jsonb WHERE json_type = 'object';
- jsonb_object_keys 
--------------------
- field1
- field2
- field3
- field4
- field5
- field6
-(6 rows)
-
--- nulls
-SELECT (test_json->'field3') IS NULL AS expect_false FROM test_jsonb WHERE json_type = 'object';
- expect_false 
---------------
- f
-(1 row)
-
-SELECT (test_json->>'field3') IS NULL AS expect_true FROM test_jsonb WHERE json_type = 'object';
- expect_true 
--------------
- t
-(1 row)
-
-SELECT (test_json->3) IS NULL AS expect_false FROM test_jsonb WHERE json_type = 'array';
- expect_false 
---------------
- f
-(1 row)
-
-SELECT (test_json->>3) IS NULL AS expect_true FROM test_jsonb WHERE json_type = 'array';
- expect_true 
--------------
- t
-(1 row)
-
--- corner cases
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::jsonb -> null::text;
- ?column? 
-----------
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::jsonb -> null::int;
- ?column? 
-----------
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::jsonb -> 1;
- ?column? 
-----------
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::jsonb -> 'z';
- ?column? 
-----------
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::jsonb -> '';
- ?column? 
-----------
-(1 row)
-
-select '[{"b": "c"}, {"b": "cc"}]'::jsonb -> 1;
-  ?column?   
--------------
- {"b": "cc"}
-(1 row)
-
-select '[{"b": "c"}, {"b": "cc"}]'::jsonb -> 3;
- ?column? 
-----------
-(1 row)
-
-select '[{"b": "c"}, {"b": "cc"}]'::jsonb -> 'z';
- ?column? 
-----------
-(1 row)
-
-select '{"a": "c", "b": null}'::jsonb -> 'b';
- ?column? 
-----------
- null
-(1 row)
-
-select '"foo"'::jsonb -> 1;
- ?column? 
-----------
-(1 row)
-
-select '"foo"'::jsonb -> 'z';
- ?column? 
-----------
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::jsonb ->> null::text;
- ?column? 
-----------
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::jsonb ->> null::int;
- ?column? 
-----------
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::jsonb ->> 1;
- ?column? 
-----------
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::jsonb ->> 'z';
- ?column? 
-----------
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::jsonb ->> '';
- ?column? 
-----------
-(1 row)
-
-select '[{"b": "c"}, {"b": "cc"}]'::jsonb ->> 1;
-  ?column?   
--------------
- {"b": "cc"}
-(1 row)
-
-select '[{"b": "c"}, {"b": "cc"}]'::jsonb ->> 3;
- ?column? 
-----------
-(1 row)
-
-select '[{"b": "c"}, {"b": "cc"}]'::jsonb ->> 'z';
- ?column? 
-----------
-(1 row)
-
-select '{"a": "c", "b": null}'::jsonb ->> 'b';
- ?column? 
-----------
-(1 row)
-
-select '"foo"'::jsonb ->> 1;
- ?column? 
-----------
-(1 row)
-
-select '"foo"'::jsonb ->> 'z';
- ?column? 
-----------
-(1 row)
-
--- equality and inequality
-SELECT '{"x":"y"}'::jsonb = '{"x":"y"}'::jsonb;
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '{"x":"y"}'::jsonb = '{"x":"z"}'::jsonb;
- ?column? 
-----------
- f
-(1 row)
-
-SELECT '{"x":"y"}'::jsonb <> '{"x":"y"}'::jsonb;
- ?column? 
-----------
- f
-(1 row)
-
-SELECT '{"x":"y"}'::jsonb <> '{"x":"z"}'::jsonb;
- ?column? 
-----------
- t
-(1 row)
-
--- containment
-SELECT jsonb_contains('{"a":"b", "b":1, "c":null}', '{"a":"b"}');
- jsonb_contains 
-----------------
- t
-(1 row)
-
-SELECT jsonb_contains('{"a":"b", "b":1, "c":null}', '{"a":"b", "c":null}');
- jsonb_contains 
-----------------
- t
-(1 row)
-
-SELECT jsonb_contains('{"a":"b", "b":1, "c":null}', '{"a":"b", "g":null}');
- jsonb_contains 
-----------------
- f
-(1 row)
-
-SELECT jsonb_contains('{"a":"b", "b":1, "c":null}', '{"g":null}');
- jsonb_contains 
-----------------
- f
-(1 row)
-
-SELECT jsonb_contains('{"a":"b", "b":1, "c":null}', '{"a":"c"}');
- jsonb_contains 
-----------------
- f
-(1 row)
-
-SELECT jsonb_contains('{"a":"b", "b":1, "c":null}', '{"a":"b"}');
- jsonb_contains 
-----------------
- t
-(1 row)
-
-SELECT jsonb_contains('{"a":"b", "b":1, "c":null}', '{"a":"b", "c":"q"}');
- jsonb_contains 
-----------------
- f
-(1 row)
-
-SELECT '{"a":"b", "b":1, "c":null}'::jsonb @> '{"a":"b"}';
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '{"a":"b", "b":1, "c":null}'::jsonb @> '{"a":"b", "c":null}';
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '{"a":"b", "b":1, "c":null}'::jsonb @> '{"a":"b", "g":null}';
- ?column? 
-----------
- f
-(1 row)
-
-SELECT '{"a":"b", "b":1, "c":null}'::jsonb @> '{"g":null}';
- ?column? 
-----------
- f
-(1 row)
-
-SELECT '{"a":"b", "b":1, "c":null}'::jsonb @> '{"a":"c"}';
- ?column? 
-----------
- f
-(1 row)
-
-SELECT '{"a":"b", "b":1, "c":null}'::jsonb @> '{"a":"b"}';
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '{"a":"b", "b":1, "c":null}'::jsonb @> '{"a":"b", "c":"q"}';
- ?column? 
-----------
- f
-(1 row)
-
-SELECT '[1,2]'::jsonb @> '[1,2,2]'::jsonb;
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '[1,1,2]'::jsonb @> '[1,2,2]'::jsonb;
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '[[1,2]]'::jsonb @> '[[1,2,2]]'::jsonb;
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '[1,2,2]'::jsonb <@ '[1,2]'::jsonb;
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '[1,2,2]'::jsonb <@ '[1,1,2]'::jsonb;
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '[[1,2,2]]'::jsonb <@ '[[1,2]]'::jsonb;
- ?column? 
-----------
- t
-(1 row)
-
-SELECT jsonb_contained('{"a":"b"}', '{"a":"b", "b":1, "c":null}');
- jsonb_contained 
------------------
- t
-(1 row)
-
-SELECT jsonb_contained('{"a":"b", "c":null}', '{"a":"b", "b":1, "c":null}');
- jsonb_contained 
------------------
- t
-(1 row)
-
-SELECT jsonb_contained('{"a":"b", "g":null}', '{"a":"b", "b":1, "c":null}');
- jsonb_contained 
------------------
- f
-(1 row)
-
-SELECT jsonb_contained('{"g":null}', '{"a":"b", "b":1, "c":null}');
- jsonb_contained 
------------------
- f
-(1 row)
-
-SELECT jsonb_contained('{"a":"c"}', '{"a":"b", "b":1, "c":null}');
- jsonb_contained 
------------------
- f
-(1 row)
-
-SELECT jsonb_contained('{"a":"b"}', '{"a":"b", "b":1, "c":null}');
- jsonb_contained 
------------------
- t
-(1 row)
-
-SELECT jsonb_contained('{"a":"b", "c":"q"}', '{"a":"b", "b":1, "c":null}');
- jsonb_contained 
------------------
- f
-(1 row)
-
-SELECT '{"a":"b"}'::jsonb <@ '{"a":"b", "b":1, "c":null}';
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '{"a":"b", "c":null}'::jsonb <@ '{"a":"b", "b":1, "c":null}';
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '{"a":"b", "g":null}'::jsonb <@ '{"a":"b", "b":1, "c":null}';
- ?column? 
-----------
- f
-(1 row)
-
-SELECT '{"g":null}'::jsonb <@ '{"a":"b", "b":1, "c":null}';
- ?column? 
-----------
- f
-(1 row)
-
-SELECT '{"a":"c"}'::jsonb <@ '{"a":"b", "b":1, "c":null}';
- ?column? 
-----------
- f
-(1 row)
-
-SELECT '{"a":"b"}'::jsonb <@ '{"a":"b", "b":1, "c":null}';
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '{"a":"b", "c":"q"}'::jsonb <@ '{"a":"b", "b":1, "c":null}';
- ?column? 
-----------
- f
-(1 row)
-
--- Raw scalar may contain another raw scalar, array may contain a raw scalar
-SELECT '[5]'::jsonb @> '[5]';
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '5'::jsonb @> '5';
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '[5]'::jsonb @> '5';
- ?column? 
-----------
- t
-(1 row)
-
--- But a raw scalar cannot contain an array
-SELECT '5'::jsonb @> '[5]';
- ?column? 
-----------
- f
-(1 row)
-
--- In general, one thing should always contain itself. Test array containment:
-SELECT '["9", ["7", "3"], 1]'::jsonb @> '["9", ["7", "3"], 1]'::jsonb;
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '["9", ["7", "3"], ["1"]]'::jsonb @> '["9", ["7", "3"], ["1"]]'::jsonb;
- ?column? 
-----------
- t
-(1 row)
-
--- array containment string matching confusion bug
-SELECT '{ "name": "Bob", "tags": [ "enim", "qui"]}'::jsonb @> '{"tags":["qu"]}';
- ?column? 
-----------
- f
-(1 row)
-
--- array length
-SELECT jsonb_array_length('[1,2,3,{"f1":1,"f2":[5,6]},4]');
- jsonb_array_length 
---------------------
-                  5
-(1 row)
-
-SELECT jsonb_array_length('[]');
- jsonb_array_length 
---------------------
-                  0
-(1 row)
-
-SELECT jsonb_array_length('{"f1":1,"f2":[5,6]}');
-ERROR:  cannot get array length of a non-array
-SELECT jsonb_array_length('4');
-ERROR:  cannot get array length of a scalar
--- each
-SELECT jsonb_each('{"f1":[1,2,3],"f2":{"f3":1},"f4":null}');
-     jsonb_each     
---------------------
- (f1,"[1, 2, 3]")
- (f2,"{""f3"": 1}")
- (f4,null)
-(3 rows)
-
-SELECT jsonb_each('{"a":{"b":"c","c":"b","1":"first"},"b":[1,2],"c":"cc","1":"first","n":null}'::jsonb) AS q;
-                          q                           
-------------------------------------------------------
- (1,"""first""")
- (a,"{""1"": ""first"", ""b"": ""c"", ""c"": ""b""}")
- (b,"[1, 2]")
- (c,"""cc""")
- (n,null)
-(5 rows)
-
-SELECT * FROM jsonb_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 * FROM jsonb_each('{"a":{"b":"c","c":"b","1":"first"},"b":[1,2],"c":"cc","1":"first","n":null}'::jsonb) AS q;
- key |               value                
------+------------------------------------
- 1   | "first"
- a   | {"1": "first", "b": "c", "c": "b"}
- b   | [1, 2]
- c   | "cc"
- n   | null
-(5 rows)
-
-SELECT jsonb_each_text('{"f1":[1,2,3],"f2":{"f3":1},"f4":null,"f5":"null"}');
-  jsonb_each_text   
---------------------
- (f1,"[1, 2, 3]")
- (f2,"{""f3"": 1}")
- (f4,)
- (f5,null)
-(4 rows)
-
-SELECT jsonb_each_text('{"a":{"b":"c","c":"b","1":"first"},"b":[1,2],"c":"cc","1":"first","n":null}'::jsonb) AS q;
-                          q                           
-------------------------------------------------------
- (1,first)
- (a,"{""1"": ""first"", ""b"": ""c"", ""c"": ""b""}")
- (b,"[1, 2]")
- (c,cc)
- (n,)
-(5 rows)
-
-SELECT * FROM jsonb_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)
-
-SELECT * FROM jsonb_each_text('{"a":{"b":"c","c":"b","1":"first"},"b":[1,2],"c":"cc","1":"first","n":null}'::jsonb) AS q;
- key |               value                
------+------------------------------------
- 1   | first
- a   | {"1": "first", "b": "c", "c": "b"}
- b   | [1, 2]
- c   | cc
- n   | 
-(5 rows)
-
--- exists
-SELECT jsonb_exists('{"a":null, "b":"qq"}', 'a');
- jsonb_exists 
---------------
- t
-(1 row)
-
-SELECT jsonb_exists('{"a":null, "b":"qq"}', 'b');
- jsonb_exists 
---------------
- t
-(1 row)
-
-SELECT jsonb_exists('{"a":null, "b":"qq"}', 'c');
- jsonb_exists 
---------------
- f
-(1 row)
-
-SELECT jsonb_exists('{"a":"null", "b":"qq"}', 'a');
- jsonb_exists 
---------------
- t
-(1 row)
-
-SELECT jsonb '{"a":null, "b":"qq"}' ? 'a';
- ?column? 
-----------
- t
-(1 row)
-
-SELECT jsonb '{"a":null, "b":"qq"}' ? 'b';
- ?column? 
-----------
- t
-(1 row)
-
-SELECT jsonb '{"a":null, "b":"qq"}' ? 'c';
- ?column? 
-----------
- f
-(1 row)
-
-SELECT jsonb '{"a":"null", "b":"qq"}' ? 'a';
- ?column? 
-----------
- t
-(1 row)
-
--- array exists - array elements should behave as keys
-SELECT count(*) from testjsonb  WHERE j->'array' ? 'bar';
- count 
--------
-     3
-(1 row)
-
--- type sensitive array exists - should return no rows (since "exists" only
--- matches strings that are either object keys or array elements)
-SELECT count(*) from testjsonb  WHERE j->'array' ? '5'::text;
- count 
--------
-     0
-(1 row)
-
--- However, a raw scalar is *contained* within the array
-SELECT count(*) from testjsonb  WHERE j->'array' @> '5'::jsonb;
- count 
--------
-     1
-(1 row)
-
-SELECT jsonb_exists_any('{"a":null, "b":"qq"}', ARRAY['a','b']);
- jsonb_exists_any 
-------------------
- t
-(1 row)
-
-SELECT jsonb_exists_any('{"a":null, "b":"qq"}', ARRAY['b','a']);
- jsonb_exists_any 
-------------------
- t
-(1 row)
-
-SELECT jsonb_exists_any('{"a":null, "b":"qq"}', ARRAY['c','a']);
- jsonb_exists_any 
-------------------
- t
-(1 row)
-
-SELECT jsonb_exists_any('{"a":null, "b":"qq"}', ARRAY['c','d']);
- jsonb_exists_any 
-------------------
- f
-(1 row)
-
-SELECT jsonb_exists_any('{"a":null, "b":"qq"}', '{}'::text[]);
- jsonb_exists_any 
-------------------
- f
-(1 row)
-
-SELECT jsonb '{"a":null, "b":"qq"}' ?| ARRAY['a','b'];
- ?column? 
-----------
- t
-(1 row)
-
-SELECT jsonb '{"a":null, "b":"qq"}' ?| ARRAY['b','a'];
- ?column? 
-----------
- t
-(1 row)
-
-SELECT jsonb '{"a":null, "b":"qq"}' ?| ARRAY['c','a'];
- ?column? 
-----------
- t
-(1 row)
-
-SELECT jsonb '{"a":null, "b":"qq"}' ?| ARRAY['c','d'];
- ?column? 
-----------
- f
-(1 row)
-
-SELECT jsonb '{"a":null, "b":"qq"}' ?| '{}'::text[];
- ?column? 
-----------
- f
-(1 row)
-
-SELECT jsonb_exists_all('{"a":null, "b":"qq"}', ARRAY['a','b']);
- jsonb_exists_all 
-------------------
- t
-(1 row)
-
-SELECT jsonb_exists_all('{"a":null, "b":"qq"}', ARRAY['b','a']);
- jsonb_exists_all 
-------------------
- t
-(1 row)
-
-SELECT jsonb_exists_all('{"a":null, "b":"qq"}', ARRAY['c','a']);
- jsonb_exists_all 
-------------------
- f
-(1 row)
-
-SELECT jsonb_exists_all('{"a":null, "b":"qq"}', ARRAY['c','d']);
- jsonb_exists_all 
-------------------
- f
-(1 row)
-
-SELECT jsonb_exists_all('{"a":null, "b":"qq"}', '{}'::text[]);
- jsonb_exists_all 
-------------------
- t
-(1 row)
-
-SELECT jsonb '{"a":null, "b":"qq"}' ?& ARRAY['a','b'];
- ?column? 
-----------
- t
-(1 row)
-
-SELECT jsonb '{"a":null, "b":"qq"}' ?& ARRAY['b','a'];
- ?column? 
-----------
- t
-(1 row)
-
-SELECT jsonb '{"a":null, "b":"qq"}' ?& ARRAY['c','a'];
- ?column? 
-----------
- f
-(1 row)
-
-SELECT jsonb '{"a":null, "b":"qq"}' ?& ARRAY['c','d'];
- ?column? 
-----------
- f
-(1 row)
-
-SELECT jsonb '{"a":null, "b":"qq"}' ?& ARRAY['a','a', 'b', 'b', 'b'];
- ?column? 
-----------
- t
-(1 row)
-
-SELECT jsonb '{"a":null, "b":"qq"}' ?& '{}'::text[];
- ?column? 
-----------
- t
-(1 row)
-
--- typeof
-SELECT jsonb_typeof('{}') AS object;
- object 
---------
- object
-(1 row)
-
-SELECT jsonb_typeof('{"c":3,"p":"o"}') AS object;
- object 
---------
- object
-(1 row)
-
-SELECT jsonb_typeof('[]') AS array;
- array 
--------
- array
-(1 row)
-
-SELECT jsonb_typeof('["a", 1]') AS array;
- array 
--------
- array
-(1 row)
-
-SELECT jsonb_typeof('null') AS "null";
- null 
-------
- null
-(1 row)
-
-SELECT jsonb_typeof('1') AS number;
- number 
---------
- number
-(1 row)
-
-SELECT jsonb_typeof('-1') AS number;
- number 
---------
- number
-(1 row)
-
-SELECT jsonb_typeof('1.0') AS number;
- number 
---------
- number
-(1 row)
-
-SELECT jsonb_typeof('1e2') AS number;
- number 
---------
- number
-(1 row)
-
-SELECT jsonb_typeof('-1.0') AS number;
- number 
---------
- number
-(1 row)
-
-SELECT jsonb_typeof('true') AS boolean;
- boolean 
----------
- boolean
-(1 row)
-
-SELECT jsonb_typeof('false') AS boolean;
- boolean 
----------
- boolean
-(1 row)
-
-SELECT jsonb_typeof('"hello"') AS string;
- string 
---------
- string
-(1 row)
-
-SELECT jsonb_typeof('"true"') AS string;
- string 
---------
- string
-(1 row)
-
-SELECT jsonb_typeof('"1.0"') AS string;
- string 
---------
- string
-(1 row)
-
--- jsonb_build_array, jsonb_build_object, jsonb_object_agg
-SELECT jsonb_build_array('a',1,'b',1.2,'c',true,'d',null,'e',json '{"x": 3, "y": [1,2,3]}');
-                            jsonb_build_array                            
--------------------------------------------------------------------------
- ["a", 1, "b", 1.2, "c", true, "d", null, "e", {"x": 3, "y": [1, 2, 3]}]
-(1 row)
-
-SELECT jsonb_build_object('a',1,'b',1.2,'c',true,'d',null,'e',json '{"x": 3, "y": [1,2,3]}');
-                           jsonb_build_object                            
--------------------------------------------------------------------------
- {"a": 1, "b": 1.2, "c": true, "d": null, "e": {"x": 3, "y": [1, 2, 3]}}
-(1 row)
-
-SELECT jsonb_build_object(
-       'a', jsonb_build_object('b',false,'c',99),
-       'd', jsonb_build_object('e',array[9,8,7]::int[],
-           'f', (select row_to_json(r) from ( select relkind, oid::regclass as name from pg_class where relname = 'pg_class') r)));
-                                       jsonb_build_object                                       
-------------------------------------------------------------------------------------------------
- {"a": {"b": false, "c": 99}, "d": {"e": [9, 8, 7], "f": {"name": "pg_class", "relkind": "r"}}}
-(1 row)
-
--- empty objects/arrays
-SELECT jsonb_build_array();
- jsonb_build_array 
--------------------
- []
-(1 row)
-
-SELECT jsonb_build_object();
- jsonb_build_object 
---------------------
- {}
-(1 row)
-
--- make sure keys are quoted
-SELECT jsonb_build_object(1,2);
- jsonb_build_object 
---------------------
- {"1": 2}
-(1 row)
-
--- keys must be scalar and not null
-SELECT jsonb_build_object(null,2);
-ERROR:  arg 1: key cannot be null
-SELECT jsonb_build_object(r,2) FROM (SELECT 1 AS a, 2 AS b) r;
-ERROR:  key value must be scalar, not array, composite or json
-SELECT jsonb_build_object(json '{"a":1,"b":2}', 3);
-ERROR:  key value must be scalar, not array, composite or json
-SELECT jsonb_build_object('{1,2,3}'::int[], 3);
-ERROR:  key value must be scalar, not array, composite or json
-CREATE TEMP TABLE foo (serial_num int, name text, type text);
-INSERT INTO foo VALUES (847001,'t15','GE1043');
-INSERT INTO foo VALUES (847002,'t16','GE1043');
-INSERT INTO foo VALUES (847003,'sub-alpha','GESS90');
-SELECT jsonb_build_object('turbines',jsonb_object_agg(serial_num,jsonb_build_object('name',name,'type',type)))
-FROM foo;
-                                                                     jsonb_build_object                                                                      
--------------------------------------------------------------------------------------------------------------------------------------------------------------
- {"turbines": {"847001": {"name": "t15", "type": "GE1043"}, "847002": {"name": "t16", "type": "GE1043"}, "847003": {"name": "sub-alpha", "type": "GESS90"}}}
-(1 row)
-
-SELECT jsonb_object_agg(name, type) FROM foo;
-                     jsonb_object_agg                      
------------------------------------------------------------
- {"t15": "GE1043", "t16": "GE1043", "sub-alpha": "GESS90"}
-(1 row)
-
-INSERT INTO foo VALUES (999999, NULL, 'bar');
-SELECT jsonb_object_agg(name, type) FROM foo;
-ERROR:  field name must not be null
--- jsonb_object
--- one dimension
-SELECT jsonb_object('{a,1,b,2,3,NULL,"d e f","a b c"}');
-                   jsonb_object                    
----------------------------------------------------
- {"3": null, "a": "1", "b": "2", "d e f": "a b c"}
-(1 row)
-
--- same but with two dimensions
-SELECT jsonb_object('{{a,1},{b,2},{3,NULL},{"d e f","a b c"}}');
-                   jsonb_object                    
----------------------------------------------------
- {"3": null, "a": "1", "b": "2", "d e f": "a b c"}
-(1 row)
-
--- odd number error
-SELECT jsonb_object('{a,b,c}');
-ERROR:  array must have even number of elements
--- one column error
-SELECT jsonb_object('{{a},{b}}');
-ERROR:  array must have two columns
--- too many columns error
-SELECT jsonb_object('{{a,b,c},{b,c,d}}');
-ERROR:  array must have two columns
--- too many dimensions error
-SELECT jsonb_object('{{{a,b},{c,d}},{{b,c},{d,e}}}');
-ERROR:  wrong number of array subscripts
---two argument form of jsonb_object
-select jsonb_object('{a,b,c,"d e f"}','{1,2,3,"a b c"}');
-                   jsonb_object                   
---------------------------------------------------
- {"a": "1", "b": "2", "c": "3", "d e f": "a b c"}
-(1 row)
-
--- too many dimensions
-SELECT jsonb_object('{{a,1},{b,2},{3,NULL},{"d e f","a b c"}}', '{{a,1},{b,2},{3,NULL},{"d e f","a b c"}}');
-ERROR:  wrong number of array subscripts
--- mismatched dimensions
-select jsonb_object('{a,b,c,"d e f",g}','{1,2,3,"a b c"}');
-ERROR:  mismatched array dimensions
-select jsonb_object('{a,b,c,"d e f"}','{1,2,3,"a b c",g}');
-ERROR:  mismatched array dimensions
--- null key error
-select jsonb_object('{a,b,NULL,"d e f"}','{1,2,3,"a b c"}');
-ERROR:  null value not allowed for object key
--- empty key is allowed
-select jsonb_object('{a,b,"","d e f"}','{1,2,3,"a b c"}');
-                  jsonb_object                   
--------------------------------------------------
- {"": "3", "a": "1", "b": "2", "d e f": "a b c"}
-(1 row)
-
--- extract_path, extract_path_as_text
-SELECT jsonb_extract_path('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f4','f6');
- jsonb_extract_path 
---------------------
- "stringy"
-(1 row)
-
-SELECT jsonb_extract_path('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f2');
- jsonb_extract_path 
---------------------
- {"f3": 1}
-(1 row)
-
-SELECT jsonb_extract_path('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',0::text);
- jsonb_extract_path 
---------------------
- "f3"
-(1 row)
-
-SELECT jsonb_extract_path('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',1::text);
- jsonb_extract_path 
---------------------
- 1
-(1 row)
-
-SELECT jsonb_extract_path_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f4','f6');
- jsonb_extract_path_text 
--------------------------
- stringy
-(1 row)
-
-SELECT jsonb_extract_path_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f2');
- jsonb_extract_path_text 
--------------------------
- {"f3": 1}
-(1 row)
-
-SELECT jsonb_extract_path_text('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',0::text);
- jsonb_extract_path_text 
--------------------------
- f3
-(1 row)
-
-SELECT jsonb_extract_path_text('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',1::text);
- jsonb_extract_path_text 
--------------------------
- 1
-(1 row)
-
--- extract_path nulls
-SELECT jsonb_extract_path('{"f2":{"f3":1},"f4":{"f5":null,"f6":"stringy"}}','f4','f5') IS NULL AS expect_false;
- expect_false 
---------------
- f
-(1 row)
-
-SELECT jsonb_extract_path_text('{"f2":{"f3":1},"f4":{"f5":null,"f6":"stringy"}}','f4','f5') IS NULL AS expect_true;
- expect_true 
--------------
- t
-(1 row)
-
-SELECT jsonb_extract_path('{"f2":{"f3":1},"f4":[0,1,2,null]}','f4','3') IS NULL AS expect_false;
- expect_false 
---------------
- f
-(1 row)
-
-SELECT jsonb_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"}}'::jsonb#>array['f4','f6'];
- ?column?  
------------
- "stringy"
-(1 row)
-
-SELECT '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>array['f2'];
- ?column?  
------------
- {"f3": 1}
-(1 row)
-
-SELECT '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>array['f2','0'];
- ?column? 
-----------
- "f3"
-(1 row)
-
-SELECT '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>array['f2','1'];
- ?column? 
-----------
- 1
-(1 row)
-
-SELECT '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>>array['f4','f6'];
- ?column? 
-----------
- stringy
-(1 row)
-
-SELECT '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>>array['f2'];
- ?column?  
------------
- {"f3": 1}
-(1 row)
-
-SELECT '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>>array['f2','0'];
- ?column? 
-----------
- f3
-(1 row)
-
-SELECT '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>>array['f2','1'];
- ?column? 
-----------
- 1
-(1 row)
-
--- corner cases for same
-select '{"a": {"b":{"c": "foo"}}}'::jsonb #> '{}';
-          ?column?          
-----------------------------
- {"a": {"b": {"c": "foo"}}}
-(1 row)
-
-select '[1,2,3]'::jsonb #> '{}';
- ?column?  
------------
- [1, 2, 3]
-(1 row)
-
-select '"foo"'::jsonb #> '{}';
- ?column? 
-----------
- "foo"
-(1 row)
-
-select '42'::jsonb #> '{}';
- ?column? 
-----------
- 42
-(1 row)
-
-select 'null'::jsonb #> '{}';
- ?column? 
-----------
- null
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::jsonb #> array['a'];
-      ?column?       
----------------------
- {"b": {"c": "foo"}}
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::jsonb #> array['a', null];
- ?column? 
-----------
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::jsonb #> array['a', ''];
- ?column? 
-----------
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::jsonb #> array['a','b'];
-   ?column?   
---------------
- {"c": "foo"}
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::jsonb #> array['a','b','c'];
- ?column? 
-----------
- "foo"
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::jsonb #> array['a','b','c','d'];
- ?column? 
-----------
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::jsonb #> array['a','z','c'];
- ?column? 
-----------
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::jsonb #> array['a','1','b'];
- ?column? 
-----------
- "cc"
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::jsonb #> array['a','z','b'];
- ?column? 
-----------
-(1 row)
-
-select '[{"b": "c"}, {"b": "cc"}]'::jsonb #> array['1','b'];
- ?column? 
-----------
- "cc"
-(1 row)
-
-select '[{"b": "c"}, {"b": "cc"}]'::jsonb #> array['z','b'];
- ?column? 
-----------
-(1 row)
-
-select '[{"b": "c"}, {"b": null}]'::jsonb #> array['1','b'];
- ?column? 
-----------
- null
-(1 row)
-
-select '"foo"'::jsonb #> array['z'];
- ?column? 
-----------
-(1 row)
-
-select '42'::jsonb #> array['f2'];
- ?column? 
-----------
-(1 row)
-
-select '42'::jsonb #> array['0'];
- ?column? 
-----------
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::jsonb #>> '{}';
-          ?column?          
-----------------------------
- {"a": {"b": {"c": "foo"}}}
-(1 row)
-
-select '[1,2,3]'::jsonb #>> '{}';
- ?column?  
------------
- [1, 2, 3]
-(1 row)
-
-select '"foo"'::jsonb #>> '{}';
- ?column? 
-----------
- foo
-(1 row)
-
-select '42'::jsonb #>> '{}';
- ?column? 
-----------
- 42
-(1 row)
-
-select 'null'::jsonb #>> '{}';
- ?column? 
-----------
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::jsonb #>> array['a'];
-      ?column?       
----------------------
- {"b": {"c": "foo"}}
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::jsonb #>> array['a', null];
- ?column? 
-----------
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::jsonb #>> array['a', ''];
- ?column? 
-----------
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::jsonb #>> array['a','b'];
-   ?column?   
---------------
- {"c": "foo"}
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::jsonb #>> array['a','b','c'];
- ?column? 
-----------
- foo
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::jsonb #>> array['a','b','c','d'];
- ?column? 
-----------
-(1 row)
-
-select '{"a": {"b":{"c": "foo"}}}'::jsonb #>> array['a','z','c'];
- ?column? 
-----------
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::jsonb #>> array['a','1','b'];
- ?column? 
-----------
- cc
-(1 row)
-
-select '{"a": [{"b": "c"}, {"b": "cc"}]}'::jsonb #>> array['a','z','b'];
- ?column? 
-----------
-(1 row)
-
-select '[{"b": "c"}, {"b": "cc"}]'::jsonb #>> array['1','b'];
- ?column? 
-----------
- cc
-(1 row)
-
-select '[{"b": "c"}, {"b": "cc"}]'::jsonb #>> array['z','b'];
- ?column? 
-----------
-(1 row)
-
-select '[{"b": "c"}, {"b": null}]'::jsonb #>> array['1','b'];
- ?column? 
-----------
-(1 row)
-
-select '"foo"'::jsonb #>> array['z'];
- ?column? 
-----------
-(1 row)
-
-select '42'::jsonb #>> array['f2'];
- ?column? 
-----------
-(1 row)
-
-select '42'::jsonb #>> array['0'];
- ?column? 
-----------
-(1 row)
-
--- array_elements
-SELECT jsonb_array_elements('[1,true,[1,[2,3]],null,{"f1":1,"f2":[7,8,9]},false]');
-    jsonb_array_elements    
-----------------------------
- 1
- true
- [1, [2, 3]]
- null
- {"f1": 1, "f2": [7, 8, 9]}
- false
-(6 rows)
-
-SELECT * FROM jsonb_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)
-
-SELECT jsonb_array_elements_text('[1,true,[1,[2,3]],null,{"f1":1,"f2":[7,8,9]},false,"stringy"]');
- jsonb_array_elements_text  
-----------------------------
- 1
- true
- [1, [2, 3]]
- {"f1": 1, "f2": [7, 8, 9]}
- false
- stringy
-(7 rows)
-
-SELECT * FROM jsonb_array_elements_text('[1,true,[1,[2,3]],null,{"f1":1,"f2":[7,8,9]},false,"stringy"]') q;
-           value            
-----------------------------
- 1
- true
- [1, [2, 3]]
- {"f1": 1, "f2": [7, 8, 9]}
- false
- stringy
-(7 rows)
-
--- populate_record
-CREATE TYPE jbpop AS (a text, b int, c timestamp);
-SELECT * FROM jsonb_populate_record(NULL::jbpop,'{"a":"blurfl","x":43.2}') q;
-   a    | b | c 
---------+---+---
- blurfl |   | 
-(1 row)
-
-SELECT * FROM jsonb_populate_record(row('x',3,'2012-12-31 15:30:56')::jbpop,'{"a":"blurfl","x":43.2}') q;
-   a    | b |            c             
---------+---+--------------------------
- blurfl | 3 | Mon Dec 31 15:30:56 2012
-(1 row)
-
-SELECT * FROM jsonb_populate_record(NULL::jbpop,'{"a":"blurfl","x":43.2}') q;
-   a    | b | c 
---------+---+---
- blurfl |   | 
-(1 row)
-
-SELECT * FROM jsonb_populate_record(row('x',3,'2012-12-31 15:30:56')::jbpop,'{"a":"blurfl","x":43.2}') q;
-   a    | b |            c             
---------+---+--------------------------
- blurfl | 3 | Mon Dec 31 15:30:56 2012
-(1 row)
-
-SELECT * FROM jsonb_populate_record(NULL::jbpop,'{"a":[100,200,false],"x":43.2}') q;
-         a         | b | c 
--------------------+---+---
- [100, 200, false] |   | 
-(1 row)
-
-SELECT * FROM jsonb_populate_record(row('x',3,'2012-12-31 15:30:56')::jbpop,'{"a":[100,200,false],"x":43.2}') q;
-         a         | b |            c             
--------------------+---+--------------------------
- [100, 200, false] | 3 | Mon Dec 31 15:30:56 2012
-(1 row)
-
-SELECT * FROM jsonb_populate_record(row('x',3,'2012-12-31 15:30:56')::jbpop,'{"c":[100,200,false],"x":43.2}') q;
-ERROR:  invalid input syntax for type timestamp: "[100, 200, false]"
--- populate_recordset
-SELECT * FROM jsonb_populate_recordset(NULL::jbpop,'[{"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 jsonb_populate_recordset(row('def',99,NULL)::jbpop,'[{"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 jsonb_populate_recordset(NULL::jbpop,'[{"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 jsonb_populate_recordset(row('def',99,NULL)::jbpop,'[{"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 jsonb_populate_recordset(row('def',99,NULL)::jbpop,'[{"a":[100,200,300],"x":43.2},{"a":{"z":true},"b":3,"c":"2012-01-20 10:42:53"}]') q;
-        a        | b  |            c             
------------------+----+--------------------------
- [100, 200, 300] | 99 | 
- {"z": true}     |  3 | Fri Jan 20 10:42:53 2012
-(2 rows)
-
-SELECT * FROM jsonb_populate_recordset(row('def',99,NULL)::jbpop,'[{"c":[100,200,300],"x":43.2},{"a":{"z":true},"b":3,"c":"2012-01-20 10:42:53"}]') q;
-ERROR:  invalid input syntax for type timestamp: "[100, 200, 300]"
-SELECT * FROM jsonb_populate_recordset(NULL::jbpop,'[{"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 jsonb_populate_recordset(row('def',99,NULL)::jbpop,'[{"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 jsonb_populate_recordset(row('def',99,NULL)::jbpop,'[{"a":[100,200,300],"x":43.2},{"a":{"z":true},"b":3,"c":"2012-01-20 10:42:53"}]') q;
-        a        | b  |            c             
------------------+----+--------------------------
- [100, 200, 300] | 99 | 
- {"z": true}     |  3 | Fri Jan 20 10:42:53 2012
-(2 rows)
-
--- handling of unicode surrogate pairs
-SELECT octet_length((jsonb '{ "a":  "\ud83d\ude04\ud83d\udc36" }' -> 'a')::text) AS correct_in_utf8;
-ERROR:  unsupported Unicode escape sequence
-LINE 1: SELECT octet_length((jsonb '{ "a":  "\ud83d\ude04\ud83d\udc3...
-                                   ^
-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 jsonb '{ "a":  "\ud83d\ud83d" }' -> 'a'; -- 2 high surrogates in a row
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT jsonb '{ "a":  "\ud83d\ud83d" }' -> 'a';
-                     ^
-DETAIL:  Unicode high surrogate must not follow a high surrogate.
-CONTEXT:  JSON data, line 1: { "a":...
-SELECT jsonb '{ "a":  "\ude04\ud83d" }' -> 'a'; -- surrogates in wrong order
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT jsonb '{ "a":  "\ude04\ud83d" }' -> 'a';
-                     ^
-DETAIL:  Unicode low surrogate must follow a high surrogate.
-CONTEXT:  JSON data, line 1: { "a":...
-SELECT jsonb '{ "a":  "\ud83dX" }' -> 'a'; -- orphan high surrogate
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT jsonb '{ "a":  "\ud83dX" }' -> 'a';
-                     ^
-DETAIL:  Unicode low surrogate must follow a high surrogate.
-CONTEXT:  JSON data, line 1: { "a":...
-SELECT jsonb '{ "a":  "\ude04X" }' -> 'a'; -- orphan low surrogate
-ERROR:  invalid input syntax for type json
-LINE 1: SELECT jsonb '{ "a":  "\ude04X" }' -> 'a';
-                     ^
-DETAIL:  Unicode low surrogate must follow a high surrogate.
-CONTEXT:  JSON data, line 1: { "a":...
--- handling of simple unicode escapes
-SELECT jsonb '{ "a":  "the Copyright \u00a9 sign" }' as correct_in_utf8;
-ERROR:  unsupported Unicode escape sequence
-LINE 1: SELECT jsonb '{ "a":  "the Copyright \u00a9 sign" }' as corr...
-                     ^
-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 jsonb '{ "a":  "dollar \u0024 character" }' as correct_everywhere;
-     correct_everywhere      
------------------------------
- {"a": "dollar $ character"}
-(1 row)
-
-SELECT jsonb '{ "a":  "dollar \\u0024 character" }' as not_an_escape;
-           not_an_escape           
------------------------------------
- {"a": "dollar \\u0024 character"}
-(1 row)
-
-SELECT jsonb '{ "a":  "null \u0000 escape" }' as fails;
-ERROR:  unsupported Unicode escape sequence
-LINE 1: SELECT jsonb '{ "a":  "null \u0000 escape" }' as fails;
-                     ^
-DETAIL:  \u0000 cannot be converted to text.
-CONTEXT:  JSON data, line 1: { "a":...
-SELECT jsonb '{ "a":  "null \\u0000 escape" }' as not_an_escape;
-        not_an_escape         
-------------------------------
- {"a": "null \\u0000 escape"}
-(1 row)
-
-SELECT jsonb '{ "a":  "the Copyright \u00a9 sign" }' ->> 'a' as correct_in_utf8;
-ERROR:  unsupported Unicode escape sequence
-LINE 1: SELECT jsonb '{ "a":  "the Copyright \u00a9 sign" }' ->> 'a'...
-                     ^
-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 jsonb '{ "a":  "dollar \u0024 character" }' ->> 'a' as correct_everywhere;
- correct_everywhere 
---------------------
- dollar $ character
-(1 row)
-
-SELECT jsonb '{ "a":  "dollar \\u0024 character" }' ->> 'a' as not_an_escape;
-      not_an_escape      
--------------------------
- dollar \u0024 character
-(1 row)
-
-SELECT jsonb '{ "a":  "null \u0000 escape" }' ->> 'a' as fails;
-ERROR:  unsupported Unicode escape sequence
-LINE 1: SELECT jsonb '{ "a":  "null \u0000 escape" }' ->> 'a' as fai...
-                     ^
-DETAIL:  \u0000 cannot be converted to text.
-CONTEXT:  JSON data, line 1: { "a":...
-SELECT jsonb '{ "a":  "null \\u0000 escape" }' ->> 'a' as not_an_escape;
-   not_an_escape    
---------------------
- null \u0000 escape
-(1 row)
-
--- jsonb_to_record and jsonb_to_recordset
-select * from jsonb_to_record('{"a":1,"b":"foo","c":"bar"}')
-    as x(a int, b text, d text);
- a |  b  | d 
----+-----+---
- 1 | foo | 
-(1 row)
-
-select * from jsonb_to_recordset('[{"a":1,"b":"foo","d":false},{"a":2,"b":"bar","c":true}]')
-    as x(a int, b text, c boolean);
- a |  b  | c 
----+-----+---
- 1 | foo | 
- 2 | bar | t
-(2 rows)
-
--- indexing
-SELECT count(*) FROM testjsonb WHERE j @> '{"wait":null}';
- count 
--------
-     1
-(1 row)
-
-SELECT count(*) FROM testjsonb WHERE j @> '{"wait":"CC"}';
- count 
--------
-    15
-(1 row)
-
-SELECT count(*) FROM testjsonb WHERE j @> '{"wait":"CC", "public":true}';
- count 
--------
-     2
-(1 row)
-
-SELECT count(*) FROM testjsonb WHERE j @> '{"age":25}';
- count 
--------
-     2
-(1 row)
-
-SELECT count(*) FROM testjsonb WHERE j @> '{"age":25.0}';
- count 
--------
-     2
-(1 row)
-
-SELECT count(*) FROM testjsonb WHERE j ? 'public';
- count 
--------
-   194
-(1 row)
-
-SELECT count(*) FROM testjsonb WHERE j ? 'bar';
- count 
--------
-     0
-(1 row)
-
-SELECT count(*) FROM testjsonb WHERE j ?| ARRAY['public','disabled'];
- count 
--------
-   337
-(1 row)
-
-SELECT count(*) FROM testjsonb WHERE j ?& ARRAY['public','disabled'];
- count 
--------
-    42
-(1 row)
-
-CREATE INDEX jidx ON testjsonb USING gin (j);
-SET enable_seqscan = off;
-SELECT count(*) FROM testjsonb WHERE j @> '{"wait":null}';
- count 
--------
-     1
-(1 row)
-
-SELECT count(*) FROM testjsonb WHERE j @> '{"wait":"CC"}';
- count 
--------
-    15
-(1 row)
-
-SELECT count(*) FROM testjsonb WHERE j @> '{"wait":"CC", "public":true}';
- count 
--------
-     2
-(1 row)
-
-SELECT count(*) FROM testjsonb WHERE j @> '{"age":25}';
- count 
--------
-     2
-(1 row)
-
-SELECT count(*) FROM testjsonb WHERE j @> '{"age":25.0}';
- count 
--------
-     2
-(1 row)
-
-SELECT count(*) FROM testjsonb WHERE j @> '{"array":["foo"]}';
- count 
--------
-     3
-(1 row)
-
-SELECT count(*) FROM testjsonb WHERE j @> '{"array":["bar"]}';
- count 
--------
-     3
-(1 row)
-
--- exercise GIN_SEARCH_MODE_ALL
-SELECT count(*) FROM testjsonb WHERE j @> '{}';
- count 
--------
-  1012
-(1 row)
-
-SELECT count(*) FROM testjsonb WHERE j ? 'public';
- count 
--------
-   194
-(1 row)
-
-SELECT count(*) FROM testjsonb WHERE j ? 'bar';
- count 
--------
-     0
-(1 row)
-
-SELECT count(*) FROM testjsonb WHERE j ?| ARRAY['public','disabled'];
- count 
--------
-   337
-(1 row)
-
-SELECT count(*) FROM testjsonb WHERE j ?& ARRAY['public','disabled'];
- count 
--------
-    42
-(1 row)
-
--- array exists - array elements should behave as keys (for GIN index scans too)
-CREATE INDEX jidx_array ON testjsonb USING gin((j->'array'));
-SELECT count(*) from testjsonb  WHERE j->'array' ? 'bar';
- count 
--------
-     3
-(1 row)
-
--- type sensitive array exists - should return no rows (since "exists" only
--- matches strings that are either object keys or array elements)
-SELECT count(*) from testjsonb  WHERE j->'array' ? '5'::text;
- count 
--------
-     0
-(1 row)
-
--- However, a raw scalar is *contained* within the array
-SELECT count(*) from testjsonb  WHERE j->'array' @> '5'::jsonb;
- count 
--------
-     1
-(1 row)
-
-RESET enable_seqscan;
-SELECT count(*) FROM (SELECT (jsonb_each(j)).key FROM testjsonb) AS wow;
- count 
--------
-  4791
-(1 row)
-
-SELECT key, count(*) FROM (SELECT (jsonb_each(j)).key FROM testjsonb) AS wow GROUP BY key ORDER BY count DESC, key;
-    key    | count 
------------+-------
- line      |   884
- query     |   207
- pos       |   203
- node      |   202
- space     |   197
- status    |   195
- public    |   194
- title     |   190
- wait      |   190
- org       |   189
- user      |   189
- coauthors |   188
- disabled  |   185
- indexed   |   184
- cleaned   |   180
- bad       |   179
- date      |   179
- world     |   176
- state     |   172
- subtitle  |   169
- auth      |   168
- abstract  |   161
- array     |     5
- age       |     2
- foo       |     2
- fool      |     1
-(26 rows)
-
--- sort/hash
-SELECT count(distinct j) FROM testjsonb;
- count 
--------
-   894
-(1 row)
-
-SET enable_hashagg = off;
-SELECT count(*) FROM (SELECT j FROM (SELECT * FROM testjsonb UNION ALL SELECT * FROM testjsonb) js GROUP BY j) js2;
- count 
--------
-   894
-(1 row)
-
-SET enable_hashagg = on;
-SET enable_sort = off;
-SELECT count(*) FROM (SELECT j FROM (SELECT * FROM testjsonb UNION ALL SELECT * FROM testjsonb) js GROUP BY j) js2;
- count 
--------
-   894
-(1 row)
-
-SELECT distinct * FROM (values (jsonb '{}' || ''::text),('{}')) v(j);
- j  
-----
- {}
-(1 row)
-
-SET enable_sort = on;
-RESET enable_hashagg;
-RESET enable_sort;
-DROP INDEX jidx;
-DROP INDEX jidx_array;
--- btree
-CREATE INDEX jidx ON testjsonb USING btree (j);
-SET enable_seqscan = off;
-SELECT count(*) FROM testjsonb WHERE j > '{"p":1}';
- count 
--------
-   884
-(1 row)
-
-SELECT count(*) FROM testjsonb WHERE j = '{"pos":98, "line":371, "node":"CBA", "indexed":true}';
- count 
--------
-     1
-(1 row)
-
---gin path opclass
-DROP INDEX jidx;
-CREATE INDEX jidx ON testjsonb USING gin (j jsonb_path_ops);
-SET enable_seqscan = off;
-SELECT count(*) FROM testjsonb WHERE j @> '{"wait":null}';
- count 
--------
-     1
-(1 row)
-
-SELECT count(*) FROM testjsonb WHERE j @> '{"wait":"CC"}';
- count 
--------
-    15
-(1 row)
-
-SELECT count(*) FROM testjsonb WHERE j @> '{"wait":"CC", "public":true}';
- count 
--------
-     2
-(1 row)
-
-SELECT count(*) FROM testjsonb WHERE j @> '{"age":25}';
- count 
--------
-     2
-(1 row)
-
-SELECT count(*) FROM testjsonb WHERE j @> '{"age":25.0}';
- count 
--------
-     2
-(1 row)
-
--- exercise GIN_SEARCH_MODE_ALL
-SELECT count(*) FROM testjsonb WHERE j @> '{}';
- count 
--------
-  1012
-(1 row)
-
-RESET enable_seqscan;
-DROP INDEX jidx;
--- nested tests
-SELECT '{"ff":{"a":12,"b":16}}'::jsonb;
-           jsonb            
-----------------------------
- {"ff": {"a": 12, "b": 16}}
-(1 row)
-
-SELECT '{"ff":{"a":12,"b":16},"qq":123}'::jsonb;
-                 jsonb                 
----------------------------------------
- {"ff": {"a": 12, "b": 16}, "qq": 123}
-(1 row)
-
-SELECT '{"aa":["a","aaa"],"qq":{"a":12,"b":16,"c":["c1","c2"],"d":{"d1":"d1","d2":"d2","d1":"d3"}}}'::jsonb;
-                                              jsonb                                               
---------------------------------------------------------------------------------------------------
- {"aa": ["a", "aaa"], "qq": {"a": 12, "b": 16, "c": ["c1", "c2"], "d": {"d1": "d3", "d2": "d2"}}}
-(1 row)
-
-SELECT '{"aa":["a","aaa"],"qq":{"a":"12","b":"16","c":["c1","c2"],"d":{"d1":"d1","d2":"d2"}}}'::jsonb;
-                                                jsonb                                                 
-------------------------------------------------------------------------------------------------------
- {"aa": ["a", "aaa"], "qq": {"a": "12", "b": "16", "c": ["c1", "c2"], "d": {"d1": "d1", "d2": "d2"}}}
-(1 row)
-
-SELECT '{"aa":["a","aaa"],"qq":{"a":"12","b":"16","c":["c1","c2",["c3"],{"c4":4}],"d":{"d1":"d1","d2":"d2"}}}'::jsonb;
-                                                          jsonb                                                          
--------------------------------------------------------------------------------------------------------------------------
- {"aa": ["a", "aaa"], "qq": {"a": "12", "b": "16", "c": ["c1", "c2", ["c3"], {"c4": 4}], "d": {"d1": "d1", "d2": "d2"}}}
-(1 row)
-
-SELECT '{"ff":["a","aaa"]}'::jsonb;
-        jsonb         
-----------------------
- {"ff": ["a", "aaa"]}
-(1 row)
-
-SELECT
-  '{"ff":{"a":12,"b":16},"qq":123,"x":[1,2],"Y":null}'::jsonb -> 'ff',
-  '{"ff":{"a":12,"b":16},"qq":123,"x":[1,2],"Y":null}'::jsonb -> 'qq',
-  ('{"ff":{"a":12,"b":16},"qq":123,"x":[1,2],"Y":null}'::jsonb -> 'Y') IS NULL AS f,
-  ('{"ff":{"a":12,"b":16},"qq":123,"x":[1,2],"Y":null}'::jsonb ->> 'Y') IS NULL AS t,
-   '{"ff":{"a":12,"b":16},"qq":123,"x":[1,2],"Y":null}'::jsonb -> 'x';
-      ?column?      | ?column? | f | t | ?column? 
---------------------+----------+---+---+----------
- {"a": 12, "b": 16} | 123      | f | t | [1, 2]
-(1 row)
-
--- nested containment
-SELECT '{"a":[1,2],"c":"b"}'::jsonb @> '{"a":[1,2]}';
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '{"a":[2,1],"c":"b"}'::jsonb @> '{"a":[1,2]}';
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '{"a":{"1":2},"c":"b"}'::jsonb @> '{"a":[1,2]}';
- ?column? 
-----------
- f
-(1 row)
-
-SELECT '{"a":{"2":1},"c":"b"}'::jsonb @> '{"a":[1,2]}';
- ?column? 
-----------
- f
-(1 row)
-
-SELECT '{"a":{"1":2},"c":"b"}'::jsonb @> '{"a":{"1":2}}';
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '{"a":{"2":1},"c":"b"}'::jsonb @> '{"a":{"1":2}}';
- ?column? 
-----------
- f
-(1 row)
-
-SELECT '["a","b"]'::jsonb @> '["a","b","c","b"]';
- ?column? 
-----------
- f
-(1 row)
-
-SELECT '["a","b","c","b"]'::jsonb @> '["a","b"]';
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '["a","b","c",[1,2]]'::jsonb @> '["a",[1,2]]';
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '["a","b","c",[1,2]]'::jsonb @> '["b",[1,2]]';
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '{"a":[1,2],"c":"b"}'::jsonb @> '{"a":[1]}';
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '{"a":[1,2],"c":"b"}'::jsonb @> '{"a":[2]}';
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '{"a":[1,2],"c":"b"}'::jsonb @> '{"a":[3]}';
- ?column? 
-----------
- f
-(1 row)
-
-SELECT '{"a":[1,2,{"c":3,"x":4}],"c":"b"}'::jsonb @> '{"a":[{"c":3}]}';
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '{"a":[1,2,{"c":3,"x":4}],"c":"b"}'::jsonb @> '{"a":[{"x":4}]}';
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '{"a":[1,2,{"c":3,"x":4}],"c":"b"}'::jsonb @> '{"a":[{"x":4},3]}';
- ?column? 
-----------
- f
-(1 row)
-
-SELECT '{"a":[1,2,{"c":3,"x":4}],"c":"b"}'::jsonb @> '{"a":[{"x":4},1]}';
- ?column? 
-----------
- t
-(1 row)
-
--- nested object field / array index lookup
-SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb -> 'n';
- ?column? 
-----------
- null
-(1 row)
-
-SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb -> 'a';
- ?column? 
-----------
- 1
-(1 row)
-
-SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb -> 'b';
- ?column? 
-----------
- [1, 2]
-(1 row)
-
-SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb -> 'c';
- ?column? 
-----------
- {"1": 2}
-(1 row)
-
-SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb -> 'd';
-   ?column?    
----------------
- {"1": [2, 3]}
-(1 row)
-
-SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb -> 'd' -> '1';
- ?column? 
-----------
- [2, 3]
-(1 row)
-
-SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb -> 'e';
- ?column? 
-----------
-(1 row)
-
-SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb -> 0; --expecting error
- ?column? 
-----------
-(1 row)
-
-SELECT '["a","b","c",[1,2],null]'::jsonb -> 0;
- ?column? 
-----------
- "a"
-(1 row)
-
-SELECT '["a","b","c",[1,2],null]'::jsonb -> 1;
- ?column? 
-----------
- "b"
-(1 row)
-
-SELECT '["a","b","c",[1,2],null]'::jsonb -> 2;
- ?column? 
-----------
- "c"
-(1 row)
-
-SELECT '["a","b","c",[1,2],null]'::jsonb -> 3;
- ?column? 
-----------
- [1, 2]
-(1 row)
-
-SELECT '["a","b","c",[1,2],null]'::jsonb -> 3 -> 1;
- ?column? 
-----------
- 2
-(1 row)
-
-SELECT '["a","b","c",[1,2],null]'::jsonb -> 4;
- ?column? 
-----------
- null
-(1 row)
-
-SELECT '["a","b","c",[1,2],null]'::jsonb -> 5;
- ?column? 
-----------
-(1 row)
-
-SELECT '["a","b","c",[1,2],null]'::jsonb -> -1;
- ?column? 
-----------
- null
-(1 row)
-
-SELECT '["a","b","c",[1,2],null]'::jsonb -> -5;
- ?column? 
-----------
- "a"
-(1 row)
-
-SELECT '["a","b","c",[1,2],null]'::jsonb -> -6;
- ?column? 
-----------
-(1 row)
-
---nested path extraction
-SELECT '{"a":"b","c":[1,2,3]}'::jsonb #> '{0}';
- ?column? 
-----------
-(1 row)
-
-SELECT '{"a":"b","c":[1,2,3]}'::jsonb #> '{a}';
- ?column? 
-----------
- "b"
-(1 row)
-
-SELECT '{"a":"b","c":[1,2,3]}'::jsonb #> '{c}';
- ?column?  
------------
- [1, 2, 3]
-(1 row)
-
-SELECT '{"a":"b","c":[1,2,3]}'::jsonb #> '{c,0}';
- ?column? 
-----------
- 1
-(1 row)
-
-SELECT '{"a":"b","c":[1,2,3]}'::jsonb #> '{c,1}';
- ?column? 
-----------
- 2
-(1 row)
-
-SELECT '{"a":"b","c":[1,2,3]}'::jsonb #> '{c,2}';
- ?column? 
-----------
- 3
-(1 row)
-
-SELECT '{"a":"b","c":[1,2,3]}'::jsonb #> '{c,3}';
- ?column? 
-----------
-(1 row)
-
-SELECT '{"a":"b","c":[1,2,3]}'::jsonb #> '{c,-1}';
- ?column? 
-----------
- 3
-(1 row)
-
-SELECT '{"a":"b","c":[1,2,3]}'::jsonb #> '{c,-3}';
- ?column? 
-----------
- 1
-(1 row)
-
-SELECT '{"a":"b","c":[1,2,3]}'::jsonb #> '{c,-4}';
- ?column? 
-----------
-(1 row)
-
-SELECT '[0,1,2,[3,4],{"5":"five"}]'::jsonb #> '{0}';
- ?column? 
-----------
- 0
-(1 row)
-
-SELECT '[0,1,2,[3,4],{"5":"five"}]'::jsonb #> '{3}';
- ?column? 
-----------
- [3, 4]
-(1 row)
-
-SELECT '[0,1,2,[3,4],{"5":"five"}]'::jsonb #> '{4}';
-   ?column?    
----------------
- {"5": "five"}
-(1 row)
-
-SELECT '[0,1,2,[3,4],{"5":"five"}]'::jsonb #> '{4,5}';
- ?column? 
-----------
- "five"
-(1 row)
-
---nested exists
-SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb ? 'n';
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb ? 'a';
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb ? 'b';
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb ? 'c';
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb ? 'd';
- ?column? 
-----------
- t
-(1 row)
-
-SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb ? 'e';
- ?column? 
-----------
- f
-(1 row)
-
--- jsonb_strip_nulls
-select jsonb_strip_nulls(null);
- jsonb_strip_nulls 
--------------------
-(1 row)
-
-select jsonb_strip_nulls('1');
- jsonb_strip_nulls 
--------------------
- 1
-(1 row)
-
-select jsonb_strip_nulls('"a string"');
- jsonb_strip_nulls 
--------------------
- "a string"
-(1 row)
-
-select jsonb_strip_nulls('null');
- jsonb_strip_nulls 
--------------------
- null
-(1 row)
-
-select jsonb_strip_nulls('[1,2,null,3,4]');
- jsonb_strip_nulls  
---------------------
- [1, 2, null, 3, 4]
-(1 row)
-
-select jsonb_strip_nulls('{"a":1,"b":null,"c":[2,null,3],"d":{"e":4,"f":null}}');
-             jsonb_strip_nulls              
---------------------------------------------
- {"a": 1, "c": [2, null, 3], "d": {"e": 4}}
-(1 row)
-
-select jsonb_strip_nulls('[1,{"a":1,"b":null,"c":2},3]');
-    jsonb_strip_nulls     
---------------------------
- [1, {"a": 1, "c": 2}, 3]
-(1 row)
-
--- an empty object is not null and should not be stripped
-select jsonb_strip_nulls('{"a": {"b": null, "c": null}, "d": {} }');
- jsonb_strip_nulls  
---------------------
- {"a": {}, "d": {}}
-(1 row)
-
-select jsonb_pretty('{"a": "test", "b": [1, 2, 3], "c": "test3", "d":{"dd": "test4", "dd2":{"ddd": "test5"}}}');
-        jsonb_pretty        
-----------------------------
- {                         +
-     "a": "test",          +
-     "b": [                +
-         1,                +
-         2,                +
-         3                 +
-     ],                    +
-     "c": "test3",         +
-     "d": {                +
-         "dd": "test4",    +
-         "dd2": {          +
-             "ddd": "test5"+
-         }                 +
-     }                     +
- }
-(1 row)
-
-select jsonb_pretty('[{"f1":1,"f2":null},2,null,[[{"x":true},6,7],8],3]');
-       jsonb_pretty        
----------------------------
- [                        +
-     {                    +
-         "f1": 1,         +
-         "f2": null       +
-     },                   +
-     2,                   +
-     null,                +
-     [                    +
-         [                +
-             {            +
-                 "x": true+
-             },           +
-             6,           +
-             7            +
-         ],               +
-         8                +
-     ],                   +
-     3                    +
- ]
-(1 row)
-
-select jsonb_pretty('{"a":["b", "c"], "d": {"e":"f"}}');
-   jsonb_pretty   
-------------------
- {               +
-     "a": [      +
-         "b",    +
-         "c"     +
-     ],          +
-     "d": {      +
-         "e": "f"+
-     }           +
- }
-(1 row)
-
-select jsonb_concat('{"d": "test", "a": [1, 2]}', '{"g": "test2", "c": {"c1":1, "c2":2}}');
-                           jsonb_concat                            
--------------------------------------------------------------------
- {"a": [1, 2], "c": {"c1": 1, "c2": 2}, "d": "test", "g": "test2"}
-(1 row)
-
-select '{"aa":1 , "b":2, "cq":3}'::jsonb || '{"cq":"l", "b":"g", "fg":false}';
-                  ?column?                   
----------------------------------------------
- {"b": "g", "aa": 1, "cq": "l", "fg": false}
-(1 row)
-
-select '{"aa":1 , "b":2, "cq":3}'::jsonb || '{"aq":"l"}';
-               ?column?                
----------------------------------------
- {"b": 2, "aa": 1, "aq": "l", "cq": 3}
-(1 row)
-
-select '{"aa":1 , "b":2, "cq":3}'::jsonb || '{"aa":"l"}';
-           ?column?           
-------------------------------
- {"b": 2, "aa": "l", "cq": 3}
-(1 row)
-
-select '{"aa":1 , "b":2, "cq":3}'::jsonb || '{}';
-          ?column?          
-----------------------------
- {"b": 2, "aa": 1, "cq": 3}
-(1 row)
-
-select '["a", "b"]'::jsonb || '["c"]';
-    ?column?     
------------------
- ["a", "b", "c"]
-(1 row)
-
-select '["a", "b"]'::jsonb || '["c", "d"]';
-       ?column?       
-----------------------
- ["a", "b", "c", "d"]
-(1 row)
-
-select '["c"]' || '["a", "b"]'::jsonb;
-    ?column?     
------------------
- ["c", "a", "b"]
-(1 row)
-
-select '["a", "b"]'::jsonb || '"c"';
-    ?column?     
------------------
- ["a", "b", "c"]
-(1 row)
-
-select '"c"' || '["a", "b"]'::jsonb;
-    ?column?     
------------------
- ["c", "a", "b"]
-(1 row)
-
-select '[]'::jsonb || '["a"]'::jsonb;
- ?column? 
-----------
- ["a"]
-(1 row)
-
-select '[]'::jsonb || '"a"'::jsonb;
- ?column? 
-----------
- ["a"]
-(1 row)
-
-select '"b"'::jsonb || '"a"'::jsonb;
-  ?column?  
-------------
- ["b", "a"]
-(1 row)
-
-select '{}'::jsonb || '{"a":"b"}'::jsonb;
-  ?column?  
-------------
- {"a": "b"}
-(1 row)
-
-select '[]'::jsonb || '{"a":"b"}'::jsonb;
-   ?column?   
---------------
- [{"a": "b"}]
-(1 row)
-
-select '{"a":"b"}'::jsonb || '[]'::jsonb;
-   ?column?   
---------------
- [{"a": "b"}]
-(1 row)
-
-select '"a"'::jsonb || '{"a":1}';
-ERROR:  invalid concatenation of jsonb objects
-select '{"a":1}' || '"a"'::jsonb;
-ERROR:  invalid concatenation of jsonb objects
-select '["a", "b"]'::jsonb || '{"c":1}';
-       ?column?       
-----------------------
- ["a", "b", {"c": 1}]
-(1 row)
-
-select '{"c": 1}'::jsonb || '["a", "b"]';
-       ?column?       
-----------------------
- [{"c": 1}, "a", "b"]
-(1 row)
-
-select '{}'::jsonb || '{"cq":"l", "b":"g", "fg":false}';
-              ?column?              
-------------------------------------
- {"b": "g", "cq": "l", "fg": false}
-(1 row)
-
-select pg_column_size('{}'::jsonb || '{}'::jsonb) = pg_column_size('{}'::jsonb);
- ?column? 
-----------
- t
-(1 row)
-
-select pg_column_size('{"aa":1}'::jsonb || '{"b":2}'::jsonb) = pg_column_size('{"aa":1, "b":2}'::jsonb);
- ?column? 
-----------
- t
-(1 row)
-
-select pg_column_size('{"aa":1, "b":2}'::jsonb || '{}'::jsonb) = pg_column_size('{"aa":1, "b":2}'::jsonb);
- ?column? 
-----------
- t
-(1 row)
-
-select pg_column_size('{}'::jsonb || '{"aa":1, "b":2}'::jsonb) = pg_column_size('{"aa":1, "b":2}'::jsonb);
- ?column? 
-----------
- t
-(1 row)
-
-select jsonb_delete('{"a":1 , "b":2, "c":3}'::jsonb, 'a');
-   jsonb_delete   
-------------------
- {"b": 2, "c": 3}
-(1 row)
-
-select jsonb_delete('{"a":null , "b":2, "c":3}'::jsonb, 'a');
-   jsonb_delete   
-------------------
- {"b": 2, "c": 3}
-(1 row)
-
-select jsonb_delete('{"a":1 , "b":2, "c":3}'::jsonb, 'b');
-   jsonb_delete   
-------------------
- {"a": 1, "c": 3}
-(1 row)
-
-select jsonb_delete('{"a":1 , "b":2, "c":3}'::jsonb, 'c');
-   jsonb_delete   
-------------------
- {"a": 1, "b": 2}
-(1 row)
-
-select jsonb_delete('{"a":1 , "b":2, "c":3}'::jsonb, 'd');
-       jsonb_delete       
---------------------------
- {"a": 1, "b": 2, "c": 3}
-(1 row)
-
-select '{"a":1 , "b":2, "c":3}'::jsonb - 'a';
-     ?column?     
-------------------
- {"b": 2, "c": 3}
-(1 row)
-
-select '{"a":null , "b":2, "c":3}'::jsonb - 'a';
-     ?column?     
-------------------
- {"b": 2, "c": 3}
-(1 row)
-
-select '{"a":1 , "b":2, "c":3}'::jsonb - 'b';
-     ?column?     
-------------------
- {"a": 1, "c": 3}
-(1 row)
-
-select '{"a":1 , "b":2, "c":3}'::jsonb - 'c';
-     ?column?     
-------------------
- {"a": 1, "b": 2}
-(1 row)
-
-select '{"a":1 , "b":2, "c":3}'::jsonb - 'd';
-         ?column?         
---------------------------
- {"a": 1, "b": 2, "c": 3}
-(1 row)
-
-select pg_column_size('{"a":1 , "b":2, "c":3}'::jsonb - 'b') = pg_column_size('{"a":1, "b":2}'::jsonb);
- ?column? 
-----------
- t
-(1 row)
-
-select '["a","b","c"]'::jsonb - 3;
-    ?column?     
------------------
- ["a", "b", "c"]
-(1 row)
-
-select '["a","b","c"]'::jsonb - 2;
-  ?column?  
-------------
- ["a", "b"]
-(1 row)
-
-select '["a","b","c"]'::jsonb - 1;
-  ?column?  
-------------
- ["a", "c"]
-(1 row)
-
-select '["a","b","c"]'::jsonb - 0;
-  ?column?  
-------------
- ["b", "c"]
-(1 row)
-
-select '["a","b","c"]'::jsonb - -1;
-  ?column?  
-------------
- ["a", "b"]
-(1 row)
-
-select '["a","b","c"]'::jsonb - -2;
-  ?column?  
-------------
- ["a", "c"]
-(1 row)
-
-select '["a","b","c"]'::jsonb - -3;
-  ?column?  
-------------
- ["b", "c"]
-(1 row)
-
-select '["a","b","c"]'::jsonb - -4;
-    ?column?     
------------------
- ["a", "b", "c"]
-(1 row)
-
-select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb, '{n}', '[1,2,3]');
-                                jsonb_set                                 
---------------------------------------------------------------------------
- {"a": 1, "b": [1, 2], "c": {"1": 2}, "d": {"1": [2, 3]}, "n": [1, 2, 3]}
-(1 row)
-
-select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb, '{b,-1}', '[1,2,3]');
-                                  jsonb_set                                  
------------------------------------------------------------------------------
- {"a": 1, "b": [1, [1, 2, 3]], "c": {"1": 2}, "d": {"1": [2, 3]}, "n": null}
-(1 row)
-
-select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb, '{d,1,0}', '[1,2,3]');
-                                  jsonb_set                                  
------------------------------------------------------------------------------
- {"a": 1, "b": [1, 2], "c": {"1": 2}, "d": {"1": [[1, 2, 3], 3]}, "n": null}
-(1 row)
-
-select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb, '{d,NULL,0}', '[1,2,3]');
-ERROR:  path element at the position 2 is NULL
-select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb, '{n}', '{"1": 2}');
-                                jsonb_set                                
--------------------------------------------------------------------------
- {"a": 1, "b": [1, 2], "c": {"1": 2}, "d": {"1": [2, 3]}, "n": {"1": 2}}
-(1 row)
-
-select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb, '{b,-1}', '{"1": 2}');
-                                 jsonb_set                                  
-----------------------------------------------------------------------------
- {"a": 1, "b": [1, {"1": 2}], "c": {"1": 2}, "d": {"1": [2, 3]}, "n": null}
-(1 row)
-
-select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb, '{d,1,0}', '{"1": 2}');
-                                 jsonb_set                                  
-----------------------------------------------------------------------------
- {"a": 1, "b": [1, 2], "c": {"1": 2}, "d": {"1": [{"1": 2}, 3]}, "n": null}
-(1 row)
-
-select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb, '{d,NULL,0}', '{"1": 2}');
-ERROR:  path element at the position 2 is NULL
-select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb, '{b,-1}', '"test"');
-                                jsonb_set                                 
---------------------------------------------------------------------------
- {"a": 1, "b": [1, "test"], "c": {"1": 2}, "d": {"1": [2, 3]}, "n": null}
-(1 row)
-
-select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb, '{b,-1}', '{"f": "test"}');
-                                    jsonb_set                                    
----------------------------------------------------------------------------------
- {"a": 1, "b": [1, {"f": "test"}], "c": {"1": 2}, "d": {"1": [2, 3]}, "n": null}
-(1 row)
-
-select jsonb_delete_path('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}', '{n}');
-                    jsonb_delete_path                     
-----------------------------------------------------------
- {"a": 1, "b": [1, 2], "c": {"1": 2}, "d": {"1": [2, 3]}}
-(1 row)
-
-select jsonb_delete_path('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}', '{b,-1}');
-                        jsonb_delete_path                         
-------------------------------------------------------------------
- {"a": 1, "b": [1], "c": {"1": 2}, "d": {"1": [2, 3]}, "n": null}
-(1 row)
-
-select jsonb_delete_path('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}', '{d,1,0}');
-                        jsonb_delete_path                         
-------------------------------------------------------------------
- {"a": 1, "b": [1, 2], "c": {"1": 2}, "d": {"1": [3]}, "n": null}
-(1 row)
-
-select '{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb #- '{n}';
-                         ?column?                         
-----------------------------------------------------------
- {"a": 1, "b": [1, 2], "c": {"1": 2}, "d": {"1": [2, 3]}}
-(1 row)
-
-select '{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb #- '{b,-1}';
-                             ?column?                             
-------------------------------------------------------------------
- {"a": 1, "b": [1], "c": {"1": 2}, "d": {"1": [2, 3]}, "n": null}
-(1 row)
-
-select '{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb #- '{b,-1e}'; -- invalid array subscript
-ERROR:  path element at the position 2 is not an integer
-select '{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb #- '{d,1,0}';
-                             ?column?                             
-------------------------------------------------------------------
- {"a": 1, "b": [1, 2], "c": {"1": 2}, "d": {"1": [3]}, "n": null}
-(1 row)
-
--- empty structure and error conditions for delete and replace
-select '"a"'::jsonb - 'a'; -- error
-ERROR:  cannot delete from scalar
-select '{}'::jsonb - 'a';
- ?column? 
-----------
- {}
-(1 row)
-
-select '[]'::jsonb - 'a';
- ?column? 
-----------
- []
-(1 row)
-
-select '"a"'::jsonb - 1; -- error
-ERROR:  cannot delete from scalar
-select '{}'::jsonb -  1; -- error
-ERROR:  cannot delete from object using integer subscript
-select '[]'::jsonb - 1;
- ?column? 
-----------
- []
-(1 row)
-
-select '"a"'::jsonb #- '{a}'; -- error
-ERROR:  cannot delete path in scalar
-select '{}'::jsonb #- '{a}';
- ?column? 
-----------
- {}
-(1 row)
-
-select '[]'::jsonb #- '{a}';
- ?column? 
-----------
- []
-(1 row)
-
-select jsonb_set('"a"','{a}','"b"'); --error
-ERROR:  cannot set path in scalar
-select jsonb_set('{}','{a}','"b"', false);
- jsonb_set 
------------
- {}
-(1 row)
-
-select jsonb_set('[]','{1}','"b"', false);
- jsonb_set 
------------
- []
-(1 row)
-
--- jsonb_set adding instead of replacing
--- prepend to array
-select jsonb_set('{"a":1,"b":[0,1,2],"c":{"d":4}}','{b,-33}','{"foo":123}');
-                       jsonb_set                       
--------------------------------------------------------
- {"a": 1, "b": [{"foo": 123}, 0, 1, 2], "c": {"d": 4}}
-(1 row)
-
--- append to array
-select jsonb_set('{"a":1,"b":[0,1,2],"c":{"d":4}}','{b,33}','{"foo":123}');
-                       jsonb_set                       
--------------------------------------------------------
- {"a": 1, "b": [0, 1, 2, {"foo": 123}], "c": {"d": 4}}
-(1 row)
-
--- check nesting levels addition
-select jsonb_set('{"a":1,"b":[4,5,[0,1,2],6,7],"c":{"d":4}}','{b,2,33}','{"foo":123}');
-                              jsonb_set                              
----------------------------------------------------------------------
- {"a": 1, "b": [4, 5, [0, 1, 2, {"foo": 123}], 6, 7], "c": {"d": 4}}
-(1 row)
-
--- add new key
-select jsonb_set('{"a":1,"b":[0,1,2],"c":{"d":4}}','{c,e}','{"foo":123}');
-                         jsonb_set                          
-------------------------------------------------------------
- {"a": 1, "b": [0, 1, 2], "c": {"d": 4, "e": {"foo": 123}}}
-(1 row)
-
--- adding doesn't do anything if elements before last aren't present
-select jsonb_set('{"a":1,"b":[0,1,2],"c":{"d":4}}','{x,-33}','{"foo":123}');
-                jsonb_set                
------------------------------------------
- {"a": 1, "b": [0, 1, 2], "c": {"d": 4}}
-(1 row)
-
-select jsonb_set('{"a":1,"b":[0,1,2],"c":{"d":4}}','{x,y}','{"foo":123}');
-                jsonb_set                
------------------------------------------
- {"a": 1, "b": [0, 1, 2], "c": {"d": 4}}
-(1 row)
-
--- add to empty object
-select jsonb_set('{}','{x}','{"foo":123}');
-      jsonb_set      
----------------------
- {"x": {"foo": 123}}
-(1 row)
-
---add to empty array
-select jsonb_set('[]','{0}','{"foo":123}');
-   jsonb_set    
-----------------
- [{"foo": 123}]
-(1 row)
-
-select jsonb_set('[]','{99}','{"foo":123}');
-   jsonb_set    
-----------------
- [{"foo": 123}]
-(1 row)
-
-select jsonb_set('[]','{-99}','{"foo":123}');
-   jsonb_set    
-----------------
- [{"foo": 123}]
-(1 row)
-
-select jsonb_set('{"a": [1, 2, 3]}', '{a, non_integer}', '"new_value"');
-ERROR:  path element at the position 2 is not an integer
-select jsonb_set('{"a": {"b": [1, 2, 3]}}', '{a, b, non_integer}', '"new_value"');
-ERROR:  path element at the position 3 is not an integer
-select jsonb_set('{"a": {"b": [1, 2, 3]}}', '{a, b, NULL}', '"new_value"');
-ERROR:  path element at the position 3 is NULL
index 6fc5d1e632d79f4a190c994b54f145ea32966efa..c63abf4b0ad57cd5f1a6c7027fc118005b5d4b2e 100644 (file)
@@ -97,7 +97,7 @@ test: rules
 # ----------
 # 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 jsonb indirect_toast equivclass
+test: select_views portals_p2 foreign_key cluster dependency guc bitmapops combocid tsearch tsdicts foreign_data window xmlmap functional_deps advisory_lock json jsonb json_encoding indirect_toast equivclass
 # ----------
 # Another group of parallel tests
 # NB: temp.sql does a reconnect which transiently uses 2 connections,
index 2ae51cf078ee0ae77a819b610d4a4493f515c697..88dcd64dfce3b2e82bf07bf813bfc1404538e12b 100644 (file)
@@ -135,6 +135,7 @@ test: functional_deps
 test: advisory_lock
 test: json
 test: jsonb
+test: json_encoding
 test: indirect_toast
 test: equivclass
 test: plancache
index da1ecbed4c42734984d29d0ed1bf62cc04396a21..78038863389bb69bf5f10aa918603beb73124232 100644 (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
@@ -405,28 +401,6 @@ select * from json_populate_recordset(null::jpop,'[{"a":"blurfl","x":43.2},{"b":
 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;
 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;
 
--- 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" }' as correct_in_utf8;
-select json '{ "a":  "dollar \u0024 character" }' as correct_everywhere;
-select json '{ "a":  "dollar \\u0024 character" }' as not_an_escape;
-select json '{ "a":  "null \u0000 escape" }' as not_unescaped;
-select json '{ "a":  "null \\u0000 escape" }' as not_an_escape;
-
-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":  "dollar \\u0024 character" }' ->> 'a' as not_an_escape;
-select json '{ "a":  "null \u0000 escape" }' ->> 'a' as fails;
-select json '{ "a":  "null \\u0000 escape" }' ->> 'a' as not_an_escape;
-
 --json_typeof() function
 select value, json_typeof(value)
   from (values (json '123.4'),
diff --git a/src/test/regress/sql/json_encoding.sql b/src/test/regress/sql/json_encoding.sql
new file mode 100644 (file)
index 0000000..47536fb
--- /dev/null
@@ -0,0 +1,68 @@
+
+-- encoding-sensitive tests for json and jsonb
+
+-- first 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" }' as correct_in_utf8;
+select json '{ "a":  "dollar \u0024 character" }' as correct_everywhere;
+select json '{ "a":  "dollar \\u0024 character" }' as not_an_escape;
+select json '{ "a":  "null \u0000 escape" }' as not_unescaped;
+select json '{ "a":  "null \\u0000 escape" }' as not_an_escape;
+
+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":  "dollar \\u0024 character" }' ->> 'a' as not_an_escape;
+select json '{ "a":  "null \u0000 escape" }' ->> 'a' as fails;
+select json '{ "a":  "null \\u0000 escape" }' ->> 'a' as not_an_escape;
+
+-- then jsonb
+
+-- basic unicode input
+SELECT '"\u"'::jsonb;                  -- ERROR, incomplete escape
+SELECT '"\u00"'::jsonb;                        -- ERROR, incomplete escape
+SELECT '"\u000g"'::jsonb;              -- ERROR, g is not a hex digit
+SELECT '"\u0045"'::jsonb;              -- OK, legal escape
+SELECT '"\u0000"'::jsonb;              -- ERROR, we don't support U+0000
+-- use octet_length here so we don't get an odd unicode char in the
+-- output
+SELECT octet_length('"\uaBcD"'::jsonb::text); -- OK, uppercase and lower case both OK
+
+-- handling of unicode surrogate pairs
+
+SELECT octet_length((jsonb '{ "a":  "\ud83d\ude04\ud83d\udc36" }' -> 'a')::text) AS correct_in_utf8;
+SELECT jsonb '{ "a":  "\ud83d\ud83d" }' -> 'a'; -- 2 high surrogates in a row
+SELECT jsonb '{ "a":  "\ude04\ud83d" }' -> 'a'; -- surrogates in wrong order
+SELECT jsonb '{ "a":  "\ud83dX" }' -> 'a'; -- orphan high surrogate
+SELECT jsonb '{ "a":  "\ude04X" }' -> 'a'; -- orphan low surrogate
+
+-- handling of simple unicode escapes
+
+SELECT jsonb '{ "a":  "the Copyright \u00a9 sign" }' as correct_in_utf8;
+SELECT jsonb '{ "a":  "dollar \u0024 character" }' as correct_everywhere;
+SELECT jsonb '{ "a":  "dollar \\u0024 character" }' as not_an_escape;
+SELECT jsonb '{ "a":  "null \u0000 escape" }' as fails;
+SELECT jsonb '{ "a":  "null \\u0000 escape" }' as not_an_escape;
+
+SELECT jsonb '{ "a":  "the Copyright \u00a9 sign" }' ->> 'a' as correct_in_utf8;
+SELECT jsonb '{ "a":  "dollar \u0024 character" }' ->> 'a' as correct_everywhere;
+SELECT jsonb '{ "a":  "dollar \\u0024 character" }' ->> 'a' as not_an_escape;
+SELECT jsonb '{ "a":  "null \u0000 escape" }' ->> 'a' as fails;
+SELECT jsonb '{ "a":  "null \\u0000 escape" }' ->> 'a' as not_an_escape;
+
index 25b5504face6a7c8019c05db1197cf49325011cf..9700b7ca7e0e7bd3aa3a7626ff857d2355d3e9fd 100644 (file)
@@ -7,14 +7,7 @@ SELECT '"abc
 def"'::jsonb;                                  -- ERROR, unescaped newline in string constant
 SELECT '"\n\"\\"'::jsonb;              -- OK, legal escapes
 SELECT '"\v"'::jsonb;                  -- ERROR, not a valid JSON escape
-SELECT '"\u"'::jsonb;                  -- ERROR, incomplete escape
-SELECT '"\u00"'::jsonb;                        -- ERROR, incomplete escape
-SELECT '"\u000g"'::jsonb;              -- ERROR, g is not a hex digit
-SELECT '"\u0045"'::jsonb;              -- OK, legal escape
-SELECT '"\u0000"'::jsonb;              -- ERROR, we don't support U+0000
--- use octet_length here so we don't get an odd unicode char in the
--- output
-SELECT octet_length('"\uaBcD"'::jsonb::text); -- OK, uppercase and lower case both OK
+-- see json_encoding test for input with unicode escapes
 
 -- Numbers.
 SELECT '1'::jsonb;                             -- OK
@@ -494,28 +487,6 @@ SELECT * FROM jsonb_populate_recordset(NULL::jbpop,'[{"a":"blurfl","x":43.2},{"b
 SELECT * FROM jsonb_populate_recordset(row('def',99,NULL)::jbpop,'[{"a":"blurfl","x":43.2},{"b":3,"c":"2012-01-20 10:42:53"}]') q;
 SELECT * FROM jsonb_populate_recordset(row('def',99,NULL)::jbpop,'[{"a":[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 octet_length((jsonb '{ "a":  "\ud83d\ude04\ud83d\udc36" }' -> 'a')::text) AS correct_in_utf8;
-SELECT jsonb '{ "a":  "\ud83d\ud83d" }' -> 'a'; -- 2 high surrogates in a row
-SELECT jsonb '{ "a":  "\ude04\ud83d" }' -> 'a'; -- surrogates in wrong order
-SELECT jsonb '{ "a":  "\ud83dX" }' -> 'a'; -- orphan high surrogate
-SELECT jsonb '{ "a":  "\ude04X" }' -> 'a'; -- orphan low surrogate
-
--- handling of simple unicode escapes
-
-SELECT jsonb '{ "a":  "the Copyright \u00a9 sign" }' as correct_in_utf8;
-SELECT jsonb '{ "a":  "dollar \u0024 character" }' as correct_everywhere;
-SELECT jsonb '{ "a":  "dollar \\u0024 character" }' as not_an_escape;
-SELECT jsonb '{ "a":  "null \u0000 escape" }' as fails;
-SELECT jsonb '{ "a":  "null \\u0000 escape" }' as not_an_escape;
-
-SELECT jsonb '{ "a":  "the Copyright \u00a9 sign" }' ->> 'a' as correct_in_utf8;
-SELECT jsonb '{ "a":  "dollar \u0024 character" }' ->> 'a' as correct_everywhere;
-SELECT jsonb '{ "a":  "dollar \\u0024 character" }' ->> 'a' as not_an_escape;
-SELECT jsonb '{ "a":  "null \u0000 escape" }' ->> 'a' as fails;
-SELECT jsonb '{ "a":  "null \\u0000 escape" }' ->> 'a' as not_an_escape;
-
 -- jsonb_to_record and jsonb_to_recordset
 
 select * from jsonb_to_record('{"a":1,"b":"foo","c":"bar"}')