Skip to content

Latest commit

 

History

History
321 lines (288 loc) · 17 KB

20230331_10.md

File metadata and controls

321 lines (288 loc) · 17 KB

PostgreSQL 16 preview - SQL/JSON: support the IS JSON predicate

作者

digoal

日期

2023-03-31

标签

PostgreSQL , PolarDB , sql/json


背景

https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=6ee30209a6f161d0a267a33f090c70c579c87c00

SQL/JSON: support the IS JSON predicate  
author	Alvaro Herrera <alvherre@alvh.no-ip.org>	  
Fri, 31 Mar 2023 20:34:04 +0000 (22:34 +0200)  
committer	Alvaro Herrera <alvherre@alvh.no-ip.org>	  
Fri, 31 Mar 2023 20:34:04 +0000 (22:34 +0200)  
commit	6ee30209a6f161d0a267a33f090c70c579c87c00  
tree	eda2b3a9f0a61f3fc484819b39abf1eb130e0d88	tree  
parent	a2a0c7c29e47f39da905577659e66b0086b769cc	commit | diff  
SQL/JSON: support the IS JSON predicate  
  
This patch introduces the SQL standard IS JSON predicate. It operates  
on text and bytea values representing JSON, as well as on the json and  
jsonb types. Each test has IS and IS NOT variants and supports a WITH  
UNIQUE KEYS flag. The tests are:  
  
IS JSON [VALUE]  
IS JSON ARRAY  
IS JSON OBJECT  
IS JSON SCALAR  
  
These should be self-explanatory.  
  
The WITH UNIQUE KEYS flag makes these return false when duplicate keys  
exist in any object within the value, not necessarily directly contained  
in the outermost object.  
  
Author: Nikita Glukhov <n.gluhov@postgrespro.ru>  
Author: Teodor Sigaev <teodor@sigaev.ru>  
Author: Oleg Bartunov <obartunov@gmail.com>  
Author: Alexander Korotkov <aekorotkov@gmail.com>  
Author: Amit Langote <amitlangote09@gmail.com>  
Author: Andrew Dunstan <andrew@dunslane.net>  
  
Reviewers have included (in no particular order) Andres Freund, Alexander  
Korotkov, Pavel Stehule, Andrew Alsup, Erik Rijkers, Zihong Yu,  
Himanshu Upadhyaya, Daniel Gustafsson, Justin Pryzby.  
  
