summaryrefslogtreecommitdiff
path: root/src/test/regress
diff options
context:
space:
mode:
authorAndrew Dunstan2014-03-23 20:40:19 +0000
committerAndrew Dunstan2014-03-23 20:40:19 +0000
commitd9134d0a355cfa447adc80db4505d5931084278a (patch)
treecefe155d0f0f71b9279444a86eab4b1b1facafdb /src/test/regress
parentb2b2491b06074e68fc7c96148cb0fdf0c8eb0469 (diff)
Introduce jsonb, a structured format for storing json.
The new format accepts exactly the same data as the json type. However, it is stored in a format that does not require reparsing the orgiginal text in order to process it, making it much more suitable for indexing and other operations. Insignificant whitespace is discarded, and the order of object keys is not preserved. Neither are duplicate object keys kept - the later value for a given key is the only one stored. The new type has all the functions and operators that the json type has, with the exception of the json generation functions (to_json, json_agg etc.) and with identical semantics. In addition, there are operator classes for hash and btree indexing, and two classes for GIN indexing, that have no equivalent in the json type. This feature grew out of previous work by Oleg Bartunov and Teodor Sigaev, which was intended to provide similar facilities to a nested hstore type, but which in the end proved to have some significant compatibility issues. Authors: Oleg Bartunov, Teodor Sigaev, Peter Geoghegan and Andrew Dunstan. Review: Andres Freund
Diffstat (limited to 'src/test/regress')
-rw-r--r--src/test/regress/data/jsonb.data1009
-rw-r--r--src/test/regress/expected/json.out49
-rw-r--r--src/test/regress/expected/json_1.out49
-rw-r--r--src/test/regress/expected/jsonb.out2056
-rw-r--r--src/test/regress/expected/jsonb_1.out2056
-rw-r--r--src/test/regress/expected/opr_sanity.out6
-rw-r--r--src/test/regress/parallel_schedule3
-rw-r--r--src/test/regress/serial_schedule1
-rw-r--r--src/test/regress/sql/json.sql18
-rw-r--r--src/test/regress/sql/jsonb.sql479
10 files changed, 5715 insertions, 11 deletions
diff --git a/src/test/regress/data/jsonb.data b/src/test/regress/data/jsonb.data
new file mode 100644
index 00000000000..1352ebe3ac7
--- /dev/null
+++ b/src/test/regress/data/jsonb.data
@@ -0,0 +1,1009 @@
+{"line":1, "date":"CB", "node":"AA"}
+{"cleaned":false, "status":59, "line":2, "disabled":false, "node":"CBB"}
+{"indexed":true, "status":35, "line":3, "disabled":false, "wait":"CAA", "subtitle":"BA", "user":"CCA"}
+{"line":4, "disabled":true, "space":"BB"}
+{"cleaned":false, "line":5, "wait":"BB", "query":"CAC", "coauthors":"ACA", "node":"CBA"}
+{"world":"CB", "query":"CBC", "indexed":false, "line":6, "pos":92, "date":"AAB", "space":"CB", "coauthors":"ACA", "node":"CBC"}
+{"state":98, "org":43, "line":7, "pos":97}
+{"auth":"BB", "title":"CAC", "query":"BA", "status":94, "line":8, "coauthors":"BBB"}
+{"auth":"BAC", "title":"CAA", "wait":"CA", "bad":true, "query":"AA", "indexed":true, "line":9, "pos":56}
+{"title":"AAC", "bad":true, "user":"AAB", "query":"AC", "line":10, "node":"AB"}
+{"world":"CAC", "user":"AB", "query":"ACA", "indexed":true, "line":11, "space":"CB"}
+{"line":12, "pos":72, "abstract":"BBA", "space":"AAC"}
+{}
+{"world":"CC", "query":"AA", "line":14, "disabled":false, "date":"CAC", "coauthors":"AB"}
+{"org":68, "title":"BBB", "query":"BAC", "line":15, "public":false}
+{"org":73, "user":"AA", "indexed":true, "line":16, "date":"CCC", "public":true, "coauthors":"AB"}
+{"indexed":false, "line":17}
+{"state":23, "auth":"BCC", "org":38, "status":28, "line":18, "disabled":false, "abstract":"CB"}
+{"state":99, "auth":"CA", "indexed":true, "line":19, "date":"BA"}
+{"wait":"CBA", "user":"BBA", "indexed":true, "line":20, "disabled":false, "abstract":"BA", "date":"ABA"}
+{"org":10, "query":"AC", "indexed":false, "line":21, "disabled":true, "abstract":"CA", "pos":44}
+{"state":65, "title":"AC", "user":"AAC", "cleaned":true, "status":93, "line":22, "abstract":"ABC", "node":"CCC"}
+{"subtitle":"AC", "user":"CCC", "line":23}
+{"state":67, "world":"ACB", "bad":true, "user":"CB", "line":24, "disabled":true}
+{}
+{"state":65, "title":"CBC", "wait":"AAC", "bad":true, "query":"ACA", "line":26, "disabled":false, "space":"CA"}
+{"auth":"BAA", "state":68, "indexed":true, "line":27, "space":"BA"}
+{"indexed":false, "line":28, "disabled":true, "space":"CC", "node":"BB"}
+{"auth":"BAB", "org":80, "title":"BBA", "query":"BBC", "status":3, "line":29}
+{"title":"AC", "status":16, "cleaned":true, "line":30}
+{"state":39, "world":"AAB", "user":"BB", "line":31, "disabled":true}
+{"wait":"BC", "bad":false, "query":"AA", "line":32, "coauthors":"CAC"}
+{"line":33, "pos":97}
+{"title":"AA", "world":"CCA", "wait":"CC", "bad":true, "status":86, "line":34, "disabled":true, "node":"ACA"}
+{}
+{"world":"BCC", "title":"ACB", "org":61, "status":99, "cleaned":true, "line":36, "pos":76, "space":"ACC", "coauthors":"AA", "node":"CB"}
+{"title":"CAA", "cleaned":false, "line":37, "abstract":"ACA", "node":"BC"}
+{"auth":"BC", "title":"BA", "world":"ACA", "indexed":true, "line":38, "abstract":"AAA", "public":true}
+{"org":90, "line":39, "public":false}
+{"state":16, "indexed":true, "line":40, "pos":53}
+{"auth":"AAB", "wait":"CAC", "status":44, "line":41}
+{"subtitle":"ACA", "bad":true, "line":42}
+{"org":19, "world":"BC", "user":"ABA", "indexed":false, "line":43, "disabled":true, "pos":48, "abstract":"CAB", "space":"CCB"}
+{"indexed":false, "line":44}
+{"indexed":true, "line":45}
+{"status":84, "line":46, "date":"CCC"}
+{"state":94, "title":"BAB", "bad":true, "user":"BBB", "indexed":true, "line":47, "public":false}
+{"org":90, "subtitle":"BAC", "query":"CAC", "cleaned":false, "line":48, "disabled":true, "abstract":"CC", "pos":17, "space":"BCA"}
+{"world":"CBC", "line":49}
+{"org":24, "line":50, "date":"CA", "public":false}
+{"world":"BC", "indexed":true, "status":44, "line":51, "pos":59, "date":"BA", "public":true}
+{"org":98, "line":52}
+{"title":"CA", "world":"ABC", "subtitle":"CBB", "line":53, "abstract":"BBA", "date":"ACB", "node":"CA"}
+{"user":"BAB", "cleaned":true, "line":54}
+{"subtitle":"CAA", "line":55, "disabled":false, "pos":55, "abstract":"AB", "public":false, "coauthors":"AA"}
+{"wait":"CC", "user":"CC", "cleaned":true, "line":56, "pos":73, "node":"ABC"}
+{"title":"BCC", "wait":"ABC", "indexed":true, "line":57, "disabled":false}
+{"org":42, "title":"BB", "line":58, "disabled":true, "public":true, "coauthors":"BCC"}
+{"wait":"CAB", "title":"CCB", "query":"BAC", "status":66, "line":59, "disabled":true}
+{"user":"CAC", "line":60}
+{"user":"BBB", "line":61, "disabled":false, "pos":31}
+{"org":18, "line":62, "coauthors":"CCC", "node":"CA"}
+{"line":63, "coauthors":"AB"}
+{"org":25, "wait":"CA", "line":64, "abstract":"BA", "date":"BBB"}
+{"title":"CB", "wait":"CC", "bad":false, "user":"BBB", "line":65, "abstract":"ACA", "public":true}
+{"line":66, "coauthors":"AC"}
+{"state":20, "wait":"CCB", "bad":true, "line":67, "abstract":"CB"}
+{"state":79, "wait":"BAC", "bad":false, "status":11, "line":68, "abstract":"BC", "public":true, "coauthors":"CBA"}
+{"state":39, "title":"CCA", "bad":false, "query":"BBA", "line":69, "pos":42, "public":false}
+{"title":"BC", "subtitle":"CA", "query":"BC", "line":70}
+{}
+{"bad":true, "query":"BBB", "line":72}
+{"state":35, "world":"CC", "bad":false, "line":73, "space":"BB", "public":false}
+{"title":"ACC", "wait":"CAB", "subtitle":"CB", "status":19, "line":74, "disabled":false, "space":"BAA", "coauthors":"CBC", "node":"AC"}
+{"subtitle":"BCB", "indexed":false, "status":83, "line":75, "public":true}
+{"state":32, "line":76, "disabled":false, "pos":66, "space":"CC"}
+{"state":43, "cleaned":true, "line":77}
+{}
+{"state":97, "wait":"CBA", "indexed":false, "cleaned":false, "line":79, "abstract":"CB", "date":"ACC", "public":false}
+{"user":"AAB", "line":80, "pos":85, "date":"AC"}
+{"world":"AC", "wait":"CC", "subtitle":"AAB", "bad":false, "cleaned":false, "line":81, "pos":91, "node":"CCC"}
+{}
+{"org":87, "bad":false, "user":"AAC", "query":"CCC", "line":83, "disabled":false, "abstract":"AC", "date":"CCA", "public":false}
+{"state":50, "line":84}
+{"wait":"AA", "subtitle":"AA", "query":"BB", "status":97, "line":85, "disabled":true, "abstract":"CB"}
+{}
+{"subtitle":"CA", "query":"BC", "line":87}
+{}
+{"title":"CC", "line":89, "disabled":false, "pos":49, "date":"CCB", "space":"CB", "node":"BB"}
+{"auth":"CC", "wait":"AA", "title":"BC", "bad":true, "line":90}
+{"state":37, "org":85, "indexed":false, "line":91, "space":"CAA", "public":true, "coauthors":"BA"}
+{"wait":"BBB", "title":"BBC", "org":95, "subtitle":"AC", "line":92, "pos":23, "date":"AC", "public":true, "space":"BBC"}
+{"org":48, "user":"AC", "line":93, "space":"CCC"}
+{}
+{"state":77, "wait":"ABA", "subtitle":"AC", "user":"BA", "status":43, "line":95, "public":false}
+{"title":"CA", "indexed":true, "status":26, "line":96}
+{"auth":"BCA", "subtitle":"ACC", "user":"CA", "line":97, "disabled":false, "node":"ACB"}
+{"query":"BB", "line":98, "coauthors":"AB"}
+{}
+{"auth":"AA", "title":"ACB", "org":58, "subtitle":"AC", "bad":false, "cleaned":false, "line":100, "space":"ACC", "public":true}
+{"subtitle":"AAB", "bad":false, "line":101, "public":true}
+{"subtitle":"AAA", "indexed":false, "cleaned":false, "line":102, "disabled":true, "pos":35}
+{}
+{"world":"CAC", "org":10, "query":"AAA", "cleaned":true, "status":79, "indexed":true, "line":104, "pos":65, "public":false, "node":"BAB"}
+{"bad":false, "line":105, "abstract":"BA", "node":"CBB"}
+{"world":"BB", "wait":"BAA", "title":"ACA", "line":106, "date":"CBC", "space":"BA"}
+{"state":92, "wait":"CAC", "title":"AAA", "bad":false, "line":107, "abstract":"CBC", "date":"BCC", "public":false}
+{"title":"CCC", "indexed":true, "line":108, "abstract":"ACB", "public":false, "coauthors":"ABB"}
+{"auth":"BB", "query":"ACC", "status":68, "line":109}
+{"user":"CC", "cleaned":false, "indexed":true, "line":110, "date":"BAA", "space":"BCB"}
+{"auth":"CC", "org":4, "wait":"BAC", "bad":false, "indexed":false, "line":111, "pos":55, "node":"BBC"}
+{"line":112, "disabled":true}
+{"org":66, "cleaned":true, "indexed":false, "line":113, "pos":96}
+{"world":"CA", "title":"ACA", "org":83, "query":"BAC", "user":"BBC", "indexed":false, "line":114}
+{"subtitle":"BCC", "line":115, "space":"AA", "public":true, "node":"CBA"}
+{"state":77, "status":23, "line":116}
+{"bad":false, "status":4, "line":117, "node":"CC"}
+{"state":99, "title":"BCC", "query":"AC", "status":98, "line":118, "date":"BA"}
+{"status":55, "line":119, "public":false, "coauthors":"BBA", "node":"BCA"}
+{"query":"CAA", "status":40, "indexed":false, "line":120, "disabled":false, "coauthors":"CA"}
+{"title":"BBC", "org":82, "subtitle":"ACB", "line":121, "abstract":"BB", "node":"CC"}
+{"state":66, "world":"AB", "subtitle":"BA", "query":"CB", "line":122, "abstract":"BBC", "pos":65, "date":"BAB"}
+{"state":96, "title":"CBC", "status":44, "line":123, "abstract":"BA", "space":"ACA", "node":"AAC"}
+{"auth":"CA", "state":59, "bad":false, "cleaned":false, "line":124, "pos":41, "date":"BBA", "coauthors":"ABB"}
+{"wait":"ACC", "line":125}
+{"org":30, "wait":"CBB", "subtitle":"CCA", "cleaned":true, "line":126, "date":"AC", "node":"ABC"}
+{}
+{"auth":"BBA", "org":66, "subtitle":"CCB", "bad":true, "cleaned":false, "line":128, "abstract":"BB", "public":true, "coauthors":"BA"}
+{"subtitle":"AC", "bad":false, "user":"BAA", "line":129, "date":"BCB", "node":"BAC"}
+{"wait":"CC", "subtitle":"CA", "line":130, "disabled":false, "pos":49, "node":"BA"}
+{"indexed":false, "line":131, "pos":79, "date":"AAA", "node":"CAC"}
+{"wait":"AC", "world":"CB", "title":"AAA", "user":"ABC", "indexed":false, "status":15, "line":132, "coauthors":"BA"}
+{"state":96, "bad":true, "line":133, "disabled":false, "space":"BAC", "coauthors":"ABA"}
+{"world":"BAC", "line":134}
+{"title":"CCC", "line":135, "coauthors":"CC"}
+{"cleaned":true, "line":136}
+{"bad":true, "query":"CCA", "user":"CA", "cleaned":false, "line":137, "disabled":true}
+{}
+{"world":"CC", "subtitle":"BBB", "line":139}
+{"wait":"CA", "status":2, "line":140}
+{"world":"BC", "bad":false, "user":"BBC", "query":"ACB", "line":141, "pos":33, "space":"ACA"}
+{"state":92, "title":"CA", "bad":true, "query":"AB", "line":142, "abstract":"BA", "date":"ABB", "space":"BC", "coauthors":"CAA"}
+{"state":79, "query":"AB", "user":"CCA", "indexed":true, "cleaned":true, "line":143, "public":true}
+{"org":37, "query":"CA", "cleaned":true, "line":144, "disabled":true, "date":"CC"}
+{"wait":"AC", "title":"CBA", "user":"AAA", "status":24, "line":145, "date":"CBC", "public":false, "coauthors":"BAC", "node":"ACC"}
+{"user":"CA", "indexed":true, "line":146, "disabled":false, "coauthors":"BA"}
+{"wait":"BC", "org":35, "bad":false, "query":"CBB", "line":147, "date":"AAA", "public":false, "space":"BBB"}
+{"org":56, "user":"AB", "indexed":true, "line":148}
+{}
+{"title":"CBB", "org":78, "subtitle":"CBA", "bad":true, "user":"AAB", "line":150, "disabled":true, "abstract":"BAC"}
+{"world":"CCA", "query":"BC", "cleaned":true, "indexed":false, "line":151, "abstract":"BC", "pos":43, "coauthors":"AB", "node":"CBA"}
+{"auth":"ABA", "status":13, "line":152, "date":"AA"}
+{"world":"CA", "line":153, "space":"CBC"}
+{"world":"BA", "user":"BBB", "status":72, "line":154}
+{"auth":"ABB", "line":155, "disabled":true, "node":"BBC"}
+{"world":"BBB", "bad":false, "line":156, "abstract":"CBC"}
+{"line":157, "pos":60, "node":"ACC"}
+{"line":158, "node":"CC"}
+{"line":159, "public":true}
+{}
+{"query":"BA", "status":53, "cleaned":false, "line":161, "public":true}
+{"line":162, "date":"CC"}
+{}
+{"title":"BC", "bad":false, "query":"CC", "line":164, "abstract":"CCB", "date":"BA"}
+{"status":36, "line":165}
+{"title":"AB", "bad":false, "status":64, "line":166, "abstract":"AB", "coauthors":"AA", "node":"AA"}
+{"wait":"AA", "line":167}
+{"subtitle":"CBC", "user":"AC", "cleaned":false, "line":168, "disabled":true, "coauthors":"BAB", "node":"CC"}
+{"state":34, "status":73, "cleaned":true, "line":169, "abstract":"BC", "public":false, "space":"BBC", "node":"BAA"}
+{"state":10, "auth":"BBB", "bad":true, "indexed":false, "status":34, "line":170, "abstract":"BC"}
+{"subtitle":"AAA", "bad":false, "user":"ACA", "status":53, "line":171, "disabled":false, "date":"AAA"}
+{"subtitle":"CB", "query":"CC", "indexed":true, "line":172, "node":"BBC"}
+{"state":5, "world":"ABC", "bad":false, "line":173, "public":false}
+{"subtitle":"AC", "line":174}
+{"auth":"AC", "org":72, "query":"CA", "indexed":false, "cleaned":true, "line":175, "disabled":true, "pos":54}
+{"title":"BCB", "bad":false, "line":176, "pos":35, "coauthors":"AAC", "node":"ABB"}
+{"title":"BB", "cleaned":true, "status":26, "line":177}
+{"state":61, "wait":"BB", "world":"CB", "query":"BAB", "line":178, "abstract":"BB", "date":"CBB", "space":"CA", "node":"AB"}
+{"wait":"CA", "cleaned":false, "indexed":true, "line":179, "space":"CBC"}
+{"org":68, "line":180}
+{"wait":"ABB", "subtitle":"CCC", "cleaned":true, "line":181, "abstract":"BC", "coauthors":"BA"}
+{"title":"ACA", "subtitle":"AAB", "line":182, "node":"BAC"}
+{}
+{}
+{"subtitle":"BA", "query":"BBB", "indexed":true, "cleaned":true, "line":185, "node":"BCC"}
+{"org":6, "title":"BCC", "user":"BA", "line":186, "pos":67, "abstract":"CBA", "coauthors":"CBB", "node":"CBC"}
+{"org":50, "title":"CAB", "subtitle":"CB", "query":"CBB", "line":187, "coauthors":"CA", "node":"CC"}
+{"bad":false, "line":188, "node":"CCB"}
+{"org":4, "world":"AAC", "query":"CAC", "line":189, "pos":90, "node":"AC"}
+{"state":86, "line":190, "pos":79}
+{"org":98, "title":"AAC", "cleaned":true, "line":191, "space":"BC", "coauthors":"AA"}
+{"wait":"CAA", "bad":false, "user":"BC", "status":23, "line":192, "disabled":true, "date":"CA", "coauthors":"BBB"}
+{"status":26, "line":193, "disabled":true}
+{"world":"CA", "subtitle":"CCC", "query":"ABB", "status":86, "line":194, "pos":97, "space":"CAC"}
+{"cleaned":true, "line":195}
+{"state":53, "org":84, "wait":"BC", "query":"BCC", "line":196, "disabled":true, "abstract":"AAC", "node":"CAC"}
+{"state":25, "status":70, "cleaned":false, "line":197, "disabled":true, "space":"AA", "public":false}
+{"org":82, "subtitle":"AAC", "line":198}
+{"org":87, "bad":true, "status":69, "line":199, "public":false}
+{"wait":"CC", "org":60, "subtitle":"BCA", "bad":true, "cleaned":false, "indexed":true, "line":200, "date":"BA"}
+{"state":9, "world":"CAA", "org":78, "user":"ACB", "cleaned":true, "line":201, "disabled":true, "abstract":"ACC", "public":false}
+{"state":50, "world":"AAA", "title":"CAA", "user":"AB", "status":37, "line":202, "disabled":false}
+{"org":36, "subtitle":"CB", "query":"BAA", "status":35, "line":203, "abstract":"CC"}
+{"auth":"CCC", "bad":true, "query":"CB", "status":84, "line":204, "disabled":false, "date":"BB"}
+{"auth":"AC", "query":"BA", "indexed":false, "line":205, "date":"AAB", "space":"ABB"}
+{"state":30, "world":"CCA", "query":"CC", "user":"BAA", "line":206}
+{"title":"CAB", "wait":"BAB", "bad":true, "query":"BCB", "indexed":true, "status":48, "cleaned":true, "line":207, "node":"ACB"}
+{"state":97, "subtitle":"BC", "status":99, "line":208, "abstract":"CB"}
+{"title":"CA", "world":"BBA", "bad":true, "indexed":false, "cleaned":false, "status":82, "line":209, "disabled":false, "pos":44, "space":"ACA"}
+{"line":210, "public":true}
+{"line":211, "space":"BBC", "node":"AAA"}
+{"wait":"BAA", "org":50, "line":212, "abstract":"BB", "public":true, "space":"AB"}
+{"line":213, "pos":57, "date":"CC", "space":"AC"}
+{"state":23, "user":"BAB", "query":"BCB", "line":214, "abstract":"BAB"}
+{"world":"ACB", "org":21, "line":215, "abstract":"AC", "public":false}
+{"state":14, "wait":"ACB", "org":79, "title":"BB", "subtitle":"BA", "line":216}
+{"wait":"BC", "line":217, "date":"BB"}
+{"wait":"AC", "user":"BB", "indexed":false, "status":83, "line":218}
+{"auth":"BC", "org":9, "user":"BA", "status":31, "line":219, "disabled":false}
+{"state":80, "world":"BA", "wait":"CA", "line":220, "pos":65, "node":"CAC"}
+{"wait":"AC", "subtitle":"ABB", "status":79, "indexed":true, "line":221, "abstract":"AC", "pos":33, "space":"BA"}
+{"state":69, "org":83, "world":"CBC", "subtitle":"CAC", "cleaned":false, "line":222, "space":"BC", "node":"CCA"}
+{"line":223, "abstract":"BC"}
+{}
+{"world":"BB", "title":"BC", "bad":false, "query":"BBC", "cleaned":false, "line":225, "disabled":false, "public":true}
+{"line":226, "date":"AC"}
+{"auth":"CB", "subtitle":"AB", "indexed":false, "status":2, "line":227, "pos":53, "space":"AB", "coauthors":"BCA"}
+{"title":"ABA", "org":36, "line":228, "space":"AA"}
+{"world":"AB", "line":229, "pos":78, "date":"BC", "space":"CC"}
+{"wait":"BBC", "org":47, "cleaned":true, "status":5, "line":230, "pos":2, "date":"CCA"}
+{"line":231, "coauthors":"CB"}
+{"state":1, "user":"CAA", "cleaned":false, "line":232, "date":"BA", "public":true, "coauthors":"AAA", "node":"BCC"}
+{"auth":"AB", "world":"CAC", "query":"BC", "cleaned":true, "line":233, "pos":47, "space":"AB", "node":"AB"}
+{"title":"CAA", "line":234, "pos":9, "public":true, "node":"AB"}
+{"auth":"CCA", "title":"AA", "org":6, "subtitle":"CA", "cleaned":true, "status":12, "indexed":false, "line":235, "space":"ABB"}
+{"auth":"CA", "bad":false, "query":"BC", "status":61, "cleaned":false, "line":236, "disabled":true, "public":true}
+{"user":"BCB", "line":237, "pos":70, "node":"CBA"}
+{"query":"CCB", "line":238, "disabled":true, "coauthors":"BAB", "node":"BC"}
+{"auth":"AC", "org":73, "title":"CA", "bad":false, "status":94, "line":239, "abstract":"CC"}
+{"subtitle":"BC", "indexed":false, "line":240, "disabled":true}
+{"auth":"AAC", "org":73, "title":"CB", "bad":true, "query":"CA", "cleaned":true, "line":241, "disabled":false, "public":false}
+{"line":242, "public":false}
+{"auth":"AC", "title":"BC", "status":61, "line":243, "disabled":false}
+{"auth":"ABB", "bad":false, "indexed":false, "line":244, "abstract":"BAB", "date":"ABC", "coauthors":"BC"}
+{"query":"BA", "line":245, "disabled":false, "space":"BAB"}
+{"world":"BCC", "bad":false, "indexed":false, "line":246, "disabled":true, "pos":80, "public":false, "coauthors":"BC"}
+{"indexed":true, "line":247}
+{"wait":"CCA", "subtitle":"CBB", "bad":false, "line":248, "pos":83, "public":false, "space":"BA"}
+{}
+{"auth":"ABA", "org":13, "title":"BA", "bad":false, "indexed":true, "line":250, "disabled":false, "abstract":"BBA", "date":"AB"}
+{"state":37, "title":"AAA", "bad":false, "line":251, "disabled":false, "coauthors":"CBC"}
+{"auth":"ACB", "world":"AC", "title":"CAA", "subtitle":"BCA", "bad":false, "status":32, "line":252, "pos":84}
+{"query":"BA", "indexed":false, "status":0, "line":253, "abstract":"CCB", "pos":48, "date":"AC", "space":"AAC"}
+{"subtitle":"BBA", "line":254, "node":"AAA"}
+{"query":"AC", "user":"CAA", "status":13, "line":255, "public":true, "coauthors":"BCC"}
+{"auth":"AAA", "state":31, "line":256}
+{}
+{}
+{"wait":"AC", "query":"AAA", "cleaned":true, "indexed":false, "line":259, "pos":89, "coauthors":"BCA", "node":"BC"}
+{"world":"CC", "query":"BB", "line":260}
+{}
+{"org":99, "bad":false, "user":"ABA", "line":262, "abstract":"BA", "coauthors":"BCC"}
+{"auth":"CAC", "world":"CBC", "subtitle":"CA", "bad":false, "status":22, "line":263, "pos":4, "public":true, "node":"BB"}
+{"wait":"BB", "subtitle":"BCC", "indexed":true, "line":264, "node":"CAC"}
+{"subtitle":"BB", "query":"CBB", "line":265}
+{"state":35, "query":"AA", "line":266, "coauthors":"AAA"}
+{"status":6, "line":267, "pos":66}
+{"auth":"BAA", "subtitle":"CCA", "bad":false, "query":"CCB", "line":268, "public":true, "space":"CAB", "node":"CAC"}
+{"world":"AC", "org":58, "user":"AC", "line":269, "node":"AB"}
+{"auth":"BCB", "org":36, "title":"AB", "line":270, "abstract":"CAB", "date":"CAB", "public":true, "coauthors":"CB", "node":"AB"}
+{"cleaned":true, "line":271}
+{"world":"ACC", "cleaned":true, "status":11, "line":272, "disabled":false, "abstract":"AA", "space":"BCA", "node":"BA"}
+{"cleaned":true, "line":273, "pos":50, "public":true}
+{"status":95, "line":274, "abstract":"BB", "coauthors":"AC"}
+{"auth":"BCC", "state":80, "cleaned":true, "line":275, "abstract":"AC"}
+{"wait":"BA", "line":276}
+{"org":62, "subtitle":"CAA", "query":"BA", "user":"BCC", "indexed":false, "line":277, "disabled":false, "abstract":"ACA", "date":"AB"}
+{"org":63, "bad":true, "line":278, "pos":26, "coauthors":"BA"}
+{"auth":"CBB", "indexed":false, "line":279, "pos":40, "space":"CA", "coauthors":"CC"}
+{"auth":"BA", "line":280, "abstract":"AAA", "public":true, "coauthors":"CAC"}
+{"org":10, "status":16, "line":281, "date":"CCC", "space":"AC"}
+{"org":76, "user":"BBC", "indexed":false, "line":282, "pos":56, "node":"CBA"}
+{"auth":"CA", "subtitle":"AB", "query":"AA", "indexed":true, "line":283, "disabled":false, "coauthors":"ABC", "node":"CAA"}
+{"title":"BA", "status":91, "line":284, "pos":7, "coauthors":"BB"}
+{"wait":"CCA", "line":285, "public":true}
+{"world":"AC", "line":286, "disabled":true}
+{"line":287, "abstract":"AAA"}
+{"user":"CCB", "status":50, "line":288, "public":false}
+{"state":41, "world":"CCC", "query":"AA", "line":289, "disabled":true, "pos":49, "public":false}
+{"wait":"CBC", "line":290, "abstract":"CCA", "space":"BBC"}
+{"auth":"CCB", "world":"BAB", "user":"CCC", "status":93, "line":291, "pos":77, "node":"BAC"}
+{"wait":"BCC", "org":8, "user":"AC", "cleaned":true, "line":292, "disabled":true, "pos":67, "date":"AA"}
+{"org":56, "query":"BCA", "line":293, "pos":81, "coauthors":"AAA", "node":"CAB"}
+{"world":"CB", "subtitle":"CBC", "bad":true, "query":"ACB", "indexed":false, "line":294, "pos":58, "date":"BC", "node":"CB"}
+{"wait":"BC", "user":"CA", "line":295}
+{"world":"ABA", "wait":"BA", "user":"BB", "status":65, "line":296, "pos":45, "date":"BB"}
+{}
+{}
+{"auth":"BA", "user":"AA", "indexed":false, "line":299, "space":"ABA", "public":false, "coauthors":"BC"}
+{"line":300, "space":"ABA"}
+{"state":36, "org":16, "world":"BBC", "status":13, "line":301, "public":false}
+{"subtitle":"CB", "user":"BC", "line":302, "date":"AA", "coauthors":"CAC"}
+{"wait":"CBC", "indexed":true, "cleaned":true, "line":303, "date":"ACC", "public":true}
+{"user":"CAC", "status":81, "line":304, "node":"CAB"}
+{"title":"CBB", "org":89, "subtitle":"CAA", "user":"CCA", "indexed":true, "line":305}
+{"state":10, "title":"CBA", "org":66, "cleaned":true, "line":306, "pos":59, "coauthors":"CAC"}
+{}
+{"auth":"AAA", "world":"AC", "wait":"ACA", "subtitle":"BAA", "status":64, "line":308, "node":"CCA"}
+{"state":31, "world":"CCC", "title":"BCB", "cleaned":false, "status":11, "line":309, "disabled":true, "date":"AA"}
+{"title":"BC", "subtitle":"CB", "indexed":false, "line":310, "disabled":true, "abstract":"BA", "space":"ACA"}
+{"wait":"ABB", "cleaned":true, "indexed":false, "line":311, "space":"CAB"}
+{}
+{"subtitle":"CA", "line":313}
+{"org":91, "title":"CAB", "line":314, "date":"CA"}
+{}
+{"state":65, "line":316, "node":"CC"}
+{"line":317, "space":"AA"}
+{}
+{"wait":"AA", "indexed":true, "line":319}
+{"wait":"BB", "org":42, "world":"AC", "subtitle":"ACC", "indexed":true, "line":320, "disabled":true}
+{}
+{"auth":"CAC", "line":322}
+{}
+{"line":324, "pos":38, "space":"CC", "node":"BBC"}
+{"title":"CC", "line":325, "public":true, "coauthors":"BAC", "node":"ACC"}
+{"world":"CC", "subtitle":"BBC", "bad":false, "user":"BA", "line":326, "date":"AAA", "space":"AA"}
+{"state":81, "title":"BC", "wait":"BA", "indexed":false, "status":48, "line":327, "coauthors":"AB"}
+{"line":328, "space":"ABB"}
+{"line":329, "date":"CCA"}
+{}
+{"auth":"BB", "world":"BAB", "subtitle":"BA", "query":"ABB", "line":331, "disabled":true, "date":"AAA", "node":"BC"}
+{"auth":"ABA", "title":"CC", "user":"CBA", "line":332, "disabled":true, "space":"ACC"}
+{"org":98, "subtitle":"ACB", "line":333, "abstract":"BC", "public":false, "coauthors":"BC", "node":"ABA"}
+{}
+{"world":"BC", "subtitle":"BAC", "user":"AB", "query":"BAA", "cleaned":true, "line":335, "space":"AC", "node":"BAA"}
+{"state":76, "indexed":true, "cleaned":false, "line":336, "node":"CAC"}
+{"org":95, "status":84, "line":337}
+{}
+{"world":"BBA", "title":"BCC", "subtitle":"ACB", "query":"BA", "line":339, "space":"ABC", "node":"AC"}
+{"title":"CBB", "user":"CBA", "cleaned":true, "line":340, "public":true, "space":"CB", "coauthors":"CAB"}
+{"wait":"AA", "status":82, "line":341}
+{"world":"CC", "line":342}
+{"auth":"BAB", "title":"CAC", "query":"BCC", "indexed":true, "line":343}
+{"org":77, "world":"BAC", "subtitle":"AA", "user":"ABA", "line":344}
+{"state":99, "org":56, "world":"CC", "title":"CAB", "wait":"CB", "subtitle":"BCC", "line":345, "pos":65}
+{"state":68, "org":97, "title":"AA", "indexed":true, "line":346, "node":"CC"}
+{"state":3, "title":"CBC", "user":"BAA", "status":98, "line":347, "disabled":true, "pos":96, "date":"BBA"}
+{"auth":"BAA", "world":"ABB", "line":348, "disabled":false, "abstract":"ACA", "pos":66, "space":"CCC", "coauthors":"CBB", "node":"BC"}
+{}
+{"status":54, "line":350}
+{"wait":"CC", "query":"ABA", "user":"AB", "status":76, "cleaned":false, "line":351, "abstract":"CBA"}
+{"line":352, "disabled":true, "public":false}
+{"state":93, "org":92, "status":88, "line":353, "space":"AB", "coauthors":"CB"}
+{"org":34, "wait":"ABC", "world":"CBA", "bad":false, "query":"BB", "indexed":false, "line":354, "date":"CB", "public":true}
+{"wait":"CBA", "title":"CAC", "cleaned":true, "indexed":true, "line":355, "pos":9, "date":"CAA"}
+{"user":"BC", "indexed":false, "cleaned":true, "status":73, "line":356, "disabled":true, "space":"CB"}
+{"state":20, "cleaned":false, "line":357, "pos":28, "abstract":"CCB", "space":"BC"}
+{"state":17, "wait":"ABC", "query":"CB", "cleaned":false, "status":4, "line":358, "disabled":false}
+{}
+{"state":83, "world":"CC", "org":53, "cleaned":false, "status":64, "line":360, "abstract":"CBC", "coauthors":"BC"}
+{"title":"BB", "indexed":false, "line":361}
+{"state":49, "wait":"BCA", "line":362}
+{"world":"CCC", "title":"CA", "query":"CCC", "cleaned":true, "line":363, "space":"AA", "coauthors":"AAC"}
+{"state":8, "wait":"BBB", "line":364, "pos":70, "public":false, "space":"BAA", "coauthors":"AB"}
+{"state":20, "indexed":false, "status":87, "cleaned":true, "line":365, "public":true}
+{}
+{"state":92, "title":"CCC", "subtitle":"CAB", "status":39, "line":367}
+{"state":54, "org":38, "line":368}
+{}
+{"auth":"ACA", "subtitle":"CBC", "status":52, "line":370, "date":"ACC", "public":true}
+{"indexed":true, "line":371, "pos":98, "node":"CBA"}
+{"world":"BA", "status":40, "line":372, "coauthors":"AA"}
+{}
+{"query":"BA", "indexed":false, "cleaned":true, "line":374, "date":"BCC"}
+{"query":"CA", "indexed":true, "line":375, "public":false}
+{"auth":"CCA", "wait":"BBC", "bad":false, "status":91, "line":376, "abstract":"BBC", "date":"ABA"}
+{"user":"BA", "query":"CB", "status":86, "indexed":false, "line":377, "pos":83, "abstract":"BCC", "space":"CBC", "public":true}
+{"title":"ACA", "org":15, "wait":"CBC", "status":85, "line":378}
+{"state":57, "bad":true, "line":379, "abstract":"BC", "date":"CAC"}
+{"world":"CC", "cleaned":true, "line":380}
+{"title":"CB", "subtitle":"AC", "line":381, "public":false}
+{}
+{}
+{"status":12, "line":384, "coauthors":"CC"}
+{"auth":"BAC", "bad":false, "line":385, "abstract":"CBB", "public":false, "space":"BBC"}
+{}
+{}
+{"world":"BBC", "bad":true, "status":71, "cleaned":false, "line":388, "node":"BB"}
+{"cleaned":false, "line":389}
+{"state":73, "line":390}
+{"wait":"BB", "org":5, "subtitle":"BAA", "bad":false, "indexed":false, "line":391, "public":false, "node":"BAA"}
+{"auth":"CCC", "org":51, "bad":false, "cleaned":true, "line":392, "space":"AC", "node":"CC"}
+{}
+{"line":394, "abstract":"ACC", "public":true}
+{"org":44, "subtitle":"BAC", "query":"BAC", "line":395}
+{"wait":"BC", "line":396}
+{"state":68, "world":"AB", "title":"ABB", "user":"CBC", "cleaned":false, "indexed":true, "line":397, "abstract":"BA", "pos":11}
+{"world":"CA", "title":"AB", "subtitle":"BC", "user":"BCB", "line":398}
+{"bad":true, "query":"BCC", "line":399}
+{"wait":"BB", "user":"BB", "cleaned":true, "indexed":false, "line":400, "date":"BC", "public":false}
+{}
+{"wait":"BA", "line":402}
+{"title":"AC", "subtitle":"BCB", "query":"BA", "line":403}
+{}
+{"auth":"BA", "org":19, "query":"CCB", "line":405, "pos":82, "date":"CAA"}
+{"state":26, "world":"CB", "subtitle":"AB", "cleaned":false, "line":406, "disabled":true, "date":"AC"}
+{}
+{"state":11, "bad":true, "indexed":true, "line":408, "pos":79, "abstract":"BA", "date":"CB", "space":"BBA"}
+{"auth":"AC", "status":59, "line":409}
+{"org":15, "line":410, "disabled":true, "date":"BAC", "space":"CCA"}
+{}
+{}
+{"state":65, "world":"AB", "status":69, "line":413, "space":"BA"}
+{}
+{"title":"CCB", "line":415}
+{"title":"BAB", "subtitle":"CA", "indexed":false, "line":416, "public":true}
+{"wait":"CAB", "user":"CAB", "cleaned":true, "line":417, "date":"BC", "coauthors":"BBA"}
+{"subtitle":"ABA", "user":"BB", "query":"AA", "indexed":true, "line":418, "pos":8, "space":"BB", "coauthors":"CBA"}
+{"state":11, "indexed":true, "line":419, "node":"AA"}
+{"state":86, "cleaned":false, "line":420, "pos":2, "node":"CBC"}
+{"org":73, "line":421, "disabled":false}
+{"query":"BAC", "user":"CB", "status":69, "line":422}
+{"status":22, "line":423}
+{"auth":"CB", "wait":"CCA", "world":"AAB", "line":424, "disabled":false, "space":"BA", "public":false}
+{"state":81, "world":"AC", "subtitle":"CBA", "bad":true, "cleaned":false, "indexed":true, "line":425, "date":"AAB", "coauthors":"BC", "node":"BAC"}
+{"wait":"CB", "query":"BCC", "status":97, "line":426}
+{"org":47, "query":"CB", "cleaned":true, "line":427, "date":"CC"}
+{"org":33, "query":"AC", "status":48, "indexed":false, "line":428, "disabled":true, "abstract":"BC", "space":"ACC"}
+{"org":10, "query":"AB", "line":429, "pos":77, "date":"BC"}
+{"line":430, "pos":7, "abstract":"CCA", "space":"AA"}
+{"bad":false, "user":"CA", "query":"CAB", "line":431, "node":"AC"}
+{"auth":"CA", "bad":false, "line":432}
+{}
+{"auth":"BAA", "org":98, "title":"CCC", "world":"BAC", "line":434, "public":true}
+{"state":54, "wait":"AA", "user":"BBA", "indexed":false, "line":435, "disabled":true, "pos":12, "space":"AB"}
+{"world":"AC", "title":"CA", "query":"AAA", "line":436, "space":"AB", "coauthors":"AA"}
+{"auth":"CB", "wait":"CCC", "bad":false, "line":437, "pos":42, "date":"ABC", "space":"AB", "coauthors":"ABC"}
+{"auth":"CBB", "title":"BB", "query":"CB", "line":438, "pos":15, "abstract":"BC", "node":"BBB"}
+{"title":"CC", "line":439, "disabled":false}
+{"title":"AB", "line":440, "disabled":false}
+{"org":3, "bad":true, "user":"BCB", "query":"AB", "indexed":false, "cleaned":true, "line":441, "disabled":false, "space":"BA", "node":"BB"}
+{"state":62, "user":"BCC", "status":12, "line":442, "pos":58, "date":"CC", "node":"CB"}
+{"world":"BCB", "bad":true, "line":443, "space":"AAB"}
+{"state":56, "bad":false, "cleaned":false, "line":444, "disabled":false, "date":"CA", "space":"BBB", "public":true}
+{}
+{"org":31, "world":"ABC", "cleaned":true, "line":446, "disabled":true, "public":true, "coauthors":"CB"}
+{"state":54, "indexed":true, "line":447}
+{"state":98, "title":"AC", "wait":"AAC", "world":"BC", "bad":false, "line":448, "disabled":true, "public":true, "node":"ABB"}
+{"world":"AAC", "indexed":true, "line":449, "disabled":true, "pos":61}
+{"org":56, "title":"CA", "line":450}
+{"auth":"BBB", "line":451, "pos":58, "date":"BB", "space":"ABA"}
+{"auth":"AB", "world":"CA", "cleaned":true, "line":452}
+{"bad":true, "line":453, "disabled":true, "abstract":"AC", "pos":20, "date":"ABB", "node":"CAB"}
+{}
+{"state":91, "wait":"AC", "org":96, "world":"AA", "subtitle":"BBC", "query":"AA", "cleaned":true, "line":455, "public":false}
+{"status":99, "line":456, "disabled":true}
+{"org":86, "line":457, "public":true, "coauthors":"AC"}
+{"status":14, "cleaned":true, "line":458, "disabled":true}
+{"world":"AB", "user":"CB", "query":"AAB", "line":459, "pos":66, "public":false, "node":"BBA"}
+{"state":58, "world":"BB", "wait":"CBA", "title":"BCA", "line":460, "pos":95, "abstract":"CCA", "space":"BC", "coauthors":"CB"}
+{}
+{"auth":"CAC", "title":"AB", "query":"BBA", "user":"CB", "line":462, "abstract":"BCC", "pos":89, "coauthors":"ABB"}
+{"org":13, "bad":false, "query":"AA", "status":49, "line":463, "disabled":false}
+{"bad":true, "cleaned":false, "line":464, "coauthors":"BB"}
+{"org":14, "query":"BA", "line":465, "pos":25, "abstract":"BBA", "space":"AAA", "node":"CAC"}
+{"org":63, "title":"CA", "subtitle":"ACC", "query":"BAC", "status":76, "line":466, "abstract":"ACA"}
+{"wait":"BA", "subtitle":"BC", "line":467, "disabled":false, "abstract":"AC"}
+{"org":76, "title":"CA", "query":"AB", "line":468, "public":false}
+{"state":95, "world":"AC", "bad":false, "status":65, "cleaned":false, "line":469, "disabled":false}
+{"wait":"AB", "subtitle":"AA", "bad":false, "user":"CC", "query":"BBC", "status":6, "line":470, "date":"CCC"}
+{"state":82, "bad":true, "indexed":true, "line":471, "date":"BB", "coauthors":"AAA"}
+{}
+{"state":12, "auth":"ACB", "world":"CBC", "bad":false, "indexed":true, "line":473, "date":"CA", "space":"ABB", "coauthors":"CC"}
+{"subtitle":"AA", "bad":false, "user":"ACC", "line":474, "pos":86, "abstract":"CAC", "space":"BBA"}
+{"cleaned":true, "line":475}
+{"title":"CC", "wait":"BB", "status":6, "line":476, "abstract":"ACC", "date":"CB", "space":"BA", "public":true}
+{"state":96, "wait":"BA", "org":30, "subtitle":"BB", "user":"CBB", "status":19, "line":477}
+{"state":78, "org":99, "title":"CC", "line":478, "node":"BAB"}
+{"world":"CBC", "bad":false, "line":479, "date":"ACB", "public":true, "node":"CB"}
+{"state":0, "query":"ABC", "status":65, "line":480, "disabled":true, "space":"CBA", "node":"BA"}
+{"auth":"BAC", "org":24, "subtitle":"BBC", "bad":false, "user":"CAC", "line":481, "date":"BBB", "public":true, "coauthors":"CBA"}
+{"org":18, "bad":true, "cleaned":false, "status":3, "indexed":true, "line":482, "date":"BB", "coauthors":"ACC"}
+{"wait":"CB", "user":"AC", "line":483, "disabled":false}
+{"world":"AC", "subtitle":"AA", "query":"AAB", "line":484, "disabled":true, "space":"CAA"}
+{"line":485, "pos":2, "space":"CA"}
+{"org":42, "indexed":false, "line":486, "date":"CB"}
+{"org":3, "wait":"CAA", "subtitle":"CA", "cleaned":true, "line":487, "disabled":true}
+{"org":68, "subtitle":"CCB", "query":"CAA", "cleaned":false, "status":46, "line":488, "pos":87, "public":false, "node":"BC"}
+{}
+{"status":60, "cleaned":false, "line":490, "space":"CC", "node":"BCB"}
+{"state":42, "org":9, "subtitle":"CBA", "user":"BA", "status":96, "line":491, "pos":36}
+{"state":16, "title":"BCC", "user":"ABC", "indexed":false, "status":24, "line":492, "disabled":true, "node":"CBC"}
+{"auth":"CC", "wait":"BBB", "line":493, "disabled":false, "public":false, "coauthors":"AB"}
+{}
+{"wait":"BB", "title":"BBC", "subtitle":"BA", "status":3, "cleaned":false, "line":495, "disabled":false, "coauthors":"AB", "node":"BAC"}
+{}
+{"query":"CC", "indexed":false, "line":497, "coauthors":"CAC", "node":"BC"}
+{"auth":"BBA", "state":68, "line":498}
+{"state":21, "title":"CCB", "wait":"AAA", "subtitle":"CCC", "user":"BAA", "indexed":true, "line":499, "coauthors":"BB"}
+{"auth":"AAA", "subtitle":"CC", "bad":true, "user":"CC", "indexed":true, "line":500, "disabled":true, "date":"AB", "node":"AC"}
+{"auth":"BB", "title":"CCA", "user":"BA", "cleaned":true, "line":501, "pos":37, "space":"BA", "public":false}
+{"auth":"BCA", "line":502, "date":"BA"}
+{"world":"ABA", "bad":true, "indexed":false, "line":503, "disabled":true, "abstract":"AC", "pos":1, "public":false}
+{"auth":"BBB", "subtitle":"ACB", "line":504, "space":"AC", "node":"BB"}
+{"auth":"CAC", "state":19, "title":"ACA", "wait":"BA", "query":"CC", "line":505}
+{"subtitle":"BC", "cleaned":false, "indexed":false, "line":506, "date":"CAB", "public":false, "node":"ABC"}
+{"state":87, "wait":"CCC", "query":"CAC", "user":"CBB", "line":507, "abstract":"BBC", "date":"AA", "coauthors":"CA"}
+{"auth":"AC", "subtitle":"BC", "bad":false, "query":"ABA", "user":"CBB", "indexed":true, "cleaned":false, "line":508, "coauthors":"BA"}
+{"auth":"AA", "title":"ABA", "subtitle":"CCA", "query":"CC", "line":509, "pos":27, "node":"CBB"}
+{"org":5, "title":"CAC", "subtitle":"BBB", "line":510, "pos":76, "abstract":"AAB", "space":"AA"}
+{"bad":true, "line":511}
+{"wait":"ACB", "indexed":false, "line":512}
+{"auth":"CBA", "world":"BA", "bad":true, "user":"CBA", "query":"CC", "line":513, "public":false, "coauthors":"CC"}
+{}
+{"state":97, "wait":"BB", "line":515, "date":"CBC", "space":"CA"}
+{"auth":"CBC", "line":516, "disabled":true}
+{"state":91, "user":"CCA", "line":517, "coauthors":"BA", "node":"CBA"}
+{"bad":false, "cleaned":true, "line":518, "space":"AAB"}
+{}
+{"title":"CA", "cleaned":false, "status":38, "line":520}
+{"auth":"BCA", "world":"AC", "org":71, "user":"CA", "line":521, "abstract":"AAB"}
+{"bad":true, "line":522, "pos":28, "abstract":"BAA"}
+{"line":523, "coauthors":"CBC", "node":"AAB"}
+{"status":51, "cleaned":false, "line":524}
+{"query":"AAB", "line":525, "disabled":true, "date":"AA", "public":true, "coauthors":"CA"}
+{"org":15, "user":"AC", "cleaned":false, "line":526, "coauthors":"CAC", "node":"BAB"}
+{"world":"ABA", "line":527, "disabled":true, "public":true}
+{"auth":"BBC", "state":48, "bad":false, "line":528, "abstract":"BB", "date":"BAC", "space":"BA", "public":true}
+{"auth":"BA", "wait":"CAC", "subtitle":"ABC", "query":"CB", "indexed":false, "cleaned":false, "line":529, "disabled":true, "date":"CA"}
+{"wait":"AC", "world":"ABA", "org":55, "bad":true, "indexed":true, "line":530, "pos":32, "space":"BCA", "public":true}
+{"title":"CBC", "wait":"BAA", "line":531}
+{"world":"AA", "line":532, "pos":35, "space":"AAB", "public":true}
+{"line":533, "space":"AB", "coauthors":"BA"}
+{"auth":"CBC", "world":"BB", "line":534, "space":"ACA", "coauthors":"CBB"}
+{"wait":"ACA", "status":47, "line":535, "public":true, "node":"BAA"}
+{"org":16, "subtitle":"BBB", "line":536, "abstract":"AC", "space":"CB", "coauthors":"CC", "node":"CBC"}
+{"wait":"AAB", "line":537, "abstract":"AB", "space":"CAC"}
+{"query":"CAC", "line":538}
+{"world":"AC", "query":"AAA", "indexed":false, "status":18, "line":539, "pos":62, "space":"BC", "coauthors":"BAC"}
+{"org":30, "world":"AA", "query":"BC", "user":"BAC", "status":12, "cleaned":true, "line":540, "space":"AB"}
+{"org":30, "user":"CCB", "query":"BB", "cleaned":false, "line":541, "disabled":true, "public":true, "node":"CBA"}
+{}
+{"subtitle":"ABB", "bad":true, "line":543}
+{"subtitle":"BBB", "bad":true, "line":544, "pos":43, "coauthors":"ABB"}
+{}
+{"subtitle":"AB", "user":"BA", "line":546, "node":"CB"}
+{"title":"BBB", "user":"AA", "line":547, "abstract":"CBB", "pos":45}
+{"wait":"CCB", "title":"AC", "world":"AAA", "line":548, "abstract":"BBC", "pos":23, "coauthors":"ACC"}
+{"org":55, "subtitle":"BA", "line":549, "disabled":true, "date":"CB", "space":"AA"}
+{"org":39, "cleaned":true, "line":550, "public":false}
+{"state":41, "auth":"CC", "world":"CB", "line":551, "space":"AAB"}
+{}
+{"state":26, "bad":false, "query":"BAA", "status":84, "indexed":true, "line":553, "disabled":false, "coauthors":"CC", "node":"CBB"}
+{"world":"ABA", "user":"CCC", "query":"ABB", "line":554, "space":"ABC", "node":"AAA"}
+{"state":18, "wait":"CCB", "bad":true, "user":"BA", "line":555, "space":"CC", "coauthors":"BB", "node":"BBB"}
+{"auth":"AA", "state":71, "subtitle":"AA", "query":"ACC", "indexed":true, "line":556, "space":"BAB", "public":false}
+{"indexed":true, "cleaned":true, "line":557, "disabled":false, "abstract":"AB"}
+{"auth":"BCC", "title":"ACB", "world":"BCA", "user":"BAB", "cleaned":false, "line":558, "space":"BB", "coauthors":"CBC"}
+{}
+{"auth":"ACC", "org":18, "wait":"AB", "status":1, "indexed":true, "line":560}
+{"status":8, "line":561, "abstract":"BA", "public":false}
+{"state":27, "title":"ABA", "bad":true, "query":"AAB", "indexed":false, "line":562, "pos":86, "public":true, "coauthors":"BA"}
+{}
+{"title":"BAC", "wait":"CCC", "user":"BA", "line":564, "disabled":false, "date":"BB", "public":true, "space":"CB", "coauthors":"CCB"}
+{"wait":"CAA", "line":565, "pos":80, "space":"AB"}
+{"auth":"CBB", "subtitle":"BCA", "user":"CB", "line":566, "abstract":"BC", "date":"AB"}
+{"title":"CCB", "status":78, "line":567, "pos":68, "node":"BA"}
+{"auth":"BC", "query":"AB", "line":568, "space":"AB", "node":"BB"}
+{}
+{"line":570, "pos":54}
+{"world":"BBB", "user":"CC", "indexed":true, "line":571, "abstract":"CC", "coauthors":"BA", "node":"ABB"}
+{"state":41, "line":572}
+{"subtitle":"CBC", "cleaned":true, "line":573, "node":"BCB"}
+{"title":"ABA", "line":574, "pos":27, "space":"CC"}
+{"status":29, "indexed":false, "cleaned":false, "line":575, "pos":52, "public":false, "coauthors":"ACC"}
+{"title":"BBB", "org":86, "wait":"AAA", "user":"CC", "query":"CA", "line":576, "disabled":false, "date":"AB", "node":"BC"}
+{"line":577, "abstract":"CAA", "date":"BB"}
+{"auth":"CCC", "subtitle":"BBB", "query":"ABA", "line":578, "pos":99, "space":"CCB", "public":true, "coauthors":"ACA", "node":"ACB"}
+{"wait":"BCC", "line":579}
+{"state":99, "world":"BAC", "user":"CA", "line":580}
+{"state":55, "world":"AAA", "title":"AAA", "cleaned":false, "line":581, "date":"AC", "public":true, "node":"AA"}
+{"query":"ACC", "cleaned":true, "line":582, "disabled":false}
+{"auth":"AAB", "query":"BAC", "line":583}
+{"auth":"AA", "user":"BAC", "line":584}
+{}
+{"org":96, "wait":"BC", "bad":false, "cleaned":false, "status":96, "line":586, "pos":95}
+{"auth":"BC", "subtitle":"BCB", "bad":true, "user":"BBC", "line":587, "pos":79, "node":"BA"}
+{"state":55, "line":588}
+{"title":"ABC", "world":"AB", "subtitle":"CBC", "user":"BA", "query":"BAB", "line":589, "date":"AC", "node":"CB"}
+{"world":"BAA", "bad":false, "user":"AAB", "cleaned":false, "indexed":false, "line":590}
+{"title":"CB", "wait":"BC", "subtitle":"BAC", "cleaned":true, "line":591, "disabled":false, "abstract":"CBB", "public":false, "node":"ACC"}
+{"user":"BC", "line":592, "public":false}
+{}
+{"wait":"CC", "org":57, "title":"BAC", "line":594, "abstract":"AA"}
+{"auth":"BBC", "state":3, "world":"AAC", "query":"BA", "line":595, "coauthors":"BB"}
+{}
+{"subtitle":"CC", "user":"CC", "line":597}
+{"wait":"BBA", "user":"AAA", "line":598, "space":"ACB", "node":"AA"}
+{"auth":"BB", "user":"ABA", "line":599, "abstract":"AB", "node":"BA"}
+{}
+{"world":"AAA", "user":"BB", "cleaned":false, "line":601, "space":"AC", "coauthors":"ABB"}
+{"title":"CAB", "bad":false, "line":602, "coauthors":"ABB"}
+{}
+{"world":"CCC", "org":79, "line":604}
+{"org":56, "query":"AB", "cleaned":true, "indexed":true, "status":20, "line":605, "public":true, "coauthors":"ACA"}
+{"auth":"BBC", "org":13, "subtitle":"CC", "bad":true, "user":"ABC", "line":606, "date":"CA", "public":false}
+{"query":"BA", "line":607}
+{"bad":true, "line":608, "pos":12, "coauthors":"CB"}
+{"bad":false, "status":42, "line":609}
+{}
+{"bad":true, "line":611}
+{"auth":"CCA", "subtitle":"BC", "bad":true, "query":"CAA", "cleaned":false, "line":612, "public":false, "node":"CBA"}
+{"org":65, "query":"BC", "line":613}
+{}
+{"wait":"BAC", "title":"AAB", "user":"CAC", "line":615, "pos":69, "space":"CC", "node":"AAC"}
+{"bad":false, "line":616, "abstract":"AB", "pos":65, "coauthors":"BBB"}
+{}
+{"org":38, "world":"BA", "line":618, "coauthors":"AA", "node":"BC"}
+{"cleaned":false, "line":619, "disabled":false}
+{"auth":"BC", "line":620, "pos":79, "date":"AB", "coauthors":"BAA", "node":"CB"}
+{"auth":"CAA", "title":"CB", "user":"BAC", "cleaned":false, "line":621, "public":false, "space":"CBA"}
+{}
+{"bad":false, "status":12, "line":623}
+{"auth":"BBB", "wait":"BAC", "org":36, "title":"AB", "indexed":false, "cleaned":false, "line":624, "date":"AB", "coauthors":"CB"}
+{"wait":"AA", "subtitle":"AB", "query":"CCB", "line":625, "node":"CBB"}
+{"wait":"BC", "subtitle":"BA", "bad":true, "user":"AA", "line":626, "pos":3, "date":"BB"}
+{"org":28, "user":"BC", "query":"AC", "status":63, "line":627, "pos":45, "public":true, "node":"BC"}
+{"query":"BC", "status":47, "line":628, "disabled":false, "date":"CA", "public":false}
+{}
+{"wait":"CB", "line":630, "pos":67, "coauthors":"AC"}
+{"org":33, "world":"BBB", "query":"BB", "status":92, "line":631}
+{"state":65, "title":"AC", "world":"CBC", "query":"CBC", "line":632, "date":"CAC", "space":"CC", "coauthors":"CC"}
+{}
+{"auth":"CC", "query":"BCA", "status":46, "line":634, "disabled":false, "pos":69}
+{"wait":"CB", "line":635, "pos":34}
+{"state":9, "wait":"CC", "status":23, "line":636, "disabled":true, "date":"BB", "space":"AC"}
+{"user":"CCB", "indexed":false, "cleaned":true, "line":637, "pos":65, "date":"AA", "public":true}
+{"auth":"BC", "wait":"AB", "title":"BB", "bad":true, "line":638, "abstract":"ACC", "date":"BC", "public":false}
+{"state":44, "auth":"BC", "world":"CBC", "line":639, "disabled":false, "date":"CAA"}
+{"world":"CB", "title":"ACB", "user":"BA", "query":"AA", "line":640, "disabled":true, "space":"AC"}
+{"state":37, "line":641, "disabled":true, "pos":66}
+{"world":"AAA", "bad":true, "user":"AAA", "query":"BA", "line":642, "disabled":true, "coauthors":"CBC"}
+{"world":"BA", "title":"ABB", "org":96, "bad":false, "query":"AAA", "status":75, "cleaned":false, "line":643, "space":"BA"}
+{"state":36, "org":66, "subtitle":"AA", "query":"CA", "cleaned":true, "status":79, "line":644, "date":"CB"}
+{"wait":"BC", "line":645, "date":"CBA", "space":"BCB", "public":true, "node":"ABA"}
+{"auth":"BB", "org":37, "query":"CAA", "indexed":true, "line":646, "abstract":"CBA", "coauthors":"CBA"}
+{}
+{}
+{"state":58, "world":"BAB", "org":11, "user":"CC", "line":649}
+{"title":"CB", "status":19, "line":650, "disabled":false, "public":false, "coauthors":"AA"}
+{"user":"BBC", "indexed":true, "line":651, "disabled":true, "pos":8}
+{"query":"CC", "cleaned":true, "indexed":false, "line":652, "pos":67, "date":"AA"}
+{"auth":"AAC", "line":653, "disabled":true, "public":false, "coauthors":"AAA", "node":"CBB"}
+{"bad":true, "query":"AC", "line":654, "disabled":false}
+{"world":"CCA", "org":15, "bad":false, "user":"CCC", "line":655, "public":true, "space":"CC"}
+{"line":656, "coauthors":"BBB"}
+{"title":"BA", "line":657, "date":"ACB"}
+{"user":"BC", "query":"CC", "cleaned":true, "line":658, "pos":51, "abstract":"BA"}
+{"subtitle":"CCA", "user":"CCA", "cleaned":false, "line":659, "abstract":"BA", "pos":95, "date":"CA"}
+{"auth":"CA", "state":23, "org":19, "bad":false, "user":"BCB", "indexed":false, "line":660, "date":"ABA"}
+{"state":64, "org":97, "bad":false, "indexed":false, "line":661, "space":"BAB", "coauthors":"BB", "node":"BA"}
+{"status":11, "line":662}
+{"title":"BCC", "org":44, "subtitle":"ACB", "cleaned":false, "line":663, "pos":58}
+{"auth":"ABB", "bad":true, "line":664, "pos":82, "coauthors":"CC", "node":"AB"}
+{"bad":false, "cleaned":true, "status":25, "line":665, "disabled":false, "abstract":"BB", "public":true}
+{"wait":"AC", "user":"CB", "line":666, "pos":71, "abstract":"ACA", "coauthors":"CBB"}
+{"title":"AA", "bad":true, "user":"BB", "line":667, "date":"CA", "space":"BC", "node":"CC"}
+{}
+{"auth":"AAB", "line":669}
+{"wait":"AAC", "query":"ABA", "status":35, "line":670, "disabled":false, "pos":56}
+{"org":3, "line":671}
+{"state":46, "bad":false, "cleaned":true, "line":672}
+{"state":30, "org":9, "status":72, "line":673, "abstract":"ACA", "coauthors":"CB"}
+{"auth":"BB", "wait":"CA", "title":"BBB", "bad":true, "user":"AAA", "status":86, "indexed":false, "line":674, "node":"BCC"}
+{"indexed":true, "line":675, "pos":63}
+{"bad":true, "query":"CBB", "status":5, "line":676, "abstract":"CCC", "public":false, "space":"BB"}
+{"title":"BBB", "org":60, "bad":true, "cleaned":false, "line":677, "pos":82, "date":"BAA", "space":"BB", "coauthors":"CAA"}
+{}
+{}
+{"state":73, "bad":false, "cleaned":false, "line":680, "abstract":"CA", "date":"CCA", "space":"CB"}
+{"state":92, "query":"CC", "line":681, "abstract":"AB", "date":"BBB", "public":true, "coauthors":"CBA"}
+{"subtitle":"CCA", "line":682}
+{"world":"BAC", "subtitle":"AC", "line":683, "disabled":true, "abstract":"AA", "pos":55, "space":"AC", "node":"CA"}
+{"state":75, "world":"ACA", "query":"BC", "line":684, "coauthors":"AAC"}
+{"status":21, "line":685}
+{"state":39, "wait":"CB", "title":"CBC", "query":"BB", "cleaned":true, "line":686, "disabled":false}
+{"world":"CCA", "wait":"AB", "user":"CC", "query":"BB", "cleaned":true, "line":687}
+{"auth":"CAC", "state":94, "wait":"ACC", "title":"BBC", "user":"BB", "line":688, "disabled":false, "pos":16, "coauthors":"AAC"}
+{}
+{"org":43, "line":690}
+{}
+{"state":4, "title":"CA", "subtitle":"AA", "query":"BC", "line":692, "pos":57, "date":"BCA", "public":false, "coauthors":"ABB"}
+{"wait":"BBA", "line":693}
+{"auth":"BCA", "bad":false, "user":"BBA", "line":694, "disabled":false, "date":"CC", "public":true, "coauthors":"CB"}
+{"state":66, "wait":"BB", "user":"CC", "indexed":true, "line":695, "pos":99, "space":"BCA"}
+{"org":1, "line":696, "disabled":false, "space":"BCC", "coauthors":"BC"}
+{"auth":"BC", "cleaned":true, "indexed":false, "line":697, "space":"CBB"}
+{"wait":"AC", "indexed":false, "line":698, "pos":44}
+{"wait":"AA", "title":"BBB", "org":31, "indexed":true, "line":699, "disabled":false}
+{"auth":"BB", "world":"ACC", "bad":true, "indexed":false, "line":700, "abstract":"CB", "pos":5, "space":"ACB", "node":"CC"}
+{"cleaned":false, "line":701, "space":"CB"}
+{"line":702, "space":"CCC"}
+{"world":"CA", "subtitle":"ABA", "line":703, "pos":5, "date":"BA", "coauthors":"AB"}
+{}
+{"line":705, "date":"BBB"}
+{"state":10, "query":"CB", "status":70, "line":706, "abstract":"ABA", "date":"BC"}
+{"auth":"CB", "line":707}
+{"wait":"BBA", "cleaned":true, "line":708, "pos":94, "date":"CBC"}
+{"state":86, "org":5, "world":"BB", "indexed":false, "line":709, "date":"BBB", "space":"CA", "public":true}
+{"world":"ACA", "query":"ABC", "status":40, "line":710, "disabled":true, "public":true, "node":"CA"}
+{"bad":true, "line":711}
+{"query":"AB", "line":712, "coauthors":"BBC", "node":"AA"}
+{"user":"ABB", "line":713, "public":false, "space":"AAA", "node":"BBA"}
+{"auth":"AC", "wait":"BAC", "bad":true, "line":714, "public":false}
+{"line":715, "abstract":"CA", "public":false}
+{"user":"AC", "indexed":true, "line":716, "coauthors":"CB"}
+{"state":4, "title":"ABB", "org":26, "indexed":true, "line":717, "public":true, "coauthors":"CCA", "node":"AC"}
+{"wait":"CA", "title":"CCA", "world":"CCC", "line":718, "abstract":"ACA"}
+{"auth":"ACA", "org":29, "subtitle":"AA", "user":"CA", "status":24, "indexed":true, "line":719, "public":false, "node":"CA"}
+{}
+{"line":721, "disabled":true, "abstract":"BAC"}
+{"world":"BC", "line":722}
+{"state":27, "auth":"AA", "title":"BC", "world":"CC", "query":"BCC", "line":723, "disabled":true, "pos":9, "public":false, "node":"BCC"}
+{"org":78, "wait":"ABA", "cleaned":true, "indexed":true, "line":724, "date":"ACB", "space":"AA"}
+{"state":60, "line":725}
+{}
+{}
+{"wait":"ABA", "title":"CAC", "user":"CCC", "line":728}
+{"wait":"CC", "indexed":true, "status":39, "line":729, "disabled":true, "public":false}
+{"auth":"CB", "subtitle":"BBA", "line":730, "coauthors":"CAC"}
+{"world":"CBB", "line":731, "space":"BCB"}
+{"cleaned":true, "line":732}
+{"org":67, "bad":true, "line":733, "pos":9, "node":"ACC"}
+{"world":"BC", "wait":"CAC", "org":58, "subtitle":"ACC", "bad":true, "query":"CAA", "line":734, "abstract":"BCA", "pos":1, "public":true}
+{"state":45, "query":"AB", "indexed":false, "line":735, "pos":82, "date":"BC", "public":false, "coauthors":"BA"}
+{"state":68, "title":"BC", "cleaned":true, "status":34, "line":736, "disabled":true, "node":"BBB"}
+{"auth":"AC", "line":737}
+{"line":738, "date":"BA", "space":"CCC", "public":false}
+{"line":739, "node":"BAA"}
+{"org":72, "title":"BC", "line":740, "pos":51, "coauthors":"CA"}
+{"state":72, "user":"CCB", "query":"ACA", "line":741}
+{"org":80, "subtitle":"BBA", "bad":true, "user":"BC", "line":742, "pos":52, "coauthors":"BCA"}
+{}
+{"query":"BC", "line":744, "abstract":"AB", "public":false, "node":"BAC"}
+{"world":"CAC", "line":745}
+{"auth":"CBB", "title":"AA", "user":"AB", "line":746, "pos":35, "public":false, "space":"AAB"}
+{"state":69, "world":"AB", "org":78, "subtitle":"BA", "bad":false, "line":747, "node":"AAA"}
+{"bad":true, "line":748, "public":true}
+{"wait":"BC", "org":47, "query":"BBB", "line":749}
+{"title":"BBB", "line":750}
+{"org":33, "query":"CB", "line":751, "disabled":true}
+{"subtitle":"BB", "line":752, "space":"CC"}
+{"org":89, "line":753}
+{"auth":"ABA", "line":754, "coauthors":"ACC"}
+{"subtitle":"BA", "line":755, "pos":47}
+{"state":81, "subtitle":"CB", "query":"AB", "status":25, "cleaned":false, "line":756, "pos":72, "date":"BA", "coauthors":"BCA"}
+{"state":46, "status":88, "line":757, "disabled":false, "public":true}
+{"world":"AB", "line":758, "disabled":true, "abstract":"BB", "coauthors":"AAA"}
+{"query":"AC", "line":759, "abstract":"AAB"}
+{"auth":"BC", "indexed":false, "line":760, "abstract":"BA", "node":"CAA"}
+{"state":10, "auth":"BAC", "title":"BC", "query":"BCA", "cleaned":true, "line":761, "disabled":true, "space":"ACC", "coauthors":"ABA"}
+{"line":762, "disabled":true, "pos":43}
+{"world":"CBA", "user":"BBC", "indexed":true, "line":763}
+{"wait":"ACB", "query":"BA", "status":22, "line":764, "pos":70, "abstract":"BAC", "public":false, "space":"BC"}
+{}
+{"line":766, "disabled":false, "abstract":"CBC", "date":"CA"}
+{"title":"CC", "bad":true, "user":"BCC", "indexed":false, "line":767, "date":"BCB", "node":"AAA"}
+{"title":"CB", "line":768, "abstract":"AA", "node":"ABB"}
+{"org":21, "user":"ABC", "line":769, "abstract":"BB", "date":"CBB", "space":"CC"}
+{"auth":"AC", "org":66, "user":"CC", "line":770, "public":false, "space":"CA", "coauthors":"AA"}
+{"org":58, "line":771, "coauthors":"BCC", "node":"AC"}
+{}
+{"auth":"BC", "wait":"CC", "line":773, "abstract":"ACC", "pos":98, "date":"CCC", "space":"ABB", "node":"CB"}
+{}
+{"query":"BC", "user":"AC", "indexed":true, "line":775, "abstract":"AAA"}
+{"subtitle":"BAA", "indexed":false, "line":776}
+{"line":777, "pos":33, "date":"CCB", "public":true}
+{"world":"BCA", "bad":true, "line":778}
+{"auth":"CA", "line":779, "date":"AC", "space":"CAC"}
+{"title":"BB", "bad":false, "cleaned":true, "line":780, "disabled":false, "date":"BAB", "space":"ACB"}
+{"auth":"CAC", "title":"AAB", "subtitle":"CA", "bad":false, "line":781, "disabled":false, "space":"CB"}
+{"state":78, "auth":"AC", "bad":true, "status":46, "line":782, "abstract":"CCA", "pos":97, "public":true}
+{"user":"BBA", "line":783}
+{}
+{"state":63, "title":"CA", "cleaned":true, "line":785, "abstract":"BA", "space":"BCC"}
+{"line":786, "node":"CAC"}
+{"line":787, "pos":65}
+{"line":788, "space":"ABB"}
+{}
+{"org":14, "line":790, "abstract":"CAB", "coauthors":"BBC"}
+{"subtitle":"CBA", "cleaned":false, "line":791, "disabled":false, "pos":57, "node":"CB"}
+{"auth":"CAA", "org":84, "wait":"AB", "indexed":true, "status":51, "line":792, "abstract":"CC"}
+{"org":72, "bad":true, "line":793, "space":"ACA"}
+{}
+{"auth":"BC", "state":76, "wait":"CC", "user":"ABB", "cleaned":false, "line":795, "pos":99, "abstract":"CA"}
+{"wait":"CCA", "world":"CBC", "line":796, "date":"CB", "public":false}
+{"state":49, "line":797, "coauthors":"CC"}
+{"wait":"BBB", "title":"ABB", "org":74, "line":798, "disabled":false, "pos":34, "space":"BB"}
+{"line":799, "abstract":"CB"}
+{"state":84, "user":"ABB", "cleaned":false, "status":18, "line":800, "disabled":true, "date":"CCA", "node":"BA"}
+{"state":81, "auth":"CB", "world":"CA", "user":"CAA", "line":801, "date":"AC", "space":"CBC", "coauthors":"BCB"}
+{"org":4, "line":802, "disabled":false, "abstract":"ABA", "public":false}
+{"auth":"CBC", "state":99, "cleaned":true, "line":803, "disabled":true, "space":"BC", "node":"BBC"}
+{"auth":"AC", "wait":"CA", "cleaned":false, "line":804, "pos":54, "date":"BAA", "public":true, "space":"AB"}
+{}
+{"auth":"BCB", "wait":"BCC", "subtitle":"AAA", "line":806}
+{"line":807, "disabled":false, "space":"ACA"}
+{"org":96, "query":"CBA", "line":808, "disabled":false, "pos":74, "space":"CA", "public":false}
+{}
+{"state":12, "title":"AA", "bad":false, "status":20, "line":810, "disabled":true, "coauthors":"CAC", "node":"AB"}
+{"auth":"ABC", "line":811, "date":"CA"}
+{"title":"AB", "indexed":false, "line":812, "disabled":false, "node":"AAC"}
+{}
+{"world":"CBA", "status":15, "line":814, "abstract":"CBA"}
+{"status":49, "line":815, "pos":49}
+{"subtitle":"CAB", "line":816}
+{}
+{}
+{"world":"CAC", "title":"CB", "wait":"AA", "query":"CA", "indexed":true, "line":819, "disabled":true}
+{"auth":"ABB", "wait":"AC", "query":"CC", "cleaned":true, "indexed":false, "line":820, "abstract":"AA", "public":false, "node":"AB"}
+{"org":5, "wait":"BA", "indexed":true, "line":821, "node":"AB"}
+{"title":"CC", "wait":"CC", "bad":false, "query":"BCC", "indexed":false, "line":822, "pos":27, "date":"CB", "node":"CBA"}
+{"query":"BC", "status":28, "line":823, "public":false}
+{"status":1, "line":824, "abstract":"BB"}
+{}
+{"auth":"AA", "title":"BC", "query":"CA", "status":33, "line":826}
+{"state":9, "title":"BB", "subtitle":"ACC", "bad":true, "query":"BA", "status":41, "line":827, "abstract":"ACB", "public":false}
+{"auth":"AB", "subtitle":"CAB", "line":828, "public":false, "coauthors":"AB", "node":"BAC"}
+{"line":829, "disabled":false, "public":true, "node":"CBC"}
+{"auth":"BAB", "line":830}
+{"wait":"BBA", "bad":true, "indexed":false, "line":831, "space":"BB"}
+{"org":70, "wait":"BC", "world":"AC", "indexed":true, "status":96, "line":832, "disabled":true, "space":"AB"}
+{"state":8, "world":"BAB", "bad":true, "indexed":true, "status":18, "line":833, "date":"BA", "space":"BA"}
+{"query":"AB", "line":834}
+{"bad":true, "status":5, "line":835}
+{"world":"BAC", "subtitle":"BB", "bad":false, "user":"AB", "indexed":false, "cleaned":true, "line":836}
+{"line":837, "public":false}
+{"line":838, "pos":7}
+{"auth":"CA", "query":"ABB", "indexed":true, "line":839, "public":true}
+{"wait":"CC", "bad":false, "line":840, "date":"AAB", "public":false, "coauthors":"BCB"}
+{"auth":"AB", "state":97, "org":24, "line":841, "pos":41, "node":"BC"}
+{"wait":"BB", "world":"CBA", "user":"BAA", "status":18, "line":842, "date":"BAB", "public":true}
+{"title":"BA", "subtitle":"CA", "query":"CCB", "line":843, "space":"BB"}
+{"auth":"BB", "world":"ACA", "line":844, "pos":29}
+{"state":65, "org":40, "query":"CAA", "user":"AB", "indexed":false, "cleaned":false, "line":845}
+{"title":"CB", "cleaned":false, "indexed":false, "line":846}
+{"wait":"CAA", "indexed":false, "line":847, "disabled":false}
+{}
+{"title":"CB", "query":"CC", "line":849, "abstract":"CB", "pos":10, "public":true}
+{"auth":"CB", "subtitle":"BA", "cleaned":true, "line":850, "disabled":true, "pos":84}
+{"org":45, "wait":"BA", "query":"CCC", "line":851, "date":"BCA", "coauthors":"CAB"}
+{"state":84, "title":"CB", "line":852, "pos":71, "space":"CA"}
+{"line":853, "public":true, "node":"AA"}
+{"subtitle":"BC", "user":"AB", "cleaned":true, "line":854, "public":true}
+{"state":26, "wait":"BA", "world":"BBB", "user":"BB", "status":53, "line":855, "abstract":"ABA", "pos":72, "space":"AC"}
+{"line":856, "public":false, "coauthors":"CA"}
+{"wait":"ABB", "subtitle":"CBA", "line":857, "pos":44}
+{"auth":"ABA", "wait":"CC", "org":0, "bad":true, "query":"BB", "line":858, "disabled":false, "public":true}
+{"bad":false, "user":"AA", "line":859, "pos":90}
+{"world":"BCC", "title":"BAA", "bad":false, "user":"CAA", "query":"BBC", "line":860, "date":"CAA", "space":"BCB", "public":true, "coauthors":"CB"}
+{"title":"BAB", "world":"BC", "subtitle":"AA", "cleaned":false, "status":9, "line":861, "pos":95}
+{"title":"AC", "line":862}
+{"wait":"CB", "bad":false, "status":89, "line":863, "coauthors":"AB"}
+{"subtitle":"ACC", "indexed":true, "cleaned":true, "line":864}
+{"title":"AB", "subtitle":"CBB", "query":"ACA", "indexed":true, "line":865, "disabled":true}
+{"title":"BC", "world":"BB", "query":"AA", "user":"ACB", "status":43, "cleaned":false, "line":866, "coauthors":"CBC", "node":"ACB"}
+{}
+{"org":25, "wait":"AC", "indexed":false, "line":868, "disabled":false, "abstract":"CA", "pos":48}
+{"bad":true, "status":34, "line":869, "pos":32, "date":"AC", "public":true, "node":"AA"}
+{"state":33, "wait":"AAC", "indexed":true, "status":20, "line":870, "abstract":"BA"}
+{"wait":"CCC", "subtitle":"AC", "line":871, "disabled":false, "space":"BA", "public":true, "coauthors":"BCC"}
+{"status":49, "line":872}
+{"state":90, "title":"ACC", "world":"CBB", "subtitle":"BAB", "bad":false, "status":94, "line":873, "abstract":"CB"}
+{"title":"BCB", "line":874}
+{"cleaned":false, "line":875}
+{"wait":"BAA", "subtitle":"BBC", "line":876}
+{"auth":"AB", "org":35, "bad":false, "indexed":false, "line":877, "coauthors":"BBA"}
+{"line":878, "public":false}
+{}
+{"auth":"CB", "wait":"CBC", "indexed":false, "line":880, "public":true}
+{"query":"CC", "status":4, "line":881, "disabled":true, "node":"CA"}
+{"title":"BB", "line":882}
+{"state":53, "bad":false, "cleaned":false, "status":63, "line":883, "coauthors":"BAA"}
+{"auth":"ACA", "world":"AC", "user":"CBC", "line":884, "date":"BCA", "node":"BBC"}
+{"auth":"BAB", "state":11, "world":"CB", "org":77, "query":"BA", "cleaned":false, "line":885, "space":"AC"}
+{"world":"CA", "user":"CA", "line":886, "node":"CB"}
+{"state":32, "org":50, "wait":"AA", "line":887, "disabled":false, "space":"BBA", "public":false}
+{"cleaned":true, "line":888, "pos":70, "node":"ABC"}
+{"org":63, "user":"AAB", "query":"BB", "line":889, "date":"BC", "space":"CBB", "node":"ABC"}
+{"wait":"BB", "user":"BB", "query":"CB", "line":890, "space":"BB", "coauthors":"BA", "node":"ABC"}
+{"auth":"BC", "world":"CC", "subtitle":"CB", "line":891, "public":false, "coauthors":"BC"}
+{"state":13, "org":38, "line":892, "coauthors":"BC", "node":"ABC"}
+{"auth":"CC", "world":"CAC", "line":893, "date":"BBA", "node":"CBC"}
+{}
+{"auth":"AA", "line":895, "coauthors":"BB"}
+{"auth":"AA", "state":76, "status":85, "line":896, "date":"CCC", "public":true, "coauthors":"AB"}
+{"auth":"AB", "indexed":true, "cleaned":false, "line":897}
+{"line":898, "coauthors":"CBB"}
+{}
+{"wait":"ACC", "line":900, "abstract":"BBA"}
+{"auth":"AA", "wait":"BCB", "cleaned":false, "line":901, "abstract":"AAC"}
+{"state":68, "title":"AC", "subtitle":"BB", "line":902}
+{"state":41, "wait":"ABA", "bad":false, "user":"BBA", "status":46, "line":903, "node":"AAB"}
+{}
+{"cleaned":false, "line":905, "pos":33}
+{"bad":false, "query":"BA", "line":906, "pos":48, "space":"CB", "public":true}
+{"query":"CB", "indexed":true, "line":907, "pos":41, "abstract":"CBB", "space":"BA", "public":false, "node":"BC"}
+{"title":"AB", "line":908}
+{"auth":"BC", "title":"CB", "line":909, "disabled":false, "space":"CA", "public":true, "coauthors":"BC"}
+{"world":"AA", "user":"ABA", "indexed":false, "line":910, "abstract":"CC"}
+{"auth":"CCA", "indexed":false, "line":911, "date":"AC", "public":false}
+{"world":"AAB", "bad":true, "line":912}
+{"subtitle":"CBB", "line":913, "public":true}
+{"wait":"CB", "line":914, "disabled":false, "pos":71, "date":"BA", "space":"CBA", "public":false, "coauthors":"BB"}
+{"org":67, "wait":"CA", "bad":false, "line":915, "disabled":false, "public":true}
+{}
+{"line":917, "date":"CB"}
+{"auth":"CBB", "world":"AAA", "status":83, "indexed":false, "line":918, "disabled":true, "date":"CBA", "coauthors":"ACC"}
+{"wait":"AB", "title":"BA", "status":33, "line":919, "disabled":false}
+{"wait":"ACB", "cleaned":false, "line":920, "abstract":"AA", "coauthors":"BCB"}
+{"wait":"ABB", "org":40, "world":"BC", "subtitle":"CA", "user":"AAC", "status":14, "indexed":true, "line":921, "pos":66}
+{"auth":"BA", "org":22, "wait":"BAB", "bad":true, "user":"ACC", "status":32, "line":922}
+{"world":"BA", "query":"CAB", "status":0, "line":923}
+{"org":84, "bad":true, "line":924, "coauthors":"BAB"}
+{"auth":"ACC", "subtitle":"AAA", "query":"CCA", "cleaned":false, "line":925, "pos":60, "space":"BC"}
+{"wait":"BC", "subtitle":"CCC", "bad":false, "cleaned":false, "indexed":false, "line":926, "public":false, "coauthors":"AC"}
+{"auth":"CA", "state":91, "org":6, "world":"AA", "wait":"ABB", "query":"AAC", "line":927, "date":"CA", "node":"BAC"}
+{"world":"BCA", "query":"AA", "user":"BBC", "line":928, "disabled":false}
+{"world":"CBC", "user":"CBC", "line":929, "date":"CAC"}
+{"world":"BCB", "bad":false, "user":"BB", "line":930}
+{"auth":"CA", "world":"AA", "query":"ABA", "user":"AA", "indexed":true, "line":931, "coauthors":"BBC"}
+{"auth":"BAA", "bad":true, "line":932, "disabled":false, "pos":93, "abstract":"CCA", "date":"BBA", "coauthors":"AA"}
+{"line":933, "space":"CAB", "node":"AB"}
+{}
+{"status":60, "cleaned":true, "indexed":true, "line":935, "pos":35, "space":"CAB", "node":"BBB"}
+{"wait":"AAA", "bad":true, "status":26, "line":936, "abstract":"ACB", "space":"BBA", "coauthors":"CCC"}
+{"title":"BA", "bad":true, "line":937, "date":"BBA", "public":true}
+{}
+{"query":"BA", "user":"BA", "line":939, "disabled":true}
+{"line":940, "date":"CC"}
+{"wait":"CAB", "query":"BCA", "user":"BC", "line":941, "pos":8, "coauthors":"ACC"}
+{"line":942, "space":"BA"}
+{"auth":"CA", "org":11, "line":943, "pos":99}
+{"org":83, "line":944, "disabled":false, "date":"BBA", "space":"AC", "node":"AC"}
+{"world":"CCA", "line":945, "node":"BC"}
+{"org":95, "title":"CA", "world":"BA", "line":946, "pos":36, "coauthors":"CA"}
+{"state":93, "line":947}
+{"cleaned":false, "status":5, "line":948, "abstract":"BB", "public":false, "coauthors":"ABC"}
+{"world":"CA", "org":61, "bad":false, "query":"CC", "cleaned":true, "line":949, "pos":14, "space":"CC"}
+{"state":91, "line":950, "abstract":"BA", "date":"AB"}
+{"auth":"BBC", "line":951, "date":"BB"}
+{"auth":"BAB", "line":952, "disabled":true, "node":"AAA"}
+{"auth":"CAA", "subtitle":"ABA", "bad":true, "line":953}
+{"auth":"CA", "wait":"BB", "org":12, "user":"BCC", "cleaned":false, "line":954, "public":false, "coauthors":"AA"}
+{"org":93, "cleaned":true, "line":955, "disabled":true, "public":true, "node":"ACA"}
+{"line":956, "pos":10}
+{"org":74, "world":"CCC", "subtitle":"AB", "user":"AAA", "cleaned":true, "line":957, "pos":70, "public":true, "node":"CC"}
+{"state":51, "line":958}
+{"world":"CCA", "title":"BCB", "user":"AB", "indexed":true, "line":959, "disabled":true, "pos":21, "date":"CBC"}
+{"org":86, "wait":"BC", "query":"BB", "user":"AA", "indexed":true, "line":960, "pos":58, "date":"AB"}
+{"line":961, "node":"CC"}
+{"auth":"BCB", "world":"ACC", "subtitle":"CA", "bad":true, "user":"BA", "indexed":false, "line":962, "public":false}
+{}
+{"status":37, "line":964}
+{"state":70, "status":76, "indexed":false, "line":965, "disabled":true, "space":"BB"}
+{}
+{"state":67, "world":"CA", "title":"AA", "line":967, "abstract":"BA", "space":"BAA"}
+{"auth":"CA", "world":"AA", "bad":true, "query":"BC", "status":53, "indexed":false, "line":968, "date":"AB", "node":"BAA"}
+{"query":"AC", "cleaned":true, "line":969, "abstract":"BC", "space":"CAB", "coauthors":"BAA"}
+{"wait":"BCA", "world":"CB", "title":"BC", "indexed":false, "line":970, "disabled":true, "pos":70, "date":"AB"}
+{}
+{"subtitle":"BC", "query":"AA", "line":972}
+{"line":973, "public":true}
+{"org":75, "world":"AAB", "subtitle":"BB", "user":"CC", "line":974, "space":"CA"}
+{"auth":"BCB", "cleaned":true, "line":975}
+{"title":"BAC", "user":"CB", "line":976, "public":false}
+{"subtitle":"BAC", "indexed":false, "cleaned":false, "line":977, "disabled":false, "abstract":"ABC", "space":"ABA"}
+{"state":63, "bad":false, "line":978, "pos":93, "node":"AAC"}
+{}
+{"cleaned":false, "line":980, "abstract":"CCB"}
+{"state":40, "title":"ABA", "subtitle":"CAB", "query":"BC", "line":981, "date":"CA", "coauthors":"AB"}
+{}
+{"auth":"ABA", "subtitle":"ACC", "user":"AA", "query":"AC", "cleaned":true, "line":983, "date":"ACB", "node":"CB"}
+{"state":32, "title":"ABC", "org":58, "status":95, "line":984, "disabled":true, "pos":6, "space":"CBB"}
+{"title":"BCC", "subtitle":"CCC", "user":"BBC", "line":985, "public":false, "coauthors":"CCB", "node":"AA"}
+{"subtitle":"ACA", "query":"BCC", "status":43, "cleaned":true, "indexed":true, "line":986, "abstract":"CAC"}
+{}
+{"world":"CAB", "org":21, "indexed":true, "line":988, "abstract":"ABC"}
+{"title":"CBC", "status":66, "line":989}
+{}
+{"array":[5]}
+{"array":["foo", "bar", "baz"]}
+{"array":["bar", "baz", "foo"]}
+{"array":["bar", "baz"]}
+{"array":["baz", "foo"]}
+{"line":991, "abstract":"BA", "node":"BBB"}
+{"line":992, "disabled":true, "pos":29, "public":false}
+{"state":53, "wait":"CB", "subtitle":"CCC", "line":993, "date":"CAC", "public":false, "coauthors":"BB"}
+{"wait":"CBA", "title":"CA", "subtitle":"BB", "user":"BAA", "line":994, "disabled":true, "date":"BB", "coauthors":"CCC", "node":"CC"}
+{"title":"BB", "user":"AA", "query":"CAA", "status":43, "line":995, "pos":6, "abstract":"CC", "public":true}
+{"wait":"AC", "query":"BA", "line":996, "coauthors":"BB", "node":"CCC"}
+{"auth":"BC", "title":"CAC", "subtitle":"BA", "line":997, "date":"BAA"}
+{"wait":"AB", "user":"ABC", "line":998, "pos":41, "node":"CAC"}
+{"state":4, "title":"AC", "bad":true, "status":59, "line":999, "disabled":true}
+{"user":"BC", "line":1000}
+{"wait":null, "line":1000}
+{"age":25}
+{"age":25.0}
+{}
diff --git a/src/test/regress/expected/json.out b/src/test/regress/expected/json.out
index 04b969ae101..9f086763c25 100644
--- a/src/test/regress/expected/json.out
+++ b/src/test/regress/expected/json.out
@@ -464,8 +464,8 @@ CREATE TEMP TABLE test_json (
);
INSERT INTO test_json VALUES
('scalar','"a scalar"'),
-('array','["zero", "one","two",null,"four","five"]'),
-('object','{"field1":"val1","field2":"val2","field3":null}');
+('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';
@@ -522,6 +522,36 @@ WHERE json_type = 'array';
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';
@@ -538,7 +568,20 @@ WHERE json_type = 'object';
field1
field2
field3
-(3 rows)
+ 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
diff --git a/src/test/regress/expected/json_1.out b/src/test/regress/expected/json_1.out
index 07b25ca96c6..13f7687608e 100644
--- a/src/test/regress/expected/json_1.out
+++ b/src/test/regress/expected/json_1.out
@@ -464,8 +464,8 @@ CREATE TEMP TABLE test_json (
);
INSERT INTO test_json VALUES
('scalar','"a scalar"'),
-('array','["zero", "one","two",null,"four","five"]'),
-('object','{"field1":"val1","field2":"val2","field3":null}');
+('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';
@@ -522,6 +522,36 @@ WHERE json_type = 'array';
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';
@@ -538,7 +568,20 @@ WHERE json_type = 'object';
field1
field2
field3
-(3 rows)
+ 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
diff --git a/src/test/regress/expected/jsonb.out b/src/test/regress/expected/jsonb.out
new file mode 100644
index 00000000000..e25483d2f53
--- /dev/null
+++ b/src/test/regress/expected/jsonb.out
@@ -0,0 +1,2056 @@
+-- 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 '"\u0000"'::jsonb; -- OK, legal escape
+ jsonb
+-----------
+ "\\u0000"
+(1 row)
+
+-- 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)
+
+-- 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...
+-- 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)
+
+-- 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';
+ERROR: cannot call jsonb_object_field (jsonb -> text operator) on a scalar
+SELECT test_json -> 'x' FROM test_jsonb WHERE json_type = 'array';
+ERROR: cannot call jsonb_object_field (jsonb -> text operator) on an array
+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';
+ERROR: cannot call jsonb_object_field_text (jsonb ->> text operator) on a scalar
+SELECT test_json ->> 'field2' FROM test_jsonb WHERE json_type = 'array';
+ERROR: cannot call jsonb_object_field_text (jsonb ->> text operator) on an array
+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';
+ERROR: cannot call jsonb_array_element (jsonb -> int operator) on a scalar
+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';
+ERROR: cannot call jsonb_array_element (jsonb -> int operator) on an object
+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';
+ERROR: cannot call jsonb_array_element_text on a scalar
+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';
+ERROR: cannot call jsonb_array_element_text on an object
+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)
+
+-- 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)
+
+CREATE TABLE testjsonb (j jsonb);
+\copy testjsonb FROM 'data/jsonb.data'
+-- 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 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)
+
+-- 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)
+
+-- same using array literals
+SELECT '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>'{f4,f6}';
+ ?column?
+-----------
+ "stringy"
+(1 row)
+
+SELECT '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>'{f2}';
+ ?column?
+-----------
+ {"f3": 1}
+(1 row)
+
+SELECT '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>'{f2,0}';
+ ?column?
+----------
+ "f3"
+(1 row)
+
+SELECT '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>'{f2,1}';
+ ?column?
+----------
+ 1
+(1 row)
+
+SELECT '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>>'{f4,f6}';
+ ?column?
+----------
+ stringy
+(1 row)
+
+SELECT '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>>'{f2}';
+ ?column?
+-----------
+ {"f3": 1}
+(1 row)
+
+SELECT '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>>'{f2,0}';
+ ?column?
+----------
+ f3
+(1 row)
+
+SELECT '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>>'{f2,1}';
+ ?column?
+----------
+ 1
+(1 row)
+
+-- same on jsonb scalars (expecting errors)
+SELECT '42'::jsonb#>array['f2'];
+ERROR: cannot call extract path from a scalar
+SELECT '42'::jsonb#>array['0'];
+ERROR: cannot call extract path from a scalar
+SELECT '42'::jsonb#>>array['f2'];
+ERROR: cannot call extract path from a scalar
+SELECT '42'::jsonb#>>array['0'];
+ERROR: cannot call extract path from a scalar
+-- 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}', true) 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}', true) 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}', true) 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}', true) 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}', true) 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"}]',false) 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"}]',false) 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"}]',true) 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"}]',true) 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"}]',true) 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"}]',true) q;
+ERROR: invalid input syntax for type timestamp: "[100, 200, 300]"
+-- using the default use_json_as_text argument
+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;
+ERROR: cannot populate with a nested object unless use_json_as_text is true
+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: cannot populate with a nested object unless use_json_as_text is true
+-- 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" }' ->> '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": "null \u0000 escape" }' ->> 'a' AS not_unescaped;
+ not_unescaped
+--------------------
+ null \u0000 escape
+(1 row)
+
+-- 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 ?| 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)
+
+-- excercise GIN_SEARCH_MODE_ALL
+SELECT count(*) FROM testjsonb WHERE j @> '{}';
+ count
+-------
+ 1009
+(1 row)
+
+SELECT count(*) FROM testjsonb WHERE j ? 'public';
+ count
+-------
+ 194
+(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
+-------
+ 4788
+(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
+(24 rows)
+
+-- sort/hash
+SELECT count(distinct j) FROM testjsonb;
+ count
+-------
+ 891
+(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
+-------
+ 891
+(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
+-------
+ 891
+(1 row)
+
+SELECT distinct * FROM (values (jsonb '{}' || ''),('{}')) 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 hash
+DROP INDEX jidx;
+CREATE INDEX jidx ON testjsonb USING gin (j jsonb_hash_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)
+
+-- excercise GIN_SEARCH_MODE_ALL
+SELECT count(*) FROM testjsonb WHERE j @> '{}';
+ count
+-------
+ 1009
+(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
+ERROR: cannot call jsonb_array_element (jsonb -> int operator) on an object
+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?
+----------
+
+(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?
+----------
+
+(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)
+
diff --git a/src/test/regress/expected/jsonb_1.out b/src/test/regress/expected/jsonb_1.out
new file mode 100644
index 00000000000..06af5c8252a
--- /dev/null
+++ b/src/test/regress/expected/jsonb_1.out
@@ -0,0 +1,2056 @@
+-- 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 '"\u0000"'::jsonb; -- OK, legal escape
+ jsonb
+-----------
+ "\\u0000"
+(1 row)
+
+-- 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: invalid input syntax for type json
+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...
+-- 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)
+
+-- 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';
+ERROR: cannot call jsonb_object_field (jsonb -> text operator) on a scalar
+SELECT test_json -> 'x' FROM test_jsonb WHERE json_type = 'array';
+ERROR: cannot call jsonb_object_field (jsonb -> text operator) on an array
+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';
+ERROR: cannot call jsonb_object_field_text (jsonb ->> text operator) on a scalar
+SELECT test_json ->> 'field2' FROM test_jsonb WHERE json_type = 'array';
+ERROR: cannot call jsonb_object_field_text (jsonb ->> text operator) on an array
+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';
+ERROR: cannot call jsonb_array_element (jsonb -> int operator) on a scalar
+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';
+ERROR: cannot call jsonb_array_element (jsonb -> int operator) on an object
+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';
+ERROR: cannot call jsonb_array_element_text on a scalar
+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';
+ERROR: cannot call jsonb_array_element_text on an object
+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)
+
+-- 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)
+
+CREATE TABLE testjsonb (j jsonb);
+\copy testjsonb FROM 'data/jsonb.data'
+-- 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 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)
+
+-- 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)
+
+-- same using array literals
+SELECT '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>'{f4,f6}';
+ ?column?
+-----------
+ "stringy"
+(1 row)
+
+SELECT '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>'{f2}';
+ ?column?
+-----------
+ {"f3": 1}
+(1 row)
+
+SELECT '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>'{f2,0}';
+ ?column?
+----------
+ "f3"
+(1 row)
+
+SELECT '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>'{f2,1}';
+ ?column?
+----------
+ 1
+(1 row)
+
+SELECT '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>>'{f4,f6}';
+ ?column?
+----------
+ stringy
+(1 row)
+
+SELECT '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>>'{f2}';
+ ?column?
+-----------
+ {"f3": 1}
+(1 row)
+
+SELECT '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>>'{f2,0}';
+ ?column?
+----------
+ f3
+(1 row)
+
+SELECT '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>>'{f2,1}';
+ ?column?
+----------
+ 1
+(1 row)
+
+-- same on jsonb scalars (expecting errors)
+SELECT '42'::jsonb#>array['f2'];
+ERROR: cannot call extract path from a scalar
+SELECT '42'::jsonb#>array['0'];
+ERROR: cannot call extract path from a scalar
+SELECT '42'::jsonb#>>array['f2'];
+ERROR: cannot call extract path from a scalar
+SELECT '42'::jsonb#>>array['0'];
+ERROR: cannot call extract path from a scalar
+-- 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}', true) 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}', true) 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}', true) 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}', true) 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}', true) 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"}]',false) 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"}]',false) 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"}]',true) 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"}]',true) 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"}]',true) 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"}]',true) q;
+ERROR: invalid input syntax for type timestamp: "[100, 200, 300]"
+-- using the default use_json_as_text argument
+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;
+ERROR: cannot populate with a nested object unless use_json_as_text is true
+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: cannot populate with a nested object unless use_json_as_text is true
+-- handling of unicode surrogate pairs
+SELECT octet_length((jsonb '{ "a": "\ud83d\ude04\ud83d\udc36" }' -> 'a')::text) AS correct_in_utf8;
+ERROR: invalid input syntax for type json
+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" }' ->> 'a' AS correct_in_utf8;
+ERROR: invalid input syntax for type json
+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": "null \u0000 escape" }' ->> 'a' AS not_unescaped;
+ not_unescaped
+--------------------
+ null \u0000 escape
+(1 row)
+
+-- 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 ?| 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)
+
+-- excercise GIN_SEARCH_MODE_ALL
+SELECT count(*) FROM testjsonb WHERE j @> '{}';
+ count
+-------
+ 1009
+(1 row)
+
+SELECT count(*) FROM testjsonb WHERE j ? 'public';
+ count
+-------
+ 194
+(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
+-------
+ 4788
+(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
+(24 rows)
+
+-- sort/hash
+SELECT count(distinct j) FROM testjsonb;
+ count
+-------
+ 891
+(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
+-------
+ 891
+(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
+-------
+ 891
+(1 row)
+
+SELECT distinct * FROM (values (jsonb '{}' || ''),('{}')) 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 hash
+DROP INDEX jidx;
+CREATE INDEX jidx ON testjsonb USING gin (j jsonb_hash_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)
+
+-- excercise GIN_SEARCH_MODE_ALL
+SELECT count(*) FROM testjsonb WHERE j @> '{}';
+ count
+-------
+ 1009
+(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
+ERROR: cannot call jsonb_array_element (jsonb -> int operator) on an object
+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?
+----------
+
+(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?
+----------
+
+(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)
+
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 5627b4a426d..bf765014357 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -1127,6 +1127,10 @@ ORDER BY 1, 2, 3;
2742 | 2 | @@@
2742 | 3 | <@
2742 | 4 | =
+ 2742 | 7 | @>
+ 2742 | 9 | ?
+ 2742 | 10 | ?|
+ 2742 | 11 | ?&
4000 | 1 | <<
4000 | 1 | ~<~
4000 | 2 | &<
@@ -1149,7 +1153,7 @@ ORDER BY 1, 2, 3;
4000 | 15 | >
4000 | 16 | @>
4000 | 18 | =
-(67 rows)
+(71 rows)
-- Check that all opclass search operators have selectivity estimators.
-- This is not absolutely required, but it seems a reasonable thing
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 2e3eba83dee..c62be2a023e 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -98,8 +98,7 @@ test: event_trigger
# ----------
# Another group of parallel tests
# ----------
-test: select_views portals_p2 foreign_key cluster dependency guc bitmapops combocid tsearch tsdicts foreign_data window xmlmap functional_deps advisory_lock json indirect_toast
-
+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
# ----------
# Another group of parallel tests
# NB: temp.sql does a reconnect which transiently uses 2 connections,
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 4f1dedec2b5..885ca9aa5dd 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -122,6 +122,7 @@ test: xmlmap
test: functional_deps
test: advisory_lock
test: json
+test: jsonb
test: indirect_toast
test: plancache
test: limit
diff --git a/src/test/regress/sql/json.sql b/src/test/regress/sql/json.sql
index 2d3f0bcc612..2ae5b827990 100644
--- a/src/test/regress/sql/json.sql
+++ b/src/test/regress/sql/json.sql
@@ -136,8 +136,8 @@ CREATE TEMP TABLE test_json (
INSERT INTO test_json VALUES
('scalar','"a scalar"'),
-('array','["zero", "one","two",null,"four","five"]'),
-('object','{"field1":"val1","field2":"val2","field3":null}');
+('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
@@ -175,6 +175,13 @@ SELECT test_json->>2
FROM test_json
WHERE json_type = 'array';
+SELECT test_json ->> 6 FROM test_json WHERE json_type = 'array';
+SELECT test_json ->> 7 FROM test_json WHERE json_type = 'array';
+
+SELECT test_json ->> 'field4' FROM test_json WHERE json_type = 'object';
+SELECT test_json ->> 'field5' FROM test_json WHERE json_type = 'object';
+SELECT test_json ->> 'field6' FROM test_json WHERE json_type = 'object';
+
SELECT json_object_keys(test_json)
FROM test_json
WHERE json_type = 'scalar';
@@ -187,6 +194,13 @@ SELECT json_object_keys(test_json)
FROM test_json
WHERE json_type = 'object';
+-- 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;
+
-- nulls
select (test_json->'field3') is null as expect_false
diff --git a/src/test/regress/sql/jsonb.sql b/src/test/regress/sql/jsonb.sql
new file mode 100644
index 00000000000..1ef49138bb8
--- /dev/null
+++ b/src/test/regress/sql/jsonb.sql
@@ -0,0 +1,479 @@
+-- Strings.
+SELECT '""'::jsonb; -- OK.
+SELECT $$''$$::jsonb; -- ERROR, single quotes are not allowed
+SELECT '"abc"'::jsonb; -- OK
+SELECT '"abc'::jsonb; -- ERROR, quotes not closed
+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 '"\u0000"'::jsonb; -- OK, legal escape
+-- 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
+
+-- Numbers.
+SELECT '1'::jsonb; -- OK
+SELECT '0'::jsonb; -- OK
+SELECT '01'::jsonb; -- ERROR, not valid according to JSON spec
+SELECT '0.1'::jsonb; -- OK
+SELECT '9223372036854775808'::jsonb; -- OK, even though it's too large for int8
+SELECT '1e100'::jsonb; -- OK
+SELECT '1.3e100'::jsonb; -- OK
+SELECT '1f2'::jsonb; -- ERROR
+SELECT '0.x1'::jsonb; -- ERROR
+SELECT '1.3ex100'::jsonb; -- ERROR
+
+-- Arrays.
+SELECT '[]'::jsonb; -- OK
+SELECT '[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]'::jsonb; -- OK
+SELECT '[1,2]'::jsonb; -- OK
+SELECT '[1,2,]'::jsonb; -- ERROR, trailing comma
+SELECT '[1,2'::jsonb; -- ERROR, no closing bracket
+SELECT '[1,[2]'::jsonb; -- ERROR, no closing bracket
+
+-- Objects.
+SELECT '{}'::jsonb; -- OK
+SELECT '{"abc"}'::jsonb; -- ERROR, no value
+SELECT '{"abc":1}'::jsonb; -- OK
+SELECT '{1:"abc"}'::jsonb; -- ERROR, keys must be strings
+SELECT '{"abc",1}'::jsonb; -- ERROR, wrong separator
+SELECT '{"abc"=1}'::jsonb; -- ERROR, totally wrong separator
+SELECT '{"abc"::1}'::jsonb; -- ERROR, another wrong separator
+SELECT '{"abc":1,"def":2,"ghi":[3,4],"hij":{"klm":5,"nop":[6]}}'::jsonb; -- OK
+SELECT '{"abc":1:2}'::jsonb; -- ERROR, colon in wrong spot
+SELECT '{"abc":1,3}'::jsonb; -- ERROR, no value
+
+-- Miscellaneous stuff.
+SELECT 'true'::jsonb; -- OK
+SELECT 'false'::jsonb; -- OK
+SELECT 'null'::jsonb; -- OK
+SELECT ' true '::jsonb; -- OK, even with extra whitespace
+SELECT 'true false'::jsonb; -- ERROR, too many values
+SELECT 'true, false'::jsonb; -- ERROR, too many values
+SELECT 'truf'::jsonb; -- ERROR, not a keyword
+SELECT 'trues'::jsonb; -- ERROR, not a keyword
+SELECT ''::jsonb; -- ERROR, no value
+SELECT ' '::jsonb; -- ERROR, no value
+
+-- make sure jsonb is passed through json generators without being escaped
+SELECT array_to_json(ARRAY [jsonb '{"a":1}', jsonb '{"b":[2,3]}']);
+
+-- 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';
+SELECT test_json -> 'x' FROM test_jsonb WHERE json_type = 'array';
+SELECT test_json -> 'x' FROM test_jsonb WHERE json_type = 'object';
+SELECT test_json -> 'field2' FROM test_jsonb WHERE json_type = 'object';
+
+SELECT test_json ->> 'field2' FROM test_jsonb WHERE json_type = 'scalar';
+SELECT test_json ->> 'field2' FROM test_jsonb WHERE json_type = 'array';
+SELECT test_json ->> 'field2' FROM test_jsonb WHERE json_type = 'object';
+
+SELECT test_json -> 2 FROM test_jsonb WHERE json_type = 'scalar';
+SELECT test_json -> 2 FROM test_jsonb WHERE json_type = 'array';
+SELECT test_json -> 9 FROM test_jsonb WHERE json_type = 'array';
+SELECT test_json -> 2 FROM test_jsonb WHERE json_type = 'object';
+
+SELECT test_json ->> 6 FROM test_jsonb WHERE json_type = 'array';
+SELECT test_json ->> 7 FROM test_jsonb WHERE json_type = 'array';
+
+SELECT test_json ->> 'field4' FROM test_jsonb WHERE json_type = 'object';
+SELECT test_json ->> 'field5' FROM test_jsonb WHERE json_type = 'object';
+SELECT test_json ->> 'field6' FROM test_jsonb WHERE json_type = 'object';
+
+SELECT test_json ->> 2 FROM test_jsonb WHERE json_type = 'scalar';
+SELECT test_json ->> 2 FROM test_jsonb WHERE json_type = 'array';
+SELECT test_json ->> 2 FROM test_jsonb WHERE json_type = 'object';
+
+SELECT jsonb_object_keys(test_json) FROM test_jsonb WHERE json_type = 'scalar';
+SELECT jsonb_object_keys(test_json) FROM test_jsonb WHERE json_type = 'array';
+SELECT jsonb_object_keys(test_json) FROM test_jsonb WHERE json_type = 'object';
+
+-- nulls
+SELECT (test_json->'field3') IS NULL AS expect_false FROM test_jsonb WHERE json_type = 'object';
+SELECT (test_json->>'field3') IS NULL AS expect_true FROM test_jsonb WHERE json_type = 'object';
+SELECT (test_json->3) IS NULL AS expect_false FROM test_jsonb WHERE json_type = 'array';
+SELECT (test_json->>3) IS NULL AS expect_true FROM test_jsonb WHERE json_type = 'array';
+
+-- equality and inequality
+SELECT '{"x":"y"}'::jsonb = '{"x":"y"}'::jsonb;
+SELECT '{"x":"y"}'::jsonb = '{"x":"z"}'::jsonb;
+
+SELECT '{"x":"y"}'::jsonb <> '{"x":"y"}'::jsonb;
+SELECT '{"x":"y"}'::jsonb <> '{"x":"z"}'::jsonb;
+
+CREATE TABLE testjsonb (j jsonb);
+\copy testjsonb FROM 'data/jsonb.data'
+
+-- containment
+SELECT jsonb_contains('{"a":"b", "b":1, "c":null}', '{"a":"b"}');
+SELECT jsonb_contains('{"a":"b", "b":1, "c":null}', '{"a":"b", "c":null}');
+SELECT jsonb_contains('{"a":"b", "b":1, "c":null}', '{"a":"b", "g":null}');
+SELECT jsonb_contains('{"a":"b", "b":1, "c":null}', '{"g":null}');
+SELECT jsonb_contains('{"a":"b", "b":1, "c":null}', '{"a":"c"}');
+SELECT jsonb_contains('{"a":"b", "b":1, "c":null}', '{"a":"b"}');
+SELECT jsonb_contains('{"a":"b", "b":1, "c":null}', '{"a":"b", "c":"q"}');
+SELECT '{"a":"b", "b":1, "c":null}'::jsonb @> '{"a":"b"}';
+SELECT '{"a":"b", "b":1, "c":null}'::jsonb @> '{"a":"b", "c":null}';
+SELECT '{"a":"b", "b":1, "c":null}'::jsonb @> '{"a":"b", "g":null}';
+SELECT '{"a":"b", "b":1, "c":null}'::jsonb @> '{"g":null}';
+SELECT '{"a":"b", "b":1, "c":null}'::jsonb @> '{"a":"c"}';
+SELECT '{"a":"b", "b":1, "c":null}'::jsonb @> '{"a":"b"}';
+SELECT '{"a":"b", "b":1, "c":null}'::jsonb @> '{"a":"b", "c":"q"}';
+
+SELECT jsonb_contained('{"a":"b"}', '{"a":"b", "b":1, "c":null}');
+SELECT jsonb_contained('{"a":"b", "c":null}', '{"a":"b", "b":1, "c":null}');
+SELECT jsonb_contained('{"a":"b", "g":null}', '{"a":"b", "b":1, "c":null}');
+SELECT jsonb_contained('{"g":null}', '{"a":"b", "b":1, "c":null}');
+SELECT jsonb_contained('{"a":"c"}', '{"a":"b", "b":1, "c":null}');
+SELECT jsonb_contained('{"a":"b"}', '{"a":"b", "b":1, "c":null}');
+SELECT jsonb_contained('{"a":"b", "c":"q"}', '{"a":"b", "b":1, "c":null}');
+SELECT '{"a":"b"}'::jsonb <@ '{"a":"b", "b":1, "c":null}';
+SELECT '{"a":"b", "c":null}'::jsonb <@ '{"a":"b", "b":1, "c":null}';
+SELECT '{"a":"b", "g":null}'::jsonb <@ '{"a":"b", "b":1, "c":null}';
+SELECT '{"g":null}'::jsonb <@ '{"a":"b", "b":1, "c":null}';
+SELECT '{"a":"c"}'::jsonb <@ '{"a":"b", "b":1, "c":null}';
+SELECT '{"a":"b"}'::jsonb <@ '{"a":"b", "b":1, "c":null}';
+SELECT '{"a":"b", "c":"q"}'::jsonb <@ '{"a":"b", "b":1, "c":null}';
+-- Raw scalar may contain another raw scalar, array may contain a raw scalar
+SELECT '[5]'::jsonb @> '[5]';
+SELECT '5'::jsonb @> '5';
+SELECT '[5]'::jsonb @> '5';
+-- But a raw scalar cannot contain an array
+SELECT '5'::jsonb @> '[5]';
+-- In general, one thing should always contain itself. Test array containment:
+SELECT '["9", ["7", "3"], 1]'::jsonb @> '["9", ["7", "3"], 1]'::jsonb;
+SELECT '["9", ["7", "3"], ["1"]]'::jsonb @> '["9", ["7", "3"], ["1"]]'::jsonb;
+-- array containment string matching confusion bug
+SELECT '{ "name": "Bob", "tags": [ "enim", "qui"]}'::jsonb @> '{"tags":["qu"]}';
+
+-- array length
+SELECT jsonb_array_length('[1,2,3,{"f1":1,"f2":[5,6]},4]');
+SELECT jsonb_array_length('[]');
+SELECT jsonb_array_length('{"f1":1,"f2":[5,6]}');
+SELECT jsonb_array_length('4');
+
+-- each
+SELECT jsonb_each('{"f1":[1,2,3],"f2":{"f3":1},"f4":null}');
+SELECT jsonb_each('{"a":{"b":"c","c":"b","1":"first"},"b":[1,2],"c":"cc","1":"first","n":null}'::jsonb) AS q;
+SELECT * FROM jsonb_each('{"f1":[1,2,3],"f2":{"f3":1},"f4":null,"f5":99,"f6":"stringy"}') q;
+SELECT * FROM jsonb_each('{"a":{"b":"c","c":"b","1":"first"},"b":[1,2],"c":"cc","1":"first","n":null}'::jsonb) AS q;
+
+SELECT jsonb_each_text('{"f1":[1,2,3],"f2":{"f3":1},"f4":null,"f5":"null"}');
+SELECT jsonb_each_text('{"a":{"b":"c","c":"b","1":"first"},"b":[1,2],"c":"cc","1":"first","n":null}'::jsonb) AS q;
+SELECT * FROM jsonb_each_text('{"f1":[1,2,3],"f2":{"f3":1},"f4":null,"f5":99,"f6":"stringy"}') q;
+SELECT * FROM jsonb_each_text('{"a":{"b":"c","c":"b","1":"first"},"b":[1,2],"c":"cc","1":"first","n":null}'::jsonb) AS q;
+
+-- exists
+SELECT jsonb_exists('{"a":null, "b":"qq"}', 'a');
+SELECT jsonb_exists('{"a":null, "b":"qq"}', 'b');
+SELECT jsonb_exists('{"a":null, "b":"qq"}', 'c');
+SELECT jsonb_exists('{"a":"null", "b":"qq"}', 'a');
+SELECT jsonb '{"a":null, "b":"qq"}' ? 'a';
+SELECT jsonb '{"a":null, "b":"qq"}' ? 'b';
+SELECT jsonb '{"a":null, "b":"qq"}' ? 'c';
+SELECT jsonb '{"a":"null", "b":"qq"}' ? 'a';
+-- array exists - array elements should behave as keys
+SELECT count(*) from testjsonb WHERE j->'array' ? 'bar';
+-- 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;
+-- However, a raw scalar is *contained* within the array
+SELECT count(*) from testjsonb WHERE j->'array' @> '5'::jsonb;
+
+SELECT jsonb_exists_any('{"a":null, "b":"qq"}', ARRAY['a','b']);
+SELECT jsonb_exists_any('{"a":null, "b":"qq"}', ARRAY['b','a']);
+SELECT jsonb_exists_any('{"a":null, "b":"qq"}', ARRAY['c','a']);
+SELECT jsonb_exists_any('{"a":null, "b":"qq"}', ARRAY['c','d']);
+SELECT jsonb_exists_any('{"a":null, "b":"qq"}', '{}'::text[]);
+SELECT jsonb '{"a":null, "b":"qq"}' ?| ARRAY['a','b'];
+SELECT jsonb '{"a":null, "b":"qq"}' ?| ARRAY['b','a'];
+SELECT jsonb '{"a":null, "b":"qq"}' ?| ARRAY['c','a'];
+SELECT jsonb '{"a":null, "b":"qq"}' ?| ARRAY['c','d'];
+SELECT jsonb '{"a":null, "b":"qq"}' ?| '{}'::text[];
+
+SELECT jsonb_exists_all('{"a":null, "b":"qq"}', ARRAY['a','b']);
+SELECT jsonb_exists_all('{"a":null, "b":"qq"}', ARRAY['b','a']);
+SELECT jsonb_exists_all('{"a":null, "b":"qq"}', ARRAY['c','a']);
+SELECT jsonb_exists_all('{"a":null, "b":"qq"}', ARRAY['c','d']);
+SELECT jsonb_exists_all('{"a":null, "b":"qq"}', '{}'::text[]);
+SELECT jsonb '{"a":null, "b":"qq"}' ?& ARRAY['a','b'];
+SELECT jsonb '{"a":null, "b":"qq"}' ?& ARRAY['b','a'];
+SELECT jsonb '{"a":null, "b":"qq"}' ?& ARRAY['c','a'];
+SELECT jsonb '{"a":null, "b":"qq"}' ?& ARRAY['c','d'];
+SELECT jsonb '{"a":null, "b":"qq"}' ?& ARRAY['a','a', 'b', 'b', 'b'];
+SELECT jsonb '{"a":null, "b":"qq"}' ?& '{}'::text[];
+
+-- typeof
+SELECT jsonb_typeof('{}') AS object;
+SELECT jsonb_typeof('{"c":3,"p":"o"}') AS object;
+SELECT jsonb_typeof('[]') AS array;
+SELECT jsonb_typeof('["a", 1]') AS array;
+SELECT jsonb_typeof('null') AS "null";
+SELECT jsonb_typeof('1') AS number;
+SELECT jsonb_typeof('-1') AS number;
+SELECT jsonb_typeof('1.0') AS number;
+SELECT jsonb_typeof('1e2') AS number;
+SELECT jsonb_typeof('-1.0') AS number;
+SELECT jsonb_typeof('true') AS boolean;
+SELECT jsonb_typeof('false') AS boolean;
+SELECT jsonb_typeof('"hello"') AS string;
+SELECT jsonb_typeof('"true"') AS string;
+SELECT jsonb_typeof('"1.0"') AS string;
+
+-- extract_path, extract_path_as_text
+SELECT jsonb_extract_path('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f4','f6');
+SELECT jsonb_extract_path('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f2');
+SELECT jsonb_extract_path('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',0::text);
+SELECT jsonb_extract_path('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',1::text);
+SELECT jsonb_extract_path_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f4','f6');
+SELECT jsonb_extract_path_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f2');
+SELECT jsonb_extract_path_text('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',0::text);
+SELECT jsonb_extract_path_text('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',1::text);
+
+-- extract_path nulls
+SELECT jsonb_extract_path('{"f2":{"f3":1},"f4":{"f5":null,"f6":"stringy"}}','f4','f5') IS NULL AS expect_false;
+SELECT jsonb_extract_path_text('{"f2":{"f3":1},"f4":{"f5":null,"f6":"stringy"}}','f4','f5') IS NULL AS expect_true;
+SELECT jsonb_extract_path('{"f2":{"f3":1},"f4":[0,1,2,null]}','f4','3') IS NULL AS expect_false;
+SELECT jsonb_extract_path_text('{"f2":{"f3":1},"f4":[0,1,2,null]}','f4','3') IS NULL AS expect_true;
+
+-- extract_path operators
+SELECT '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>array['f4','f6'];
+SELECT '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>array['f2'];
+SELECT '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>array['f2','0'];
+SELECT '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>array['f2','1'];
+SELECT '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>>array['f4','f6'];
+SELECT '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>>array['f2'];
+SELECT '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>>array['f2','0'];
+SELECT '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>>array['f2','1'];
+
+-- same using array literals
+SELECT '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>'{f4,f6}';
+SELECT '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>'{f2}';
+SELECT '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>'{f2,0}';
+SELECT '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>'{f2,1}';
+SELECT '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>>'{f4,f6}';
+SELECT '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>>'{f2}';
+SELECT '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>>'{f2,0}';
+SELECT '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::jsonb#>>'{f2,1}';
+
+-- same on jsonb scalars (expecting errors)
+SELECT '42'::jsonb#>array['f2'];
+SELECT '42'::jsonb#>array['0'];
+SELECT '42'::jsonb#>>array['f2'];
+SELECT '42'::jsonb#>>array['0'];
+
+-- array_elements
+SELECT jsonb_array_elements('[1,true,[1,[2,3]],null,{"f1":1,"f2":[7,8,9]},false]');
+SELECT * FROM jsonb_array_elements('[1,true,[1,[2,3]],null,{"f1":1,"f2":[7,8,9]},false]') q;
+SELECT jsonb_array_elements_text('[1,true,[1,[2,3]],null,{"f1":1,"f2":[7,8,9]},false,"stringy"]');
+SELECT * FROM jsonb_array_elements_text('[1,true,[1,[2,3]],null,{"f1":1,"f2":[7,8,9]},false,"stringy"]') q;
+
+-- 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;
+SELECT * FROM jsonb_populate_record(row('x',3,'2012-12-31 15:30:56')::jbpop,'{"a":"blurfl","x":43.2}') q;
+
+SELECT * FROM jsonb_populate_record(NULL::jbpop,'{"a":"blurfl","x":43.2}', true) q;
+SELECT * FROM jsonb_populate_record(row('x',3,'2012-12-31 15:30:56')::jbpop,'{"a":"blurfl","x":43.2}', true) q;
+
+SELECT * FROM jsonb_populate_record(NULL::jbpop,'{"a":[100,200,false],"x":43.2}', true) q;
+SELECT * FROM jsonb_populate_record(row('x',3,'2012-12-31 15:30:56')::jbpop,'{"a":[100,200,false],"x":43.2}', true) q;
+SELECT * FROM jsonb_populate_record(row('x',3,'2012-12-31 15:30:56')::jbpop,'{"c":[100,200,false],"x":43.2}', true) q;
+
+-- populate_recordset
+SELECT * FROM jsonb_populate_recordset(NULL::jbpop,'[{"a":"blurfl","x":43.2},{"b":3,"c":"2012-01-20 10:42:53"}]',false) q;
+SELECT * FROM jsonb_populate_recordset(row('def',99,NULL)::jbpop,'[{"a":"blurfl","x":43.2},{"b":3,"c":"2012-01-20 10:42:53"}]',false) q;
+SELECT * FROM jsonb_populate_recordset(NULL::jbpop,'[{"a":"blurfl","x":43.2},{"b":3,"c":"2012-01-20 10:42:53"}]',true) q;
+SELECT * FROM jsonb_populate_recordset(row('def',99,NULL)::jbpop,'[{"a":"blurfl","x":43.2},{"b":3,"c":"2012-01-20 10:42:53"}]',true) 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"}]',true) q;
+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"}]',true) q;
+
+-- using the default use_json_as_text argument
+SELECT * FROM jsonb_populate_recordset(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":"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;
+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;
+
+
+-- 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" }' ->> 'a' AS correct_in_utf8;
+SELECT jsonb '{ "a": "dollar \u0024 character" }' ->> 'a' AS correct_everyWHERE;
+SELECT jsonb '{ "a": "null \u0000 escape" }' ->> 'a' AS not_unescaped;
+
+-- indexing
+SELECT count(*) FROM testjsonb WHERE j @> '{"wait":null}';
+SELECT count(*) FROM testjsonb WHERE j @> '{"wait":"CC"}';
+SELECT count(*) FROM testjsonb WHERE j @> '{"wait":"CC", "public":true}';
+SELECT count(*) FROM testjsonb WHERE j @> '{"age":25}';
+SELECT count(*) FROM testjsonb WHERE j @> '{"age":25.0}';
+SELECT count(*) FROM testjsonb WHERE j ? 'public';
+SELECT count(*) FROM testjsonb WHERE j ?| ARRAY['public','disabled'];
+SELECT count(*) FROM testjsonb WHERE j ?& ARRAY['public','disabled'];
+
+CREATE INDEX jidx ON testjsonb USING gin (j);
+SET enable_seqscan = off;
+
+SELECT count(*) FROM testjsonb WHERE j @> '{"wait":null}';
+SELECT count(*) FROM testjsonb WHERE j @> '{"wait":"CC"}';
+SELECT count(*) FROM testjsonb WHERE j @> '{"wait":"CC", "public":true}';
+SELECT count(*) FROM testjsonb WHERE j @> '{"age":25}';
+SELECT count(*) FROM testjsonb WHERE j @> '{"age":25.0}';
+SELECT count(*) FROM testjsonb WHERE j @> '{"array":["foo"]}';
+SELECT count(*) FROM testjsonb WHERE j @> '{"array":["bar"]}';
+-- excercise GIN_SEARCH_MODE_ALL
+SELECT count(*) FROM testjsonb WHERE j @> '{}';
+SELECT count(*) FROM testjsonb WHERE j ? 'public';
+SELECT count(*) FROM testjsonb WHERE j ?| ARRAY['public','disabled'];
+SELECT count(*) FROM testjsonb WHERE j ?& ARRAY['public','disabled'];
+
+-- 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';
+-- 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;
+-- However, a raw scalar is *contained* within the array
+SELECT count(*) from testjsonb WHERE j->'array' @> '5'::jsonb;
+
+RESET enable_seqscan;
+
+SELECT count(*) FROM (SELECT (jsonb_each(j)).key FROM testjsonb) AS wow;
+SELECT key, count(*) FROM (SELECT (jsonb_each(j)).key FROM testjsonb) AS wow GROUP BY key ORDER BY count DESC, key;
+
+-- sort/hash
+SELECT count(distinct j) FROM testjsonb;
+SET enable_hashagg = off;
+SELECT count(*) FROM (SELECT j FROM (SELECT * FROM testjsonb UNION ALL SELECT * FROM testjsonb) js GROUP BY j) js2;
+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;
+SELECT distinct * FROM (values (jsonb '{}' || ''),('{}')) v(j);
+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}';
+SELECT count(*) FROM testjsonb WHERE j = '{"pos":98, "line":371, "node":"CBA", "indexed":true}';
+
+--gin hash
+DROP INDEX jidx;
+CREATE INDEX jidx ON testjsonb USING gin (j jsonb_hash_ops);
+SET enable_seqscan = off;
+
+SELECT count(*) FROM testjsonb WHERE j @> '{"wait":null}';
+SELECT count(*) FROM testjsonb WHERE j @> '{"wait":"CC"}';
+SELECT count(*) FROM testjsonb WHERE j @> '{"wait":"CC", "public":true}';
+SELECT count(*) FROM testjsonb WHERE j @> '{"age":25}';
+SELECT count(*) FROM testjsonb WHERE j @> '{"age":25.0}';
+-- excercise GIN_SEARCH_MODE_ALL
+SELECT count(*) FROM testjsonb WHERE j @> '{}';
+
+RESET enable_seqscan;
+DROP INDEX jidx;
+
+-- nested tests
+SELECT '{"ff":{"a":12,"b":16}}'::jsonb;
+SELECT '{"ff":{"a":12,"b":16},"qq":123}'::jsonb;
+SELECT '{"aa":["a","aaa"],"qq":{"a":12,"b":16,"c":["c1","c2"],"d":{"d1":"d1","d2":"d2","d1":"d3"}}}'::jsonb;
+SELECT '{"aa":["a","aaa"],"qq":{"a":"12","b":"16","c":["c1","c2"],"d":{"d1":"d1","d2":"d2"}}}'::jsonb;
+SELECT '{"aa":["a","aaa"],"qq":{"a":"12","b":"16","c":["c1","c2",["c3"],{"c4":4}],"d":{"d1":"d1","d2":"d2"}}}'::jsonb;
+SELECT '{"ff":["a","aaa"]}'::jsonb;
+
+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';
+
+-- nested containment
+SELECT '{"a":[1,2],"c":"b"}'::jsonb @> '{"a":[1,2]}';
+SELECT '{"a":[2,1],"c":"b"}'::jsonb @> '{"a":[1,2]}';
+SELECT '{"a":{"1":2},"c":"b"}'::jsonb @> '{"a":[1,2]}';
+SELECT '{"a":{"2":1},"c":"b"}'::jsonb @> '{"a":[1,2]}';
+SELECT '{"a":{"1":2},"c":"b"}'::jsonb @> '{"a":{"1":2}}';
+SELECT '{"a":{"2":1},"c":"b"}'::jsonb @> '{"a":{"1":2}}';
+SELECT '["a","b"]'::jsonb @> '["a","b","c","b"]';
+SELECT '["a","b","c","b"]'::jsonb @> '["a","b"]';
+SELECT '["a","b","c",[1,2]]'::jsonb @> '["a",[1,2]]';
+SELECT '["a","b","c",[1,2]]'::jsonb @> '["b",[1,2]]';
+
+SELECT '{"a":[1,2],"c":"b"}'::jsonb @> '{"a":[1]}';
+SELECT '{"a":[1,2],"c":"b"}'::jsonb @> '{"a":[2]}';
+SELECT '{"a":[1,2],"c":"b"}'::jsonb @> '{"a":[3]}';
+
+SELECT '{"a":[1,2,{"c":3,"x":4}],"c":"b"}'::jsonb @> '{"a":[{"c":3}]}';
+SELECT '{"a":[1,2,{"c":3,"x":4}],"c":"b"}'::jsonb @> '{"a":[{"x":4}]}';
+SELECT '{"a":[1,2,{"c":3,"x":4}],"c":"b"}'::jsonb @> '{"a":[{"x":4},3]}';
+SELECT '{"a":[1,2,{"c":3,"x":4}],"c":"b"}'::jsonb @> '{"a":[{"x":4},1]}';
+
+-- nested object field / array index lookup
+SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb -> 'n';
+SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb -> 'a';
+SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb -> 'b';
+SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb -> 'c';
+SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb -> 'd';
+SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb -> 'd' -> '1';
+SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb -> 'e';
+SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb -> 0; --expecting error
+
+SELECT '["a","b","c",[1,2],null]'::jsonb -> 0;
+SELECT '["a","b","c",[1,2],null]'::jsonb -> 1;
+SELECT '["a","b","c",[1,2],null]'::jsonb -> 2;
+SELECT '["a","b","c",[1,2],null]'::jsonb -> 3;
+SELECT '["a","b","c",[1,2],null]'::jsonb -> 3 -> 1;
+SELECT '["a","b","c",[1,2],null]'::jsonb -> 4;
+SELECT '["a","b","c",[1,2],null]'::jsonb -> 5;
+SELECT '["a","b","c",[1,2],null]'::jsonb -> -1;
+
+--nested path extraction
+SELECT '{"a":"b","c":[1,2,3]}'::jsonb #> '{0}';
+SELECT '{"a":"b","c":[1,2,3]}'::jsonb #> '{a}';
+SELECT '{"a":"b","c":[1,2,3]}'::jsonb #> '{c}';
+SELECT '{"a":"b","c":[1,2,3]}'::jsonb #> '{c,0}';
+SELECT '{"a":"b","c":[1,2,3]}'::jsonb #> '{c,1}';
+SELECT '{"a":"b","c":[1,2,3]}'::jsonb #> '{c,2}';
+SELECT '{"a":"b","c":[1,2,3]}'::jsonb #> '{c,3}';
+SELECT '{"a":"b","c":[1,2,3]}'::jsonb #> '{c,-1}';
+
+SELECT '[0,1,2,[3,4],{"5":"five"}]'::jsonb #> '{0}';
+SELECT '[0,1,2,[3,4],{"5":"five"}]'::jsonb #> '{3}';
+SELECT '[0,1,2,[3,4],{"5":"five"}]'::jsonb #> '{4}';
+SELECT '[0,1,2,[3,4],{"5":"five"}]'::jsonb #> '{4,5}';
+
+--nested exists
+SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb ? 'n';
+SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb ? 'a';
+SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb ? 'b';
+SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb ? 'c';
+SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb ? 'd';
+SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]}}'::jsonb ? 'e';