Discussion: https://postgr.es/m/CAF4Au4w2x-5LTnN_bxky-mq4=WOqsGsxSpENCzHRAzSnEd8+WQ@mail.gmail.com  
Discussion: https://postgr.es/m/cd0bb935-0158-78a7-08b5-904886deac4b@postgrespro.ru  
Discussion: https://postgr.es/m/20220616233130.rparivafipt6doj3@alap3.anarazel.de  
Discussion: https://postgr.es/m/abd9b83b-aa66-f230-3d6d-734817f0995d%40postgresql.org  
+SELECT js,  
+  js IS JSON "json?",  
+  js IS JSON SCALAR "scalar?",  
+  js IS JSON OBJECT "object?",  
+  js IS JSON ARRAY "array?"  
+FROM (VALUES  
+      ('123'), ('"abc"'), ('{"a": "b"}'), ('[1,2]'),('abc')) foo(js);  
+     js     | json? | scalar? | object? | array?   
+------------+-------+---------+---------+--------  
+ 123        | t     | t       | f       | f  
+ "abc"      | t     | t       | f       | f  
+ {"a": "b"} | t     | f       | t       | f  
+ [1,2]      | t     | f       | f       | t  
+ abc        | f     | f       | f       | f  
+</programlisting>  
+       </para>  
+       <para>  
+<programlisting>  
+SELECT js,  
+  js IS JSON OBJECT "object?",  
+  js IS JSON ARRAY "array?",  
+  js IS JSON ARRAY WITH UNIQUE KEYS "array w. UK?",  
+  js IS JSON ARRAY WITHOUT UNIQUE KEYS "array w/o UK?"  
+FROM (VALUES ('[{"a":"1"},  
+ {"b":"2","b":"3"}]')) foo(js);  
+-[ RECORD 1 ]-+--------------------  
+js            | [{"a":"1"},        +  
+              |  {"b":"2","b":"3"}]  
+object?       | f  
+array?        | t  
+array w. UK?  | f  
+array w/o UK? | t  
+-- IS JSON predicate  
+SELECT NULL IS JSON;  
+ ?column?   
+----------  
+   
+(1 row)  
+  
+SELECT NULL IS NOT JSON;  
+ ?column?   
+----------  
+   
+(1 row)  
+  
+SELECT NULL::json IS JSON;  
+ ?column?   
+----------  
+   
+(1 row)  
+  
+SELECT NULL::jsonb IS JSON;  
+ ?column?   
+----------  
+   
+(1 row)  
+  
+SELECT NULL::text IS JSON;  
+ ?column?   
+----------  
+   
+(1 row)  
+  
+SELECT NULL::bytea IS JSON;  
+ ?column?   
+----------  
+   
+(1 row)  
+  
+SELECT NULL::int IS JSON;  
+ERROR:  cannot use type integer in IS JSON predicate  
+SELECT '' IS JSON;  
+ ?column?   
+----------  
+ f  
+(1 row)  
+  
+SELECT bytea '\x00' IS JSON;  
+ERROR:  invalid byte sequence for encoding "UTF8": 0x00  
+CREATE TABLE test_is_json (js text);  
+INSERT INTO test_is_json VALUES  
+ (NULL),  
+ (''),  
+ ('123'),  
+ ('"aaa "'),  
+ ('true'),  
+ ('null'),  
+ ('[]'),  
+ ('[1, "2", {}]'),  
+ ('{}'),  
+ ('{ "a": 1, "b": null }'),  
+ ('{ "a": 1, "a": null }'),  
+ ('{ "a": 1, "b": [{ "a": 1 }, { "a": 2 }] }'),  
+ ('{ "a": 1, "b": [{ "a": 1, "b": 0, "a": 2 }] }'),  
+ ('aaa'),  
+ ('{a:1}'),  
+ ('["a",]');  
+SELECT  
+   js,  
+   js IS JSON "IS JSON",  
+   js IS NOT JSON "IS NOT JSON",  
+   js IS JSON VALUE "IS VALUE",  
+   js IS JSON OBJECT "IS OBJECT",  
+   js IS JSON ARRAY "IS ARRAY",  
+   js IS JSON SCALAR "IS SCALAR",  
+   js IS JSON WITHOUT UNIQUE KEYS "WITHOUT UNIQUE",  
+   js IS JSON WITH UNIQUE KEYS "WITH UNIQUE"  
+FROM  
+   test_is_json;  
+                      js                       | IS JSON | IS NOT JSON | IS VALUE | IS OBJECT | IS ARRAY | IS SCALAR | WITHOUT UNIQUE | WITH UNIQUE   
+-----------------------------------------------+---------+-------------+----------+-----------+----------+-----------+----------------+-------------  
+                                               |         |             |          |           |          |           |                |   
+                                               | f       | t           | f        | f         | f        | f         | f              | f  
+ 123                                           | t       | f           | t        | f         | f        | t         | t              | t  
+ "aaa "                                        | t       | f           | t        | f         | f        | t         | t              | t  
+ true                                          | t       | f           | t        | f         | f        | t         | t              | t  
+ null                                          | t       | f           | t        | f         | f        | t         | t              | t  
+ []                                            | t       | f           | t        | f         | t        | f         | t              | t  
+ [1, "2", {}]                                  | t       | f           | t        | f         | t        | f         | t              | t  
+ {}                                            | t       | f           | t        | t         | f        | f         | t              | t  
+ { "a": 1, "b": null }                         | t       | f           | t        | t         | f        | f         | t              | t  
+ { "a": 1, "a": null }                         | t       | f           | t        | t         | f        | f         | t              | f  
+ { "a": 1, "b": [{ "a": 1 }, { "a": 2 }] }     | t       | f           | t        | t         | f        | f         | t              | t  
+ { "a": 1, "b": [{ "a": 1, "b": 0, "a": 2 }] } | t       | f           | t        | t         | f        | f         | t              | f  
+ aaa                                           | f       | t           | f        | f         | f        | f         | f              | f  
+ {a:1}                                         | f       | t           | f        | f         | f        | f         | f              | f  
+ ["a",]                                        | f       | t           | f        | f         | f        | f         | f              | f  
+(16 rows)  
+  
+SELECT  
+   js,  
+   js IS JSON "IS JSON",  
+   js IS NOT JSON "IS NOT JSON",  
+   js IS JSON VALUE "IS VALUE",  
+   js IS JSON OBJECT "IS OBJECT",  
+   js IS JSON ARRAY "IS ARRAY",  
+   js IS JSON SCALAR "IS SCALAR",  
+   js IS JSON WITHOUT UNIQUE KEYS "WITHOUT UNIQUE",  
+   js IS JSON WITH UNIQUE KEYS "WITH UNIQUE"  
+FROM  
+   (SELECT js::json FROM test_is_json WHERE js IS JSON) foo(js);  
+                      js                       | IS JSON | IS NOT JSON | IS VALUE | IS OBJECT | IS ARRAY | IS SCALAR | WITHOUT UNIQUE | WITH UNIQUE   
+-----------------------------------------------+---------+-------------+----------+-----------+----------+-----------+----------------+-------------  
+ 123                                           | t       | f           | t        | f         | f        | t         | t              | t  
+ "aaa "                                        | t       | f           | t        | f         | f        | t         | t              | t  
+ true                                          | t       | f           | t        | f         | f        | t         | t              | t  
+ null                                          | t       | f           | t        | f         | f        | t         | t              | t  
+ []                                            | t       | f           | t        | f         | t        | f         | t              | t  
+ [1, "2", {}]                                  | t       | f           | t        | f         | t        | f         | t              | t  
+ {}                                            | t       | f           | t        | t         | f        | f         | t              | t  
+ { "a": 1, "b": null }                         | t       | f           | t        | t         | f        | f         | t              | t  
+ { "a": 1, "a": null }                         | t       | f           | t        | t         | f        | f         | t              | f  
+ { "a": 1, "b": [{ "a": 1 }, { "a": 2 }] }     | t       | f           | t        | t         | f        | f         | t              | t  
+ { "a": 1, "b": [{ "a": 1, "b": 0, "a": 2 }] } | t       | f           | t        | t         | f        | f         | t              | f  
+(11 rows)  
+  
+SELECT  
+   js0,  
+   js IS JSON "IS JSON",  
+   js IS NOT JSON "IS NOT JSON",  
+   js IS JSON VALUE "IS VALUE",  
+   js IS JSON OBJECT "IS OBJECT",  
+   js IS JSON ARRAY "IS ARRAY",  
+   js IS JSON SCALAR "IS SCALAR",  
+   js IS JSON WITHOUT UNIQUE KEYS "WITHOUT UNIQUE",  
+   js IS JSON WITH UNIQUE KEYS "WITH UNIQUE"  
+FROM  
+   (SELECT js, js::bytea FROM test_is_json WHERE js IS JSON) foo(js0, js);  
+                      js0                      | IS JSON | IS NOT JSON | IS VALUE | IS OBJECT | IS ARRAY | IS SCALAR | WITHOUT UNIQUE | WITH UNIQUE   
+-----------------------------------------------+---------+-------------+----------+-----------+----------+-----------+----------------+-------------  
+ 123                                           | t       | f           | t        | f         | f        | t         | t              | t  
+ "aaa "                                        | t       | f           | t        | f         | f        | t         | t              | t  
+ true                                          | t       | f           | t        | f         | f        | t         | t              | t  
+ null                                          | t       | f           | t        | f         | f        | t         | t              | t  
+ []                                            | t       | f           | t        | f         | t        | f         | t              | t  
+ [1, "2", {}]                                  | t       | f           | t        | f         | t        | f         | t              | t  
+ {}                                            | t       | f           | t        | t         | f        | f         | t              | t  
+ { "a": 1, "b": null }                         | t       | f           | t        | t         | f        | f         | t              | t  
+ { "a": 1, "a": null }                         | t       | f           | t        | t         | f        | f         | t              | f  
+ { "a": 1, "b": [{ "a": 1 }, { "a": 2 }] }     | t       | f           | t        | t         | f        | f         | t              | t  
+ { "a": 1, "b": [{ "a": 1, "b": 0, "a": 2 }] } | t       | f           | t        | t         | f        | f         | t              | f  
+(11 rows)  
+  
+SELECT  
+   js,  
+   js IS JSON "IS JSON",  
+   js IS NOT JSON "IS NOT JSON",  
+   js IS JSON VALUE "IS VALUE",  
+   js IS JSON OBJECT "IS OBJECT",  
+   js IS JSON ARRAY "IS ARRAY",  
+   js IS JSON SCALAR "IS SCALAR",  
+   js IS JSON WITHOUT UNIQUE KEYS "WITHOUT UNIQUE",  
+   js IS JSON WITH UNIQUE KEYS "WITH UNIQUE"  
+FROM  
+   (SELECT js::jsonb FROM test_is_json WHERE js IS JSON) foo(js);  
+                 js                  | IS JSON | IS NOT JSON | IS VALUE | IS OBJECT | IS ARRAY | IS SCALAR | WITHOUT UNIQUE | WITH UNIQUE   
+-------------------------------------+---------+-------------+----------+-----------+----------+-----------+----------------+-------------  
+ 123                                 | t       | f           | t        | f         | f        | t         | t              | t  
+ "aaa "                              | t       | f           | t        | f         | f        | t         | t              | t  
+ true                                | t       | f           | t        | f         | f        | t         | t              | t  
+ null                                | t       | f           | t        | f         | f        | t         | t              | t  
+ []                                  | t       | f           | t        | f         | t        | f         | t              | t  
+ [1, "2", {}]                        | t       | f           | t        | f         | t        | f         | t              | t  
+ {}                                  | t       | f           | t        | t         | f        | f         | t              | t  
+ {"a": 1, "b": null}                 | t       | f           | t        | t         | f        | f         | t              | t  
+ {"a": null}                         | t       | f           | t        | t         | f        | f         | t              | t  
+ {"a": 1, "b": [{"a": 1}, {"a": 2}]} | t       | f           | t        | t         | f        | f         | t              | t  
+ {"a": 1, "b": [{"a": 2, "b": 0}]}   | t       | f           | t        | t         | f        | f         | t              | t  
+(11 rows)  
+  
+-- Test IS JSON deparsing  
+EXPLAIN (VERBOSE, COSTS OFF)  
+SELECT '1' IS JSON AS "any", ('1' || i) IS JSON SCALAR AS "scalar", '[]' IS NOT JSON ARRAY AS "array", '{}' IS JSON OBJECT WITH UNIQUE AS "object" FROM generate_series(1, 3) i;  
+                                                                        QUERY PLAN                                                                          
+----------------------------------------------------------------------------------------------------------------------------------------------------------  
+ Function Scan on pg_catalog.generate_series i  
+   Output: ('1'::text IS JSON), (('1'::text || (i)::text) IS JSON SCALAR), (NOT ('[]'::text IS JSON ARRAY)), ('{}'::text IS JSON OBJECT WITH UNIQUE KEYS)  
+   Function Call: generate_series(1, 3)  
+(3 rows)  
+  
+CREATE VIEW is_json_view AS  
+SELECT '1' IS JSON AS "any", ('1' || i) IS JSON SCALAR AS "scalar", '[]' IS NOT JSON ARRAY AS "array", '{}' IS JSON OBJECT WITH UNIQUE AS "object" FROM generate_series(1, 3) i;  
+\sv is_json_view  
+CREATE OR REPLACE VIEW public.is_json_view AS  
+ SELECT '1'::text IS JSON AS "any",  
+    ('1'::text || i) IS JSON SCALAR AS scalar,  
+    NOT '[]'::text IS JSON ARRAY AS "array",  
+    '{}'::text IS JSON OBJECT WITH UNIQUE KEYS AS object  
+   FROM generate_series(1, 3) i(i)  
+DROP VIEW is_json_view;  

digoal's wechat