diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index f87afefeae7..ee515cec8f3 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -16294,7 +16294,7 @@ table2-mapping jsonb_set_lax('[{"f1":1,"f2":null},2,null,3]', '{0,f1}', null) - [{"f1": null, "f2": null}, 2, null, 3] + [{"f1":null,"f2":null},2,null,3] jsonb_set_lax('[{"f1":99,"f2":null},2]', '{0,f3}', null, true, 'return_target') @@ -16533,7 +16533,7 @@ table2-mapping comparisons. - jsonb_path_exists_tz('["2015-08-01 12:00:00-05"]', '$[*] ? (@.datetime() < "2015-08-02".datetime())') + jsonb_path_exists_tz('["2015-08-01 12:00:00 -05"]', '$[*] ? (@.datetime() < "2015-08-02".datetime())') t @@ -17571,937 +17571,7 @@ $.* ? (@ like_regex "^\\d+$") - - - - SQL/JSON Functions and Expressions - - SQL/JSON - functions and expressions - - - - To provide native support for JSON data types within the SQL environment, - PostgreSQL implements the - SQL/JSON data model. - This model comprises sequences of items. Each item can hold SQL scalar - values, with an additional SQL/JSON null value, and composite data structures - that use JSON arrays and objects. The model is a formalization of the implied - data model in the JSON specification - RFC 7159. - - - - SQL/JSON allows you to handle JSON data alongside regular SQL data, - with transaction support, including: - - - - - - Uploading JSON data into the database and storing it in - regular SQL columns as character or binary strings. - - - - - Generating JSON objects and arrays from relational data. - - - - - Querying JSON data using SQL/JSON query functions and - SQL/JSON path language expressions. - - - - - - There are two groups of SQL/JSON functions. - Constructor functions - generate JSON data from values of SQL types. - Query functions - evaluate SQL/JSON path language expressions against JSON values - and produce values of SQL/JSON types, which are converted to SQL types. - - - - Many SQL/JSON functions have an optional FORMAT - clause. This is provided to conform with the SQL standard, but has no - effect except where noted otherwise. - - - - lists the SQL/JSON - Constructor functions. Each function has a RETURNING - clause specifying the data type returned. For the json and - json_scalar functions, this needs to be either json or - jsonb. For the other constructor functions it must be one of json, - jsonb, bytea, a character string type (text, char, - varchar, or nchar), or a type for which there is a cast - from json to that type. - By default, the json type is returned. - - - - - Many of the results that can be obtained from the SQL/JSON Constructor - functions can also be obtained by calling - PostgreSQL-specific functions detailed in - and - . - - - - - SQL/JSON Constructor Functions - - - - - Function signature - - - Description - - - Example(s) - - - - - - - json constructor - json ( - expression - FORMAT JSON ENCODING UTF8 - { WITH | WITHOUT } UNIQUE KEYS - RETURNING json_data_type ) - - - The expression can be any text type or a - bytea in UTF8 encoding. If the - expression is NULL, an - SQL null value is returned. - If WITH UNIQUE is specified, the - expression must not contain any duplicate - object keys. - - - json('{"a":123, "b":[true,"foo"], "a":"bar"}') - {"a":123, "b":[true,"foo"], "a":"bar"} - - - json('{"a":123,"b":[true,"foo"],"a":"bar"}' returning jsonb) - {"a": "bar", "b": [true, "foo"]} - - - - - json_scalar - json_scalar (expression - RETURNING json_data_type ) - - - Returns a JSON scalar value representing - expression. - If the input is NULL, an SQL NULL is returned. If the input is a number - or a boolean value, a corresponding JSON number or boolean value is - returned. For any other value a JSON string is returned. - - - json_scalar(123.45) - 123.45 - - - json_scalar(CURRENT_TIMESTAMP) - "2022-05-10T10:51:04.62128-04:00" - - - - - json_object - json_object ( - { key_expression { VALUE | ':' } - value_expression FORMAT JSON ENCODING UTF8 }, ... - { NULL | ABSENT } ON NULL - { WITH | WITHOUT } UNIQUE KEYS - RETURNING data_type FORMAT JSON ENCODING UTF8 ) - - - Constructs a JSON object of all the key value pairs given, - or an empty object if none are given. - key_expression is a scalar expression - defining the JSON key, which is - converted to the text type. - It cannot be NULL nor can it - belong to a type that has a cast to the json. - If WITH UNIQUE is specified, there must not - be any duplicate key_expression. - If ABSENT ON NULL is specified, the entire - pair is omitted if the value_expression - is NULL. - - - json_object('code' VALUE 'P123', 'title': 'Jaws') - {"code" : "P123", "title" : "Jaws"} - - - - - json_objectagg - json_objectagg ( - { key_expression { VALUE | ':' } value_expression } - { NULL | ABSENT } ON NULL - { WITH | WITHOUT } UNIQUE KEYS - RETURNING data_type FORMAT JSON ENCODING UTF8 ) - - - Behaves like json_object above, but as an - aggregate function, so it only takes one - key_expression and one - value_expression parameter. - - - SELECT json_objectagg(k:v) FROM (VALUES ('a'::text,current_date),('b',current_date + 1)) AS t(k,v) - { "a" : "2022-05-10", "b" : "2022-05-11" } - - - - - json_array - json_array ( - { value_expression FORMAT JSON } , ... - { NULL | ABSENT } ON NULL - RETURNING data_type FORMAT JSON ENCODING UTF8 ) - - - json_array ( - query_expression - RETURNING data_type FORMAT JSON ENCODING UTF8 ) - - - Constructs a JSON array from either a series of - value_expression parameters or from the results - of query_expression, - which must be a SELECT query returning a single column. If - ABSENT ON NULL is specified, NULL values are ignored. - This is always the case if a - query_expression is used. - - - json_array(1,true,json '{"a":null}') - [1, true, {"a":null}] - - - json_array(SELECT * FROM (VALUES(1),(2)) t) - [1, 2] - - - - - json_arrayagg - json_arrayagg ( - value_expression - ORDER BY sort_expression - { NULL | ABSENT } ON NULL - RETURNING data_type FORMAT JSON ENCODING UTF8 ) - - - Behaves in the same way as json_array - but as an aggregate function so it only takes one - value_expression parameter. - If ABSENT ON NULL is specified, any NULL - values are omitted. - If ORDER BY is specified, the elements will - appear in the array in that order rather than in the input order. - - - SELECT json_arrayagg(v) FROM (VALUES(2),(1)) t(v) - [2, 1] - - - - -
- - - details SQL/JSON - facilities for testing and serializing JSON. - - - - SQL/JSON Testing and Serializing Functions - - - - - Function signature - - - Description - - - Example(s) - - - - - - - IS JSON - expression IS NOT JSON - { VALUE | SCALAR | ARRAY | OBJECT } - { WITH | WITHOUT } UNIQUE KEYS - - - This predicate tests whether expression can be - parsed as JSON, possibly of a specified type. - If SCALAR or ARRAY or - OBJECT is specified, the - test is whether or not the JSON is of that particular type. If - WITH UNIQUE is specified, then an any object in the - expression is also tested to see if it - has duplicate keys. - - - -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 - - - - - - json_serialize ( - expression FORMAT JSON ENCODING UTF8 - RETURNING data_type FORMAT JSON ENCODING UTF8 ) - - - Transforms an SQL/JSON value into a character or binary string. The - expression can be of any JSON type, any - character string type, or bytea in UTF8 encoding. - The returned type can be any character string type or - bytea. The default is text. - - - json_serialize('{ "a" : 1 } ' RETURNING bytea) - \x7b20226122203a2031207d20 - - - - -
- - - details the SQL/JSON - functions that can be used to query JSON data, except - for json_table. - - - - - SQL/JSON paths can only be applied to the jsonb type, so it - might be necessary to cast the context_item - argument of these functions to jsonb. - - - - - SQL/JSON Query Functions - - - - - Function signature - - - Description - - - Example(s) - - - - - - - json_exists - json_exists ( - context_item, path_expression PASSING { value AS varname } , ... - RETURNING data_type - { TRUE | FALSE | UNKNOWN | ERROR } ON ERROR ) - - - Returns true if the SQL/JSON path_expression - applied to the context_item using the - values yields any items. - The ON ERROR clause specifies what is returned if - an error occurs. Note that if the path_expression - is strict, an error is generated if it yields no items. - The default value is UNKNOWN which causes a NULL - result. - - - json_exists(jsonb '{"key1": [1,2,3]}', 'strict $.key1[*] ? (@ > 2)') - t - - - json_exists(jsonb '{"a": [1,2,3]}', 'lax $.a[5]' ERROR ON ERROR) - f - - - json_exists(jsonb '{"a": [1,2,3]}', 'strict $.a[5]' ERROR ON ERROR) - ERROR: jsonpath array subscript is out of bounds - - - - - json_value - json_value ( - context_item, path_expression - PASSING { value AS varname } , ... - RETURNING data_type - { ERROR | NULL | DEFAULT expression } ON EMPTY - { ERROR | NULL | DEFAULT expression } ON ERROR ) - - - Returns the result of applying the - path_expression to the - context_item using the - values. The extracted value must be - a single SQL/JSON scalar item. For results that - are objects or arrays, use the json_query - instead. - The returned data_type has the same semantics - as for constructor functions like json_objectagg. - The default returned type is text. - The ON EMPTY clause specifies the behavior if the - path_expression yields no value at all. - The ON ERROR clause specifies the behavior if an - error occurs, as a result of either the evaluation or the application - of the ON EMPTY clause. - - - json_value(jsonb '"123.45"', '$' RETURNING float) - 123.45 - - - json_value(jsonb '"03:04 2015-02-01"', '$.datetime("HH24:MI YYYY-MM-DD")' RETURNING date) - 2015-02-01 - - - json_value(jsonb '[1,2]', 'strict $[*]' DEFAULT 9 ON ERROR) - 9 - - - - - json_query - json_query ( - context_item, path_expression PASSING { value AS varname } , ... - RETURNING data_type FORMAT JSON ENCODING UTF8 - { WITHOUT | WITH { CONDITIONAL | UNCONDITIONAL } } ARRAY WRAPPER - { KEEP | OMIT } QUOTES ON SCALAR STRING - { ERROR | NULL | EMPTY { ARRAY | OBJECT } | DEFAULT expression } ON EMPTY - { ERROR | NULL | EMPTY { ARRAY | OBJECT } | DEFAULT expression } ON ERROR ) - - - Returns the result of applying the - path_expression to the - context_item using the - values. - This function must return a JSON string, so if the path expression - returns multiple SQL/JSON items, you must wrap the result using the - WITH WRAPPER clause. If the wrapper is - UNCONDITIONAL, an array wrapper will always - be applied, even if the returned value is already a single JSON object - or array, but if it is CONDITIONAL it will not be - applied to a single array or object. UNCONDITIONAL - is the default. - If the result is a scalar string, by default the value returned will have - surrounding quotes making it a valid JSON value. However, this behavior - is reversed if OMIT QUOTES is specified. - The ON ERROR and ON EMPTY - clauses have similar semantics to those clauses for - json_value. - The returned data_type has the same semantics - as for constructor functions like json_objectagg. - The default returned type is text. - - - json_query(jsonb '[1,[2,3],null]', 'lax $[*][1]' WITH CONDITIONAL WRAPPER) - [3] - - - - -
- -
- - - JSON_TABLE - - json_table - - - - json_table is an SQL/JSON function which - queries JSON data - and presents the results as a relational view, which can be accessed as a - regular SQL table. You can only use json_table inside the - FROM clause of a SELECT statement. - - - - Taking JSON data as input, json_table uses - a path expression to extract a part of the provided data that - will be used as a row pattern for the - constructed view. Each SQL/JSON item at the top level of the row pattern serves - as the source for a separate row in the constructed relational view. - - - - To split the row pattern into columns, json_table - provides the COLUMNS clause that defines the - schema of the created view. For each column to be constructed, - this clause provides a separate path expression that evaluates - the row pattern, extracts a JSON item, and returns it as a - separate SQL value for the specified column. If the required value - is stored in a nested level of the row pattern, it can be extracted - using the NESTED PATH subclause. Joining the - columns returned by NESTED PATH can add multiple - new rows to the constructed view. Such rows are called - child rows, as opposed to the parent row - that generates them. - - - - The rows produced by JSON_TABLE are laterally - joined to the row that generated them, so you do not have to explicitly join - the constructed view with the original table holding JSON - data. Optionally, you can specify how to join the columns returned - by NESTED PATH using the PLAN clause. - - - - Each NESTED PATH clause can generate one or more - columns. Columns produced by NESTED PATHs at the - same level are considered to be siblings, - while a column produced by a NESTED PATH is - considered to be a child of the column produced by and - NESTED PATH or row expression at a higher level. - Sibling columns are always joined first. Once they are processed, - the resulting rows are joined to the parent row. - - - - - - context_item, path_expression AS json_path_name PASSING { value AS varname } , ... - - - - The input data to query, the JSON path expression defining the query, - and an optional PASSING clause, which can provide data - values to the path_expression. - The result of the input data - evaluation is called the row pattern. The row - pattern is used as the source for row values in the constructed view. - - - - - - - COLUMNS( json_table_column , ... ) - - - - - The COLUMNS clause defining the schema of the - constructed view. In this clause, you must specify all the columns - to be filled with SQL/JSON items. - The json_table_column - expression has the following syntax variants: - - - - - - name type - PATH json_path_specification - - - - - Inserts a single SQL/JSON item into each row of - the specified column. - - - The provided PATH expression parses the - row pattern defined by json_api_common_syntax - and fills the column with produced SQL/JSON items, one for each row. - If the PATH expression is omitted, - JSON_TABLE uses the - $.name path expression, - where name is the provided column name. - In this case, the column name must correspond to one of the - keys within the SQL/JSON item produced by the row pattern. - - - Optionally, you can add ON EMPTY and - ON ERROR clauses to define how to handle missing values - or structural errors. - WRAPPER and QUOTES clauses can only - be used with JSON, array, and composite types. - These clauses have the same syntax and semantics as for - json_value and json_query. - - - - - - - name type FORMAT json_representation - PATH json_path_specification - - - - - Generates a column and inserts a composite SQL/JSON - item into each row of this column. - - - The provided PATH expression parses the - row pattern defined by json_api_common_syntax - and fills the column with produced SQL/JSON items, one for each row. - If the PATH expression is omitted, - JSON_TABLE uses the - $.name path expression, - where name is the provided column name. - In this case, the column name must correspond to one of the - keys within the SQL/JSON item produced by the row pattern. - - - Optionally, you can add WRAPPER, QUOTES, - ON EMPTY and ON ERROR clauses - to define additional settings for the returned SQL/JSON items. - These clauses have the same syntax and semantics as - for json_query. - - - - - - - name type - EXISTS PATH json_path_specification - - - - - Generates a column and inserts a boolean item into each row of this column. - - - The provided PATH expression parses the - row pattern defined by json_api_common_syntax, - checks whether any SQL/JSON items were returned, and fills the column with - resulting boolean value, one for each row. - The specified type should have cast from - boolean. - If the PATH expression is omitted, - JSON_TABLE uses the - $.name path expression, - where name is the provided column name. - - - Optionally, you can add ON ERROR clause to define - error behavior. This clause has the same syntax and semantics as - for json_exists. - - - - - - - NESTED PATH json_path_specification AS json_path_name - COLUMNS ( json_table_column , ... ) - - - - - Extracts SQL/JSON items from nested levels of the row pattern, - generates one or more columns as defined by the COLUMNS - subclause, and inserts the extracted SQL/JSON items into each row of these columns. - The json_table_column expression in the - COLUMNS subclause uses the same syntax as in the - parent COLUMNS clause. - - - - The NESTED PATH syntax is recursive, - so you can go down multiple nested levels by specifying several - NESTED PATH subclauses within each other. - It allows to unnest the hierarchy of JSON objects and arrays - in a single function invocation rather than chaining several - JSON_TABLE expressions in an SQL statement. - - - - You can use the PLAN clause to define how - to join the columns returned by NESTED PATH clauses. - - - - - - - name FOR ORDINALITY - - - - - Adds an ordinality column that provides sequential row numbering. - You can have only one ordinality column per table. Row numbering - is 1-based. For child rows that result from the NESTED PATH - clauses, the parent row number is repeated. - - - - - - - - - - - AS json_path_name - - - - - The optional json_path_name serves as an - identifier of the provided json_path_specification. - The path name must be unique and distinct from the column names. - When using the PLAN clause, you must specify the names - for all the paths, including the row pattern. Each path name can appear in - the PLAN clause only once. - - - - - - - PLAN ( json_table_plan ) - - - - - Defines how to join the data returned by NESTED PATH - clauses to the constructed view. - - - To join columns with parent/child relationship, you can use: - - - - - INNER - - - - - Use INNER JOIN, so that the parent row - is omitted from the output if it does not have any child rows - after joining the data returned by NESTED PATH. - - - - - - - OUTER - - - - - Use LEFT OUTER JOIN, so that the parent row - is always included into the output even if it does not have any child rows - after joining the data returned by NESTED PATH, with NULL values - inserted into the child columns if the corresponding - values are missing. - - - This is the default option for joining columns with parent/child relationship. - - - - - - - To join sibling columns, you can use: - - - - - - UNION - - - - - Generate one row for each value produced by each of the sibling - columns. The columns from the other siblings are set to null. - - - This is the default option for joining sibling columns. - - - - - - - CROSS - - - - - Generate one row for each combination of values from the sibling columns. - - - - - - - - - - - - PLAN DEFAULT ( OUTER | INNER , UNION | CROSS ) - - - - The terms can also be specified in reverse order. The - INNER or OUTER option defines the - joining plan for parent/child columns, while UNION or - CROSS affects joins of sibling columns. This form - of PLAN overrides the default plan for - all columns at once. Even though the path names are not included in the - PLAN DEFAULT form, to conform to the SQL/JSON standard - they must be provided for all the paths if the PLAN - clause is used. - - - PLAN DEFAULT is simpler than specifying a complete - PLAN, and is often all that is required to get the desired - output. - - - - - - Examples - - - In these examples the following small table storing some JSON data will be used: - -CREATE TABLE my_films ( js jsonb ); - -INSERT INTO my_films VALUES ( -'{ "favorites" : [ - { "kind" : "comedy", "films" : [ - { "title" : "Bananas", - "director" : "Woody Allen"}, - { "title" : "The Dinner Game", - "director" : "Francis Veber" } ] }, - { "kind" : "horror", "films" : [ - { "title" : "Psycho", - "director" : "Alfred Hitchcock" } ] }, - { "kind" : "thriller", "films" : [ - { "title" : "Vertigo", - "director" : "Alfred Hitchcock" } ] }, - { "kind" : "drama", "films" : [ - { "title" : "Yojimbo", - "director" : "Akira Kurosawa" } ] } - ] }'); - - - - Query the my_films table holding - some JSON data about the films and create a view that - distributes the film genre, title, and director between separate columns: - -SELECT jt.* FROM - my_films, - JSON_TABLE ( js, '$.favorites[*]' COLUMNS ( - id FOR ORDINALITY, - kind text PATH '$.kind', - NESTED PATH '$.films[*]' COLUMNS ( - title text PATH '$.title', - director text PATH '$.director'))) AS jt; -----+----------+------------------+------------------- - id | kind | title | director -----+----------+------------------+------------------- - 1 | comedy | Bananas | Woody Allen - 1 | comedy | The Dinner Game | Francis Veber - 2 | horror | Psycho | Alfred Hitchcock - 3 | thriller | Vertigo | Alfred Hitchcock - 4 | drama | Yojimbo | Akira Kurosawa - (5 rows) - - - - - Find a director that has done films in two different genres: - -SELECT - director1 AS director, title1, kind1, title2, kind2 -FROM - my_films, - JSON_TABLE ( js, '$.favorites' AS favs COLUMNS ( - NESTED PATH '$[*]' AS films1 COLUMNS ( - kind1 text PATH '$.kind', - NESTED PATH '$.films[*]' AS film1 COLUMNS ( - title1 text PATH '$.title', - director1 text PATH '$.director') - ), - NESTED PATH '$[*]' AS films2 COLUMNS ( - kind2 text PATH '$.kind', - NESTED PATH '$.films[*]' AS film2 COLUMNS ( - title2 text PATH '$.title', - director2 text PATH '$.director' - ) - ) - ) - PLAN (favs OUTER ((films1 INNER film1) CROSS (films2 INNER film2))) - ) AS jt - WHERE kind1 > kind2 AND director1 = director2; - - director | title1 | kind1 | title2 | kind2 -------------------+---------+----------+--------+-------- - Alfred Hitchcock | Vertigo | thriller | Psycho | horror -(1 row) - - - - + @@ -20879,29 +19949,6 @@ SELECT NULLIF(value, '(none)') ... No - - - - json_agg_strict - - json_agg_strict ( anyelement ) - json - - - - jsonb_agg_strict - - jsonb_agg_strict ( anyelement ) - jsonb - - - Collects all the input values, skipping nulls, into a JSON array. - Values are converted to JSON as per to_json - or to_jsonb. - - No - - @@ -20923,97 +19970,9 @@ SELECT NULLIF(value, '(none)') ... Collects all the key/value pairs into a JSON object. Key arguments - are coerced to text; value arguments are converted as per - to_json or to_jsonb - Values can be null, but keys cannot. - - No - - - - - - json_object_agg_strict - - json_object_agg_strict ( - key "any", - value "any" ) - json - - - - jsonb_object_agg_strict - - jsonb_object_agg_strict ( - key "any", - value "any" ) - jsonb - - - Collects all the key/value pairs into a JSON object. Key arguments - are coerced to text; value arguments are converted as per - to_json or to_jsonb. - The key can not be null. If the - value is null then the entry is skipped, - - No - - - - - - json_object_agg_unique - - json_object_agg_unique ( - key "any", - value "any" ) - json - - - - jsonb_object_agg_unique - - jsonb_object_agg_unique ( - key "any", - value "any" ) - jsonb - - - Collects all the key/value pairs into a JSON object. Key arguments - are coerced to text; value arguments are converted as per - to_json or to_jsonb. - Values can be null, but keys cannot. - If there is a duplicate key an error is thrown. - - No - - - - - - json_object_agg_unique_strict - - json_object_agg_unique_strict ( - key "any", - value "any" ) - json - - - - jsonb_object_agg_unique_strict - - jsonb_object_agg_unique_strict ( - key "any", - value "any" ) - jsonb - - - Collects all the key/value pairs into a JSON object. Key arguments - are coerced to text; value arguments are converted as per - to_json or to_jsonb. - The key can not be null. If the - value is null then the entry is skipped, - If there is a duplicate key an error is thrown. + are coerced to text; value arguments are converted as + per to_json or to_jsonb. + Values can be null, but not keys. No @@ -21191,12 +20150,7 @@ SELECT NULLIF(value, '(none)') ... The aggregate functions array_agg, json_agg, jsonb_agg, - json_agg_strict, jsonb_agg_strict, json_object_agg, jsonb_object_agg, - json_object_agg_strict, jsonb_object_agg_strict, - json_object_agg_unique, jsonb_object_agg_unique, - json_object_agg_unique_strict, - jsonb_object_agg_unique_strict, string_agg, and xmlagg, as well as similar user-defined aggregate functions, produce meaningfully different result values @@ -21216,13 +20170,6 @@ SELECT xmlagg(x) FROM (SELECT x FROM test ORDER BY y DESC) AS tab; subquery's output to be reordered before the aggregate is computed. - - - In addition to the JSON aggregates shown here, see the json_objectagg - and json_arrayagg constructors in . - - - ANY diff --git a/doc/src/sgml/keywords/sql2016-02-reserved.txt b/doc/src/sgml/keywords/sql2016-02-reserved.txt index 7e1a5e4d893..b1bb0776dcb 100644 --- a/doc/src/sgml/keywords/sql2016-02-reserved.txt +++ b/doc/src/sgml/keywords/sql2016-02-reserved.txt @@ -157,7 +157,6 @@ INTERVAL INTO IS JOIN -JSON JSON_ARRAY JSON_ARRAYAGG JSON_EXISTS diff --git a/src/backend/catalog/sql_features.txt b/src/backend/catalog/sql_features.txt index 0a9c7df4f49..da7c9c772e0 100644 --- a/src/backend/catalog/sql_features.txt +++ b/src/backend/catalog/sql_features.txt @@ -527,20 +527,20 @@ T652 SQL-dynamic statements in SQL routines NO T653 SQL-schema statements in external routines YES T654 SQL-dynamic statements in external routines NO T655 Cyclically dependent routines YES -T811 Basic SQL/JSON constructor functions YES -T812 SQL/JSON: JSON_OBJECTAGG YES -T813 SQL/JSON: JSON_ARRAYAGG with ORDER BY YES -T814 Colon in JSON_OBJECT or JSON_OBJECTAGG YES -T821 Basic SQL/JSON query operators YES -T822 SQL/JSON: IS JSON WITH UNIQUE KEYS predicate YES -T823 SQL/JSON: PASSING clause YES -T824 JSON_TABLE: specific PLAN clause YES -T825 SQL/JSON: ON EMPTY and ON ERROR clauses YES -T826 General value expression in ON ERROR or ON EMPTY clauses YES -T827 JSON_TABLE: sibling NESTED COLUMNS clauses YES -T828 JSON_QUERY YES -T829 JSON_QUERY: array wrapper options YES -T830 Enforcing unique keys in SQL/JSON constructor functions YES +T811 Basic SQL/JSON constructor functions NO +T812 SQL/JSON: JSON_OBJECTAGG NO +T813 SQL/JSON: JSON_ARRAYAGG with ORDER BY NO +T814 Colon in JSON_OBJECT or JSON_OBJECTAGG NO +T821 Basic SQL/JSON query operators NO +T822 SQL/JSON: IS JSON WITH UNIQUE KEYS predicate NO +T823 SQL/JSON: PASSING clause NO +T824 JSON_TABLE: specific PLAN clause NO +T825 SQL/JSON: ON EMPTY and ON ERROR clauses NO +T826 General value expression in ON ERROR or ON EMPTY clauses NO +T827 JSON_TABLE: sibling NESTED COLUMNS clauses NO +T828 JSON_QUERY NO +T829 JSON_QUERY: array wrapper options NO +T830 Enforcing unique keys in SQL/JSON constructor functions NO T831 SQL/JSON path language: strict mode YES T832 SQL/JSON path language: item method YES T833 SQL/JSON path language: multiple subscripts YES @@ -548,7 +548,7 @@ T834 SQL/JSON path language: wildcard member accessor YES T835 SQL/JSON path language: filter expressions YES T836 SQL/JSON path language: starts with predicate YES T837 SQL/JSON path language: regex_like predicate YES -T838 JSON_TABLE: PLAN DEFAULT clause YES +T838 JSON_TABLE: PLAN DEFAULT clause NO T839 Formatted cast of datetimes to/from character strings NO M001 Datalinks NO M002 Datalinks via SQL/CLI NO diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index e078456b191..053d2ca5ae4 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -3851,13 +3851,7 @@ ExplainTargetRel(Plan *plan, Index rti, ExplainState *es) break; case T_TableFuncScan: Assert(rte->rtekind == RTE_TABLEFUNC); - if (rte->tablefunc) - if (rte->tablefunc->functype == TFT_XMLTABLE) - objectname = "xmltable"; - else /* Must be TFT_JSON_TABLE */ - objectname = "json_table"; - else - objectname = NULL; + objectname = "xmltable"; objecttag = "Table Function Name"; break; case T_ValuesScan: diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c index d0a57c7aaee..25a94bbaaaa 100644 --- a/src/backend/executor/execExpr.c +++ b/src/backend/executor/execExpr.c @@ -47,9 +47,6 @@ #include "utils/array.h" #include "utils/builtins.h" #include "utils/datum.h" -#include "utils/json.h" -#include "utils/jsonb.h" -#include "utils/jsonpath.h" #include "utils/lsyscache.h" #include "utils/typcache.h" @@ -88,40 +85,6 @@ static void ExecBuildAggTransCall(ExprState *state, AggState *aggstate, bool nullcheck); -static ExprState * -ExecInitExprInternal(Expr *node, PlanState *parent, ParamListInfo ext_params, - Datum *caseval, bool *casenull) -{ - ExprState *state; - ExprEvalStep scratch = {0}; - - /* Special case: NULL expression produces a NULL ExprState pointer */ - if (node == NULL) - return NULL; - - /* Initialize ExprState with empty step list */ - state = makeNode(ExprState); - state->expr = node; - state->parent = parent; - state->ext_params = ext_params; - state->innermost_caseval = caseval; - state->innermost_casenull = casenull; - - /* Insert EEOP_*_FETCHSOME steps as needed */ - ExecInitExprSlots(state, (Node *) node); - - /* Compile the expression proper */ - ExecInitExprRec(node, state, &state->resvalue, &state->resnull); - - /* Finally, append a DONE step */ - scratch.opcode = EEOP_DONE; - ExprEvalPushStep(state, &scratch); - - ExecReadyExpr(state); - - return state; -} - /* * ExecInitExpr: prepare an expression tree for execution * @@ -159,7 +122,32 @@ ExecInitExprInternal(Expr *node, PlanState *parent, ParamListInfo ext_params, ExprState * ExecInitExpr(Expr *node, PlanState *parent) { - return ExecInitExprInternal(node, parent, NULL, NULL, NULL); + ExprState *state; + ExprEvalStep scratch = {0}; + + /* Special case: NULL expression produces a NULL ExprState pointer */ + if (node == NULL) + return NULL; + + /* Initialize ExprState with empty step list */ + state = makeNode(ExprState); + state->expr = node; + state->parent = parent; + state->ext_params = NULL; + + /* Insert EEOP_*_FETCHSOME steps as needed */ + ExecInitExprSlots(state, (Node *) node); + + /* Compile the expression proper */ + ExecInitExprRec(node, state, &state->resvalue, &state->resnull); + + /* Finally, append a DONE step */ + scratch.opcode = EEOP_DONE; + ExprEvalPushStep(state, &scratch); + + ExecReadyExpr(state); + + return state; } /* @@ -171,20 +159,32 @@ ExecInitExpr(Expr *node, PlanState *parent) ExprState * ExecInitExprWithParams(Expr *node, ParamListInfo ext_params) { - return ExecInitExprInternal(node, NULL, ext_params, NULL, NULL); -} + ExprState *state; + ExprEvalStep scratch = {0}; -/* - * ExecInitExprWithCaseValue: prepare an expression tree for execution - * - * This is the same as ExecInitExpr, except that a pointer to the value for - * CasTestExpr is passed here. - */ -ExprState * -ExecInitExprWithCaseValue(Expr *node, PlanState *parent, - Datum *caseval, bool *casenull) -{ - return ExecInitExprInternal(node, parent, NULL, caseval, casenull); + /* Special case: NULL expression produces a NULL ExprState pointer */ + if (node == NULL) + return NULL; + + /* Initialize ExprState with empty step list */ + state = makeNode(ExprState); + state->expr = node; + state->parent = NULL; + state->ext_params = ext_params; + + /* Insert EEOP_*_FETCHSOME steps as needed */ + ExecInitExprSlots(state, (Node *) node); + + /* Compile the expression proper */ + ExecInitExprRec(node, state, &state->resvalue, &state->resnull); + + /* Finally, append a DONE step */ + scratch.opcode = EEOP_DONE; + ExprEvalPushStep(state, &scratch); + + ExecReadyExpr(state); + + return state; } /* @@ -2411,263 +2411,6 @@ ExecInitExprRec(Expr *node, ExprState *state, break; } - case T_JsonValueExpr: - { - JsonValueExpr *jve = (JsonValueExpr *) node; - - ExecInitExprRec(jve->raw_expr, state, resv, resnull); - - if (jve->formatted_expr) - { - Datum *innermost_caseval = state->innermost_caseval; - bool *innermost_isnull = state->innermost_casenull; - - state->innermost_caseval = resv; - state->innermost_casenull = resnull; - - ExecInitExprRec(jve->formatted_expr, state, resv, resnull); - - state->innermost_caseval = innermost_caseval; - state->innermost_casenull = innermost_isnull; - } - break; - } - - case T_JsonConstructorExpr: - { - JsonConstructorExpr *ctor = (JsonConstructorExpr *) node; - List *args = ctor->args; - ListCell *lc; - int nargs = list_length(args); - int argno = 0; - - if (ctor->func) - { - ExecInitExprRec(ctor->func, state, resv, resnull); - } - else if ((ctor->type == JSCTOR_JSON_PARSE && !ctor->unique) || - ctor->type == JSCTOR_JSON_SERIALIZE) - { - /* Use the value of the first argument as a result */ - ExecInitExprRec(linitial(args), state, resv, resnull); - } - else - { - JsonConstructorExprState *jcstate; - - jcstate = palloc0(sizeof(JsonConstructorExprState)); - - scratch.opcode = EEOP_JSON_CONSTRUCTOR; - scratch.d.json_constructor.jcstate = jcstate; - - jcstate->constructor = ctor; - jcstate->arg_values = palloc(sizeof(Datum) * nargs); - jcstate->arg_nulls = palloc(sizeof(bool) * nargs); - jcstate->arg_types = palloc(sizeof(Oid) * nargs); - jcstate->nargs = nargs; - - foreach(lc, args) - { - Expr *arg = (Expr *) lfirst(lc); - - jcstate->arg_types[argno] = exprType((Node *) arg); - - if (IsA(arg, Const)) - { - /* Don't evaluate const arguments every round */ - Const *con = (Const *) arg; - - jcstate->arg_values[argno] = con->constvalue; - jcstate->arg_nulls[argno] = con->constisnull; - } - else - { - ExecInitExprRec(arg, state, - &jcstate->arg_values[argno], - &jcstate->arg_nulls[argno]); - } - argno++; - } - - /* prepare type cache for datum_to_json[b]() */ - if (ctor->type == JSCTOR_JSON_SCALAR) - { - bool is_jsonb = - ctor->returning->format->format_type == JS_FORMAT_JSONB; - - jcstate->arg_type_cache = - palloc(sizeof(*jcstate->arg_type_cache) * nargs); - - for (int i = 0; i < nargs; i++) - { - int category; - Oid outfuncid; - Oid typid = jcstate->arg_types[i]; - - if (is_jsonb) - { - JsonbTypeCategory jbcat; - - jsonb_categorize_type(typid, &jbcat, &outfuncid); - - category = (int) jbcat; - } - else - { - JsonTypeCategory jscat; - - json_categorize_type(typid, &jscat, &outfuncid); - - category = (int) jscat; - } - - jcstate->arg_type_cache[i].outfuncid = outfuncid; - jcstate->arg_type_cache[i].category = category; - } - } - - ExprEvalPushStep(state, &scratch); - } - - if (ctor->coercion) - { - Datum *innermost_caseval = state->innermost_caseval; - bool *innermost_isnull = state->innermost_casenull; - - state->innermost_caseval = resv; - state->innermost_casenull = resnull; - - ExecInitExprRec(ctor->coercion, state, resv, resnull); - - state->innermost_caseval = innermost_caseval; - state->innermost_casenull = innermost_isnull; - } - } - break; - - case T_JsonIsPredicate: - { - JsonIsPredicate *pred = (JsonIsPredicate *) node; - - ExecInitExprRec((Expr *) pred->expr, state, resv, resnull); - - scratch.opcode = EEOP_IS_JSON; - scratch.d.is_json.pred = pred; - - ExprEvalPushStep(state, &scratch); - break; - } - - case T_JsonExpr: - { - JsonExpr *jexpr = castNode(JsonExpr, node); - JsonExprState *jsestate = palloc0(sizeof(JsonExprState)); - ListCell *argexprlc; - ListCell *argnamelc; - - scratch.opcode = EEOP_JSONEXPR; - scratch.d.jsonexpr.jsestate = jsestate; - - jsestate->jsexpr = jexpr; - - jsestate->formatted_expr = - palloc(sizeof(*jsestate->formatted_expr)); - - ExecInitExprRec((Expr *) jexpr->formatted_expr, state, - &jsestate->formatted_expr->value, - &jsestate->formatted_expr->isnull); - - jsestate->pathspec = - palloc(sizeof(*jsestate->pathspec)); - - ExecInitExprRec((Expr *) jexpr->path_spec, state, - &jsestate->pathspec->value, - &jsestate->pathspec->isnull); - - jsestate->res_expr = - palloc(sizeof(*jsestate->res_expr)); - - jsestate->result_expr = jexpr->result_coercion - ? ExecInitExprWithCaseValue((Expr *) jexpr->result_coercion->expr, - state->parent, - &jsestate->res_expr->value, - &jsestate->res_expr->isnull) - : NULL; - - jsestate->default_on_empty = !jexpr->on_empty ? NULL : - ExecInitExpr((Expr *) jexpr->on_empty->default_expr, - state->parent); - - jsestate->default_on_error = - ExecInitExpr((Expr *) jexpr->on_error->default_expr, - state->parent); - - if (jexpr->omit_quotes || - (jexpr->result_coercion && jexpr->result_coercion->via_io)) - { - Oid typinput; - - /* lookup the result type's input function */ - getTypeInputInfo(jexpr->returning->typid, &typinput, - &jsestate->input.typioparam); - fmgr_info(typinput, &jsestate->input.func); - } - - jsestate->args = NIL; - - forboth(argexprlc, jexpr->passing_values, - argnamelc, jexpr->passing_names) - { - Expr *argexpr = (Expr *) lfirst(argexprlc); - String *argname = lfirst_node(String, argnamelc); - JsonPathVariableEvalContext *var = palloc(sizeof(*var)); - - var->name = pstrdup(argname->sval); - var->typid = exprType((Node *) argexpr); - var->typmod = exprTypmod((Node *) argexpr); - var->estate = ExecInitExpr(argexpr, state->parent); - var->econtext = NULL; - var->mcxt = NULL; - var->evaluated = false; - var->value = (Datum) 0; - var->isnull = true; - - jsestate->args = - lappend(jsestate->args, var); - } - - jsestate->cache = NULL; - - if (jexpr->coercions) - { - JsonCoercion **coercion; - struct JsonCoercionState *cstate; - Datum *caseval; - bool *casenull; - - jsestate->coercion_expr = - palloc(sizeof(*jsestate->coercion_expr)); - - caseval = &jsestate->coercion_expr->value; - casenull = &jsestate->coercion_expr->isnull; - - for (cstate = &jsestate->coercions.null, - coercion = &jexpr->coercions->null; - coercion <= &jexpr->coercions->composite; - coercion++, cstate++) - { - cstate->coercion = *coercion; - cstate->estate = *coercion ? - ExecInitExprWithCaseValue((Expr *) (*coercion)->expr, - state->parent, - caseval, casenull) : NULL; - } - } - - ExprEvalPushStep(state, &scratch); - break; - } - default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node)); diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index 636794ca6f1..9b9bbf00a97 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -57,31 +57,22 @@ #include "postgres.h" #include "access/heaptoast.h" -#include "access/xact.h" -#include "catalog/pg_proc.h" #include "catalog/pg_type.h" #include "commands/sequence.h" #include "executor/execExpr.h" #include "executor/nodeSubplan.h" #include "funcapi.h" #include "miscadmin.h" -#include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" #include "parser/parsetree.h" -#include "parser/parse_expr.h" #include "pgstat.h" #include "utils/array.h" #include "utils/builtins.h" #include "utils/date.h" #include "utils/datum.h" #include "utils/expandedrecord.h" -#include "utils/json.h" -#include "utils/jsonb.h" -#include "utils/jsonfuncs.h" -#include "utils/jsonpath.h" #include "utils/lsyscache.h" #include "utils/memutils.h" -#include "utils/resowner.h" #include "utils/timestamp.h" #include "utils/typcache.h" #include "utils/xml.h" @@ -488,9 +479,6 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) &&CASE_EEOP_GROUPING_FUNC, &&CASE_EEOP_WINDOW_FUNC, &&CASE_EEOP_SUBPLAN, - &&CASE_EEOP_JSON_CONSTRUCTOR, - &&CASE_EEOP_IS_JSON, - &&CASE_EEOP_JSONEXPR, &&CASE_EEOP_AGG_STRICT_DESERIALIZE, &&CASE_EEOP_AGG_DESERIALIZE, &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS, @@ -1824,27 +1812,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) { /* too complex for an inline implementation */ ExecEvalAggOrderedTransTuple(state, op, econtext); - EEO_NEXT(); - } - - EEO_CASE(EEOP_JSON_CONSTRUCTOR) - { - /* too complex for an inline implementation */ - ExecEvalJsonConstructor(state, op, econtext); - EEO_NEXT(); - } - - EEO_CASE(EEOP_IS_JSON) - { - /* too complex for an inline implementation */ - ExecEvalJsonIsPredicate(state, op); - EEO_NEXT(); - } - EEO_CASE(EEOP_JSONEXPR) - { - /* too complex for an inline implementation */ - ExecEvalJson(state, op, econtext); EEO_NEXT(); } @@ -3972,91 +3940,6 @@ ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op) } } -void -ExecEvalJsonIsPredicate(ExprState *state, ExprEvalStep *op) -{ - JsonIsPredicate *pred = op->d.is_json.pred; - Datum js = *op->resvalue; - Oid exprtype; - bool res; - - if (*op->resnull) - { - *op->resvalue = BoolGetDatum(false); - return; - } - - exprtype = exprType(pred->expr); - - if (exprtype == TEXTOID || exprtype == JSONOID) - { - text *json = DatumGetTextP(js); - - if (pred->item_type == JS_TYPE_ANY) - res = true; - else - { - switch (json_get_first_token(json, false)) - { - case JSON_TOKEN_OBJECT_START: - res = pred->item_type == JS_TYPE_OBJECT; - break; - case JSON_TOKEN_ARRAY_START: - res = pred->item_type == JS_TYPE_ARRAY; - break; - case JSON_TOKEN_STRING: - case JSON_TOKEN_NUMBER: - case JSON_TOKEN_TRUE: - case JSON_TOKEN_FALSE: - case JSON_TOKEN_NULL: - res = pred->item_type == JS_TYPE_SCALAR; - break; - default: - res = false; - break; - } - } - - /* - * Do full parsing pass only for uniqueness check or for JSON text - * validation. - */ - if (res && (pred->unique_keys || exprtype == TEXTOID)) - res = json_validate(json, pred->unique_keys, false); - } - else if (exprtype == JSONBOID) - { - if (pred->item_type == JS_TYPE_ANY) - res = true; - else - { - Jsonb *jb = DatumGetJsonbP(js); - - switch (pred->item_type) - { - case JS_TYPE_OBJECT: - res = JB_ROOT_IS_OBJECT(jb); - break; - case JS_TYPE_ARRAY: - res = JB_ROOT_IS_ARRAY(jb) && !JB_ROOT_IS_SCALAR(jb); - break; - case JS_TYPE_SCALAR: - res = JB_ROOT_IS_ARRAY(jb) && JB_ROOT_IS_SCALAR(jb); - break; - default: - res = false; - break; - } - } - - /* Key uniqueness check is redundant for jsonb */ - } - else - res = false; - - *op->resvalue = BoolGetDatum(res); -} - /* * ExecEvalGroupingFunc * @@ -4619,629 +4502,3 @@ ExecAggPlainTransByRef(AggState *aggstate, AggStatePerTrans pertrans, MemoryContextSwitchTo(oldContext); } - -/* - * Evaluate a JSON constructor expression. - */ -void -ExecEvalJsonConstructor(ExprState *state, ExprEvalStep *op, - ExprContext *econtext) -{ - Datum res; - JsonConstructorExprState *jcstate = op->d.json_constructor.jcstate; - JsonConstructorExpr *ctor = jcstate->constructor; - bool is_jsonb = ctor->returning->format->format_type == JS_FORMAT_JSONB; - bool isnull = false; - - if (ctor->type == JSCTOR_JSON_ARRAY) - res = (is_jsonb ? - jsonb_build_array_worker : - json_build_array_worker) (jcstate->nargs, - jcstate->arg_values, - jcstate->arg_nulls, - jcstate->arg_types, - ctor->absent_on_null); - else if (ctor->type == JSCTOR_JSON_OBJECT) - res = (is_jsonb ? - jsonb_build_object_worker : - json_build_object_worker) (jcstate->nargs, - jcstate->arg_values, - jcstate->arg_nulls, - jcstate->arg_types, - ctor->absent_on_null, - ctor->unique); - else if (ctor->type == JSCTOR_JSON_SCALAR) - { - if (jcstate->arg_nulls[0]) - { - res = (Datum) 0; - isnull = true; - } - else - { - Datum value = jcstate->arg_values[0]; - int category = jcstate->arg_type_cache[0].category; - Oid outfuncid = jcstate->arg_type_cache[0].outfuncid; - - if (is_jsonb) - res = to_jsonb_worker(value, category, outfuncid); - else - res = to_json_worker(value, category, outfuncid); - } - } - else if (ctor->type == JSCTOR_JSON_PARSE) - { - if (jcstate->arg_nulls[0]) - { - res = (Datum) 0; - isnull = true; - } - else - { - Datum value = jcstate->arg_values[0]; - text *js = DatumGetTextP(value); - - if (is_jsonb) - res = jsonb_from_text(js, true); - else - { - (void) json_validate(js, true, true); - res = value; - } - } - } - else - { - res = (Datum) 0; - elog(ERROR, "invalid JsonConstructorExpr type %d", ctor->type); - } - - *op->resvalue = res; - *op->resnull = isnull; -} - -/* - * Evaluate a JSON error/empty behavior result. - */ -static Datum -ExecEvalJsonBehavior(ExprContext *econtext, JsonBehavior *behavior, - ExprState *default_estate, bool *is_null) -{ - *is_null = false; - - switch (behavior->btype) - { - case JSON_BEHAVIOR_EMPTY_ARRAY: - return JsonbPGetDatum(JsonbMakeEmptyArray()); - - case JSON_BEHAVIOR_EMPTY_OBJECT: - return JsonbPGetDatum(JsonbMakeEmptyObject()); - - case JSON_BEHAVIOR_TRUE: - return BoolGetDatum(true); - - case JSON_BEHAVIOR_FALSE: - return BoolGetDatum(false); - - case JSON_BEHAVIOR_NULL: - case JSON_BEHAVIOR_UNKNOWN: - case JSON_BEHAVIOR_EMPTY: - *is_null = true; - return (Datum) 0; - - case JSON_BEHAVIOR_DEFAULT: - return ExecEvalExpr(default_estate, econtext, is_null); - - default: - elog(ERROR, "unrecognized SQL/JSON behavior %d", behavior->btype); - return (Datum) 0; - } -} - -/* - * Evaluate a coercion of a JSON item to the target type. - */ -static Datum -ExecEvalJsonExprCoercion(ExprEvalStep *op, ExprContext *econtext, - Datum res, bool *isNull, void *p, bool *error) -{ - ExprState *estate = p; - JsonExprState *jsestate; - - if (estate) /* coerce using specified expression */ - return ExecEvalExpr(estate, econtext, isNull); - - jsestate = op->d.jsonexpr.jsestate; - - if (jsestate->jsexpr->op != JSON_EXISTS_OP) - { - JsonCoercion *coercion = jsestate->jsexpr->result_coercion; - JsonExpr *jexpr = jsestate->jsexpr; - Jsonb *jb = *isNull ? NULL : DatumGetJsonbP(res); - - if ((coercion && coercion->via_io) || - (jexpr->omit_quotes && !*isNull && - JB_ROOT_IS_SCALAR(jb))) - { - /* strip quotes and call typinput function */ - char *str = *isNull ? NULL : JsonbUnquote(jb); - - return InputFunctionCall(&jsestate->input.func, str, - jsestate->input.typioparam, - jexpr->returning->typmod); - } - else if (coercion && coercion->via_populate) - return json_populate_type(res, JSONBOID, - jexpr->returning->typid, - jexpr->returning->typmod, - &jsestate->cache, - econtext->ecxt_per_query_memory, - isNull); - } - - if (jsestate->result_expr) - { - jsestate->res_expr->value = res; - jsestate->res_expr->isnull = *isNull; - - res = ExecEvalExpr(jsestate->result_expr, econtext, isNull); - } - - return res; -} - -/* - * Evaluate a JSON path variable caching computed value. - */ -int -EvalJsonPathVar(void *cxt, char *varName, int varNameLen, - JsonbValue *val, JsonbValue *baseObject) -{ - JsonPathVariableEvalContext *var = NULL; - List *vars = cxt; - ListCell *lc; - int id = 1; - - if (!varName) - return list_length(vars); - - foreach(lc, vars) - { - var = lfirst(lc); - - if (!strncmp(var->name, varName, varNameLen)) - break; - - var = NULL; - id++; - } - - if (!var) - return -1; - - if (!var->evaluated) - { - MemoryContext oldcxt = var->mcxt ? - MemoryContextSwitchTo(var->mcxt) : NULL; - - var->value = ExecEvalExpr(var->estate, var->econtext, &var->isnull); - var->evaluated = true; - - if (oldcxt) - MemoryContextSwitchTo(oldcxt); - } - - if (var->isnull) - { - val->type = jbvNull; - return 0; - } - - JsonItemFromDatum(var->value, var->typid, var->typmod, val); - - *baseObject = *val; - return id; -} - -/* - * Prepare SQL/JSON item coercion to the output type. Returned a datum of the - * corresponding SQL type and a pointer to the coercion state. - */ -Datum -ExecPrepareJsonItemCoercion(JsonbValue *item, - JsonReturning *returning, - struct JsonCoercionsState *coercions, - struct JsonCoercionState **pcoercion) -{ - struct JsonCoercionState *coercion; - Datum res; - JsonbValue buf; - - if (item->type == jbvBinary && - JsonContainerIsScalar(item->val.binary.data)) - { - bool res PG_USED_FOR_ASSERTS_ONLY; - - res = JsonbExtractScalar(item->val.binary.data, &buf); - item = &buf; - Assert(res); - } - - /* get coercion state reference and datum of the corresponding SQL type */ - switch (item->type) - { - case jbvNull: - coercion = &coercions->null; - res = (Datum) 0; - break; - - case jbvString: - coercion = &coercions->string; - res = PointerGetDatum(cstring_to_text_with_len(item->val.string.val, - item->val.string.len)); - break; - - case jbvNumeric: - coercion = &coercions->numeric; - res = NumericGetDatum(item->val.numeric); - break; - - case jbvBool: - coercion = &coercions->boolean; - res = BoolGetDatum(item->val.boolean); - break; - - case jbvDatetime: - res = item->val.datetime.value; - switch (item->val.datetime.typid) - { - case DATEOID: - coercion = &coercions->date; - break; - case TIMEOID: - coercion = &coercions->time; - break; - case TIMETZOID: - coercion = &coercions->timetz; - break; - case TIMESTAMPOID: - coercion = &coercions->timestamp; - break; - case TIMESTAMPTZOID: - coercion = &coercions->timestamptz; - break; - default: - elog(ERROR, "unexpected jsonb datetime type oid %u", - item->val.datetime.typid); - return (Datum) 0; - } - break; - - case jbvArray: - case jbvObject: - case jbvBinary: - coercion = &coercions->composite; - res = JsonbPGetDatum(JsonbValueToJsonb(item)); - break; - - default: - elog(ERROR, "unexpected jsonb value type %d", item->type); - return (Datum) 0; - } - - *pcoercion = coercion; - - return res; -} - -typedef Datum (*JsonFunc) (ExprEvalStep *op, ExprContext *econtext, - Datum item, bool *resnull, void *p, bool *error); - -static Datum -ExecEvalJsonExprSubtrans(JsonFunc func, ExprEvalStep *op, - ExprContext *econtext, - Datum res, bool *resnull, - void *p, bool *error, bool subtrans) -{ - MemoryContext oldcontext; - ResourceOwner oldowner; - - if (!subtrans) - /* No need to use subtransactions. */ - return func(op, econtext, res, resnull, p, error); - - /* - * We should catch exceptions of category ERRCODE_DATA_EXCEPTION and - * execute the corresponding ON ERROR behavior then. - */ - oldcontext = CurrentMemoryContext; - oldowner = CurrentResourceOwner; - - Assert(error); - - BeginInternalSubTransaction(NULL); - /* Want to execute expressions inside function's memory context */ - MemoryContextSwitchTo(oldcontext); - - PG_TRY(); - { - res = func(op, econtext, res, resnull, p, error); - - /* Commit the inner transaction, return to outer xact context */ - ReleaseCurrentSubTransaction(); - MemoryContextSwitchTo(oldcontext); - CurrentResourceOwner = oldowner; - } - PG_CATCH(); - { - ErrorData *edata; - int ecategory; - - /* Save error info in oldcontext */ - MemoryContextSwitchTo(oldcontext); - edata = CopyErrorData(); - FlushErrorState(); - - /* Abort the inner transaction */ - RollbackAndReleaseCurrentSubTransaction(); - MemoryContextSwitchTo(oldcontext); - CurrentResourceOwner = oldowner; - - ecategory = ERRCODE_TO_CATEGORY(edata->sqlerrcode); - - if (ecategory != ERRCODE_DATA_EXCEPTION && /* jsonpath and other data - * errors */ - ecategory != ERRCODE_INTEGRITY_CONSTRAINT_VIOLATION) /* domain errors */ - ReThrowError(edata); - - res = (Datum) 0; - *error = true; - } - PG_END_TRY(); - - return res; -} - - -typedef struct -{ - JsonPath *path; - bool *error; - bool coercionInSubtrans; -} ExecEvalJsonExprContext; - -static Datum -ExecEvalJsonExpr(ExprEvalStep *op, ExprContext *econtext, - Datum item, bool *resnull, void *pcxt, - bool *error) -{ - ExecEvalJsonExprContext *cxt = pcxt; - JsonPath *path = cxt->path; - JsonExprState *jsestate = op->d.jsonexpr.jsestate; - JsonExpr *jexpr = jsestate->jsexpr; - ExprState *estate = NULL; - bool empty = false; - Datum res = (Datum) 0; - - switch (jexpr->op) - { - case JSON_QUERY_OP: - res = JsonPathQuery(item, path, jexpr->wrapper, &empty, error, - jsestate->args); - if (error && *error) - { - *resnull = true; - return (Datum) 0; - } - *resnull = !DatumGetPointer(res); - break; - - case JSON_VALUE_OP: - { - struct JsonCoercionState *jcstate; - JsonbValue *jbv = JsonPathValue(item, path, &empty, error, - jsestate->args); - - if (error && *error) - return (Datum) 0; - - if (!jbv) /* NULL or empty */ - break; - - Assert(!empty); - - *resnull = false; - - /* coerce scalar item to the output type */ - if (jexpr->returning->typid == JSONOID || - jexpr->returning->typid == JSONBOID) - { - /* Use result coercion from json[b] to the output type */ - res = JsonbPGetDatum(JsonbValueToJsonb(jbv)); - break; - } - - /* Use coercion from SQL/JSON item type to the output type */ - res = ExecPrepareJsonItemCoercion(jbv, - jsestate->jsexpr->returning, - &jsestate->coercions, - &jcstate); - - if (jcstate->coercion && - (jcstate->coercion->via_io || - jcstate->coercion->via_populate)) - { - if (error) - { - *error = true; - return (Datum) 0; - } - - /* - * Coercion via I/O means here that the cast to the target - * type simply does not exist. - */ - ereport(ERROR, - (errcode(ERRCODE_SQL_JSON_ITEM_CANNOT_BE_CAST_TO_TARGET_TYPE), - errmsg("SQL/JSON item cannot be cast to target type"))); - } - else if (!jcstate->estate) - return res; /* no coercion */ - - /* coerce using specific expression */ - estate = jcstate->estate; - jsestate->coercion_expr->value = res; - jsestate->coercion_expr->isnull = *resnull; - break; - } - - case JSON_EXISTS_OP: - { - bool exists = JsonPathExists(item, path, - jsestate->args, - error); - - *resnull = error && *error; - res = BoolGetDatum(exists); - - if (!jsestate->result_expr) - return res; - - /* coerce using result expression */ - estate = jsestate->result_expr; - jsestate->res_expr->value = res; - jsestate->res_expr->isnull = *resnull; - break; - } - - case JSON_TABLE_OP: - *resnull = false; - return item; - - default: - elog(ERROR, "unrecognized SQL/JSON expression op %d", jexpr->op); - return (Datum) 0; - } - - if (empty) - { - Assert(jexpr->on_empty); /* it is not JSON_EXISTS */ - - if (jexpr->on_empty->btype == JSON_BEHAVIOR_ERROR) - { - if (error) - { - *error = true; - return (Datum) 0; - } - - ereport(ERROR, - (errcode(ERRCODE_NO_SQL_JSON_ITEM), - errmsg("no SQL/JSON item"))); - } - - if (jexpr->on_empty->btype == JSON_BEHAVIOR_DEFAULT) - - /* - * Execute DEFAULT expression as a coercion expression, because - * its result is already coerced to the target type. - */ - estate = jsestate->default_on_empty; - else - /* Execute ON EMPTY behavior */ - res = ExecEvalJsonBehavior(econtext, jexpr->on_empty, - jsestate->default_on_empty, - resnull); - } - - return ExecEvalJsonExprSubtrans(ExecEvalJsonExprCoercion, op, econtext, - res, resnull, estate, error, - cxt->coercionInSubtrans); -} - -bool -ExecEvalJsonNeedsSubTransaction(JsonExpr *jsexpr, - struct JsonCoercionsState *coercions) -{ - if (jsexpr->on_error->btype == JSON_BEHAVIOR_ERROR) - return false; - - if (jsexpr->op == JSON_EXISTS_OP && !jsexpr->result_coercion) - return false; - - if (!coercions) - return true; - - return false; -} - -/* ---------------------------------------------------------------- - * ExecEvalJson - * ---------------------------------------------------------------- - */ -void -ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext) -{ - ExecEvalJsonExprContext cxt; - JsonExprState *jsestate = op->d.jsonexpr.jsestate; - JsonExpr *jexpr = jsestate->jsexpr; - Datum item; - Datum res = (Datum) 0; - JsonPath *path; - ListCell *lc; - bool error = false; - bool needSubtrans; - bool throwErrors = jexpr->on_error->btype == JSON_BEHAVIOR_ERROR; - - *op->resnull = true; /* until we get a result */ - *op->resvalue = (Datum) 0; - - if (jsestate->formatted_expr->isnull || jsestate->pathspec->isnull) - { - /* execute domain checks for NULLs */ - (void) ExecEvalJsonExprCoercion(op, econtext, res, op->resnull, - NULL, NULL); - - Assert(*op->resnull); - return; - } - - item = jsestate->formatted_expr->value; - path = DatumGetJsonPathP(jsestate->pathspec->value); - - /* reset JSON path variable contexts */ - foreach(lc, jsestate->args) - { - JsonPathVariableEvalContext *var = lfirst(lc); - - var->econtext = econtext; - var->evaluated = false; - } - - needSubtrans = ExecEvalJsonNeedsSubTransaction(jexpr, &jsestate->coercions); - - cxt.path = path; - cxt.error = throwErrors ? NULL : &error; - cxt.coercionInSubtrans = !needSubtrans && !throwErrors; - Assert(!needSubtrans || cxt.error); - - res = ExecEvalJsonExprSubtrans(ExecEvalJsonExpr, op, econtext, item, - op->resnull, &cxt, cxt.error, - needSubtrans); - - if (error) - { - /* Execute ON ERROR behavior */ - res = ExecEvalJsonBehavior(econtext, jexpr->on_error, - jsestate->default_on_error, - op->resnull); - - /* result is already coerced in DEFAULT behavior case */ - if (jexpr->on_error->btype != JSON_BEHAVIOR_DEFAULT) - res = ExecEvalJsonExprCoercion(op, econtext, res, - op->resnull, - NULL, NULL); - } - - *op->resvalue = res; -} diff --git a/src/backend/executor/nodeTableFuncscan.c b/src/backend/executor/nodeTableFuncscan.c index 691c3e28cef..0db4ed0c2fe 100644 --- a/src/backend/executor/nodeTableFuncscan.c +++ b/src/backend/executor/nodeTableFuncscan.c @@ -28,7 +28,6 @@ #include "miscadmin.h" #include "nodes/execnodes.h" #include "utils/builtins.h" -#include "utils/jsonpath.h" #include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/xml.h" @@ -162,9 +161,8 @@ ExecInitTableFuncScan(TableFuncScan *node, EState *estate, int eflags) scanstate->ss.ps.qual = ExecInitQual(node->scan.plan.qual, &scanstate->ss.ps); - /* Only XMLTABLE and JSON_TABLE are supported currently */ - scanstate->routine = - tf->functype == TFT_XMLTABLE ? &XmlTableRoutine : &JsonbTableRoutine; + /* Only XMLTABLE is supported currently */ + scanstate->routine = &XmlTableRoutine; scanstate->perTableCxt = AllocSetContextCreate(CurrentMemoryContext, @@ -383,17 +381,14 @@ tfuncInitialize(TableFuncScanState *tstate, ExprContext *econtext, Datum doc) routine->SetNamespace(tstate, ns_name, ns_uri); } - if (routine->SetRowFilter) - { - /* Install the row filter expression into the table builder context */ - value = ExecEvalExpr(tstate->rowexpr, econtext, &isnull); - if (isnull) - ereport(ERROR, - (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("row filter expression must not be null"))); + /* Install the row filter expression into the table builder context */ + value = ExecEvalExpr(tstate->rowexpr, econtext, &isnull); + if (isnull) + ereport(ERROR, + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("row filter expression must not be null"))); - routine->SetRowFilter(tstate, TextDatumGetCString(value)); - } + routine->SetRowFilter(tstate, TextDatumGetCString(value)); /* * Install the column filter expressions into the table builder context. diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c index bd3965143da..95d0807bdde 100644 --- a/src/backend/jit/llvm/llvmjit_expr.c +++ b/src/backend/jit/llvm/llvmjit_expr.c @@ -2395,24 +2395,6 @@ llvm_compile_expr(ExprState *state) LLVMBuildBr(b, opblocks[opno + 1]); break; - case EEOP_JSON_CONSTRUCTOR: - build_EvalXFunc(b, mod, "ExecEvalJsonConstructor", - v_state, op, v_econtext); - LLVMBuildBr(b, opblocks[opno + 1]); - break; - - case EEOP_IS_JSON: - build_EvalXFunc(b, mod, "ExecEvalJsonIsPredicate", - v_state, op); - LLVMBuildBr(b, opblocks[opno + 1]); - break; - - case EEOP_JSONEXPR: - build_EvalXFunc(b, mod, "ExecEvalJson", - v_state, op, v_econtext); - LLVMBuildBr(b, opblocks[opno + 1]); - break; - case EEOP_LAST: Assert(false); break; diff --git a/src/backend/jit/llvm/llvmjit_types.c b/src/backend/jit/llvm/llvmjit_types.c index 373471ad27f..90ac6b83b5a 100644 --- a/src/backend/jit/llvm/llvmjit_types.c +++ b/src/backend/jit/llvm/llvmjit_types.c @@ -133,9 +133,6 @@ void *referenced_functions[] = ExecEvalSysVar, ExecEvalWholeRowVar, ExecEvalXmlExpr, - ExecEvalJsonConstructor, - ExecEvalJsonIsPredicate, - ExecEvalJson, MakeExpandedObjectReadOnlyInternal, slot_getmissingattrs, slot_getsomeattrs_int, diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c index 28288dcfc10..c85d8fe9751 100644 --- a/src/backend/nodes/makefuncs.c +++ b/src/backend/nodes/makefuncs.c @@ -19,7 +19,6 @@ #include "catalog/pg_type.h" #include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" -#include "utils/errcodes.h" #include "utils/lsyscache.h" @@ -819,124 +818,3 @@ makeVacuumRelation(RangeVar *relation, Oid oid, List *va_cols) v->va_cols = va_cols; return v; } - -/* - * makeJsonFormat - - * creates a JsonFormat node - */ -JsonFormat * -makeJsonFormat(JsonFormatType type, JsonEncoding encoding, int location) -{ - JsonFormat *jf = makeNode(JsonFormat); - - jf->format_type = type; - jf->encoding = encoding; - jf->location = location; - - return jf; -} - -/* - * makeJsonValueExpr - - * creates a JsonValueExpr node - */ -JsonValueExpr * -makeJsonValueExpr(Expr *expr, JsonFormat *format) -{ - JsonValueExpr *jve = makeNode(JsonValueExpr); - - jve->raw_expr = expr; - jve->formatted_expr = NULL; - jve->format = format; - - return jve; -} - -/* - * makeJsonBehavior - - * creates a JsonBehavior node - */ -JsonBehavior * -makeJsonBehavior(JsonBehaviorType type, Node *default_expr) -{ - JsonBehavior *behavior = makeNode(JsonBehavior); - - behavior->btype = type; - behavior->default_expr = default_expr; - - return behavior; -} - -/* - * makeJsonTableJoinedPlan - - * creates a joined JsonTablePlan node - */ -Node * -makeJsonTableJoinedPlan(JsonTablePlanJoinType type, Node *plan1, Node *plan2, - int location) -{ - JsonTablePlan *n = makeNode(JsonTablePlan); - - n->plan_type = JSTP_JOINED; - n->join_type = type; - n->plan1 = castNode(JsonTablePlan, plan1); - n->plan2 = castNode(JsonTablePlan, plan2); - n->location = location; - - return (Node *) n; -} - -/* - * makeJsonEncoding - - * converts JSON encoding name to enum JsonEncoding - */ -JsonEncoding -makeJsonEncoding(char *name) -{ - if (!pg_strcasecmp(name, "utf8")) - return JS_ENC_UTF8; - if (!pg_strcasecmp(name, "utf16")) - return JS_ENC_UTF16; - if (!pg_strcasecmp(name, "utf32")) - return JS_ENC_UTF32; - - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("unrecognized JSON encoding: %s", name))); - - return JS_ENC_DEFAULT; -} - -/* - * makeJsonKeyValue - - * creates a JsonKeyValue node - */ -Node * -makeJsonKeyValue(Node *key, Node *value) -{ - JsonKeyValue *n = makeNode(JsonKeyValue); - - n->key = (Expr *) key; - n->value = castNode(JsonValueExpr, value); - - return (Node *) n; -} - -/* - * makeJsonIsPredicate - - * creates a JsonIsPredicate node - */ -Node * -makeJsonIsPredicate(Node *expr, JsonFormat *format, JsonValueType item_type, - bool unique_keys, int location) -{ - JsonIsPredicate *n = makeNode(JsonIsPredicate); - - n->expr = expr; - n->format = format; - n->item_type = item_type; - n->unique_keys = unique_keys; - n->location = location; - - return (Node *) n; -} diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index af1e8567d15..1e8a8d0d340 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -252,25 +252,6 @@ exprType(const Node *expr) case T_PlaceHolderVar: type = exprType((Node *) ((const PlaceHolderVar *) expr)->phexpr); break; - case T_JsonValueExpr: - { - const JsonValueExpr *jve = (const JsonValueExpr *) expr; - - type = exprType((Node *) (jve->formatted_expr ? jve->formatted_expr : jve->raw_expr)); - } - break; - case T_JsonConstructorExpr: - type = ((const JsonConstructorExpr *) expr)->returning->typid; - break; - case T_JsonIsPredicate: - type = BOOLOID; - break; - case T_JsonExpr: - type = ((const JsonExpr *) expr)->returning->typid; - break; - case T_JsonCoercion: - type = exprType(((const JsonCoercion *) expr)->expr); - break; default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr)); type = InvalidOid; /* keep compiler quiet */ @@ -506,14 +487,6 @@ exprTypmod(const Node *expr) return ((const SetToDefault *) expr)->typeMod; case T_PlaceHolderVar: return exprTypmod((Node *) ((const PlaceHolderVar *) expr)->phexpr); - case T_JsonValueExpr: - return exprTypmod((Node *) ((const JsonValueExpr *) expr)->formatted_expr); - case T_JsonConstructorExpr: - return ((const JsonConstructorExpr *) expr)->returning->typmod; - case T_JsonExpr: - return ((JsonExpr *) expr)->returning->typmod; - case T_JsonCoercion: - return exprTypmod(((const JsonCoercion *) expr)->expr); default: break; } @@ -996,37 +969,6 @@ exprCollation(const Node *expr) case T_PlaceHolderVar: coll = exprCollation((Node *) ((const PlaceHolderVar *) expr)->phexpr); break; - case T_JsonValueExpr: - coll = exprCollation((Node *) ((const JsonValueExpr *) expr)->formatted_expr); - break; - case T_JsonConstructorExpr: - { - const JsonConstructorExpr *ctor = (const JsonConstructorExpr *) expr; - - if (ctor->coercion) - coll = exprCollation((Node *) ctor->coercion); - else - coll = InvalidOid; - } - break; - case T_JsonIsPredicate: - coll = InvalidOid; /* result is always an boolean type */ - break; - case T_JsonExpr: - { - JsonExpr *jexpr = (JsonExpr *) expr; - JsonCoercion *coercion = jexpr->result_coercion; - - if (!coercion) - coll = InvalidOid; - else if (coercion->expr) - coll = exprCollation(coercion->expr); - else if (coercion->via_io || coercion->via_populate) - coll = coercion->collation; - else - coll = InvalidOid; - } - break; default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr)); coll = InvalidOid; /* keep compiler quiet */ @@ -1245,39 +1187,6 @@ exprSetCollation(Node *expr, Oid collation) /* NextValueExpr's result is an integer type ... */ Assert(!OidIsValid(collation)); /* ... so never set a collation */ break; - case T_JsonValueExpr: - exprSetCollation((Node *) ((JsonValueExpr *) expr)->formatted_expr, - collation); - break; - case T_JsonConstructorExpr: - { - JsonConstructorExpr *ctor = (JsonConstructorExpr *) expr; - - if (ctor->coercion) - exprSetCollation((Node *) ctor->coercion, collation); - else - Assert(!OidIsValid(collation)); /* result is always a - * json[b] type */ - } - break; - case T_JsonIsPredicate: - Assert(!OidIsValid(collation)); /* result is always boolean */ - break; - case T_JsonExpr: - { - JsonExpr *jexpr = (JsonExpr *) expr; - JsonCoercion *coercion = jexpr->result_coercion; - - if (!coercion) - Assert(!OidIsValid(collation)); - else if (coercion->expr) - exprSetCollation(coercion->expr, collation); - else if (coercion->via_io || coercion->via_populate) - coercion->collation = collation; - else - Assert(!OidIsValid(collation)); - } - break; default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr)); break; @@ -1724,24 +1633,6 @@ exprLocation(const Node *expr) case T_PartitionRangeDatum: loc = ((const PartitionRangeDatum *) expr)->location; break; - case T_JsonValueExpr: - loc = exprLocation((Node *) ((const JsonValueExpr *) expr)->raw_expr); - break; - case T_JsonConstructorExpr: - loc = ((const JsonConstructorExpr *) expr)->location; - break; - case T_JsonIsPredicate: - loc = ((const JsonIsPredicate *) expr)->location; - break; - case T_JsonExpr: - { - const JsonExpr *jsexpr = (const JsonExpr *) expr; - - /* consider both function name and leftmost arg */ - loc = leftmostLoc(jsexpr->location, - exprLocation(jsexpr->formatted_expr)); - } - break; default: /* for any other node type it's just unknown... */ loc = -1; @@ -2484,80 +2375,6 @@ expression_tree_walker(Node *node, return true; if (walker(tf->coldefexprs, context)) return true; - if (walker(tf->colvalexprs, context)) - return true; - } - break; - case T_JsonValueExpr: - { - JsonValueExpr *jve = (JsonValueExpr *) node; - - if (walker(jve->raw_expr, context)) - return true; - if (walker(jve->formatted_expr, context)) - return true; - } - break; - case T_JsonConstructorExpr: - { - JsonConstructorExpr *ctor = (JsonConstructorExpr *) node; - - if (walker(ctor->args, context)) - return true; - if (walker(ctor->func, context)) - return true; - if (walker(ctor->coercion, context)) - return true; - } - break; - case T_JsonIsPredicate: - return walker(((JsonIsPredicate *) node)->expr, context); - case T_JsonExpr: - { - JsonExpr *jexpr = (JsonExpr *) node; - - if (walker(jexpr->formatted_expr, context)) - return true; - if (walker(jexpr->result_coercion, context)) - return true; - if (walker(jexpr->passing_values, context)) - return true; - /* we assume walker doesn't care about passing_names */ - if (jexpr->on_empty && - walker(jexpr->on_empty->default_expr, context)) - return true; - if (walker(jexpr->on_error->default_expr, context)) - return true; - if (walker(jexpr->coercions, context)) - return true; - } - break; - case T_JsonCoercion: - return walker(((JsonCoercion *) node)->expr, context); - case T_JsonItemCoercions: - { - JsonItemCoercions *coercions = (JsonItemCoercions *) node; - - if (walker(coercions->null, context)) - return true; - if (walker(coercions->string, context)) - return true; - if (walker(coercions->numeric, context)) - return true; - if (walker(coercions->boolean, context)) - return true; - if (walker(coercions->date, context)) - return true; - if (walker(coercions->time, context)) - return true; - if (walker(coercions->timetz, context)) - return true; - if (walker(coercions->timestamp, context)) - return true; - if (walker(coercions->timestamptz, context)) - return true; - if (walker(coercions->composite, context)) - return true; } break; default: @@ -2887,7 +2704,6 @@ expression_tree_mutator(Node *node, case T_RangeTblRef: case T_SortGroupClause: case T_CTESearchClause: - case T_JsonFormat: return (Node *) copyObject(node); case T_WithCheckOption: { @@ -3528,102 +3344,6 @@ expression_tree_mutator(Node *node, MUTATE(newnode->rowexpr, tf->rowexpr, Node *); MUTATE(newnode->colexprs, tf->colexprs, List *); MUTATE(newnode->coldefexprs, tf->coldefexprs, List *); - MUTATE(newnode->colvalexprs, tf->colvalexprs, List *); - return (Node *) newnode; - } - break; - case T_JsonReturning: - { - JsonReturning *jr = (JsonReturning *) node; - JsonReturning *newnode; - - FLATCOPY(newnode, jr, JsonReturning); - MUTATE(newnode->format, jr->format, JsonFormat *); - - return (Node *) newnode; - } - case T_JsonValueExpr: - { - JsonValueExpr *jve = (JsonValueExpr *) node; - JsonValueExpr *newnode; - - FLATCOPY(newnode, jve, JsonValueExpr); - MUTATE(newnode->raw_expr, jve->raw_expr, Expr *); - MUTATE(newnode->formatted_expr, jve->formatted_expr, Expr *); - MUTATE(newnode->format, jve->format, JsonFormat *); - - return (Node *) newnode; - } - case T_JsonConstructorExpr: - { - JsonConstructorExpr *jve = (JsonConstructorExpr *) node; - JsonConstructorExpr *newnode; - - FLATCOPY(newnode, jve, JsonConstructorExpr); - MUTATE(newnode->args, jve->args, List *); - MUTATE(newnode->func, jve->func, Expr *); - MUTATE(newnode->coercion, jve->coercion, Expr *); - MUTATE(newnode->returning, jve->returning, JsonReturning *); - - return (Node *) newnode; - } - break; - case T_JsonIsPredicate: - { - JsonIsPredicate *pred = (JsonIsPredicate *) node; - JsonIsPredicate *newnode; - - FLATCOPY(newnode, pred, JsonIsPredicate); - MUTATE(newnode->expr, pred->expr, Node *); - - return (Node *) newnode; - } - break; - case T_JsonExpr: - { - JsonExpr *jexpr = (JsonExpr *) node; - JsonExpr *newnode; - - FLATCOPY(newnode, jexpr, JsonExpr); - MUTATE(newnode->path_spec, jexpr->path_spec, Node *); - MUTATE(newnode->formatted_expr, jexpr->formatted_expr, Node *); - MUTATE(newnode->result_coercion, jexpr->result_coercion, JsonCoercion *); - MUTATE(newnode->passing_values, jexpr->passing_values, List *); - /* assume mutator does not care about passing_names */ - if (newnode->on_empty) - MUTATE(newnode->on_empty->default_expr, - jexpr->on_empty->default_expr, Node *); - MUTATE(newnode->on_error->default_expr, - jexpr->on_error->default_expr, Node *); - return (Node *) newnode; - } - break; - case T_JsonCoercion: - { - JsonCoercion *coercion = (JsonCoercion *) node; - JsonCoercion *newnode; - - FLATCOPY(newnode, coercion, JsonCoercion); - MUTATE(newnode->expr, coercion->expr, Node *); - return (Node *) newnode; - } - break; - case T_JsonItemCoercions: - { - JsonItemCoercions *coercions = (JsonItemCoercions *) node; - JsonItemCoercions *newnode; - - FLATCOPY(newnode, coercions, JsonItemCoercions); - MUTATE(newnode->null, coercions->null, JsonCoercion *); - MUTATE(newnode->string, coercions->string, JsonCoercion *); - MUTATE(newnode->numeric, coercions->numeric, JsonCoercion *); - MUTATE(newnode->boolean, coercions->boolean, JsonCoercion *); - MUTATE(newnode->date, coercions->date, JsonCoercion *); - MUTATE(newnode->time, coercions->time, JsonCoercion *); - MUTATE(newnode->timetz, coercions->timetz, JsonCoercion *); - MUTATE(newnode->timestamp, coercions->timestamp, JsonCoercion *); - MUTATE(newnode->timestamptz, coercions->timestamptz, JsonCoercion *); - MUTATE(newnode->composite, coercions->composite, JsonCoercion *); return (Node *) newnode; } break; @@ -3900,7 +3620,6 @@ raw_expression_tree_walker(Node *node, case T_ParamRef: case T_A_Const: case T_A_Star: - case T_JsonFormat: /* primitive node types with no subnodes */ break; case T_Alias: @@ -4363,211 +4082,6 @@ raw_expression_tree_walker(Node *node, case T_CommonTableExpr: /* search_clause and cycle_clause are not interesting here */ return walker(((CommonTableExpr *) node)->ctequery, context); - case T_JsonReturning: - return walker(((JsonReturning *) node)->format, context); - case T_JsonValueExpr: - { - JsonValueExpr *jve = (JsonValueExpr *) node; - - if (walker(jve->raw_expr, context)) - return true; - if (walker(jve->formatted_expr, context)) - return true; - if (walker(jve->format, context)) - return true; - } - break; - case T_JsonParseExpr: - { - JsonParseExpr *jpe = (JsonParseExpr *) node; - - if (walker(jpe->expr, context)) - return true; - if (walker(jpe->output, context)) - return true; - } - break; - case T_JsonScalarExpr: - { - JsonScalarExpr *jse = (JsonScalarExpr *) node; - - if (walker(jse->expr, context)) - return true; - if (walker(jse->output, context)) - return true; - } - break; - case T_JsonSerializeExpr: - { - JsonSerializeExpr *jse = (JsonSerializeExpr *) node; - - if (walker(jse->expr, context)) - return true; - if (walker(jse->output, context)) - return true; - } - break; - case T_JsonConstructorExpr: - { - JsonConstructorExpr *ctor = (JsonConstructorExpr *) node; - - if (walker(ctor->args, context)) - return true; - if (walker(ctor->func, context)) - return true; - if (walker(ctor->coercion, context)) - return true; - if (walker(ctor->returning, context)) - return true; - } - break; - case T_JsonOutput: - { - JsonOutput *out = (JsonOutput *) node; - - if (walker(out->typeName, context)) - return true; - if (walker(out->returning, context)) - return true; - } - break; - case T_JsonKeyValue: - { - JsonKeyValue *jkv = (JsonKeyValue *) node; - - if (walker(jkv->key, context)) - return true; - if (walker(jkv->value, context)) - return true; - } - break; - case T_JsonObjectConstructor: - { - JsonObjectConstructor *joc = (JsonObjectConstructor *) node; - - if (walker(joc->output, context)) - return true; - if (walker(joc->exprs, context)) - return true; - } - break; - case T_JsonArrayConstructor: - { - JsonArrayConstructor *jac = (JsonArrayConstructor *) node; - - if (walker(jac->output, context)) - return true; - if (walker(jac->exprs, context)) - return true; - } - break; - case T_JsonAggConstructor: - { - JsonAggConstructor *ctor = (JsonAggConstructor *) node; - - if (walker(ctor->output, context)) - return true; - if (walker(ctor->agg_order, context)) - return true; - if (walker(ctor->agg_filter, context)) - return true; - if (walker(ctor->over, context)) - return true; - } - break; - case T_JsonObjectAgg: - { - JsonObjectAgg *joa = (JsonObjectAgg *) node; - - if (walker(joa->constructor, context)) - return true; - if (walker(joa->arg, context)) - return true; - } - break; - case T_JsonArrayAgg: - { - JsonArrayAgg *jaa = (JsonArrayAgg *) node; - - if (walker(jaa->constructor, context)) - return true; - if (walker(jaa->arg, context)) - return true; - } - break; - case T_JsonArrayQueryConstructor: - { - JsonArrayQueryConstructor *jaqc = (JsonArrayQueryConstructor *) node; - - if (walker(jaqc->output, context)) - return true; - if (walker(jaqc->query, context)) - return true; - } - break; - case T_JsonIsPredicate: - return walker(((JsonIsPredicate *) node)->expr, context); - case T_JsonArgument: - return walker(((JsonArgument *) node)->val, context); - case T_JsonCommon: - { - JsonCommon *jc = (JsonCommon *) node; - - if (walker(jc->expr, context)) - return true; - if (walker(jc->pathspec, context)) - return true; - if (walker(jc->passing, context)) - return true; - } - break; - case T_JsonBehavior: - { - JsonBehavior *jb = (JsonBehavior *) node; - - if (jb->btype == JSON_BEHAVIOR_DEFAULT && - walker(jb->default_expr, context)) - return true; - } - break; - case T_JsonFuncExpr: - { - JsonFuncExpr *jfe = (JsonFuncExpr *) node; - - if (walker(jfe->common, context)) - return true; - if (jfe->output && walker(jfe->output, context)) - return true; - if (walker(jfe->on_empty, context)) - return true; - if (walker(jfe->on_error, context)) - return true; - } - break; - case T_JsonTable: - { - JsonTable *jt = (JsonTable *) node; - - if (walker(jt->common, context)) - return true; - if (walker(jt->columns, context)) - return true; - } - break; - case T_JsonTableColumn: - { - JsonTableColumn *jtc = (JsonTableColumn *) node; - - if (walker(jtc->typeName, context)) - return true; - if (walker(jtc->on_empty, context)) - return true; - if (walker(jtc->on_error, context)) - return true; - if (jtc->coltype == JTC_NESTED && walker(jtc->columns, context)) - return true; - } - break; default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node)); diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 75acea149c7..f486d42441b 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -4923,8 +4923,7 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context) IsA(node, SQLValueFunction) || IsA(node, XmlExpr) || IsA(node, CoerceToDomain) || - IsA(node, NextValueExpr) || - IsA(node, JsonExpr)) + IsA(node, NextValueExpr)) { /* Treat all these as having cost 1 */ context->total.per_tuple += cpu_operator_cost; diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 272c27fe835..349ce82f9d4 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -28,7 +28,6 @@ #include "catalog/pg_type.h" #include "executor/executor.h" #include "executor/functions.h" -#include "executor/execExpr.h" #include "funcapi.h" #include "miscadmin.h" #include "nodes/makefuncs.h" @@ -52,9 +51,6 @@ #include "utils/builtins.h" #include "utils/datum.h" #include "utils/fmgroids.h" -#include "utils/json.h" -#include "utils/jsonb.h" -#include "utils/jsonpath.h" #include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/syscache.h" @@ -392,45 +388,6 @@ contain_mutable_functions_walker(Node *node, void *context) context)) return true; - if (IsA(node, JsonConstructorExpr)) - { - const JsonConstructorExpr *ctor = (JsonConstructorExpr *) node; - ListCell *lc; - bool is_jsonb = - ctor->returning->format->format_type == JS_FORMAT_JSONB; - - /* Check argument_type => json[b] conversions */ - foreach(lc, ctor->args) - { - Oid typid = exprType(lfirst(lc)); - - if (is_jsonb ? - !to_jsonb_is_immutable(typid) : - !to_json_is_immutable(typid)) - return true; - } - - /* Check all subnodes */ - } - - if (IsA(node, JsonExpr)) - { - JsonExpr *jexpr = castNode(JsonExpr, node); - Const *cnst; - - if (!IsA(jexpr->path_spec, Const)) - return true; - - cnst = castNode(Const, jexpr->path_spec); - - Assert(cnst->consttype == JSONPATHOID); - if (cnst->constisnull) - return false; - - return jspIsMutable(DatumGetJsonPathP(cnst->constvalue), - jexpr->passing_names, jexpr->passing_values); - } - if (IsA(node, SQLValueFunction)) { /* all variants of SQLValueFunction are stable */ @@ -902,18 +859,6 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context) context, 0); } - /* JsonExpr is parallel-unsafe if subtransactions can be used. */ - else if (IsA(node, JsonExpr)) - { - JsonExpr *jsexpr = (JsonExpr *) node; - - if (ExecEvalJsonNeedsSubTransaction(jsexpr, NULL)) - { - context->max_hazard = PROPARALLEL_UNSAFE; - return true; - } - } - /* Recurse to check arguments */ return expression_tree_walker(node, max_parallel_hazard_walker, @@ -3574,29 +3519,6 @@ eval_const_expressions_mutator(Node *node, return ece_evaluate_expr((Node *) newcre); return (Node *) newcre; } - case T_JsonValueExpr: - { - JsonValueExpr *jve = (JsonValueExpr *) node; - Node *raw = eval_const_expressions_mutator((Node *) jve->raw_expr, - context); - - if (raw && IsA(raw, Const)) - { - Node *formatted; - Node *save_case_val = context->case_val; - - context->case_val = raw; - - formatted = eval_const_expressions_mutator((Node *) jve->formatted_expr, - context); - - context->case_val = save_case_val; - - if (formatted && IsA(formatted, Const)) - return formatted; - } - break; - } default: break; } diff --git a/src/backend/parser/Makefile b/src/backend/parser/Makefile index f4c0cc7f101..9f1c4022bbe 100644 --- a/src/backend/parser/Makefile +++ b/src/backend/parser/Makefile @@ -23,7 +23,6 @@ OBJS = \ parse_enr.o \ parse_expr.o \ parse_func.o \ - parse_jsontable.o \ parse_merge.o \ parse_node.o \ parse_oper.o \ diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 3580e1bf7b2..9cce8d3d062 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -295,13 +295,6 @@ fix_domain_typmods_hook_type fix_domain_typmods_hook = NULL; MergeWhenClause *mergewhen; struct KeyActions *keyactions; struct KeyAction *keyaction; - JsonBehavior *jsbehavior; - struct - { - JsonBehavior *on_empty; - JsonBehavior *on_error; - } on_behavior; - JsonQuotes js_quotes; } %type stmt toplevel_stmt schema_stmt routine_body_stmt @@ -590,7 +583,7 @@ fix_domain_typmods_hook_type fix_domain_typmods_hook = NULL; %type copy_options %type Typename SimpleTypename ConstTypename - GenericType Numeric opt_float JsonType + GenericType Numeric opt_float Character ConstCharacter CharacterWithLength CharacterWithoutLength ConstDatetime ConstInterval @@ -670,101 +663,6 @@ fix_domain_typmods_hook_type fix_domain_typmods_hook = NULL; %type hash_partbound_elem -%type json_format_clause_opt - json_representation - json_value_expr - json_func_expr - json_value_func_expr - json_query_expr - json_exists_predicate - json_parse_expr - json_scalar_expr - json_serialize_expr - json_api_common_syntax - json_context_item - json_argument - json_output_clause_opt - json_returning_clause_opt - json_value_constructor - json_object_constructor - json_object_constructor_args - json_object_constructor_args_opt - json_object_args - json_object_func_args - json_array_constructor - json_name_and_value - json_aggregate_func - json_object_aggregate_constructor - json_array_aggregate_constructor - json_path_specification - json_table - json_table_column_definition - json_table_ordinality_column_definition - json_table_regular_column_definition - json_table_formatted_column_definition - json_table_exists_column_definition - json_table_nested_columns - json_table_plan_clause_opt - json_table_specific_plan - json_table_plan - json_table_plan_simple - json_table_plan_parent_child - json_table_plan_outer - json_table_plan_inner - json_table_plan_sibling - json_table_plan_union - json_table_plan_cross - json_table_plan_primary - json_table_default_plan - -%type json_name_and_value_list - json_value_expr_list - json_array_aggregate_order_by_clause_opt - json_arguments - json_passing_clause_opt - json_table_columns_clause - json_table_column_definition_list - -%type json_table_path_name - json_as_path_name_clause_opt - json_table_column_path_specification_clause_opt - -%type json_encoding - json_encoding_clause_opt - json_table_default_plan_choices - json_table_default_plan_inner_outer - json_table_default_plan_union_cross - json_wrapper_clause_opt - json_wrapper_behavior - json_conditional_or_unconditional_opt - json_predicate_type_constraint_opt - -%type json_behavior_error - json_behavior_null - json_behavior_true - json_behavior_false - json_behavior_unknown - json_behavior_empty - json_behavior_empty_array - json_behavior_empty_object - json_behavior_default - json_value_behavior - json_query_behavior - json_exists_error_behavior - json_exists_error_clause_opt - json_table_error_behavior - json_table_error_clause_opt - -%type json_value_on_behavior_clause_opt - json_query_on_behavior_clause_opt - -%type json_quotes_behavior - json_quotes_clause_opt - -%type json_key_uniqueness_constraint_opt - json_object_constructor_null_clause_opt - json_array_constructor_null_clause_opt - /* * Non-keyword token types. These are hard-wired into the "flex" lexer. * They must be listed first so that their numeric codes do not depend on @@ -795,7 +693,7 @@ fix_domain_typmods_hook_type fix_domain_typmods_hook = NULL; */ /* ordinary key words in alphabetical order */ -%token ABORT_P ABSENT ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER +%token ABORT_P ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER AGGREGATE ALL ALSO ALTER ALWAYS ANALYSE ANALYZE AND ANY ARRAY AS ASC ASENSITIVE ASSERTION ASSIGNMENT ASYMMETRIC ATOMIC AT ATTACH ATTRIBUTE AUTHORIZATION @@ -805,7 +703,7 @@ fix_domain_typmods_hook_type fix_domain_typmods_hook = NULL; CACHE CALL CALLED CASCADE CASCADED CASE CAST CATALOG_P CHAIN CHAR_P CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE CLUSTER COALESCE COLLATE COLLATION COLUMN COLUMNS COMMENT COMMENTS COMMIT - COMMITTED COMPRESSION CONCURRENTLY CONDITIONAL CONFIGURATION CONFLICT + COMMITTED COMPRESSION CONCURRENTLY CONFIGURATION CONFLICT CONNECTION CONSTRAINT CONSTRAINTS CONTENT_P CONTINUE_P CONVERSION_P COPY COST CREATE CROSS CSV CUBE CURRENT_P CURRENT_CATALOG CURRENT_DATE CURRENT_ROLE CURRENT_SCHEMA @@ -816,12 +714,12 @@ fix_domain_typmods_hook_type fix_domain_typmods_hook = NULL; DETACH DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP - EACH ELSE EMPTY_P ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ERROR_P ESCAPE - EVENT EXCEPT EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN EXPRESSION + EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ESCAPE EVENT EXCEPT + EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN EXPRESSION EXTENSION EXTERNAL EXTRACT FALSE_P FAMILY FETCH FILTER FINALIZE FIRST_P FLOAT_P FOLLOWING FOR - FORCE FOREIGN FORMAT FORWARD FREEZE FROM FULL FUNCTION FUNCTIONS + FORCE FOREIGN FORWARD FREEZE FROM FULL FUNCTION FUNCTIONS GENERATED GLOBAL GRANT GRANTED GREATEST GROUP_P GROUPING GROUPS @@ -832,10 +730,9 @@ fix_domain_typmods_hook_type fix_domain_typmods_hook = NULL; INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION - JOIN JSON JSON_ARRAY JSON_ARRAYAGG JSON_EXISTS JSON_OBJECT JSON_OBJECTAGG - JSON_QUERY JSON_SCALAR JSON_SERIALIZE JSON_TABLE JSON_VALUE + JOIN - KEY KEYS KEEP + KEY LABEL LANGUAGE LARGE_P LAST_P LATERAL_P LEADING LEAKPROOF LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL @@ -844,31 +741,31 @@ fix_domain_typmods_hook_type fix_domain_typmods_hook = NULL; MAPPING MATCH MATCHED MATERIALIZED MAXVALUE MERGE METHOD MINUTE_P MINVALUE MODE MONTH_P MOVE - NAME_P NAMES NATIONAL NATURAL NCHAR NESTED NEW NEXT NFC NFD NFKC NFKD NO - NONE NORMALIZE NORMALIZED + NAME_P NAMES NATIONAL NATURAL NCHAR NEW NEXT NFC NFD NFKC NFKD NO NONE + NORMALIZE NORMALIZED NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF NULLS_P NUMERIC - OBJECT_P OF OFF OFFSET OIDS OLD OMIT ON ONLY OPERATOR OPTION OPTIONS OR + OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OPTIONS OR ORDER ORDINALITY OTHERS OUT_P OUTER_P OVER OVERLAPS OVERLAY OVERRIDING OWNED OWNER - PARALLEL PARAMETER PARSER PARTIAL PARTITION PASSING PASSWORD PATH - PLACING PLAN PLANS POLICY + PARALLEL PARAMETER PARSER PARTIAL PARTITION PASSING PASSWORD + PLACING PLANS POLICY POSITION PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROCEDURES PROGRAM PUBLICATION - QUOTE QUOTES + QUOTE RANGE READ REAL REASSIGN RECHECK RECURSIVE REF_P REFERENCES REFERENCING REFRESH REINDEX RELATIVE_P RELEASE RENAME REPEATABLE REPLACE REPLICA RESET RESTART RESTRICT RETURN RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP ROUTINE ROUTINES ROW ROWS RULE - SAVEPOINT SCALAR SCHEMA SCHEMAS SCROLL SEARCH SECOND_P SECURITY SELECT - SEQUENCE SEQUENCES SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF - SHARE SHOW SIMILAR SIMPLE SKIP SMALLINT SNAPSHOT SOME SQL_P STABLE STANDALONE_P - START STATEMENT STATISTICS STDIN STDOUT STORAGE STORED STRICT_P STRING STRIP_P + SAVEPOINT SCHEMA SCHEMAS SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE SEQUENCES + SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF SHARE SHOW + SIMILAR SIMPLE SKIP SMALLINT SNAPSHOT SOME SQL_P STABLE STANDALONE_P + START STATEMENT STATISTICS STDIN STDOUT STORAGE STORED STRICT_P STRIP_P SUBSCRIPTION SUBSTRING SUPPORT SYMMETRIC SYSID SYSTEM_P TABLE TABLES TABLESAMPLE TABLESPACE TEMP TEMPLATE TEMPORARY TEXT_P THEN @@ -876,7 +773,7 @@ fix_domain_typmods_hook_type fix_domain_typmods_hook = NULL; TREAT TRIGGER TRIM TRUE_P TRUNCATE TRUSTED TYPE_P TYPES_P - UESCAPE UNBOUNDED UNCONDITIONAL UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN + UESCAPE UNBOUNDED UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNLOGGED UNTIL UPDATE USER USING VACUUM VALID VALIDATE VALIDATOR VALUE_P VALUES VARCHAR VARIADIC VARYING @@ -901,7 +798,7 @@ fix_domain_typmods_hook_type fix_domain_typmods_hook = NULL; * as NOT, at least with respect to their left-hand subexpression. * NULLS_LA and WITH_LA are needed to make the grammar LALR(1). */ -%token NOT_LA NULLS_LA WITH_LA WITH_LA_UNIQUE WITHOUT_LA +%token NOT_LA NULLS_LA WITH_LA /* * The grammar likewise thinks these tokens are keywords, but they are never @@ -919,7 +816,6 @@ fix_domain_typmods_hook_type fix_domain_typmods_hook = NULL; /* Precedence: lowest to highest */ %nonassoc SET /* see relation_expr_opt_alias */ -%right FORMAT %left UNION EXCEPT %left INTERSECT %left OR @@ -955,8 +851,6 @@ fix_domain_typmods_hook_type fix_domain_typmods_hook = NULL; * Using the same precedence as IDENT seems right for the reasons given above. */ %nonassoc UNBOUNDED /* ideally would have same precedence as IDENT */ -%nonassoc ERROR_P EMPTY_P DEFAULT ABSENT /* JSON error/empty behavior */ -%nonassoc FALSE_P KEEP OMIT PASSING TRUE_P UNKNOWN UNIQUE JSON COLUMNS %nonassoc IDENT PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP /* Please note that the following line will be replaced with the contents of given file name even if with starting with a comment */ /*$$include "gram-tsql-nonassoc-ident-tokens"*/ @@ -964,8 +858,6 @@ fix_domain_typmods_hook_type fix_domain_typmods_hook = NULL; %left '+' '-' %left '*' '/' '%' %left '^' -%left KEYS /* UNIQUE [ KEYS ] */ -%left OBJECT_P SCALAR VALUE_P /* JSON [ OBJECT | SCALAR | VALUE ] */ /* Unary Operators */ %left AT /* sets precedence for AT TIME ZONE */ %left COLLATE @@ -983,13 +875,6 @@ fix_domain_typmods_hook_type fix_domain_typmods_hook = NULL; */ %left JOIN CROSS LEFT FULL RIGHT INNER_P NATURAL -%nonassoc json_table_column -%nonassoc NESTED -%left PATH - -%nonassoc empty_json_unique -%left WITHOUT WITH_LA_UNIQUE - /* Please note that the following line will be replaced with the contents of given file name even if with starting with a comment */ /*$$include "gram-tsql-decl.y"*/ @@ -13473,21 +13358,6 @@ table_ref: relation_expr opt_alias_clause $2->alias = $4; $$ = (Node *) $2; } - | json_table opt_alias_clause - { - JsonTable *jt = castNode(JsonTable, $1); - - jt->alias = $2; - $$ = (Node *) jt; - } - | LATERAL_P json_table opt_alias_clause - { - JsonTable *jt = castNode(JsonTable, $2); - - jt->alias = $3; - jt->lateral = true; - $$ = (Node *) jt; - } ; @@ -14055,8 +13925,6 @@ xmltable_column_option_el: { $$ = makeDefElem("is_not_null", (Node *) makeBoolean(true), @1); } | NULL_P { $$ = makeDefElem("is_not_null", (Node *) makeBoolean(false), @1); } - | PATH b_expr - { $$ = makeDefElem("path", $2, @1); } ; xml_namespace_list: @@ -14159,7 +14027,6 @@ SimpleTypename: $$->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1), makeIntConst($3, @3)); } - | JsonType { $$ = $1; } ; /* We have a separate ConstTypename to allow defaulting fixed-length @@ -14178,7 +14045,6 @@ ConstTypename: | ConstBit { $$ = $1; } | ConstCharacter { $$ = $1; } | ConstDatetime { $$ = $1; } - | JsonType { $$ = $1; } ; /* @@ -14204,7 +14070,7 @@ GenericType: if (fix_domain_typmods_hook) (*fix_domain_typmods_hook)($$); } - | type_function_name attrs opt_type_modifiers WITHOUT_LA TIME ZONE + | type_function_name attrs opt_type_modifiers WITHOUT TIME ZONE { /* * This gram rule should only be allowed when we restore @@ -14551,7 +14417,7 @@ ConstInterval: opt_timezone: WITH_LA TIME ZONE { $$ = true; } - | WITHOUT_LA TIME ZONE { $$ = false; } + | WITHOUT TIME ZONE { $$ = false; } | /*EMPTY*/ { $$ = false; } ; @@ -14626,13 +14492,6 @@ interval_second: } ; -JsonType: - JSON - { - $$ = SystemTypeName("json"); - $$->location = @1; - } - ; /***************************************************************************** * @@ -15113,47 +14972,6 @@ a_expr: c_expr { $$ = $1; } @2), @2); } - | a_expr - IS json_predicate_type_constraint_opt - json_key_uniqueness_constraint_opt %prec IS - { - JsonFormat *format = makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1); - $$ = makeJsonIsPredicate($1, format, $3, $4, @1); - } - /* - * Required by standard, but it would conflict with expressions - * like: 'str' || format(...) - | a_expr - FORMAT json_representation - IS json_predicate_type_constraint_opt - json_key_uniqueness_constraint_opt %prec FORMAT - { - $3.location = @2; - $$ = makeJsonIsPredicate($1, $3, $5, $6, @1); - } - */ - | a_expr - IS NOT - json_predicate_type_constraint_opt - json_key_uniqueness_constraint_opt %prec IS - { - JsonFormat *format = makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1); - - $$ = makeNotExpr(makeJsonIsPredicate($1, format, $4, $5, @1), @1); - } - /* - * Required by standard, but it would conflict with expressions - * like: 'str' || format(...) - | a_expr - FORMAT json_representation - IS NOT - json_predicate_type_constraint_opt - json_key_uniqueness_constraint_opt %prec FORMAT - { - $3.location = @2; - $$ = makeNotExpr(makeJsonIsPredicate($1, $3, $6, $7, @1), @1); - } - */ | DEFAULT { /* @@ -15237,25 +15055,6 @@ b_expr: c_expr } ; -json_predicate_type_constraint_opt: - JSON { $$ = JS_TYPE_ANY; } - | JSON VALUE_P { $$ = JS_TYPE_ANY; } - | JSON ARRAY { $$ = JS_TYPE_ARRAY; } - | JSON OBJECT_P { $$ = JS_TYPE_OBJECT; } - | JSON SCALAR { $$ = JS_TYPE_SCALAR; } - ; - -json_key_uniqueness_constraint_opt: - WITH_LA_UNIQUE unique_keys { $$ = true; } - | WITHOUT unique_keys { $$ = false; } - | /* EMPTY */ %prec empty_json_unique { $$ = false; } - ; - -unique_keys: - UNIQUE - | UNIQUE KEYS - ; - /* * Productions that can be used in both a_expr and b_expr. * @@ -15526,16 +15325,6 @@ func_expr: func_application within_group_clause filter_clause over_clause n->over = $4; $$ = (Node *) n; } - | json_aggregate_func filter_clause over_clause - { - JsonAggConstructor *n = IsA($1, JsonObjectAgg) ? - ((JsonObjectAgg *) $1)->constructor : - ((JsonArrayAgg *) $1)->constructor; - - n->agg_filter = $2; - n->over = $3; - $$ = (Node *) $1; - } | func_expr_common_subexpr { $$ = $1; } ; @@ -15549,7 +15338,6 @@ func_expr: func_application within_group_clause filter_clause over_clause func_expr_windowless: func_application { $$ = $1; } | func_expr_common_subexpr { $$ = $1; } - | json_aggregate_func { $$ = $1; } ; /* @@ -15860,8 +15648,6 @@ func_expr_common_subexpr: n->location = @1; $$ = (Node *) n; } - | json_func_expr - { $$ = $1; } ; /* @@ -16583,813 +16369,6 @@ opt_asymmetric: ASYMMETRIC | /*EMPTY*/ ; -/* SQL/JSON support */ -json_func_expr: - json_value_constructor - | json_value_func_expr - | json_query_expr - | json_exists_predicate - | json_parse_expr - | json_scalar_expr - | json_serialize_expr - ; - -json_parse_expr: - JSON '(' json_value_expr json_key_uniqueness_constraint_opt - json_returning_clause_opt ')' - { - JsonParseExpr *n = makeNode(JsonParseExpr); - - n->expr = (JsonValueExpr *) $3; - n->unique_keys = $4; - n->output = (JsonOutput *) $5; - n->location = @1; - $$ = (Node *) n; - } - ; - -json_scalar_expr: - JSON_SCALAR '(' a_expr json_returning_clause_opt ')' - { - JsonScalarExpr *n = makeNode(JsonScalarExpr); - - n->expr = (Expr *) $3; - n->output = (JsonOutput *) $4; - n->location = @1; - $$ = (Node *) n; - } - ; - -json_serialize_expr: - JSON_SERIALIZE '(' json_value_expr json_output_clause_opt ')' - { - JsonSerializeExpr *n = makeNode(JsonSerializeExpr); - - n->expr = (JsonValueExpr *) $3; - n->output = (JsonOutput *) $4; - n->location = @1; - $$ = (Node *) n; - } - ; - -json_value_func_expr: - JSON_VALUE '(' - json_api_common_syntax - json_returning_clause_opt - json_value_on_behavior_clause_opt - ')' - { - JsonFuncExpr *n = makeNode(JsonFuncExpr); - - n->op = JSON_VALUE_OP; - n->common = (JsonCommon *) $3; - n->output = (JsonOutput *) $4; - n->on_empty = $5.on_empty; - n->on_error = $5.on_error; - n->location = @1; - $$ = (Node *) n; - } - ; - -json_api_common_syntax: - json_context_item ',' json_path_specification - json_as_path_name_clause_opt - json_passing_clause_opt - { - JsonCommon *n = makeNode(JsonCommon); - - n->expr = (JsonValueExpr *) $1; - n->pathspec = $3; - n->pathname = $4; - n->passing = $5; - n->location = @1; - $$ = (Node *) n; - } - ; - -json_context_item: - json_value_expr { $$ = $1; } - ; - -json_path_specification: - a_expr { $$ = $1; } - ; - -json_as_path_name_clause_opt: - AS json_table_path_name { $$ = $2; } - | /* EMPTY */ { $$ = NULL; } - ; - -json_table_path_name: - name { $$ = $1; } - ; - -json_passing_clause_opt: - PASSING json_arguments { $$ = $2; } - | /* EMPTY */ { $$ = NIL; } - ; - -json_arguments: - json_argument { $$ = list_make1($1); } - | json_arguments ',' json_argument { $$ = lappend($1, $3); } - ; - -json_argument: - json_value_expr AS ColLabel - { - JsonArgument *n = makeNode(JsonArgument); - - n->val = (JsonValueExpr *) $1; - n->name = $3; - $$ = (Node *) n; - } - ; - -json_value_expr: - a_expr json_format_clause_opt - { - $$ = (Node *) makeJsonValueExpr((Expr *) $1, castNode(JsonFormat, $2)); - } - ; - -json_format_clause_opt: - FORMAT json_representation - { - $$ = $2; - castNode(JsonFormat, $$)->location = @1; - } - | /* EMPTY */ - { - $$ = (Node *) makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1); - } - ; - -json_representation: - JSON json_encoding_clause_opt - { - $$ = (Node *) makeJsonFormat(JS_FORMAT_JSON, $2, @1); - } - /* | other implementation defined JSON representation options (BSON, AVRO etc) */ - ; - -json_encoding_clause_opt: - ENCODING json_encoding { $$ = $2; } - | /* EMPTY */ { $$ = JS_ENC_DEFAULT; } - ; - -json_encoding: - name { $$ = makeJsonEncoding($1); } - ; - -json_behavior_error: - ERROR_P { $$ = makeJsonBehavior(JSON_BEHAVIOR_ERROR, NULL); } - ; - -json_behavior_null: - NULL_P { $$ = makeJsonBehavior(JSON_BEHAVIOR_NULL, NULL); } - ; - -json_behavior_true: - TRUE_P { $$ = makeJsonBehavior(JSON_BEHAVIOR_TRUE, NULL); } - ; - -json_behavior_false: - FALSE_P { $$ = makeJsonBehavior(JSON_BEHAVIOR_FALSE, NULL); } - ; - -json_behavior_unknown: - UNKNOWN { $$ = makeJsonBehavior(JSON_BEHAVIOR_UNKNOWN, NULL); } - ; - -json_behavior_empty: - EMPTY_P { $$ = makeJsonBehavior(JSON_BEHAVIOR_EMPTY_OBJECT, NULL); } - ; - -json_behavior_empty_array: - EMPTY_P ARRAY { $$ = makeJsonBehavior(JSON_BEHAVIOR_EMPTY_ARRAY, NULL); } - /* non-standard, for Oracle compatibility only */ - | EMPTY_P { $$ = makeJsonBehavior(JSON_BEHAVIOR_EMPTY_ARRAY, NULL); } - ; - -json_behavior_empty_object: - EMPTY_P OBJECT_P { $$ = makeJsonBehavior(JSON_BEHAVIOR_EMPTY_OBJECT, NULL); } - ; - -json_behavior_default: - DEFAULT a_expr { $$ = makeJsonBehavior(JSON_BEHAVIOR_DEFAULT, $2); } - ; - - -json_value_behavior: - json_behavior_null - | json_behavior_error - | json_behavior_default - ; - -json_value_on_behavior_clause_opt: - json_value_behavior ON EMPTY_P - { $$.on_empty = $1; $$.on_error = NULL; } - | json_value_behavior ON EMPTY_P json_value_behavior ON ERROR_P - { $$.on_empty = $1; $$.on_error = $4; } - | json_value_behavior ON ERROR_P - { $$.on_empty = NULL; $$.on_error = $1; } - | /* EMPTY */ - { $$.on_empty = NULL; $$.on_error = NULL; } - ; - -json_query_expr: - JSON_QUERY '(' - json_api_common_syntax - json_output_clause_opt - json_wrapper_clause_opt - json_quotes_clause_opt - json_query_on_behavior_clause_opt - ')' - { - JsonFuncExpr *n = makeNode(JsonFuncExpr); - - n->op = JSON_QUERY_OP; - n->common = (JsonCommon *) $3; - n->output = (JsonOutput *) $4; - n->wrapper = $5; - if (n->wrapper != JSW_NONE && $6 != JS_QUOTES_UNSPEC) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("SQL/JSON QUOTES behavior must not be specified when WITH WRAPPER is used"), - parser_errposition(@6))); - n->omit_quotes = $6 == JS_QUOTES_OMIT; - n->on_empty = $7.on_empty; - n->on_error = $7.on_error; - n->location = @1; - $$ = (Node *) n; - } - ; - -json_wrapper_clause_opt: - json_wrapper_behavior WRAPPER { $$ = $1; } - | /* EMPTY */ { $$ = 0; } - ; - -json_wrapper_behavior: - WITHOUT array_opt { $$ = JSW_NONE; } - | WITH json_conditional_or_unconditional_opt array_opt { $$ = $2; } - ; - -array_opt: - ARRAY { } - | /* EMPTY */ { } - ; - -json_conditional_or_unconditional_opt: - CONDITIONAL { $$ = JSW_CONDITIONAL; } - | UNCONDITIONAL { $$ = JSW_UNCONDITIONAL; } - | /* EMPTY */ { $$ = JSW_UNCONDITIONAL; } - ; - -json_quotes_clause_opt: - json_quotes_behavior QUOTES json_on_scalar_string_opt { $$ = $1; } - | /* EMPTY */ { $$ = JS_QUOTES_UNSPEC; } - ; - -json_quotes_behavior: - KEEP { $$ = JS_QUOTES_KEEP; } - | OMIT { $$ = JS_QUOTES_OMIT; } - ; - -json_on_scalar_string_opt: - ON SCALAR STRING { } - | /* EMPTY */ { } - ; - -json_query_behavior: - json_behavior_error - | json_behavior_null - | json_behavior_empty_array - | json_behavior_empty_object - | json_behavior_default - ; - -json_query_on_behavior_clause_opt: - json_query_behavior ON EMPTY_P - { $$.on_empty = $1; $$.on_error = NULL; } - | json_query_behavior ON EMPTY_P json_query_behavior ON ERROR_P - { $$.on_empty = $1; $$.on_error = $4; } - | json_query_behavior ON ERROR_P - { $$.on_empty = NULL; $$.on_error = $1; } - | /* EMPTY */ - { $$.on_empty = NULL; $$.on_error = NULL; } - ; - -json_table: - JSON_TABLE '(' - json_api_common_syntax - json_table_columns_clause - json_table_plan_clause_opt - json_table_error_clause_opt - ')' - { - JsonTable *n = makeNode(JsonTable); - - n->common = (JsonCommon *) $3; - n->columns = $4; - n->plan = (JsonTablePlan *) $5; - n->on_error = $6; - n->location = @1; - $$ = (Node *) n; - } - ; - -json_table_columns_clause: - COLUMNS '(' json_table_column_definition_list ')' { $$ = $3; } - ; - -json_table_column_definition_list: - json_table_column_definition - { $$ = list_make1($1); } - | json_table_column_definition_list ',' json_table_column_definition - { $$ = lappend($1, $3); } - ; - -json_table_column_definition: - json_table_ordinality_column_definition %prec json_table_column - | json_table_regular_column_definition %prec json_table_column - | json_table_formatted_column_definition %prec json_table_column - | json_table_exists_column_definition %prec json_table_column - | json_table_nested_columns - ; - -json_table_ordinality_column_definition: - ColId FOR ORDINALITY - { - JsonTableColumn *n = makeNode(JsonTableColumn); - - n->coltype = JTC_FOR_ORDINALITY; - n->name = $1; - n->location = @1; - $$ = (Node *) n; - } - ; - -json_table_regular_column_definition: - ColId Typename - json_table_column_path_specification_clause_opt - json_wrapper_clause_opt - json_quotes_clause_opt - json_value_on_behavior_clause_opt - { - JsonTableColumn *n = makeNode(JsonTableColumn); - - n->coltype = JTC_REGULAR; - n->name = $1; - n->typeName = $2; - n->format = makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1); - n->wrapper = $4; /* JSW_NONE */ - n->omit_quotes = $5; /* false */ - n->pathspec = $3; - n->on_empty = $6.on_empty; - n->on_error = $6.on_error; - n->location = @1; - $$ = (Node *) n; - } - ; - -json_table_exists_column_definition: - ColId Typename - EXISTS json_table_column_path_specification_clause_opt - json_exists_error_clause_opt - { - JsonTableColumn *n = makeNode(JsonTableColumn); - - n->coltype = JTC_EXISTS; - n->name = $1; - n->typeName = $2; - n->format = makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1); - n->wrapper = JSW_NONE; - n->omit_quotes = false; - n->pathspec = $4; - n->on_empty = NULL; - n->on_error = $5; - n->location = @1; - $$ = (Node *) n; - } - ; - -json_table_error_behavior: - json_behavior_error - | json_behavior_empty - ; - -json_table_error_clause_opt: - json_table_error_behavior ON ERROR_P { $$ = $1; } - | /* EMPTY */ { $$ = NULL; } - ; - -json_table_column_path_specification_clause_opt: - PATH Sconst { $$ = $2; } - | /* EMPTY */ %prec json_table_column { $$ = NULL; } - ; - -json_table_formatted_column_definition: - ColId Typename FORMAT json_representation - json_table_column_path_specification_clause_opt - json_wrapper_clause_opt - json_quotes_clause_opt - json_query_on_behavior_clause_opt - { - JsonTableColumn *n = makeNode(JsonTableColumn); - - n->coltype = JTC_FORMATTED; - n->name = $1; - n->typeName = $2; - n->format = castNode(JsonFormat, $4); - n->pathspec = $5; - n->wrapper = $6; - if (n->wrapper != JSW_NONE && $7 != JS_QUOTES_UNSPEC) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("SQL/JSON QUOTES behavior must not be specified when WITH WRAPPER is used"), - parser_errposition(@7))); - n->omit_quotes = $7 == JS_QUOTES_OMIT; - n->on_empty = $8.on_empty; - n->on_error = $8.on_error; - n->location = @1; - $$ = (Node *) n; - } - ; - -json_table_nested_columns: - NESTED path_opt Sconst - json_as_path_name_clause_opt - json_table_columns_clause - { - JsonTableColumn *n = makeNode(JsonTableColumn); - - n->coltype = JTC_NESTED; - n->pathspec = $3; - n->pathname = $4; - n->columns = $5; - n->location = @1; - $$ = (Node *) n; - } - ; - -path_opt: - PATH { } - | /* EMPTY */ { } - ; - -json_table_plan_clause_opt: - json_table_specific_plan { $$ = $1; } - | json_table_default_plan { $$ = $1; } - | /* EMPTY */ { $$ = NULL; } - ; - -json_table_specific_plan: - PLAN '(' json_table_plan ')' { $$ = $3; } - ; - -json_table_plan: - json_table_plan_simple - | json_table_plan_parent_child - | json_table_plan_sibling - ; - -json_table_plan_simple: - json_table_path_name - { - JsonTablePlan *n = makeNode(JsonTablePlan); - - n->plan_type = JSTP_SIMPLE; - n->pathname = $1; - n->location = @1; - $$ = (Node *) n; - } - ; - -json_table_plan_parent_child: - json_table_plan_outer - | json_table_plan_inner - ; - -json_table_plan_outer: - json_table_plan_simple OUTER_P json_table_plan_primary - { $$ = makeJsonTableJoinedPlan(JSTPJ_OUTER, $1, $3, @1); } - ; - -json_table_plan_inner: - json_table_plan_simple INNER_P json_table_plan_primary - { $$ = makeJsonTableJoinedPlan(JSTPJ_INNER, $1, $3, @1); } - ; - -json_table_plan_sibling: - json_table_plan_union - | json_table_plan_cross - ; - -json_table_plan_union: - json_table_plan_primary UNION json_table_plan_primary - { $$ = makeJsonTableJoinedPlan(JSTPJ_UNION, $1, $3, @1); } - | json_table_plan_union UNION json_table_plan_primary - { $$ = makeJsonTableJoinedPlan(JSTPJ_UNION, $1, $3, @1); } - ; - -json_table_plan_cross: - json_table_plan_primary CROSS json_table_plan_primary - { $$ = makeJsonTableJoinedPlan(JSTPJ_CROSS, $1, $3, @1); } - | json_table_plan_cross CROSS json_table_plan_primary - { $$ = makeJsonTableJoinedPlan(JSTPJ_CROSS, $1, $3, @1); } - ; - -json_table_plan_primary: - json_table_plan_simple { $$ = $1; } - | '(' json_table_plan ')' - { - castNode(JsonTablePlan, $2)->location = @1; - $$ = $2; - } - ; - -json_table_default_plan: - PLAN DEFAULT '(' json_table_default_plan_choices ')' - { - JsonTablePlan *n = makeNode(JsonTablePlan); - - n->plan_type = JSTP_DEFAULT; - n->join_type = $4; - n->location = @1; - $$ = (Node *) n; - } - ; - -json_table_default_plan_choices: - json_table_default_plan_inner_outer { $$ = $1 | JSTPJ_UNION; } - | json_table_default_plan_inner_outer ',' - json_table_default_plan_union_cross { $$ = $1 | $3; } - | json_table_default_plan_union_cross { $$ = $1 | JSTPJ_OUTER; } - | json_table_default_plan_union_cross ',' - json_table_default_plan_inner_outer { $$ = $1 | $3; } - ; - -json_table_default_plan_inner_outer: - INNER_P { $$ = JSTPJ_INNER; } - | OUTER_P { $$ = JSTPJ_OUTER; } - ; - -json_table_default_plan_union_cross: - UNION { $$ = JSTPJ_UNION; } - | CROSS { $$ = JSTPJ_CROSS; } - ; - -json_returning_clause_opt: - RETURNING Typename - { - JsonOutput *n = makeNode(JsonOutput); - - n->typeName = $2; - n->returning = makeNode(JsonReturning); - n->returning->format = - makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, @2); - $$ = (Node *) n; - } - | /* EMPTY */ { $$ = NULL; } - ; - -json_output_clause_opt: - RETURNING Typename json_format_clause_opt - { - JsonOutput *n = makeNode(JsonOutput); - - n->typeName = $2; - n->returning = makeNode(JsonReturning); - n->returning->format = (JsonFormat *) $3; - $$ = (Node *) n; - } - | /* EMPTY */ { $$ = NULL; } - ; - -json_exists_predicate: - JSON_EXISTS '(' - json_api_common_syntax - json_returning_clause_opt - json_exists_error_clause_opt - ')' - { - JsonFuncExpr *p = makeNode(JsonFuncExpr); - - p->op = JSON_EXISTS_OP; - p->common = (JsonCommon *) $3; - p->output = (JsonOutput *) $4; - p->on_error = $5; - p->location = @1; - $$ = (Node *) p; - } - ; - -json_exists_error_clause_opt: - json_exists_error_behavior ON ERROR_P { $$ = $1; } - | /* EMPTY */ { $$ = NULL; } - ; - -json_exists_error_behavior: - json_behavior_error - | json_behavior_true - | json_behavior_false - | json_behavior_unknown - ; - -json_value_constructor: - json_object_constructor - | json_array_constructor - ; - -json_object_constructor: - JSON_OBJECT '(' json_object_args ')' - { - $$ = $3; - } - ; - -json_object_args: - json_object_constructor_args - | json_object_func_args - ; - -json_object_func_args: - func_arg_list - { - List *func = list_make1(makeString("json_object")); - - $$ = (Node *) makeFuncCall(func, $1, COERCE_EXPLICIT_CALL, @1); - } - ; - -json_object_constructor_args: - json_object_constructor_args_opt json_output_clause_opt - { - JsonObjectConstructor *n = (JsonObjectConstructor *) $1; - - n->output = (JsonOutput *) $2; - n->location = @1; - $$ = (Node *) n; - } - ; - -json_object_constructor_args_opt: - json_name_and_value_list - json_object_constructor_null_clause_opt - json_key_uniqueness_constraint_opt - { - JsonObjectConstructor *n = makeNode(JsonObjectConstructor); - - n->exprs = $1; - n->absent_on_null = $2; - n->unique = $3; - $$ = (Node *) n; - } - | /* EMPTY */ - { - JsonObjectConstructor *n = makeNode(JsonObjectConstructor); - - n->exprs = NULL; - n->absent_on_null = false; - n->unique = false; - $$ = (Node *) n; - } - ; - -json_name_and_value_list: - json_name_and_value - { $$ = list_make1($1); } - | json_name_and_value_list ',' json_name_and_value - { $$ = lappend($1, $3); } - ; - -json_name_and_value: -/* TODO This is not supported due to conflicts - KEY c_expr VALUE_P json_value_expr %prec POSTFIXOP - { $$ = makeJsonKeyValue($2, $4); } - | -*/ - c_expr VALUE_P json_value_expr - { $$ = makeJsonKeyValue($1, $3); } - | - a_expr ':' json_value_expr - { $$ = makeJsonKeyValue($1, $3); } - ; - -json_object_constructor_null_clause_opt: - NULL_P ON NULL_P { $$ = false; } - | ABSENT ON NULL_P { $$ = true; } - | /* EMPTY */ { $$ = false; } - ; - -json_array_constructor: - JSON_ARRAY '(' - json_value_expr_list - json_array_constructor_null_clause_opt - json_output_clause_opt - ')' - { - JsonArrayConstructor *n = makeNode(JsonArrayConstructor); - - n->exprs = $3; - n->absent_on_null = $4; - n->output = (JsonOutput *) $5; - n->location = @1; - $$ = (Node *) n; - } - | JSON_ARRAY '(' - select_no_parens - /* json_format_clause_opt */ - /* json_array_constructor_null_clause_opt */ - json_output_clause_opt - ')' - { - JsonArrayQueryConstructor *n = makeNode(JsonArrayQueryConstructor); - - n->query = $3; - n->format = makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1); - /* n->format = $4; */ - n->absent_on_null = true /* $5 */; - n->output = (JsonOutput *) $4; - n->location = @1; - $$ = (Node *) n; - } - | JSON_ARRAY '(' - json_output_clause_opt - ')' - { - JsonArrayConstructor *n = makeNode(JsonArrayConstructor); - - n->exprs = NIL; - n->absent_on_null = true; - n->output = (JsonOutput *) $3; - n->location = @1; - $$ = (Node *) n; - } - ; - -json_value_expr_list: - json_value_expr { $$ = list_make1($1); } - | json_value_expr_list ',' json_value_expr { $$ = lappend($1, $3);} - ; - -json_array_constructor_null_clause_opt: - NULL_P ON NULL_P { $$ = false; } - | ABSENT ON NULL_P { $$ = true; } - | /* EMPTY */ { $$ = true; } - ; - -json_aggregate_func: - json_object_aggregate_constructor - | json_array_aggregate_constructor - ; - -json_object_aggregate_constructor: - JSON_OBJECTAGG '(' - json_name_and_value - json_object_constructor_null_clause_opt - json_key_uniqueness_constraint_opt - json_output_clause_opt - ')' - { - JsonObjectAgg *n = makeNode(JsonObjectAgg); - - n->arg = (JsonKeyValue *) $3; - n->absent_on_null = $4; - n->unique = $5; - n->constructor = makeNode(JsonAggConstructor); - n->constructor->output = (JsonOutput *) $6; - n->constructor->agg_order = NULL; - n->constructor->location = @1; - $$ = (Node *) n; - } - ; - -json_array_aggregate_constructor: - JSON_ARRAYAGG '(' - json_value_expr - json_array_aggregate_order_by_clause_opt - json_array_constructor_null_clause_opt - json_output_clause_opt - ')' - { - JsonArrayAgg *n = makeNode(JsonArrayAgg); - - n->arg = (JsonValueExpr *) $3; - n->absent_on_null = $5; - n->constructor = makeNode(JsonAggConstructor); - n->constructor->agg_order = $4; - n->constructor->output = (JsonOutput *) $6; - n->constructor->location = @1; - $$ = (Node *) n; - } - ; - -json_array_aggregate_order_by_clause_opt: - ORDER BY sortby_list { $$ = $3; } - | /* EMPTY */ { $$ = NIL; } - ; /***************************************************************************** * @@ -17906,7 +16885,6 @@ BareColLabel: IDENT { $$ = $1; } */ unreserved_keyword: ABORT_P - | ABSENT | ABSOLUTE_P | ACCESS | ACTION @@ -17947,7 +16925,6 @@ unreserved_keyword: | COMMIT | COMMITTED | COMPRESSION - | CONDITIONAL | CONFIGURATION | CONFLICT | CONNECTION @@ -17984,12 +16961,10 @@ unreserved_keyword: | DOUBLE_P | DROP | EACH - | EMPTY_P | ENABLE_P | ENCODING | ENCRYPTED | ENUM_P - | ERROR_P | ESCAPE | EVENT | EXCLUDE @@ -18006,7 +16981,6 @@ unreserved_keyword: | FIRST_P | FOLLOWING | FORCE - | FORMAT | FORWARD | FUNCTION | FUNCTIONS @@ -18038,9 +17012,7 @@ unreserved_keyword: | INSTEAD | INVOKER | ISOLATION - | KEEP | KEY - | KEYS | LABEL | LANGUAGE | LARGE_P @@ -18068,7 +17040,6 @@ unreserved_keyword: | MOVE | NAME_P | NAMES - | NESTED | NEW | NEXT | NFC @@ -18086,7 +17057,6 @@ unreserved_keyword: | OFF | OIDS | OLD - | OMIT | OPERATOR | OPTION | OPTIONS @@ -18103,8 +17073,6 @@ unreserved_keyword: | PARTITION | PASSING | PASSWORD - | PATH - | PLAN | PLANS | POLICY | PRECEDING @@ -18119,7 +17087,6 @@ unreserved_keyword: | PROGRAM | PUBLICATION | QUOTE - | QUOTES | RANGE | READ | REASSIGN @@ -18149,7 +17116,6 @@ unreserved_keyword: | ROWS | RULE | SAVEPOINT - | SCALAR | SCHEMA | SCHEMAS | SCROLL @@ -18179,7 +17145,6 @@ unreserved_keyword: | STORAGE | STORED | STRICT_P - | STRING | STRIP_P | SUBSCRIPTION | SUPPORT @@ -18202,7 +17167,6 @@ unreserved_keyword: | UESCAPE | UNBOUNDED | UNCOMMITTED - | UNCONDITIONAL | UNENCRYPTED | UNKNOWN | UNLISTEN @@ -18260,17 +17224,6 @@ col_name_keyword: | INT_P | INTEGER | INTERVAL - | JSON - | JSON_ARRAY - | JSON_ARRAYAGG - | JSON_EXISTS - | JSON_OBJECT - | JSON_OBJECTAGG - | JSON_QUERY - | JSON_SCALAR - | JSON_SERIALIZE - | JSON_TABLE - | JSON_VALUE | LEAST | NATIONAL | NCHAR @@ -18439,7 +17392,6 @@ reserved_keyword: */ bare_label_keyword: ABORT_P - | ABSENT | ABSOLUTE_P | ACCESS | ACTION @@ -18502,7 +17454,6 @@ bare_label_keyword: | COMMITTED | COMPRESSION | CONCURRENTLY - | CONDITIONAL | CONFIGURATION | CONFLICT | CONNECTION @@ -18555,13 +17506,11 @@ bare_label_keyword: | DROP | EACH | ELSE - | EMPTY_P | ENABLE_P | ENCODING | ENCRYPTED | END_P | ENUM_P - | ERROR_P | ESCAPE | EVENT | EXCLUDE @@ -18582,7 +17531,6 @@ bare_label_keyword: | FOLLOWING | FORCE | FOREIGN - | FORMAT | FORWARD | FREEZE | FULL @@ -18627,20 +17575,7 @@ bare_label_keyword: | IS | ISOLATION | JOIN - | JSON - | JSON_ARRAY - | JSON_ARRAYAGG - | JSON_EXISTS - | JSON_OBJECT - | JSON_OBJECTAGG - | JSON_QUERY - | JSON_SCALAR - | JSON_SERIALIZE - | JSON_TABLE - | JSON_VALUE - | KEEP | KEY - | KEYS | LABEL | LANGUAGE | LARGE_P @@ -18676,7 +17611,6 @@ bare_label_keyword: | NATIONAL | NATURAL | NCHAR - | NESTED | NEW | NEXT | NFC @@ -18700,7 +17634,6 @@ bare_label_keyword: | OFF | OIDS | OLD - | OMIT | ONLY | OPERATOR | OPTION @@ -18721,9 +17654,7 @@ bare_label_keyword: | PARTITION | PASSING | PASSWORD - | PATH | PLACING - | PLAN | PLANS | POLICY | POSITION @@ -18740,7 +17671,6 @@ bare_label_keyword: | PROGRAM | PUBLICATION | QUOTE - | QUOTES | RANGE | READ | REAL @@ -18774,7 +17704,6 @@ bare_label_keyword: | ROWS | RULE | SAVEPOINT - | SCALAR | SCHEMA | SCHEMAS | SCROLL @@ -18809,7 +17738,6 @@ bare_label_keyword: | STORAGE | STORED | STRICT_P - | STRING | STRIP_P | SUBSCRIPTION | SUBSTRING @@ -18843,7 +17771,6 @@ bare_label_keyword: | UESCAPE | UNBOUNDED | UNCOMMITTED - | UNCONDITIONAL | UNENCRYPTED | UNIQUE | UNKNOWN diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index 526a17285f4..22c8d9c9296 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -698,9 +698,7 @@ transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf) char **names; int colno; - /* Currently only XMLTABLE and JSON_TABLE are supported */ - - tf->functype = TFT_XMLTABLE; + /* Currently only XMLTABLE is supported */ constructName = "XMLTABLE"; docType = XMLOID; @@ -1107,17 +1105,13 @@ transformFromClauseItem(ParseState *pstate, Node *n, rtr->rtindex = nsitem->p_rtindex; return (Node *) rtr; } - else if (IsA(n, RangeTableFunc) || IsA(n, JsonTable)) + else if (IsA(n, RangeTableFunc)) { /* table function is like a plain relation */ RangeTblRef *rtr; ParseNamespaceItem *nsitem; - if (IsA(n, RangeTableFunc)) - nsitem = transformRangeTableFunc(pstate, (RangeTableFunc *) n); - else - nsitem = transformJsonTable(pstate, (JsonTable *) n); - + nsitem = transformRangeTableFunc(pstate, (RangeTableFunc *) n); *top_nsitem = nsitem; *namespace = list_make1(nsitem); rtr = makeNode(RangeTblRef); diff --git a/src/backend/parser/parse_collate.c b/src/backend/parser/parse_collate.c index bd0f2039b8a..4fb7ae178f4 100644 --- a/src/backend/parser/parse_collate.c +++ b/src/backend/parser/parse_collate.c @@ -696,13 +696,6 @@ assign_collations_walker(Node *node, assign_collations_context *context) &loccontext); } break; - case T_JsonExpr: - - /* - * Context item and PASSING arguments are already - * marked with collations in parse_expr.c. - */ - break; default: /* diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index ca2dd3695b7..55529e13962 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -15,8 +15,6 @@ #include "postgres.h" -#include "catalog/pg_aggregate.h" -#include "catalog/pg_proc.h" #include "catalog/namespace.h" #include "catalog/pg_type.h" #include "commands/dbcommands.h" @@ -38,7 +36,6 @@ #include "parser/parser.h" #include "utils/builtins.h" #include "utils/date.h" -#include "utils/fmgroids.h" #include "utils/lsyscache.h" #include "utils/rel.h" #include "utils/timestamp.h" @@ -80,21 +77,6 @@ static Node *transformWholeRowRef(ParseState *pstate, static Node *transformIndirection(ParseState *pstate, A_Indirection *ind); static Node *transformTypeCast(ParseState *pstate, TypeCast *tc); static Node *transformCollateClause(ParseState *pstate, CollateClause *c); -static Node *transformJsonObjectConstructor(ParseState *pstate, - JsonObjectConstructor *ctor); -static Node *transformJsonArrayConstructor(ParseState *pstate, - JsonArrayConstructor *ctor); -static Node *transformJsonArrayQueryConstructor(ParseState *pstate, - JsonArrayQueryConstructor *ctor); -static Node *transformJsonObjectAgg(ParseState *pstate, JsonObjectAgg *agg); -static Node *transformJsonArrayAgg(ParseState *pstate, JsonArrayAgg *agg); -static Node *transformJsonIsPredicate(ParseState *pstate, JsonIsPredicate *p); -static Node *transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *p); -static Node *transformJsonValueExpr(ParseState *pstate, JsonValueExpr *jve); -static Node *transformJsonParseExpr(ParseState *pstate, JsonParseExpr *expr); -static Node *transformJsonScalarExpr(ParseState *pstate, JsonScalarExpr *expr); -static Node *transformJsonSerializeExpr(ParseState *pstate, - JsonSerializeExpr *expr); static Node *make_row_comparison_op(ParseState *pstate, List *opname, List *largs, List *rargs, int location); static Node *make_row_distinct_op(ParseState *pstate, List *opname, @@ -323,50 +305,6 @@ transformExprRecurse(ParseState *pstate, Node *expr) break; } - case T_JsonObjectConstructor: - result = transformJsonObjectConstructor(pstate, (JsonObjectConstructor *) expr); - break; - - case T_JsonArrayConstructor: - result = transformJsonArrayConstructor(pstate, (JsonArrayConstructor *) expr); - break; - - case T_JsonArrayQueryConstructor: - result = transformJsonArrayQueryConstructor(pstate, (JsonArrayQueryConstructor *) expr); - break; - - case T_JsonObjectAgg: - result = transformJsonObjectAgg(pstate, (JsonObjectAgg *) expr); - break; - - case T_JsonArrayAgg: - result = transformJsonArrayAgg(pstate, (JsonArrayAgg *) expr); - break; - - case T_JsonIsPredicate: - result = transformJsonIsPredicate(pstate, (JsonIsPredicate *) expr); - break; - - case T_JsonFuncExpr: - result = transformJsonFuncExpr(pstate, (JsonFuncExpr *) expr); - break; - - case T_JsonValueExpr: - result = transformJsonValueExpr(pstate, (JsonValueExpr *) expr); - break; - - case T_JsonParseExpr: - result = transformJsonParseExpr(pstate, (JsonParseExpr *) expr); - break; - - case T_JsonScalarExpr: - result = transformJsonScalarExpr(pstate, (JsonScalarExpr *) expr); - break; - - case T_JsonSerializeExpr: - result = transformJsonSerializeExpr(pstate, (JsonSerializeExpr *) expr); - break; - default: /* should not reach here */ elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr)); @@ -3344,1450 +3282,9 @@ ParseExprKindName(ParseExprKind exprKind) return "unrecognized expression kind"; } -/* - * Make string Const node from JSON encoding name. - * - * UTF8 is default encoding. - */ -static Const * -getJsonEncodingConst(JsonFormat *format) -{ - JsonEncoding encoding; - const char *enc; - Name encname = palloc(sizeof(NameData)); - - if (!format || - format->format_type == JS_FORMAT_DEFAULT || - format->encoding == JS_ENC_DEFAULT) - encoding = JS_ENC_UTF8; - else - encoding = format->encoding; - - switch (encoding) - { - case JS_ENC_UTF16: - enc = "UTF16"; - break; - case JS_ENC_UTF32: - enc = "UTF32"; - break; - case JS_ENC_UTF8: - enc = "UTF8"; - break; - default: - elog(ERROR, "invalid JSON encoding: %d", encoding); - break; - } - - namestrcpy(encname, enc); - - return makeConst(NAMEOID, -1, InvalidOid, NAMEDATALEN, - NameGetDatum(encname), false, false); -} - -/* - * Make bytea => text conversion using specified JSON format encoding. - */ -static Node * -makeJsonByteaToTextConversion(Node *expr, JsonFormat *format, int location) -{ - Const *encoding = getJsonEncodingConst(format); - FuncExpr *fexpr = makeFuncExpr(F_CONVERT_FROM, TEXTOID, - list_make2(expr, encoding), - InvalidOid, InvalidOid, - COERCE_EXPLICIT_CALL); - - fexpr->location = location; - - return (Node *) fexpr; -} - -/* - * Make CaseTestExpr node. - */ -static Node * -makeCaseTestExpr(Node *expr) -{ - CaseTestExpr *placeholder = makeNode(CaseTestExpr); - - placeholder->typeId = exprType(expr); - placeholder->typeMod = exprTypmod(expr); - placeholder->collation = exprCollation(expr); - - return (Node *) placeholder; -} - -/* - * Transform JSON value expression using specified input JSON format or - * default format otherwise. - */ -static Node * -transformJsonValueExprExt(ParseState *pstate, JsonValueExpr *ve, - JsonFormatType default_format, bool isarg, - Oid targettype) -{ - Node *expr = transformExprRecurse(pstate, (Node *) ve->raw_expr); - Node *rawexpr; - JsonFormatType format; - Oid exprtype; - int location; - char typcategory; - bool typispreferred; - - if (exprType(expr) == UNKNOWNOID) - expr = coerce_to_specific_type(pstate, expr, TEXTOID, "JSON_VALUE_EXPR"); - - rawexpr = expr; - exprtype = exprType(expr); - location = exprLocation(expr); - - get_type_category_preferred(exprtype, &typcategory, &typispreferred); - - rawexpr = expr; - - if (ve->format->format_type != JS_FORMAT_DEFAULT) - { - if (ve->format->encoding != JS_ENC_DEFAULT && exprtype != BYTEAOID) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("JSON ENCODING clause is only allowed for bytea input type"), - parser_errposition(pstate, ve->format->location))); - - if (exprtype == JSONOID || exprtype == JSONBOID) - { - format = JS_FORMAT_DEFAULT; /* do not format json[b] types */ - ereport(WARNING, - (errmsg("FORMAT JSON has no effect for json and jsonb types"), - parser_errposition(pstate, ve->format->location))); - } - else - format = ve->format->format_type; - } - else if (isarg) - { - /* Pass SQL/JSON item types directly without conversion to json[b]. */ - switch (exprtype) - { - case TEXTOID: - case NUMERICOID: - case BOOLOID: - case INT2OID: - case INT4OID: - case INT8OID: - case FLOAT4OID: - case FLOAT8OID: - case DATEOID: - case TIMEOID: - case TIMETZOID: - case TIMESTAMPOID: - case TIMESTAMPTZOID: - return expr; - - default: - if (typcategory == TYPCATEGORY_STRING) - return coerce_to_specific_type(pstate, expr, TEXTOID, - "JSON_VALUE_EXPR"); - /* else convert argument to json[b] type */ - break; - } - - format = default_format; - } - else if (exprtype == JSONOID || exprtype == JSONBOID) - format = JS_FORMAT_DEFAULT; /* do not format json[b] types */ - else - format = default_format; - - if (format == JS_FORMAT_DEFAULT && - (!OidIsValid(targettype) || exprtype == targettype)) - expr = rawexpr; - else - { - Node *orig = makeCaseTestExpr(expr); - Node *coerced; - bool cast_is_needed = OidIsValid(targettype); - - if (!isarg && !cast_is_needed && - exprtype != BYTEAOID && typcategory != TYPCATEGORY_STRING) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg(ve->format->format_type == JS_FORMAT_DEFAULT ? - "cannot use non-string types with implicit FORMAT JSON clause" : - "cannot use non-string types with explicit FORMAT JSON clause"), - parser_errposition(pstate, ve->format->location >= 0 ? - ve->format->location : location))); - - expr = orig; - - /* Convert encoded JSON text from bytea. */ - if (format == JS_FORMAT_JSON && exprtype == BYTEAOID) - { - expr = makeJsonByteaToTextConversion(expr, ve->format, location); - exprtype = TEXTOID; - } - - if (!OidIsValid(targettype)) - targettype = format == JS_FORMAT_JSONB ? JSONBOID : JSONOID; - - /* Try to coerce to the target type. */ - coerced = coerce_to_target_type(pstate, expr, exprtype, - targettype, -1, - COERCION_EXPLICIT, - COERCE_EXPLICIT_CAST, - location); - - if (!coerced) - { - /* If coercion failed, use to_json()/to_jsonb() functions. */ - FuncExpr *fexpr; - Oid fnoid; - - if (cast_is_needed) /* only CAST is allowed */ - ereport(ERROR, - (errcode(ERRCODE_CANNOT_COERCE), - errmsg("cannot cast type %s to %s", - format_type_be(exprtype), - format_type_be(targettype)), - parser_errposition(pstate, location))); - - fnoid = targettype == JSONOID ? F_TO_JSON : F_TO_JSONB; - fexpr = makeFuncExpr(fnoid, targettype, list_make1(expr), - InvalidOid, InvalidOid, COERCE_EXPLICIT_CALL); - - fexpr->location = location; - - coerced = (Node *) fexpr; - } - - if (coerced == orig) - expr = rawexpr; - else - { - ve = copyObject(ve); - ve->raw_expr = (Expr *) rawexpr; - ve->formatted_expr = (Expr *) coerced; - - expr = (Node *) ve; - } - } - - return expr; -} - -/* - * Transform JSON value expression using FORMAT JSON by default. - */ -static Node * -transformJsonValueExpr(ParseState *pstate, JsonValueExpr *jve) -{ - return transformJsonValueExprExt(pstate, jve, JS_FORMAT_JSON, false, - InvalidOid); -} - -/* - * Transform JSON value expression using unspecified format by default. - */ -static Node * -transformJsonValueExprDefault(ParseState *pstate, JsonValueExpr *jve) -{ - return transformJsonValueExprExt(pstate, jve, JS_FORMAT_DEFAULT, false, - InvalidOid); -} - -/* - * Checks specified output format for its applicability to the target type. - */ -static void -checkJsonOutputFormat(ParseState *pstate, const JsonFormat *format, - Oid targettype, bool allow_format_for_non_strings) -{ - if (!allow_format_for_non_strings && - format->format_type != JS_FORMAT_DEFAULT && - (targettype != BYTEAOID && - targettype != JSONOID && - targettype != JSONBOID)) - { - char typcategory; - bool typispreferred; - - get_type_category_preferred(targettype, &typcategory, &typispreferred); - - if (typcategory != TYPCATEGORY_STRING) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - parser_errposition(pstate, format->location), - errmsg("cannot use JSON format with non-string output types"))); - } - - if (format->format_type == JS_FORMAT_JSON) - { - JsonEncoding enc = format->encoding != JS_ENC_DEFAULT ? - format->encoding : JS_ENC_UTF8; - - if (targettype != BYTEAOID && - format->encoding != JS_ENC_DEFAULT) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - parser_errposition(pstate, format->location), - errmsg("cannot set JSON encoding for non-bytea output types"))); - - if (enc != JS_ENC_UTF8) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("unsupported JSON encoding"), - errhint("Only UTF8 JSON encoding is supported."), - parser_errposition(pstate, format->location))); - } -} - -/* - * Transform JSON output clause. - * - * Assigns target type oid and modifier. - * Assigns default format or checks specified format for its applicability to - * the target type. - */ -static JsonReturning * -transformJsonOutput(ParseState *pstate, const JsonOutput *output, - bool allow_format) -{ - JsonReturning *ret; - - /* if output clause is not specified, make default clause value */ - if (!output) - { - ret = makeNode(JsonReturning); - - ret->format = makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1); - ret->typid = InvalidOid; - ret->typmod = -1; - - return ret; - } - - ret = copyObject(output->returning); - - typenameTypeIdAndMod(pstate, output->typeName, &ret->typid, &ret->typmod); - - if (output->typeName->setof) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("returning SETOF types is not supported in SQL/JSON functions"))); - - if (ret->format->format_type == JS_FORMAT_DEFAULT) - /* assign JSONB format when returning jsonb, or JSON format otherwise */ - ret->format->format_type = - ret->typid == JSONBOID ? JS_FORMAT_JSONB : JS_FORMAT_JSON; - else - checkJsonOutputFormat(pstate, ret->format, ret->typid, allow_format); - - return ret; -} - -/* - * Transform JSON output clause of JSON constructor functions. - * - * Derive RETURNING type, if not specified, from argument types. - */ -static JsonReturning * -transformJsonConstructorOutput(ParseState *pstate, JsonOutput *output, - List *args) -{ - JsonReturning *returning = transformJsonOutput(pstate, output, true); - - if (!OidIsValid(returning->typid)) - { - ListCell *lc; - bool have_jsonb = false; - - foreach(lc, args) - { - Node *expr = lfirst(lc); - Oid typid = exprType(expr); - - have_jsonb |= typid == JSONBOID; - - if (have_jsonb) - break; - } - - if (have_jsonb) - { - returning->typid = JSONBOID; - returning->format->format_type = JS_FORMAT_JSONB; - } - else - { - /* XXX TEXT is default by the standard, but we return JSON */ - returning->typid = JSONOID; - returning->format->format_type = JS_FORMAT_JSON; - } - - returning->typmod = -1; - } - - return returning; -} - -/* - * Coerce json[b]-valued function expression to the output type. - */ -static Node * -coerceJsonFuncExpr(ParseState *pstate, Node *expr, - const JsonReturning *returning, bool report_error) -{ - Node *res; - int location; - Oid exprtype = exprType(expr); - - /* if output type is not specified or equals to function type, return */ - if (!OidIsValid(returning->typid) || returning->typid == exprtype) - return expr; - - location = exprLocation(expr); - - if (location < 0) - location = returning->format->location; - - /* special case for RETURNING bytea FORMAT json */ - if (returning->format->format_type == JS_FORMAT_JSON && - returning->typid == BYTEAOID) - { - /* encode json text into bytea using pg_convert_to() */ - Node *texpr = coerce_to_specific_type(pstate, expr, TEXTOID, - "JSON_FUNCTION"); - Const *enc = getJsonEncodingConst(returning->format); - FuncExpr *fexpr = makeFuncExpr(F_CONVERT_TO, BYTEAOID, - list_make2(texpr, enc), - InvalidOid, InvalidOid, - COERCE_EXPLICIT_CALL); - - fexpr->location = location; - - return (Node *) fexpr; - } - - /* try to coerce expression to the output type */ - res = coerce_to_target_type(pstate, expr, exprtype, - returning->typid, returning->typmod, - /* XXX throwing errors when casting to char(N) */ - COERCION_EXPLICIT, - COERCE_EXPLICIT_CAST, - location); - - if (!res && report_error) - ereport(ERROR, - (errcode(ERRCODE_CANNOT_COERCE), - errmsg("cannot cast type %s to %s", - format_type_be(exprtype), - format_type_be(returning->typid)), - parser_coercion_errposition(pstate, location, expr))); - - return res; -} - -static Node * -makeJsonConstructorExpr(ParseState *pstate, JsonConstructorType type, - List *args, Expr *fexpr, JsonReturning *returning, - bool unique, bool absent_on_null, int location) -{ - JsonConstructorExpr *jsctor = makeNode(JsonConstructorExpr); - Node *placeholder; - Node *coercion; - Oid intermediate_typid = - returning->format->format_type == JS_FORMAT_JSONB ? JSONBOID : JSONOID; - - jsctor->args = args; - jsctor->func = fexpr; - jsctor->type = type; - jsctor->returning = returning; - jsctor->unique = unique; - jsctor->absent_on_null = absent_on_null; - jsctor->location = location; - - if (fexpr) - placeholder = makeCaseTestExpr((Node *) fexpr); - else - { - CaseTestExpr *cte = makeNode(CaseTestExpr); - - cte->typeId = intermediate_typid; - cte->typeMod = -1; - cte->collation = InvalidOid; - - placeholder = (Node *) cte; - } - - coercion = coerceJsonFuncExpr(pstate, placeholder, returning, true); - - if (coercion != placeholder) - jsctor->coercion = (Expr *) coercion; - - return (Node *) jsctor; -} - -/* - * Transform JSON_OBJECT() constructor. - * - * JSON_OBJECT() is transformed into json[b]_build_object[_ext]() call - * depending on the output JSON format. The first two arguments of - * json[b]_build_object_ext() are absent_on_null and check_key_uniqueness. - * - * Then function call result is coerced to the target type. - */ -static Node * -transformJsonObjectConstructor(ParseState *pstate, JsonObjectConstructor *ctor) -{ - JsonReturning *returning; - List *args = NIL; - - /* transform key-value pairs, if any */ - if (ctor->exprs) - { - ListCell *lc; - - /* transform and append key-value arguments */ - foreach(lc, ctor->exprs) - { - JsonKeyValue *kv = castNode(JsonKeyValue, lfirst(lc)); - Node *key = transformExprRecurse(pstate, (Node *) kv->key); - Node *val = transformJsonValueExprDefault(pstate, kv->value); - - args = lappend(args, key); - args = lappend(args, val); - } - } - - returning = transformJsonConstructorOutput(pstate, ctor->output, args); - - return makeJsonConstructorExpr(pstate, JSCTOR_JSON_OBJECT, args, NULL, - returning, ctor->unique, - ctor->absent_on_null, ctor->location); -} - -/* - * Transform JSON_ARRAY(query [FORMAT] [RETURNING] [ON NULL]) into - * (SELECT JSON_ARRAYAGG(a [FORMAT] [RETURNING] [ON NULL]) FROM (query) q(a)) - */ -static Node * -transformJsonArrayQueryConstructor(ParseState *pstate, - JsonArrayQueryConstructor *ctor) -{ - SubLink *sublink = makeNode(SubLink); - SelectStmt *select = makeNode(SelectStmt); - RangeSubselect *range = makeNode(RangeSubselect); - Alias *alias = makeNode(Alias); - ResTarget *target = makeNode(ResTarget); - JsonArrayAgg *agg = makeNode(JsonArrayAgg); - ColumnRef *colref = makeNode(ColumnRef); - Query *query; - ParseState *qpstate; - - /* Transform query only for counting target list entries. */ - qpstate = make_parsestate(pstate); - - query = transformStmt(qpstate, ctor->query); - - if (count_nonjunk_tlist_entries(query->targetList) != 1) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("subquery must return only one column"), - parser_errposition(pstate, ctor->location))); - - free_parsestate(qpstate); - - colref->fields = list_make2(makeString(pstrdup("q")), - makeString(pstrdup("a"))); - colref->location = ctor->location; - - agg->arg = makeJsonValueExpr((Expr *) colref, ctor->format); - agg->absent_on_null = ctor->absent_on_null; - agg->constructor = makeNode(JsonAggConstructor); - agg->constructor->agg_order = NIL; - agg->constructor->output = ctor->output; - agg->constructor->location = ctor->location; - - target->name = NULL; - target->indirection = NIL; - target->val = (Node *) agg; - target->location = ctor->location; - - alias->aliasname = pstrdup("q"); - alias->colnames = list_make1(makeString(pstrdup("a"))); - - range->lateral = false; - range->subquery = ctor->query; - range->alias = alias; - - select->targetList = list_make1(target); - select->fromClause = list_make1(range); - - sublink->subLinkType = EXPR_SUBLINK; - sublink->subLinkId = 0; - sublink->testexpr = NULL; - sublink->operName = NIL; - sublink->subselect = (Node *) select; - sublink->location = ctor->location; - - return transformExprRecurse(pstate, (Node *) sublink); -} - -/* - * Common code for JSON_OBJECTAGG and JSON_ARRAYAGG transformation. - */ -static Node * -transformJsonAggConstructor(ParseState *pstate, JsonAggConstructor *agg_ctor, - JsonReturning *returning, List *args, - const char *aggfn, Oid aggtype, - JsonConstructorType ctor_type, - bool unique, bool absent_on_null) -{ - Oid aggfnoid; - Node *node; - Expr *aggfilter = agg_ctor->agg_filter ? (Expr *) - transformWhereClause(pstate, agg_ctor->agg_filter, - EXPR_KIND_FILTER, "FILTER") : NULL; - - aggfnoid = DatumGetInt32(DirectFunctionCall1(regprocin, - CStringGetDatum(aggfn))); - - if (agg_ctor->over) - { - /* window function */ - WindowFunc *wfunc = makeNode(WindowFunc); - - wfunc->winfnoid = aggfnoid; - wfunc->wintype = aggtype; - /* wincollid and inputcollid will be set by parse_collate.c */ - wfunc->args = args; - /* winref will be set by transformWindowFuncCall */ - wfunc->winstar = false; - wfunc->winagg = true; - wfunc->aggfilter = aggfilter; - wfunc->location = agg_ctor->location; - - /* - * ordered aggs not allowed in windows yet - */ - if (agg_ctor->agg_order != NIL) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("aggregate ORDER BY is not implemented for window functions"), - parser_errposition(pstate, agg_ctor->location))); - - /* parse_agg.c does additional window-func-specific processing */ - transformWindowFuncCall(pstate, wfunc, agg_ctor->over); - - node = (Node *) wfunc; - } - else - { - Aggref *aggref = makeNode(Aggref); - - aggref->aggfnoid = aggfnoid; - aggref->aggtype = aggtype; - - /* aggcollid and inputcollid will be set by parse_collate.c */ - aggref->aggtranstype = InvalidOid; /* will be set by planner */ - /* aggargtypes will be set by transformAggregateCall */ - /* aggdirectargs and args will be set by transformAggregateCall */ - /* aggorder and aggdistinct will be set by transformAggregateCall */ - aggref->aggfilter = aggfilter; - aggref->aggstar = false; - aggref->aggvariadic = false; - aggref->aggkind = AGGKIND_NORMAL; - aggref->aggpresorted = false; - /* agglevelsup will be set by transformAggregateCall */ - aggref->aggsplit = AGGSPLIT_SIMPLE; /* planner might change this */ - aggref->location = agg_ctor->location; - - transformAggregateCall(pstate, aggref, args, agg_ctor->agg_order, false); - - node = (Node *) aggref; - } - - return makeJsonConstructorExpr(pstate, ctor_type, NIL, (Expr *) node, - returning, unique, absent_on_null, - agg_ctor->location); -} - -/* - * Transform JSON_OBJECTAGG() aggregate function. - * - * JSON_OBJECTAGG() is transformed into - * json[b]_objectagg(key, value, absent_on_null, check_unique) call depending on - * the output JSON format. Then the function call result is coerced to the - * target output type. - */ -static Node * -transformJsonObjectAgg(ParseState *pstate, JsonObjectAgg *agg) -{ - JsonReturning *returning; - Node *key; - Node *val; - List *args; - const char *aggfnname; - Oid aggtype; - - key = transformExprRecurse(pstate, (Node *) agg->arg->key); - val = transformJsonValueExprDefault(pstate, agg->arg->value); - args = list_make2(key, val); - - returning = transformJsonConstructorOutput(pstate, agg->constructor->output, - args); - - if (returning->format->format_type == JS_FORMAT_JSONB) - { - if (agg->absent_on_null) - if (agg->unique) - aggfnname = "pg_catalog.jsonb_object_agg_unique_strict"; /* F_JSONB_OBJECT_AGG_UNIQUE_STRICT */ - else - aggfnname = "pg_catalog.jsonb_object_agg_strict"; /* F_JSONB_OBJECT_AGG_STRICT */ - else if (agg->unique) - aggfnname = "pg_catalog.jsonb_object_agg_unique"; /* F_JSONB_OBJECT_AGG_UNIQUE */ - else - aggfnname = "pg_catalog.jsonb_object_agg"; /* F_JSONB_OBJECT_AGG */ - - aggtype = JSONBOID; - } - else - { - if (agg->absent_on_null) - if (agg->unique) - aggfnname = "pg_catalog.json_object_agg_unique_strict"; /* F_JSON_OBJECT_AGG_UNIQUE_STRICT */ - else - aggfnname = "pg_catalog.json_object_agg_strict"; /* F_JSON_OBJECT_AGG_STRICT */ - else if (agg->unique) - aggfnname = "pg_catalog.json_object_agg_unique"; /* F_JSON_OBJECT_AGG_UNIQUE */ - else - aggfnname = "pg_catalog.json_object_agg"; /* F_JSON_OBJECT_AGG */ - - aggtype = JSONOID; - } - - return transformJsonAggConstructor(pstate, agg->constructor, returning, - args, aggfnname, aggtype, - JSCTOR_JSON_OBJECTAGG, - agg->unique, agg->absent_on_null); -} - -/* - * Transform JSON_ARRAYAGG() aggregate function. - * - * JSON_ARRAYAGG() is transformed into json[b]_agg[_strict]() call depending - * on the output JSON format and absent_on_null. Then the function call result - * is coerced to the target output type. - */ -static Node * -transformJsonArrayAgg(ParseState *pstate, JsonArrayAgg *agg) -{ - JsonReturning *returning; - Node *arg; - const char *aggfnname; - Oid aggtype; - - arg = transformJsonValueExprDefault(pstate, agg->arg); - - returning = transformJsonConstructorOutput(pstate, agg->constructor->output, - list_make1(arg)); - - if (returning->format->format_type == JS_FORMAT_JSONB) - { - aggfnname = agg->absent_on_null ? - "pg_catalog.jsonb_agg_strict" : "pg_catalog.jsonb_agg"; - aggtype = JSONBOID; - } - else - { - aggfnname = agg->absent_on_null ? - "pg_catalog.json_agg_strict" : "pg_catalog.json_agg"; - aggtype = JSONOID; - } - - return transformJsonAggConstructor(pstate, agg->constructor, returning, - list_make1(arg), aggfnname, aggtype, - JSCTOR_JSON_ARRAYAGG, - false, agg->absent_on_null); -} - -/* - * Transform JSON_ARRAY() constructor. - * - * JSON_ARRAY() is transformed into json[b]_build_array[_ext]() call - * depending on the output JSON format. The first argument of - * json[b]_build_array_ext() is absent_on_null. - * - * Then function call result is coerced to the target type. - */ -static Node * -transformJsonArrayConstructor(ParseState *pstate, JsonArrayConstructor *ctor) -{ - JsonReturning *returning; - List *args = NIL; - - /* transform element expressions, if any */ - if (ctor->exprs) - { - ListCell *lc; - - /* transform and append element arguments */ - foreach(lc, ctor->exprs) - { - JsonValueExpr *jsval = castNode(JsonValueExpr, lfirst(lc)); - Node *val = transformJsonValueExprDefault(pstate, jsval); - - args = lappend(args, val); - } - } - - returning = transformJsonConstructorOutput(pstate, ctor->output, args); - - return makeJsonConstructorExpr(pstate, JSCTOR_JSON_ARRAY, args, NULL, - returning, false, ctor->absent_on_null, - ctor->location); -} - -static Node * -transformJsonParseArg(ParseState *pstate, Node *jsexpr, JsonFormat *format, - Oid *exprtype) -{ - Node *raw_expr = transformExprRecurse(pstate, jsexpr); - Node *expr = raw_expr; - - *exprtype = exprType(expr); - - /* prepare input document */ - if (*exprtype == BYTEAOID) - { - JsonValueExpr *jve; - - expr = makeCaseTestExpr(raw_expr); - expr = makeJsonByteaToTextConversion(expr, format, exprLocation(expr)); - *exprtype = TEXTOID; - - jve = makeJsonValueExpr((Expr *) raw_expr, format); - - jve->formatted_expr = (Expr *) expr; - expr = (Node *) jve; - } - else - { - char typcategory; - bool typispreferred; - - get_type_category_preferred(*exprtype, &typcategory, &typispreferred); - - if (*exprtype == UNKNOWNOID || typcategory == TYPCATEGORY_STRING) - { - expr = coerce_to_target_type(pstate, (Node *) expr, *exprtype, - TEXTOID, -1, - COERCION_IMPLICIT, - COERCE_IMPLICIT_CAST, -1); - *exprtype = TEXTOID; - } - - if (format->encoding != JS_ENC_DEFAULT) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - parser_errposition(pstate, format->location), - errmsg("cannot use JSON FORMAT ENCODING clause for non-bytea input types"))); - } - - return expr; -} - -/* - * Transform IS JSON predicate. - */ -static Node * -transformJsonIsPredicate(ParseState *pstate, JsonIsPredicate *pred) -{ - Oid exprtype; - Node *expr = transformJsonParseArg(pstate, pred->expr, pred->format, - &exprtype); - - /* make resulting expression */ - if (exprtype != TEXTOID && exprtype != JSONOID && exprtype != JSONBOID) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("cannot use type %s in IS JSON predicate", - format_type_be(exprtype)))); - - /* This intentionally(?) drops the format clause. */ - return makeJsonIsPredicate(expr, NULL, pred->item_type, - pred->unique_keys, pred->location); -} - -/* - * Transform a JSON PASSING clause. - */ -static void -transformJsonPassingArgs(ParseState *pstate, JsonFormatType format, List *args, - List **passing_values, List **passing_names) -{ - ListCell *lc; - - *passing_values = NIL; - *passing_names = NIL; - - foreach(lc, args) - { - JsonArgument *arg = castNode(JsonArgument, lfirst(lc)); - Node *expr = transformJsonValueExprExt(pstate, arg->val, - format, true, InvalidOid); - - assign_expr_collations(pstate, expr); - - *passing_values = lappend(*passing_values, expr); - *passing_names = lappend(*passing_names, makeString(arg->name)); - } -} - -/* - * Transform a JSON BEHAVIOR clause. - */ -static JsonBehavior * -transformJsonBehavior(ParseState *pstate, JsonBehavior *behavior, - JsonBehaviorType default_behavior) -{ - JsonBehaviorType behavior_type = default_behavior; - Node *default_expr = NULL; - - if (behavior) - { - behavior_type = behavior->btype; - if (behavior_type == JSON_BEHAVIOR_DEFAULT) - default_expr = transformExprRecurse(pstate, behavior->default_expr); - } - return makeJsonBehavior(behavior_type, default_expr); -} - -/* - * Common code for JSON_VALUE, JSON_QUERY, JSON_EXISTS transformation - * into a JsonExpr node. - */ -static JsonExpr * -transformJsonExprCommon(ParseState *pstate, JsonFuncExpr *func) -{ - JsonExpr *jsexpr = makeNode(JsonExpr); - Node *pathspec; - JsonFormatType format; - - if (func->common->pathname && func->op != JSON_TABLE_OP) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("JSON_TABLE path name is not allowed here"), - parser_errposition(pstate, func->location))); - - jsexpr->location = func->location; - jsexpr->op = func->op; - jsexpr->formatted_expr = transformJsonValueExpr(pstate, func->common->expr); - - assign_expr_collations(pstate, jsexpr->formatted_expr); - - /* format is determined by context item type */ - format = exprType(jsexpr->formatted_expr) == JSONBOID ? JS_FORMAT_JSONB : JS_FORMAT_JSON; - - jsexpr->result_coercion = NULL; - jsexpr->omit_quotes = false; - - jsexpr->format = func->common->expr->format; - - pathspec = transformExprRecurse(pstate, func->common->pathspec); - - jsexpr->path_spec = - coerce_to_target_type(pstate, pathspec, exprType(pathspec), - JSONPATHOID, -1, - COERCION_EXPLICIT, COERCE_IMPLICIT_CAST, - exprLocation(pathspec)); - if (!jsexpr->path_spec) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("JSON path expression must be type %s, not type %s", - "jsonpath", format_type_be(exprType(pathspec))), - parser_errposition(pstate, exprLocation(pathspec)))); - - /* transform and coerce to json[b] passing arguments */ - transformJsonPassingArgs(pstate, format, func->common->passing, - &jsexpr->passing_values, &jsexpr->passing_names); - - if (func->op != JSON_EXISTS_OP && func->op != JSON_TABLE_OP) - jsexpr->on_empty = transformJsonBehavior(pstate, func->on_empty, - JSON_BEHAVIOR_NULL); - - if (func->op == JSON_EXISTS_OP) - jsexpr->on_error = transformJsonBehavior(pstate, func->on_error, - JSON_BEHAVIOR_FALSE); - else if (func->op == JSON_TABLE_OP) - jsexpr->on_error = transformJsonBehavior(pstate, func->on_error, - JSON_BEHAVIOR_EMPTY); - else - jsexpr->on_error = transformJsonBehavior(pstate, func->on_error, - JSON_BEHAVIOR_NULL); - - return jsexpr; -} - -/* - * Assign default JSON returning type from the specified format or from - * the context item type. - */ -static void -assignDefaultJsonReturningType(Node *context_item, JsonFormat *context_format, - JsonReturning *ret) -{ - bool is_jsonb; - - ret->format = copyObject(context_format); - - if (ret->format->format_type == JS_FORMAT_DEFAULT) - is_jsonb = exprType(context_item) == JSONBOID; - else - is_jsonb = ret->format->format_type == JS_FORMAT_JSONB; - - ret->typid = is_jsonb ? JSONBOID : JSONOID; - ret->typmod = -1; -} - -/* - * Try to coerce expression to the output type or - * use json_populate_type() for composite, array and domain types or - * use coercion via I/O. - */ -static JsonCoercion * -coerceJsonExpr(ParseState *pstate, Node *expr, const JsonReturning *returning) -{ - char typtype; - JsonCoercion *coercion = makeNode(JsonCoercion); - - coercion->expr = coerceJsonFuncExpr(pstate, expr, returning, false); - - if (coercion->expr) - { - if (coercion->expr == expr) - coercion->expr = NULL; - - return coercion; - } - - typtype = get_typtype(returning->typid); - - if (returning->typid == RECORDOID || - typtype == TYPTYPE_COMPOSITE || - typtype == TYPTYPE_DOMAIN || - type_is_array(returning->typid)) - coercion->via_populate = true; - else - coercion->via_io = true; - - return coercion; -} - -/* - * Transform a JSON output clause of JSON_VALUE and JSON_QUERY. - */ -static void -transformJsonFuncExprOutput(ParseState *pstate, JsonFuncExpr *func, - JsonExpr *jsexpr) -{ - Node *expr = jsexpr->formatted_expr; - - jsexpr->returning = transformJsonOutput(pstate, func->output, false); - - /* JSON_VALUE returns text by default */ - if (func->op == JSON_VALUE_OP && !OidIsValid(jsexpr->returning->typid)) - { - jsexpr->returning->typid = TEXTOID; - jsexpr->returning->typmod = -1; - } - - if (OidIsValid(jsexpr->returning->typid)) - { - JsonReturning ret; - - if (func->op == JSON_VALUE_OP && - jsexpr->returning->typid != JSONOID && - jsexpr->returning->typid != JSONBOID) - { - /* Forced coercion via I/O for JSON_VALUE for non-JSON types */ - jsexpr->result_coercion = makeNode(JsonCoercion); - jsexpr->result_coercion->expr = NULL; - jsexpr->result_coercion->via_io = true; - return; - } - - assignDefaultJsonReturningType(jsexpr->formatted_expr, jsexpr->format, &ret); - - if (ret.typid != jsexpr->returning->typid || - ret.typmod != jsexpr->returning->typmod) - { - Node *placeholder = makeCaseTestExpr(expr); - - Assert(((CaseTestExpr *) placeholder)->typeId == ret.typid); - Assert(((CaseTestExpr *) placeholder)->typeMod == ret.typmod); - - jsexpr->result_coercion = coerceJsonExpr(pstate, placeholder, - jsexpr->returning); - } - } - else - assignDefaultJsonReturningType(jsexpr->formatted_expr, jsexpr->format, - jsexpr->returning); -} - -/* - * Coerce an expression in JSON DEFAULT behavior to the target output type. - */ -static Node * -coerceDefaultJsonExpr(ParseState *pstate, JsonExpr *jsexpr, Node *defexpr) -{ - int location; - Oid exprtype; - - if (!defexpr) - return NULL; - - exprtype = exprType(defexpr); - location = exprLocation(defexpr); - - if (location < 0) - location = jsexpr->location; - - defexpr = coerce_to_target_type(pstate, - defexpr, - exprtype, - jsexpr->returning->typid, - jsexpr->returning->typmod, - COERCION_EXPLICIT, - COERCE_IMPLICIT_CAST, - location); - - if (!defexpr) - ereport(ERROR, - (errcode(ERRCODE_CANNOT_COERCE), - errmsg("cannot cast DEFAULT expression type %s to %s", - format_type_be(exprtype), - format_type_be(jsexpr->returning->typid)), - parser_errposition(pstate, location))); - - return defexpr; -} - -/* - * Initialize SQL/JSON item coercion from the SQL type "typid" to the target - * "returning" type. - */ -static JsonCoercion * -initJsonItemCoercion(ParseState *pstate, Oid typid, - const JsonReturning *returning) -{ - Node *expr; - - if (typid == UNKNOWNOID) - { - expr = (Node *) makeNullConst(UNKNOWNOID, -1, InvalidOid); - } - else - { - CaseTestExpr *placeholder = makeNode(CaseTestExpr); - - placeholder->typeId = typid; - placeholder->typeMod = -1; - placeholder->collation = InvalidOid; - - expr = (Node *) placeholder; - } - - return coerceJsonExpr(pstate, expr, returning); -} - -static void -initJsonItemCoercions(ParseState *pstate, JsonItemCoercions *coercions, - const JsonReturning *returning, Oid contextItemTypeId) -{ - struct - { - JsonCoercion **coercion; - Oid typid; - } *p, - coercionTypids[] = - { - {&coercions->null, UNKNOWNOID}, - {&coercions->string, TEXTOID}, - {&coercions->numeric, NUMERICOID}, - {&coercions->boolean, BOOLOID}, - {&coercions->date, DATEOID}, - {&coercions->time, TIMEOID}, - {&coercions->timetz, TIMETZOID}, - {&coercions->timestamp, TIMESTAMPOID}, - {&coercions->timestamptz, TIMESTAMPTZOID}, - {&coercions->composite, contextItemTypeId}, - {NULL, InvalidOid} - }; - - for (p = coercionTypids; p->coercion; p++) - *p->coercion = initJsonItemCoercion(pstate, p->typid, returning); -} - -/* - * Transform JSON_VALUE, JSON_QUERY, JSON_EXISTS functions into a JsonExpr node. - */ -static Node * -transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func) -{ - JsonExpr *jsexpr = transformJsonExprCommon(pstate, func); - const char *func_name = NULL; - Node *contextItemExpr = jsexpr->formatted_expr; - - switch (func->op) - { - case JSON_VALUE_OP: - func_name = "JSON_VALUE"; - - transformJsonFuncExprOutput(pstate, func, jsexpr); - - jsexpr->returning->format->format_type = JS_FORMAT_DEFAULT; - jsexpr->returning->format->encoding = JS_ENC_DEFAULT; - - jsexpr->on_empty->default_expr = - coerceDefaultJsonExpr(pstate, jsexpr, - jsexpr->on_empty->default_expr); - - jsexpr->on_error->default_expr = - coerceDefaultJsonExpr(pstate, jsexpr, - jsexpr->on_error->default_expr); - - jsexpr->coercions = makeNode(JsonItemCoercions); - initJsonItemCoercions(pstate, jsexpr->coercions, jsexpr->returning, - exprType(contextItemExpr)); - - break; - - case JSON_QUERY_OP: - func_name = "JSON_QUERY"; - - transformJsonFuncExprOutput(pstate, func, jsexpr); - - jsexpr->on_empty->default_expr = - coerceDefaultJsonExpr(pstate, jsexpr, - jsexpr->on_empty->default_expr); - - jsexpr->on_error->default_expr = - coerceDefaultJsonExpr(pstate, jsexpr, - jsexpr->on_error->default_expr); - - jsexpr->wrapper = func->wrapper; - jsexpr->omit_quotes = func->omit_quotes; - - break; - - case JSON_EXISTS_OP: - func_name = "JSON_EXISTS"; - - jsexpr->returning = transformJsonOutput(pstate, func->output, false); - - jsexpr->returning->format->format_type = JS_FORMAT_DEFAULT; - jsexpr->returning->format->encoding = JS_ENC_DEFAULT; - - if (!OidIsValid(jsexpr->returning->typid)) - { - jsexpr->returning->typid = BOOLOID; - jsexpr->returning->typmod = -1; - } - else if (jsexpr->returning->typid != BOOLOID) - { - CaseTestExpr *placeholder = makeNode(CaseTestExpr); - int location = exprLocation((Node *) jsexpr); - - placeholder->typeId = BOOLOID; - placeholder->typeMod = -1; - placeholder->collation = InvalidOid; - - jsexpr->result_coercion = makeNode(JsonCoercion); - jsexpr->result_coercion->expr = - coerce_to_target_type(pstate, (Node *) placeholder, BOOLOID, - jsexpr->returning->typid, - jsexpr->returning->typmod, - COERCION_EXPLICIT, - COERCE_IMPLICIT_CAST, - location); - - if (!jsexpr->result_coercion->expr) - ereport(ERROR, - (errcode(ERRCODE_CANNOT_COERCE), - errmsg("cannot cast type %s to %s", - format_type_be(BOOLOID), - format_type_be(jsexpr->returning->typid)), - parser_coercion_errposition(pstate, location, (Node *) jsexpr))); - - if (jsexpr->result_coercion->expr == (Node *) placeholder) - jsexpr->result_coercion->expr = NULL; - } - break; - - case JSON_TABLE_OP: - jsexpr->returning = makeNode(JsonReturning); - jsexpr->returning->format = makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1); - jsexpr->returning->typid = exprType(contextItemExpr); - jsexpr->returning->typmod = -1; - - if (jsexpr->returning->typid != JSONBOID) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("JSON_TABLE() is not yet implemented for the json type"), - errhint("Try casting the argument to jsonb"), - parser_errposition(pstate, func->location))); - - break; - } - - if (exprType(contextItemExpr) != JSONBOID) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("%s() is not yet implemented for the json type", func_name), - errhint("Try casting the argument to jsonb"), - parser_errposition(pstate, func->location))); - - return (Node *) jsexpr; -} - -static JsonReturning * -transformJsonConstructorRet(ParseState *pstate, JsonOutput *output, const char *fname) -{ - JsonReturning *returning; - - if (output) - { - returning = transformJsonOutput(pstate, output, false); - - Assert(OidIsValid(returning->typid)); - - if (returning->typid != JSONOID && returning->typid != JSONBOID) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("cannot use RETURNING type %s in %s", - format_type_be(returning->typid), fname), - parser_errposition(pstate, output->typeName->location))); - } - else - { - Oid targettype = JSONOID; - JsonFormatType format = JS_FORMAT_JSON; - - returning = makeNode(JsonReturning); - returning->format = makeJsonFormat(format, JS_ENC_DEFAULT, -1); - returning->typid = targettype; - returning->typmod = -1; - } - - return returning; -} - -/* - * Transform a JSON() expression. - */ -static Node * -transformJsonParseExpr(ParseState *pstate, JsonParseExpr *jsexpr) -{ - JsonReturning *returning = transformJsonConstructorRet(pstate, jsexpr->output, - "JSON()"); - Node *arg; - - if (jsexpr->unique_keys) - { - /* - * Coerce string argument to text and then to json[b] in the executor - * node with key uniqueness check. - */ - JsonValueExpr *jve = jsexpr->expr; - Oid arg_type; - - arg = transformJsonParseArg(pstate, (Node *) jve->raw_expr, jve->format, - &arg_type); - - if (arg_type != TEXTOID) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("cannot use non-string types with WITH UNIQUE KEYS clause"), - parser_errposition(pstate, jsexpr->location))); - } - else - { - /* - * Coerce argument to target type using CAST for compatibility with PG - * function-like CASTs. - */ - arg = transformJsonValueExprExt(pstate, jsexpr->expr, JS_FORMAT_JSON, - false, returning->typid); - } - - return makeJsonConstructorExpr(pstate, JSCTOR_JSON_PARSE, list_make1(arg), NULL, - returning, jsexpr->unique_keys, false, - jsexpr->location); -} - -/* - * Transform a JSON_SCALAR() expression. - */ -static Node * -transformJsonScalarExpr(ParseState *pstate, JsonScalarExpr *jsexpr) -{ - Node *arg = transformExprRecurse(pstate, (Node *) jsexpr->expr); - JsonReturning *returning = transformJsonConstructorRet(pstate, jsexpr->output, - "JSON_SCALAR()"); - - if (exprType(arg) == UNKNOWNOID) - arg = coerce_to_specific_type(pstate, arg, TEXTOID, "JSON_SCALAR"); - - return makeJsonConstructorExpr(pstate, JSCTOR_JSON_SCALAR, list_make1(arg), NULL, - returning, false, false, jsexpr->location); -} - -/* - * Transform a JSON_SERIALIZE() expression. - */ -static Node * -transformJsonSerializeExpr(ParseState *pstate, JsonSerializeExpr *expr) -{ - Node *arg = transformJsonValueExpr(pstate, expr->expr); - JsonReturning *returning; - - if (expr->output) - { - returning = transformJsonOutput(pstate, expr->output, true); - - if (returning->typid != BYTEAOID) - { - char typcategory; - bool typispreferred; - - get_type_category_preferred(returning->typid, &typcategory, - &typispreferred); - if (typcategory != TYPCATEGORY_STRING) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("cannot use RETURNING type %s in %s", - format_type_be(returning->typid), - "JSON_SERIALIZE()"), - errhint("Try returning a string type or bytea."))); - } - } - else - { - /* RETURNING TEXT FORMAT JSON is by default */ - returning = makeNode(JsonReturning); - returning->format = makeJsonFormat(JS_FORMAT_JSON, JS_ENC_DEFAULT, -1); - returning->typid = TEXTOID; - returning->typmod = -1; - } - - return makeJsonConstructorExpr(pstate, JSCTOR_JSON_SERIALIZE, list_make1(arg), - NULL, returning, false, false, expr->location); -} - -// Expands checksum(*) to checksum(c1, c2, ...) -List * -ExpandChecksumStar(ParseState *pstate, FuncCall *fn, int location) +// Expands checksum(*) to checksum(c1, c2, ...) +List * +ExpandChecksumStar(ParseState *pstate, FuncCall *fn, int location) { List *target = NIL; ListCell *lc; @@ -4798,4 +3295,4 @@ ExpandChecksumStar(ParseState *pstate, FuncCall *fn, int location) } fn->agg_star = false; return target; -} +} \ No newline at end of file diff --git a/src/backend/parser/parse_jsontable.c b/src/backend/parser/parse_jsontable.c deleted file mode 100644 index 3e94071248e..00000000000 --- a/src/backend/parser/parse_jsontable.c +++ /dev/null @@ -1,732 +0,0 @@ -/*------------------------------------------------------------------------- - * - * parse_jsontable.c - * parsing of JSON_TABLE - * - * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * src/backend/parser/parse_jsontable.c - * - *------------------------------------------------------------------------- - */ - -#include "postgres.h" - -#include "catalog/pg_collation.h" -#include "catalog/pg_type.h" -#include "miscadmin.h" -#include "nodes/makefuncs.h" -#include "nodes/nodeFuncs.h" -#include "optimizer/optimizer.h" -#include "parser/parse_clause.h" -#include "parser/parse_collate.h" -#include "parser/parse_expr.h" -#include "parser/parse_relation.h" -#include "parser/parse_type.h" -#include "utils/builtins.h" -#include "utils/json.h" -#include "utils/lsyscache.h" - -/* Context for JSON_TABLE transformation */ -typedef struct JsonTableContext -{ - ParseState *pstate; /* parsing state */ - JsonTable *table; /* untransformed node */ - TableFunc *tablefunc; /* transformed node */ - List *pathNames; /* list of all path and columns names */ - int pathNameId; /* path name id counter */ - Oid contextItemTypid; /* type oid of context item (json/jsonb) */ -} JsonTableContext; - -static JsonTableParent *transformJsonTableColumns(JsonTableContext *cxt, - JsonTablePlan *plan, - List *columns, - char *pathSpec, - char **pathName, - int location); - -static Node * -makeStringConst(char *str, int location) -{ - A_Const *n = makeNode(A_Const); - - n->val.node.type = T_String; - n->val.sval.sval = str; - n->location = location; - - return (Node *) n; -} - -/* - * Transform JSON_TABLE column - * - regular column into JSON_VALUE() - * - FORMAT JSON column into JSON_QUERY() - * - EXISTS column into JSON_EXISTS() - */ -static Node * -transformJsonTableColumn(JsonTableColumn *jtc, Node *contextItemExpr, - List *passingArgs, bool errorOnError) -{ - JsonFuncExpr *jfexpr = makeNode(JsonFuncExpr); - JsonCommon *common = makeNode(JsonCommon); - JsonOutput *output = makeNode(JsonOutput); - char *pathspec; - JsonFormat *default_format; - - jfexpr->op = - jtc->coltype == JTC_REGULAR ? JSON_VALUE_OP : - jtc->coltype == JTC_EXISTS ? JSON_EXISTS_OP : JSON_QUERY_OP; - jfexpr->common = common; - jfexpr->output = output; - jfexpr->on_empty = jtc->on_empty; - jfexpr->on_error = jtc->on_error; - if (!jfexpr->on_error && errorOnError) - jfexpr->on_error = makeJsonBehavior(JSON_BEHAVIOR_ERROR, NULL); - jfexpr->omit_quotes = jtc->omit_quotes; - jfexpr->wrapper = jtc->wrapper; - jfexpr->location = jtc->location; - - output->typeName = jtc->typeName; - output->returning = makeNode(JsonReturning); - output->returning->format = jtc->format; - - default_format = makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1); - - common->pathname = NULL; - common->expr = makeJsonValueExpr((Expr *) contextItemExpr, default_format); - common->passing = passingArgs; - - if (jtc->pathspec) - pathspec = jtc->pathspec; - else - { - /* Construct default path as '$."column_name"' */ - StringInfoData path; - - initStringInfo(&path); - - appendStringInfoString(&path, "$."); - escape_json(&path, jtc->name); - - pathspec = path.data; - } - - common->pathspec = makeStringConst(pathspec, -1); - - return (Node *) jfexpr; -} - -static bool -isJsonTablePathNameDuplicate(JsonTableContext *cxt, const char *pathname) -{ - ListCell *lc; - - foreach(lc, cxt->pathNames) - { - if (!strcmp(pathname, (const char *) lfirst(lc))) - return true; - } - - return false; -} - -/* Register the column name in the path name list. */ -static void -registerJsonTableColumn(JsonTableContext *cxt, char *colname) -{ - if (isJsonTablePathNameDuplicate(cxt, colname)) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_ALIAS), - errmsg("duplicate JSON_TABLE column name: %s", colname), - errhint("JSON_TABLE column names must be distinct from one another."))); - - cxt->pathNames = lappend(cxt->pathNames, colname); -} - -/* Recursively register all nested column names in the path name list. */ -static void -registerAllJsonTableColumns(JsonTableContext *cxt, List *columns) -{ - ListCell *lc; - - foreach(lc, columns) - { - JsonTableColumn *jtc = castNode(JsonTableColumn, lfirst(lc)); - - if (jtc->coltype == JTC_NESTED) - { - if (jtc->pathname) - registerJsonTableColumn(cxt, jtc->pathname); - - registerAllJsonTableColumns(cxt, jtc->columns); - } - else - { - registerJsonTableColumn(cxt, jtc->name); - } - } -} - -/* Generate a new unique JSON_TABLE path name. */ -static char * -generateJsonTablePathName(JsonTableContext *cxt) -{ - char namebuf[32]; - char *name = namebuf; - - do - { - snprintf(namebuf, sizeof(namebuf), "json_table_path_%d", - ++cxt->pathNameId); - } while (isJsonTablePathNameDuplicate(cxt, name)); - - name = pstrdup(name); - cxt->pathNames = lappend(cxt->pathNames, name); - - return name; -} - -/* Collect sibling path names from plan to the specified list. */ -static void -collectSiblingPathsInJsonTablePlan(JsonTablePlan *plan, List **paths) -{ - if (plan->plan_type == JSTP_SIMPLE) - *paths = lappend(*paths, plan->pathname); - else if (plan->plan_type == JSTP_JOINED) - { - if (plan->join_type == JSTPJ_INNER || - plan->join_type == JSTPJ_OUTER) - { - Assert(plan->plan1->plan_type == JSTP_SIMPLE); - *paths = lappend(*paths, plan->plan1->pathname); - } - else if (plan->join_type == JSTPJ_CROSS || - plan->join_type == JSTPJ_UNION) - { - collectSiblingPathsInJsonTablePlan(plan->plan1, paths); - collectSiblingPathsInJsonTablePlan(plan->plan2, paths); - } - else - elog(ERROR, "invalid JSON_TABLE join type %d", - plan->join_type); - } -} - -/* - * Validate child JSON_TABLE plan by checking that: - * - all nested columns have path names specified - * - all nested columns have corresponding node in the sibling plan - * - plan does not contain duplicate or extra nodes - */ -static void -validateJsonTableChildPlan(ParseState *pstate, JsonTablePlan *plan, - List *columns) -{ - ListCell *lc1; - List *siblings = NIL; - int nchildren = 0; - - if (plan) - collectSiblingPathsInJsonTablePlan(plan, &siblings); - - foreach(lc1, columns) - { - JsonTableColumn *jtc = castNode(JsonTableColumn, lfirst(lc1)); - - if (jtc->coltype == JTC_NESTED) - { - ListCell *lc2; - bool found = false; - - if (!jtc->pathname) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("nested JSON_TABLE columns must contain an explicit AS pathname specification if an explicit PLAN clause is used"), - parser_errposition(pstate, jtc->location))); - - /* find nested path name in the list of sibling path names */ - foreach(lc2, siblings) - { - if ((found = !strcmp(jtc->pathname, lfirst(lc2)))) - break; - } - - if (!found) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("invalid JSON_TABLE plan"), - errdetail("Plan node for nested path %s was not found in plan.", jtc->pathname), - parser_errposition(pstate, jtc->location))); - - nchildren++; - } - } - - if (list_length(siblings) > nchildren) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("invalid JSON_TABLE plan"), - errdetail("Plan node contains some extra or duplicate sibling nodes."), - parser_errposition(pstate, plan ? plan->location : -1))); -} - -static JsonTableColumn * -findNestedJsonTableColumn(List *columns, const char *pathname) -{ - ListCell *lc; - - foreach(lc, columns) - { - JsonTableColumn *jtc = castNode(JsonTableColumn, lfirst(lc)); - - if (jtc->coltype == JTC_NESTED && - jtc->pathname && - !strcmp(jtc->pathname, pathname)) - return jtc; - } - - return NULL; -} - -static Node * -transformNestedJsonTableColumn(JsonTableContext *cxt, JsonTableColumn *jtc, - JsonTablePlan *plan) -{ - JsonTableParent *node; - char *pathname = jtc->pathname; - - node = transformJsonTableColumns(cxt, plan, jtc->columns, jtc->pathspec, - &pathname, jtc->location); - node->name = pstrdup(pathname); - - return (Node *) node; -} - -static Node * -makeJsonTableSiblingJoin(bool cross, Node *lnode, Node *rnode) -{ - JsonTableSibling *join = makeNode(JsonTableSibling); - - join->larg = lnode; - join->rarg = rnode; - join->cross = cross; - - return (Node *) join; -} - -/* - * Recursively transform child JSON_TABLE plan. - * - * Default plan is transformed into a cross/union join of its nested columns. - * Simple and outer/inner plans are transformed into a JsonTableParent by - * finding and transforming corresponding nested column. - * Sibling plans are recursively transformed into a JsonTableSibling. - */ -static Node * -transformJsonTableChildPlan(JsonTableContext *cxt, JsonTablePlan *plan, - List *columns) -{ - JsonTableColumn *jtc = NULL; - - if (!plan || plan->plan_type == JSTP_DEFAULT) - { - /* unspecified or default plan */ - Node *res = NULL; - ListCell *lc; - bool cross = plan && (plan->join_type & JSTPJ_CROSS); - - /* transform all nested columns into cross/union join */ - foreach(lc, columns) - { - JsonTableColumn *col = castNode(JsonTableColumn, lfirst(lc)); - Node *node; - - if (col->coltype != JTC_NESTED) - continue; - - node = transformNestedJsonTableColumn(cxt, col, plan); - - /* join transformed node with previous sibling nodes */ - res = res ? makeJsonTableSiblingJoin(cross, res, node) : node; - } - - return res; - } - else if (plan->plan_type == JSTP_SIMPLE) - { - jtc = findNestedJsonTableColumn(columns, plan->pathname); - } - else if (plan->plan_type == JSTP_JOINED) - { - if (plan->join_type == JSTPJ_INNER || - plan->join_type == JSTPJ_OUTER) - { - Assert(plan->plan1->plan_type == JSTP_SIMPLE); - jtc = findNestedJsonTableColumn(columns, plan->plan1->pathname); - } - else - { - Node *node1 = transformJsonTableChildPlan(cxt, plan->plan1, - columns); - Node *node2 = transformJsonTableChildPlan(cxt, plan->plan2, - columns); - - return makeJsonTableSiblingJoin(plan->join_type == JSTPJ_CROSS, - node1, node2); - } - } - else - elog(ERROR, "invalid JSON_TABLE plan type %d", plan->plan_type); - - if (!jtc) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("invalid JSON_TABLE plan"), - errdetail("Path name was %s not found in nested columns list.", - plan->pathname), - parser_errposition(cxt->pstate, plan->location))); - - return transformNestedJsonTableColumn(cxt, jtc, plan); -} - -/* Check whether type is json/jsonb, array, or record. */ -static bool -typeIsComposite(Oid typid) -{ - char typtype; - - if (typid == JSONOID || - typid == JSONBOID || - typid == RECORDOID || - type_is_array(typid)) - return true; - - typtype = get_typtype(typid); - - if (typtype == TYPTYPE_COMPOSITE) - return true; - - if (typtype == TYPTYPE_DOMAIN) - return typeIsComposite(getBaseType(typid)); - - return false; -} - -/* Append transformed non-nested JSON_TABLE columns to the TableFunc node */ -static void -appendJsonTableColumns(JsonTableContext *cxt, List *columns) -{ - ListCell *col; - ParseState *pstate = cxt->pstate; - JsonTable *jt = cxt->table; - TableFunc *tf = cxt->tablefunc; - bool errorOnError = jt->on_error && - jt->on_error->btype == JSON_BEHAVIOR_ERROR; - - foreach(col, columns) - { - JsonTableColumn *rawc = castNode(JsonTableColumn, lfirst(col)); - Oid typid; - int32 typmod; - Node *colexpr; - - if (rawc->name) - { - /* make sure column names are unique */ - ListCell *colname; - - foreach(colname, tf->colnames) - if (!strcmp((const char *) colname, rawc->name)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("column name \"%s\" is not unique", - rawc->name), - parser_errposition(pstate, rawc->location))); - - tf->colnames = lappend(tf->colnames, - makeString(pstrdup(rawc->name))); - } - - /* - * Determine the type and typmod for the new column. FOR ORDINALITY - * columns are INTEGER by standard; the others are user-specified. - */ - switch (rawc->coltype) - { - case JTC_FOR_ORDINALITY: - colexpr = NULL; - typid = INT4OID; - typmod = -1; - break; - - case JTC_REGULAR: - typenameTypeIdAndMod(pstate, rawc->typeName, &typid, &typmod); - - /* - * Use implicit FORMAT JSON for composite types (arrays and - * records) - */ - if (typeIsComposite(typid)) - rawc->coltype = JTC_FORMATTED; - else if (rawc->wrapper != JSW_NONE) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("cannot use WITH WRAPPER clause with scalar columns"), - parser_errposition(pstate, rawc->location))); - else if (rawc->omit_quotes) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("cannot use OMIT QUOTES clause with scalar columns"), - parser_errposition(pstate, rawc->location))); - - /* FALLTHROUGH */ - case JTC_EXISTS: - case JTC_FORMATTED: - { - Node *je; - CaseTestExpr *param = makeNode(CaseTestExpr); - - param->collation = InvalidOid; - param->typeId = cxt->contextItemTypid; - param->typeMod = -1; - - je = transformJsonTableColumn(rawc, (Node *) param, - NIL, errorOnError); - - colexpr = transformExpr(pstate, je, EXPR_KIND_FROM_FUNCTION); - assign_expr_collations(pstate, colexpr); - - typid = exprType(colexpr); - typmod = exprTypmod(colexpr); - break; - } - - case JTC_NESTED: - continue; - - default: - elog(ERROR, "unknown JSON_TABLE column type: %d", rawc->coltype); - break; - } - - tf->coltypes = lappend_oid(tf->coltypes, typid); - tf->coltypmods = lappend_int(tf->coltypmods, typmod); - tf->colcollations = lappend_oid(tf->colcollations, get_typcollation(typid)); - tf->colvalexprs = lappend(tf->colvalexprs, colexpr); - } -} - -/* - * Create transformed JSON_TABLE parent plan node by appending all non-nested - * columns to the TableFunc node and remembering their indices in the - * colvalexprs list. - */ -static JsonTableParent * -makeParentJsonTableNode(JsonTableContext *cxt, char *pathSpec, List *columns) -{ - JsonTableParent *node = makeNode(JsonTableParent); - - node->path = makeConst(JSONPATHOID, -1, InvalidOid, -1, - DirectFunctionCall1(jsonpath_in, - CStringGetDatum(pathSpec)), - false, false); - - /* save start of column range */ - node->colMin = list_length(cxt->tablefunc->colvalexprs); - - appendJsonTableColumns(cxt, columns); - - /* save end of column range */ - node->colMax = list_length(cxt->tablefunc->colvalexprs) - 1; - - node->errorOnError = - cxt->table->on_error && - cxt->table->on_error->btype == JSON_BEHAVIOR_ERROR; - - return node; -} - -static JsonTableParent * -transformJsonTableColumns(JsonTableContext *cxt, JsonTablePlan *plan, - List *columns, char *pathSpec, char **pathName, - int location) -{ - JsonTableParent *node; - JsonTablePlan *childPlan; - bool defaultPlan = !plan || plan->plan_type == JSTP_DEFAULT; - - if (!*pathName) - { - if (cxt->table->plan) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("invalid JSON_TABLE expression"), - errdetail("JSON_TABLE columns must contain " - "explicit AS pathname specification if " - "explicit PLAN clause is used"), - parser_errposition(cxt->pstate, location))); - - *pathName = generateJsonTablePathName(cxt); - } - - if (defaultPlan) - childPlan = plan; - else - { - /* validate parent and child plans */ - JsonTablePlan *parentPlan; - - if (plan->plan_type == JSTP_JOINED) - { - if (plan->join_type != JSTPJ_INNER && - plan->join_type != JSTPJ_OUTER) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("invalid JSON_TABLE plan"), - errdetail("Expected INNER or OUTER JSON_TABLE plan node."), - parser_errposition(cxt->pstate, plan->location))); - - parentPlan = plan->plan1; - childPlan = plan->plan2; - - Assert(parentPlan->plan_type != JSTP_JOINED); - Assert(parentPlan->pathname); - } - else - { - parentPlan = plan; - childPlan = NULL; - } - - if (strcmp(parentPlan->pathname, *pathName)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("invalid JSON_TABLE plan"), - errdetail("Path name mismatch: expected %s but %s is given.", - *pathName, parentPlan->pathname), - parser_errposition(cxt->pstate, plan->location))); - - validateJsonTableChildPlan(cxt->pstate, childPlan, columns); - } - - /* transform only non-nested columns */ - node = makeParentJsonTableNode(cxt, pathSpec, columns); - node->name = pstrdup(*pathName); - - if (childPlan || defaultPlan) - { - /* transform recursively nested columns */ - node->child = transformJsonTableChildPlan(cxt, childPlan, columns); - if (node->child) - node->outerJoin = !plan || (plan->join_type & JSTPJ_OUTER); - /* else: default plan case, no children found */ - } - - return node; -} - -/* - * transformJsonTable - - * Transform a raw JsonTable into TableFunc. - * - * Transform the document-generating expression, the row-generating expression, - * the column-generating expressions, and the default value expressions. - */ -ParseNamespaceItem * -transformJsonTable(ParseState *pstate, JsonTable *jt) -{ - JsonTableContext cxt; - TableFunc *tf = makeNode(TableFunc); - JsonFuncExpr *jfe = makeNode(JsonFuncExpr); - JsonTablePlan *plan = jt->plan; - JsonCommon *jscommon; - char *rootPathName = jt->common->pathname; - char *rootPath; - bool is_lateral; - - cxt.pstate = pstate; - cxt.table = jt; - cxt.tablefunc = tf; - cxt.pathNames = NIL; - cxt.pathNameId = 0; - - if (rootPathName) - registerJsonTableColumn(&cxt, rootPathName); - - registerAllJsonTableColumns(&cxt, jt->columns); - -#if 0 /* XXX it' unclear from the standard whether - * root path name is mandatory or not */ - if (plan && plan->plan_type != JSTP_DEFAULT && !rootPathName) - { - /* Assign root path name and create corresponding plan node */ - JsonTablePlan *rootNode = makeNode(JsonTablePlan); - JsonTablePlan *rootPlan = (JsonTablePlan *) - makeJsonTableJoinedPlan(JSTPJ_OUTER, (Node *) rootNode, - (Node *) plan, jt->location); - - rootPathName = generateJsonTablePathName(&cxt); - - rootNode->plan_type = JSTP_SIMPLE; - rootNode->pathname = rootPathName; - - plan = rootPlan; - } -#endif - - jscommon = copyObject(jt->common); - jscommon->pathspec = makeStringConst(pstrdup("$"), -1); - - jfe->op = JSON_TABLE_OP; - jfe->common = jscommon; - jfe->on_error = jt->on_error; - jfe->location = jt->common->location; - - /* - * We make lateral_only names of this level visible, whether or not the - * RangeTableFunc is explicitly marked LATERAL. This is needed for SQL - * spec compliance and seems useful on convenience grounds for all - * functions in FROM. - * - * (LATERAL can't nest within a single pstate level, so we don't need - * save/restore logic here.) - */ - Assert(!pstate->p_lateral_active); - pstate->p_lateral_active = true; - - tf->functype = TFT_JSON_TABLE; - tf->docexpr = transformExpr(pstate, (Node *) jfe, EXPR_KIND_FROM_FUNCTION); - - cxt.contextItemTypid = exprType(tf->docexpr); - - if (!IsA(jt->common->pathspec, A_Const) || - castNode(A_Const, jt->common->pathspec)->val.node.type != T_String) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("only string constants supported in JSON_TABLE path specification"), - parser_errposition(pstate, - exprLocation(jt->common->pathspec)))); - - rootPath = castNode(A_Const, jt->common->pathspec)->val.sval.sval; - - tf->plan = (Node *) transformJsonTableColumns(&cxt, plan, jt->columns, - rootPath, &rootPathName, - jt->common->location); - - tf->ordinalitycol = -1; /* undefine ordinality column number */ - tf->location = jt->location; - - pstate->p_lateral_active = false; - - /* - * Mark the RTE as LATERAL if the user said LATERAL explicitly, or if - * there are any lateral cross-references in it. - */ - is_lateral = jt->lateral || contain_vars_of_level((Node *) tf, 0); - - return addRangeTableEntryForTableFunc(pstate, - tf, jt->alias, is_lateral, true); -} diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index f0b21792c7b..b42d07631c7 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -2045,7 +2045,7 @@ addRangeTableEntryForTableFunc(ParseState *pstate, bool inFromCl) { RangeTblEntry *rte = makeNode(RangeTblEntry); - char *refname; + char *refname = alias ? alias->aliasname : pstrdup("xmltable"); Alias *eref; int numaliases; @@ -2063,8 +2063,7 @@ addRangeTableEntryForTableFunc(ParseState *pstate, Assert(list_length(tf->coltypmods) == list_length(tf->colnames)); Assert(list_length(tf->colcollations) == list_length(tf->colnames)); - refname = alias ? alias->aliasname : - pstrdup(tf->functype == TFT_XMLTABLE ? "xmltable" : "json_table"); + refname = alias ? alias->aliasname : pstrdup("xmltable"); rte->rtekind = RTE_TABLEFUNC; rte->relid = InvalidOid; @@ -2087,7 +2086,7 @@ addRangeTableEntryForTableFunc(ParseState *pstate, ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("%s function has %d columns available but %d columns specified", - tf->functype == TFT_XMLTABLE ? "XMLTABLE" : "JSON_TABLE", + "XMLTABLE", list_length(tf->colnames), numaliases))); rte->eref = eref; diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index 34106073714..0eef2d5cbae 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -2002,46 +2002,6 @@ FigureColnameInternal(Node *node, char **name) case T_XmlSerialize: *name = "xmlserialize"; return 2; - case T_JsonParseExpr: - *name = "json"; - return 2; - case T_JsonScalarExpr: - *name = "json_scalar"; - return 2; - case T_JsonSerializeExpr: - *name = "json_serialize"; - return 2; - case T_JsonObjectConstructor: - *name = "json_object"; - return 2; - case T_JsonArrayConstructor: - case T_JsonArrayQueryConstructor: - *name = "json_array"; - return 2; - case T_JsonObjectAgg: - *name = "json_objectagg"; - return 2; - case T_JsonArrayAgg: - *name = "json_arrayagg"; - return 2; - case T_JsonFuncExpr: - /* make SQL/JSON functions act like a regular function */ - switch (((JsonFuncExpr *) node)->op) - { - case JSON_QUERY_OP: - *name = "json_query"; - return 2; - case JSON_VALUE_OP: - *name = "json_value"; - return 2; - case JSON_EXISTS_OP: - *name = "json_exists"; - return 2; - case JSON_TABLE_OP: - *name = "json_table"; - return 2; - } - break; default: break; } diff --git a/src/backend/parser/parser.c b/src/backend/parser/parser.c index b32090ebdcc..ffd7797a18c 100644 --- a/src/backend/parser/parser.c +++ b/src/backend/parser/parser.c @@ -154,9 +154,6 @@ base_yylex(YYSTYPE *lvalp, YYLTYPE *llocp, core_yyscan_t yyscanner) case USCONST: cur_token_length = strlen(yyextra->core_yy_extra.scanbuf + *llocp); break; - case WITHOUT: - cur_token_length = 7; - break; default: return cur_token; } @@ -228,19 +225,6 @@ base_yylex(YYSTYPE *lvalp, YYLTYPE *llocp, core_yyscan_t yyscanner) case ORDINALITY: cur_token = WITH_LA; break; - case UNIQUE: - cur_token = WITH_LA_UNIQUE; - break; - } - break; - - case WITHOUT: - /* Replace WITHOUT by WITHOUT_LA if it's followed by TIME */ - switch (next_token) - { - case TIME: - cur_token = WITHOUT_LA; - break; } break; diff --git a/src/backend/utils/adt/format_type.c b/src/backend/utils/adt/format_type.c index 4dab497411b..d8e85b8278a 100644 --- a/src/backend/utils/adt/format_type.c +++ b/src/backend/utils/adt/format_type.c @@ -294,10 +294,6 @@ format_type_extended(Oid type_oid, int32 typemod, bits16 flags) else buf = pstrdup("character varying"); break; - - case JSONOID: - buf = pstrdup("json"); - break; } if (buf == NULL) diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c index 6f8734a947d..26f498b5df4 100644 --- a/src/backend/utils/adt/formatting.c +++ b/src/backend/utils/adt/formatting.c @@ -1045,6 +1045,11 @@ typedef struct NUMProc *L_currency_symbol; } NUMProc; +/* Return flags for DCH_from_char() */ +#define DCH_DATED 0x01 +#define DCH_TIMED 0x02 +#define DCH_ZONED 0x04 + /* ---------- * Functions * ---------- @@ -6707,43 +6712,3 @@ float8_to_char(PG_FUNCTION_ARGS) NUM_TOCHAR_finish; PG_RETURN_TEXT_P(result); } - -int -datetime_format_flags(const char *fmt_str, bool *have_error) -{ - bool incache; - int fmt_len = strlen(fmt_str); - int result; - FormatNode *format; - - if (fmt_len > DCH_CACHE_SIZE) - { - /* - * Allocate new memory if format picture is bigger than static cache - * and do not use cache (call parser always) - */ - incache = false; - - format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode)); - - parse_format(format, fmt_str, DCH_keywords, - DCH_suff, DCH_index, DCH_FLAG, NULL); - } - else - { - /* - * Use cache buffers - */ - DCHCacheEntry *ent = DCH_cache_fetch(fmt_str, false); - - incache = true; - format = ent->format; - } - - result = DCH_datetime_type(format, have_error); - - if (!incache) - pfree(format); - - return result; -} diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c index 328cbb89313..6691cca6493 100644 --- a/src/backend/utils/adt/json.c +++ b/src/backend/utils/adt/json.c @@ -13,10 +13,7 @@ */ #include "postgres.h" -#include "access/hash.h" -#include "catalog/pg_proc.h" #include "catalog/pg_type.h" -#include "common/hashfn.h" #include "funcapi.h" #include "libpq/pqformat.h" #include "miscadmin.h" @@ -30,41 +27,20 @@ #include "utils/lsyscache.h" #include "utils/typcache.h" -/* Common context for key uniqueness check */ -typedef struct HTAB *JsonUniqueCheckState; /* hash table for key names */ - -/* Hash entry for JsonUniqueCheckState */ -typedef struct JsonUniqueHashEntry -{ - const char *key; - int key_len; - int object_id; -} JsonUniqueHashEntry; - -/* Context for key uniqueness check in builder functions */ -typedef struct JsonUniqueBuilderState -{ - JsonUniqueCheckState check; /* unique check */ - StringInfoData skipped_keys; /* skipped keys with NULL values */ - MemoryContext mcxt; /* context for saving skipped keys */ -} JsonUniqueBuilderState; - -/* Element of object stack for key uniqueness check during json parsing */ -typedef struct JsonUniqueStackEntry +typedef enum /* type categories for datum_to_json */ { - struct JsonUniqueStackEntry *parent; - int object_id; -} JsonUniqueStackEntry; - -/* State for key uniqueness check during json parsing */ -typedef struct JsonUniqueParsingState -{ - JsonLexContext *lex; - JsonUniqueCheckState check; - JsonUniqueStackEntry *stack; - int id_counter; - bool unique; -} JsonUniqueParsingState; + JSONTYPE_NULL, /* null, so we didn't bother to identify */ + JSONTYPE_BOOL, /* boolean (built-in types only) */ + JSONTYPE_NUMERIC, /* numeric (ditto) */ + JSONTYPE_DATE, /* we use special formatting for datetimes */ + JSONTYPE_TIMESTAMP, + JSONTYPE_TIMESTAMPTZ, + JSONTYPE_JSON, /* JSON itself (and JSONB) */ + JSONTYPE_ARRAY, /* array */ + JSONTYPE_COMPOSITE, /* composite */ + JSONTYPE_CAST, /* something with an explicit cast to JSON */ + JSONTYPE_OTHER /* all else */ +} JsonTypeCategory; typedef struct JsonAggState { @@ -73,7 +49,6 @@ typedef struct JsonAggState Oid key_output_func; JsonTypeCategory val_category; Oid val_output_func; - JsonUniqueBuilderState unique_check; } JsonAggState; static void composite_to_json(Datum composite, StringInfo result, @@ -84,6 +59,9 @@ static void array_dim_to_json(StringInfo result, int dim, int ndims, int *dims, bool use_line_feeds); static void array_to_json_internal(Datum array, StringInfo result, bool use_line_feeds); +static void json_categorize_type(Oid typoid, + JsonTypeCategory *tcategory, + Oid *outfuncoid); static void datum_to_json(Datum val, bool is_null, StringInfo result, JsonTypeCategory tcategory, Oid outfuncoid, bool key_scalar); @@ -162,7 +140,7 @@ json_recv(PG_FUNCTION_ARGS) * output function OID. If the returned category is JSONTYPE_CAST, we * return the OID of the type->JSON cast function instead. */ -void +static void json_categorize_type(Oid typoid, JsonTypeCategory *tcategory, Oid *outfuncoid) @@ -744,48 +722,6 @@ row_to_json_pretty(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len)); } -Datum -to_json_worker(Datum val, JsonTypeCategory tcategory, Oid outfuncoid) -{ - StringInfo result = makeStringInfo(); - - datum_to_json(val, false, result, tcategory, outfuncoid, false); - - return PointerGetDatum(cstring_to_text_with_len(result->data, result->len)); -} - -bool -to_json_is_immutable(Oid typoid) -{ - JsonTypeCategory tcategory; - Oid outfuncoid; - - json_categorize_type(typoid, &tcategory, &outfuncoid); - - switch (tcategory) - { - case JSONTYPE_BOOL: - case JSONTYPE_JSON: - return true; - - case JSONTYPE_DATE: - case JSONTYPE_TIMESTAMP: - case JSONTYPE_TIMESTAMPTZ: - return false; - - case JSONTYPE_ARRAY: - return false; /* TODO recurse into elements */ - - case JSONTYPE_COMPOSITE: - return false; /* TODO recurse into fields */ - - case JSONTYPE_NUMERIC: - case JSONTYPE_CAST: - default: - return func_volatile(outfuncoid) == PROVOLATILE_IMMUTABLE; - } -} - /* * SQL function to_json(anyvalue) */ @@ -794,6 +730,7 @@ to_json(PG_FUNCTION_ARGS) { Datum val = PG_GETARG_DATUM(0); Oid val_type = get_fn_expr_argtype(fcinfo->flinfo, 0); + StringInfo result; JsonTypeCategory tcategory; Oid outfuncoid; @@ -805,7 +742,11 @@ to_json(PG_FUNCTION_ARGS) json_categorize_type(val_type, &tcategory, &outfuncoid); - PG_RETURN_DATUM(to_json_worker(val, tcategory, outfuncoid)); + result = makeStringInfo(); + + datum_to_json(val, false, result, tcategory, outfuncoid, false); + + PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len)); } /* @@ -813,8 +754,8 @@ to_json(PG_FUNCTION_ARGS) * * aggregate input column as a json array value. */ -static Datum -json_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null) +Datum +json_agg_transfn(PG_FUNCTION_ARGS) { MemoryContext aggcontext, oldcontext; @@ -854,13 +795,8 @@ json_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null) else { state = (JsonAggState *) PG_GETARG_POINTER(0); - } - - if (absent_on_null && PG_ARGISNULL(1)) - PG_RETURN_POINTER(state); - - if (state->str->len > 1) appendStringInfoString(state->str, ", "); + } /* fast path for NULLs */ if (PG_ARGISNULL(1)) @@ -873,7 +809,7 @@ json_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null) val = PG_GETARG_DATUM(1); /* add some whitespace if structured type and not first item */ - if (!PG_ARGISNULL(0) && state->str->len > 1 && + if (!PG_ARGISNULL(0) && (state->val_category == JSONTYPE_ARRAY || state->val_category == JSONTYPE_COMPOSITE)) { @@ -891,25 +827,6 @@ json_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null) PG_RETURN_POINTER(state); } - -/* - * json_agg aggregate function - */ -Datum -json_agg_transfn(PG_FUNCTION_ARGS) -{ - return json_agg_transfn_worker(fcinfo, false); -} - -/* - * json_agg_strict aggregate function - */ -Datum -json_agg_strict_transfn(PG_FUNCTION_ARGS) -{ - return json_agg_transfn_worker(fcinfo, true); -} - /* * json_agg final function */ @@ -933,108 +850,18 @@ json_agg_finalfn(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(catenate_stringinfo_string(state->str, "]")); } -/* Functions implementing hash table for key uniqueness check */ -static uint32 -json_unique_hash(const void *key, Size keysize) -{ - const JsonUniqueHashEntry *entry = (JsonUniqueHashEntry *) key; - uint32 hash = hash_bytes_uint32(entry->object_id); - - hash ^= hash_bytes((const unsigned char *) entry->key, entry->key_len); - - return DatumGetUInt32(hash); -} - -static int -json_unique_hash_match(const void *key1, const void *key2, Size keysize) -{ - const JsonUniqueHashEntry *entry1 = (const JsonUniqueHashEntry *) key1; - const JsonUniqueHashEntry *entry2 = (const JsonUniqueHashEntry *) key2; - - if (entry1->object_id != entry2->object_id) - return entry1->object_id > entry2->object_id ? 1 : -1; - - if (entry1->key_len != entry2->key_len) - return entry1->key_len > entry2->key_len ? 1 : -1; - - return strncmp(entry1->key, entry2->key, entry1->key_len); -} - -/* Functions implementing object key uniqueness check */ -static void -json_unique_check_init(JsonUniqueCheckState *cxt) -{ - HASHCTL ctl; - - memset(&ctl, 0, sizeof(ctl)); - ctl.keysize = sizeof(JsonUniqueHashEntry); - ctl.entrysize = sizeof(JsonUniqueHashEntry); - ctl.hcxt = CurrentMemoryContext; - ctl.hash = json_unique_hash; - ctl.match = json_unique_hash_match; - - *cxt = hash_create("json object hashtable", - 32, - &ctl, - HASH_ELEM | HASH_CONTEXT | HASH_FUNCTION | HASH_COMPARE); -} - -static bool -json_unique_check_key(JsonUniqueCheckState *cxt, const char *key, int object_id) -{ - JsonUniqueHashEntry entry; - bool found; - - entry.key = key; - entry.key_len = strlen(key); - entry.object_id = object_id; - - (void) hash_search(*cxt, &entry, HASH_ENTER, &found); - - return !found; -} - -static void -json_unique_builder_init(JsonUniqueBuilderState *cxt) -{ - json_unique_check_init(&cxt->check); - cxt->mcxt = CurrentMemoryContext; - cxt->skipped_keys.data = NULL; -} - -/* On-demand initialization of skipped_keys StringInfo structure */ -static StringInfo -json_unique_builder_get_skipped_keys(JsonUniqueBuilderState *cxt) -{ - StringInfo out = &cxt->skipped_keys; - - if (!out->data) - { - MemoryContext oldcxt = MemoryContextSwitchTo(cxt->mcxt); - - initStringInfo(out); - MemoryContextSwitchTo(oldcxt); - } - - return out; -} - /* * json_object_agg transition function. * * aggregate two input columns as a single json object value. */ -static Datum -json_object_agg_transfn_worker(FunctionCallInfo fcinfo, - bool absent_on_null, bool unique_keys) +Datum +json_object_agg_transfn(PG_FUNCTION_ARGS) { MemoryContext aggcontext, oldcontext; JsonAggState *state; - StringInfo out; Datum arg; - bool skip; - int key_offset; if (!AggCheckCallContext(fcinfo, &aggcontext)) { @@ -1055,10 +882,6 @@ json_object_agg_transfn_worker(FunctionCallInfo fcinfo, oldcontext = MemoryContextSwitchTo(aggcontext); state = (JsonAggState *) palloc(sizeof(JsonAggState)); state->str = makeStringInfo(); - if (unique_keys) - json_unique_builder_init(&state->unique_check); - else - memset(&state->unique_check, 0, sizeof(state->unique_check)); MemoryContextSwitchTo(oldcontext); arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1); @@ -1086,6 +909,7 @@ json_object_agg_transfn_worker(FunctionCallInfo fcinfo, else { state = (JsonAggState *) PG_GETARG_POINTER(0); + appendStringInfoString(state->str, ", "); } /* @@ -1101,49 +925,11 @@ json_object_agg_transfn_worker(FunctionCallInfo fcinfo, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("field name must not be null"))); - /* Skip null values if absent_on_null */ - skip = absent_on_null && PG_ARGISNULL(2); - - if (skip) - { - /* If key uniqueness check is needed we must save skipped keys */ - if (!unique_keys) - PG_RETURN_POINTER(state); - - out = json_unique_builder_get_skipped_keys(&state->unique_check); - } - else - { - out = state->str; - - /* - * Append comma delimiter only if we have already outputted some - * fields after the initial string "{ ". - */ - if (out->len > 2) - appendStringInfoString(out, ", "); - } - arg = PG_GETARG_DATUM(1); - key_offset = out->len; - - datum_to_json(arg, false, out, state->key_category, + datum_to_json(arg, false, state->str, state->key_category, state->key_output_func, true); - if (unique_keys) - { - const char *key = &out->data[key_offset]; - - if (!json_unique_check_key(&state->unique_check.check, key, 0)) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_JSON_OBJECT_KEY_VALUE), - errmsg("duplicate JSON key %s", key))); - - if (skip) - PG_RETURN_POINTER(state); - } - appendStringInfoString(state->str, " : "); if (PG_ARGISNULL(2)) @@ -1157,42 +943,6 @@ json_object_agg_transfn_worker(FunctionCallInfo fcinfo, PG_RETURN_POINTER(state); } -/* - * json_object_agg aggregate function - */ -Datum -json_object_agg_transfn(PG_FUNCTION_ARGS) -{ - return json_object_agg_transfn_worker(fcinfo, false, false); -} - -/* - * json_object_agg_strict aggregate function - */ -Datum -json_object_agg_strict_transfn(PG_FUNCTION_ARGS) -{ - return json_object_agg_transfn_worker(fcinfo, true, false); -} - -/* - * json_object_agg_unique aggregate function - */ -Datum -json_object_agg_unique_transfn(PG_FUNCTION_ARGS) -{ - return json_object_agg_transfn_worker(fcinfo, false, true); -} - -/* - * json_object_agg_unique_strict aggregate function - */ -Datum -json_object_agg_unique_strict_transfn(PG_FUNCTION_ARGS) -{ - return json_object_agg_transfn_worker(fcinfo, true, true); -} - /* * json_object_agg final function. */ @@ -1234,14 +984,25 @@ catenate_stringinfo_string(StringInfo buffer, const char *addon) return result; } +/* + * SQL function json_build_object(variadic "any") + */ Datum -json_build_object_worker(int nargs, Datum *args, bool *nulls, Oid *types, - bool absent_on_null, bool unique_keys) +json_build_object(PG_FUNCTION_ARGS) { + int nargs; int i; const char *sep = ""; StringInfo result; - JsonUniqueBuilderState unique_check; + Datum *args; + bool *nulls; + Oid *types; + + /* fetch argument values to build the object */ + nargs = extract_variadic_args(fcinfo, 0, false, &args, &types, &nulls); + + if (nargs < 0) + PG_RETURN_NULL(); if (nargs % 2 != 0) ereport(ERROR, @@ -1255,32 +1016,10 @@ json_build_object_worker(int nargs, Datum *args, bool *nulls, Oid *types, appendStringInfoChar(result, '{'); - if (unique_keys) - json_unique_builder_init(&unique_check); - for (i = 0; i < nargs; i += 2) { - StringInfo out; - bool skip; - int key_offset; - - /* Skip null values if absent_on_null */ - skip = absent_on_null && nulls[i + 1]; - - if (skip) - { - /* If key uniqueness check is needed we must save skipped keys */ - if (!unique_keys) - continue; - - out = json_unique_builder_get_skipped_keys(&unique_check); - } - else - { - appendStringInfoString(result, sep); - sep = ", "; - out = result; - } + appendStringInfoString(result, sep); + sep = ", "; /* process key */ if (nulls[i]) @@ -1289,24 +1028,7 @@ json_build_object_worker(int nargs, Datum *args, bool *nulls, Oid *types, errmsg("argument %d cannot be null", i + 1), errhint("Object keys should be text."))); - /* save key offset before key appending */ - key_offset = out->len; - - add_json(args[i], false, out, types[i], true); - - if (unique_keys) - { - /* check key uniqueness after key appending */ - const char *key = &out->data[key_offset]; - - if (!json_unique_check_key(&unique_check.check, key, 0)) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_JSON_OBJECT_KEY_VALUE), - errmsg("duplicate JSON key %s", key))); - - if (skip) - continue; - } + add_json(args[i], false, result, types[i], true); appendStringInfoString(result, " : "); @@ -1316,27 +1038,7 @@ json_build_object_worker(int nargs, Datum *args, bool *nulls, Oid *types, appendStringInfoChar(result, '}'); - return PointerGetDatum(cstring_to_text_with_len(result->data, result->len)); -} - -/* - * SQL function json_build_object(variadic "any") - */ -Datum -json_build_object(PG_FUNCTION_ARGS) -{ - Datum *args; - bool *nulls; - Oid *types; - - /* build argument values to build the object */ - int nargs = extract_variadic_args(fcinfo, 0, true, - &args, &types, &nulls); - - if (nargs < 0) - PG_RETURN_NULL(); - - PG_RETURN_DATUM(json_build_object_worker(nargs, args, nulls, types, false, false)); + PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len)); } /* @@ -1348,13 +1050,25 @@ json_build_object_noargs(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(cstring_to_text_with_len("{}", 2)); } +/* + * SQL function json_build_array(variadic "any") + */ Datum -json_build_array_worker(int nargs, Datum *args, bool *nulls, Oid *types, - bool absent_on_null) +json_build_array(PG_FUNCTION_ARGS) { + int nargs; int i; const char *sep = ""; StringInfo result; + Datum *args; + bool *nulls; + Oid *types; + + /* fetch argument values to build the array */ + nargs = extract_variadic_args(fcinfo, 0, false, &args, &types, &nulls); + + if (nargs < 0) + PG_RETURN_NULL(); result = makeStringInfo(); @@ -1362,9 +1076,6 @@ json_build_array_worker(int nargs, Datum *args, bool *nulls, Oid *types, for (i = 0; i < nargs; i++) { - if (absent_on_null && nulls[i]) - continue; - appendStringInfoString(result, sep); sep = ", "; add_json(args[i], nulls[i], result, types[i], false); @@ -1372,27 +1083,7 @@ json_build_array_worker(int nargs, Datum *args, bool *nulls, Oid *types, appendStringInfoChar(result, ']'); - return PointerGetDatum(cstring_to_text_with_len(result->data, result->len)); -} - -/* - * SQL function json_build_array(variadic "any") - */ -Datum -json_build_array(PG_FUNCTION_ARGS) -{ - Datum *args; - bool *nulls; - Oid *types; - - /* build argument values to build the object */ - int nargs = extract_variadic_args(fcinfo, 0, true, - &args, &types, &nulls); - - if (nargs < 0) - PG_RETURN_NULL(); - - PG_RETURN_DATUM(json_build_array_worker(nargs, args, nulls, types, false)); + PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len)); } /* @@ -1618,106 +1309,6 @@ escape_json(StringInfo buf, const char *str) appendStringInfoCharMacro(buf, '"'); } -/* Semantic actions for key uniqueness check */ -static void -json_unique_object_start(void *_state) -{ - JsonUniqueParsingState *state = _state; - JsonUniqueStackEntry *entry; - - if (!state->unique) - return; - - /* push object entry to stack */ - entry = palloc(sizeof(*entry)); - entry->object_id = state->id_counter++; - entry->parent = state->stack; - state->stack = entry; -} - -static void -json_unique_object_end(void *_state) -{ - JsonUniqueParsingState *state = _state; - JsonUniqueStackEntry *entry; - - if (!state->unique) - return; - - entry = state->stack; - state->stack = entry->parent; /* pop object from stack */ - pfree(entry); -} - -static void -json_unique_object_field_start(void *_state, char *field, bool isnull) -{ - JsonUniqueParsingState *state = _state; - JsonUniqueStackEntry *entry; - - if (!state->unique) - return; - - /* find key collision in the current object */ - if (json_unique_check_key(&state->check, field, state->stack->object_id)) - return; - - state->unique = false; - - /* pop all objects entries */ - while ((entry = state->stack)) - { - state->stack = entry->parent; - pfree(entry); - } -} - -/* Validate JSON text and additionally check key uniqueness */ -bool -json_validate(text *json, bool check_unique_keys, bool throw_error) -{ - JsonLexContext *lex = makeJsonLexContext(json, check_unique_keys); - JsonSemAction uniqueSemAction = {0}; - JsonUniqueParsingState state; - JsonParseErrorType result; - - if (check_unique_keys) - { - state.lex = lex; - state.stack = NULL; - state.id_counter = 0; - state.unique = true; - json_unique_check_init(&state.check); - - uniqueSemAction.semstate = &state; - uniqueSemAction.object_start = json_unique_object_start; - uniqueSemAction.object_field_start = json_unique_object_field_start; - uniqueSemAction.object_end = json_unique_object_end; - } - - result = pg_parse_json(lex, check_unique_keys ? &uniqueSemAction : &nullSemAction); - - if (result != JSON_SUCCESS) - { - if (throw_error) - json_ereport_error(result, lex); - - return false; /* invalid json */ - } - - if (check_unique_keys && !state.unique) - { - if (throw_error) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_JSON_OBJECT_KEY_VALUE), - errmsg("duplicate JSON object key value"))); - - return false; /* not unique keys */ - } - - return true; /* ok */ -} - /* * SQL function json_typeof(json) -> text * @@ -1733,13 +1324,21 @@ json_validate(text *json, bool check_unique_keys, bool throw_error) Datum json_typeof(PG_FUNCTION_ARGS) { - text *json = PG_GETARG_TEXT_PP(0); - char *type; + text *json; + + JsonLexContext *lex; JsonTokenType tok; + char *type; + JsonParseErrorType result; - /* Lex exactly one token from the input and check its type. */ - tok = json_get_first_token(json, true); + json = PG_GETARG_TEXT_PP(0); + lex = makeJsonLexContext(json, false); + /* Lex exactly one token from the input and check its type. */ + result = json_lex(lex); + if (result != JSON_SUCCESS) + json_ereport_error(result, lex); + tok = lex->token_type; switch (tok) { case JSON_TOKEN_OBJECT_START: diff --git a/src/backend/utils/adt/jsonb.c b/src/backend/utils/adt/jsonb.c index d59fb0dfd16..3a970b9fa17 100644 --- a/src/backend/utils/adt/jsonb.c +++ b/src/backend/utils/adt/jsonb.c @@ -14,7 +14,6 @@ #include "access/htup_details.h" #include "access/transam.h" -#include "catalog/pg_proc.h" #include "catalog/pg_type.h" #include "funcapi.h" #include "libpq/pqformat.h" @@ -34,9 +33,25 @@ typedef struct JsonbInState { JsonbParseState *parseState; JsonbValue *res; - bool unique_keys; } JsonbInState; +/* unlike with json categories, we need to treat json and jsonb differently */ +typedef enum /* type categories for datum_to_jsonb */ +{ + JSONBTYPE_NULL, /* null, so we didn't bother to identify */ + JSONBTYPE_BOOL, /* boolean (built-in types only) */ + JSONBTYPE_NUMERIC, /* numeric (ditto) */ + JSONBTYPE_DATE, /* we use special formatting for datetimes */ + JSONBTYPE_TIMESTAMP, /* we use special formatting for timestamp */ + JSONBTYPE_TIMESTAMPTZ, /* ... and timestamptz */ + JSONBTYPE_JSON, /* JSON */ + JSONBTYPE_JSONB, /* JSONB */ + JSONBTYPE_ARRAY, /* array */ + JSONBTYPE_COMPOSITE, /* composite */ + JSONBTYPE_JSONCAST, /* something with an explicit cast to JSON */ + JSONBTYPE_OTHER /* all else */ +} JsonbTypeCategory; + typedef struct JsonbAggState { JsonbInState *res; @@ -46,7 +61,7 @@ typedef struct JsonbAggState Oid val_output_func; } JsonbAggState; -static inline Datum jsonb_from_cstring(char *json, int len, bool unique_keys); +static inline Datum jsonb_from_cstring(char *json, int len); static size_t checkStringLen(size_t len); static void jsonb_in_object_start(void *pstate); static void jsonb_in_object_end(void *pstate); @@ -55,11 +70,17 @@ static void jsonb_in_array_end(void *pstate); static void jsonb_in_object_field_start(void *pstate, char *fname, bool isnull); static void jsonb_put_escaped_value(StringInfo out, JsonbValue *scalarVal); static void jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype); +static void jsonb_categorize_type(Oid typoid, + JsonbTypeCategory *tcategory, + Oid *outfuncoid); static void composite_to_jsonb(Datum composite, JsonbInState *result); static void array_dim_to_jsonb(JsonbInState *result, int dim, int ndims, int *dims, Datum *vals, bool *nulls, int *valcount, JsonbTypeCategory tcategory, Oid outfuncoid); static void array_to_jsonb_internal(Datum array, JsonbInState *result); +static void jsonb_categorize_type(Oid typoid, + JsonbTypeCategory *tcategory, + Oid *outfuncoid); static void datum_to_jsonb(Datum val, bool is_null, JsonbInState *result, JsonbTypeCategory tcategory, Oid outfuncoid, bool key_scalar); @@ -77,7 +98,7 @@ jsonb_in(PG_FUNCTION_ARGS) { char *json = PG_GETARG_CSTRING(0); - return jsonb_from_cstring(json, strlen(json), false); + return jsonb_from_cstring(json, strlen(json)); } /* @@ -101,7 +122,7 @@ jsonb_recv(PG_FUNCTION_ARGS) else elog(ERROR, "unsupported jsonb version number %d", version); - return jsonb_from_cstring(str, nbytes, false); + return jsonb_from_cstring(str, nbytes); } /* @@ -142,14 +163,6 @@ jsonb_send(PG_FUNCTION_ARGS) PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); } -Datum -jsonb_from_text(text *js, bool unique_keys) -{ - return jsonb_from_cstring(VARDATA_ANY(js), - VARSIZE_ANY_EXHDR(js), - unique_keys); -} - /* * Get the type name of a jsonb container. */ @@ -240,7 +253,7 @@ jsonb_typeof(PG_FUNCTION_ARGS) * Uses the json parser (with hooks) to construct a jsonb. */ static inline Datum -jsonb_from_cstring(char *json, int len, bool unique_keys) +jsonb_from_cstring(char *json, int len) { JsonLexContext *lex; JsonbInState state; @@ -250,8 +263,6 @@ jsonb_from_cstring(char *json, int len, bool unique_keys) memset(&sem, 0, sizeof(sem)); lex = makeJsonLexContextCstringLen(json, len, GetDatabaseEncoding(), true); - state.unique_keys = unique_keys; - sem.semstate = (void *) &state; sem.object_start = jsonb_in_object_start; @@ -286,7 +297,6 @@ jsonb_in_object_start(void *pstate) JsonbInState *_state = (JsonbInState *) pstate; _state->res = pushJsonbValue(&_state->parseState, WJB_BEGIN_OBJECT, NULL); - _state->parseState->unique_keys = _state->unique_keys; } static void @@ -619,7 +629,7 @@ add_indent(StringInfo out, bool indent, int level) * output function OID. If the returned category is JSONBTYPE_JSONCAST, * we return the OID of the relevant cast function instead. */ -void +static void jsonb_categorize_type(Oid typoid, JsonbTypeCategory *tcategory, Oid *outfuncoid) @@ -1125,51 +1135,6 @@ add_jsonb(Datum val, bool is_null, JsonbInState *result, datum_to_jsonb(val, is_null, result, tcategory, outfuncoid, key_scalar); } -Datum -to_jsonb_worker(Datum val, JsonbTypeCategory tcategory, Oid outfuncoid) -{ - JsonbInState result; - - memset(&result, 0, sizeof(JsonbInState)); - - datum_to_jsonb(val, false, &result, tcategory, outfuncoid, false); - - return JsonbPGetDatum(JsonbValueToJsonb(result.res)); -} - -bool -to_jsonb_is_immutable(Oid typoid) -{ - JsonbTypeCategory tcategory; - Oid outfuncoid; - - jsonb_categorize_type(typoid, &tcategory, &outfuncoid); - - switch (tcategory) - { - case JSONBTYPE_BOOL: - case JSONBTYPE_JSON: - case JSONBTYPE_JSONB: - return true; - - case JSONBTYPE_DATE: - case JSONBTYPE_TIMESTAMP: - case JSONBTYPE_TIMESTAMPTZ: - return false; - - case JSONBTYPE_ARRAY: - return false; /* TODO recurse into elements */ - - case JSONBTYPE_COMPOSITE: - return false; /* TODO recurse into fields */ - - case JSONBTYPE_NUMERIC: - case JSONBTYPE_JSONCAST: - default: - return func_volatile(outfuncoid) == PROVOLATILE_IMMUTABLE; - } -} - /* * SQL function to_jsonb(anyvalue) */ @@ -1178,6 +1143,7 @@ to_jsonb(PG_FUNCTION_ARGS) { Datum val = PG_GETARG_DATUM(0); Oid val_type = get_fn_expr_argtype(fcinfo->flinfo, 0); + JsonbInState result; JsonbTypeCategory tcategory; Oid outfuncoid; @@ -1189,15 +1155,31 @@ to_jsonb(PG_FUNCTION_ARGS) jsonb_categorize_type(val_type, &tcategory, &outfuncoid); - PG_RETURN_DATUM(to_jsonb_worker(val, tcategory, outfuncoid)); + memset(&result, 0, sizeof(JsonbInState)); + + datum_to_jsonb(val, false, &result, tcategory, outfuncoid, false); + + PG_RETURN_POINTER(JsonbValueToJsonb(result.res)); } +/* + * SQL function jsonb_build_object(variadic "any") + */ Datum -jsonb_build_object_worker(int nargs, Datum *args, bool *nulls, Oid *types, - bool absent_on_null, bool unique_keys) +jsonb_build_object(PG_FUNCTION_ARGS) { + int nargs; int i; JsonbInState result; + Datum *args; + bool *nulls; + Oid *types; + + /* build argument values to build the object */ + nargs = extract_variadic_args(fcinfo, 0, true, &args, &types, &nulls); + + if (nargs < 0) + PG_RETURN_NULL(); if (nargs % 2 != 0) ereport(ERROR, @@ -1210,26 +1192,15 @@ jsonb_build_object_worker(int nargs, Datum *args, bool *nulls, Oid *types, memset(&result, 0, sizeof(JsonbInState)); result.res = pushJsonbValue(&result.parseState, WJB_BEGIN_OBJECT, NULL); - result.parseState->unique_keys = unique_keys; - result.parseState->skip_nulls = absent_on_null; for (i = 0; i < nargs; i += 2) { /* process key */ - bool skip; - if (nulls[i]) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("argument %d: key must not be null", i + 1))); - /* skip null values if absent_on_null */ - skip = absent_on_null && nulls[i + 1]; - - /* we need to save skipped keys for the key uniqueness check */ - if (skip && !unique_keys) - continue; - add_jsonb(args[i], false, &result, types[i], true); /* process value */ @@ -1238,27 +1209,7 @@ jsonb_build_object_worker(int nargs, Datum *args, bool *nulls, Oid *types, result.res = pushJsonbValue(&result.parseState, WJB_END_OBJECT, NULL); - return JsonbPGetDatum(JsonbValueToJsonb(result.res)); -} - -/* - * SQL function jsonb_build_object(variadic "any") - */ -Datum -jsonb_build_object(PG_FUNCTION_ARGS) -{ - Datum *args; - bool *nulls; - Oid *types; - - /* build argument values to build the object */ - int nargs = extract_variadic_args(fcinfo, 0, true, - &args, &types, &nulls); - - if (nargs < 0) - PG_RETURN_NULL(); - - PG_RETURN_DATUM(jsonb_build_object_worker(nargs, args, nulls, types, false, false)); + PG_RETURN_POINTER(JsonbValueToJsonb(result.res)); } /* @@ -1277,50 +1228,36 @@ jsonb_build_object_noargs(PG_FUNCTION_ARGS) PG_RETURN_POINTER(JsonbValueToJsonb(result.res)); } -Datum -jsonb_build_array_worker(int nargs, Datum *args, bool *nulls, Oid *types, - bool absent_on_null) -{ - int i; - JsonbInState result; - - memset(&result, 0, sizeof(JsonbInState)); - - result.res = pushJsonbValue(&result.parseState, WJB_BEGIN_ARRAY, NULL); - - for (i = 0; i < nargs; i++) - { - if (absent_on_null && nulls[i]) - continue; - - add_jsonb(args[i], nulls[i], &result, types[i], false); - } - - result.res = pushJsonbValue(&result.parseState, WJB_END_ARRAY, NULL); - - return JsonbPGetDatum(JsonbValueToJsonb(result.res)); -} - /* * SQL function jsonb_build_array(variadic "any") */ Datum jsonb_build_array(PG_FUNCTION_ARGS) { + int nargs; + int i; + JsonbInState result; Datum *args; bool *nulls; Oid *types; - /* build argument values to build the object */ - int nargs = extract_variadic_args(fcinfo, 0, true, - &args, &types, &nulls); + /* build argument values to build the array */ + nargs = extract_variadic_args(fcinfo, 0, true, &args, &types, &nulls); if (nargs < 0) PG_RETURN_NULL(); - PG_RETURN_DATUM(jsonb_build_array_worker(nargs, args, nulls, types, false)); -} + memset(&result, 0, sizeof(JsonbInState)); + + result.res = pushJsonbValue(&result.parseState, WJB_BEGIN_ARRAY, NULL); + for (i = 0; i < nargs; i++) + add_jsonb(args[i], nulls[i], &result, types[i], false); + + result.res = pushJsonbValue(&result.parseState, WJB_END_ARRAY, NULL); + + PG_RETURN_POINTER(JsonbValueToJsonb(result.res)); +} /* * degenerate case of jsonb_build_array where it gets 0 arguments. @@ -1555,8 +1492,6 @@ clone_parse_state(JsonbParseState *state) { ocursor->contVal = icursor->contVal; ocursor->size = icursor->size; - ocursor->unique_keys = icursor->unique_keys; - ocursor->skip_nulls = icursor->skip_nulls; icursor = icursor->next; if (icursor == NULL) break; @@ -1568,8 +1503,12 @@ clone_parse_state(JsonbParseState *state) return result; } -static Datum -jsonb_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null) + +/* + * jsonb_agg aggregate function + */ +Datum +jsonb_agg_transfn(PG_FUNCTION_ARGS) { MemoryContext oldcontext, aggcontext; @@ -1617,9 +1556,6 @@ jsonb_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null) result = state->res; } - if (absent_on_null && PG_ARGISNULL(1)) - PG_RETURN_POINTER(state); - /* turn the argument into jsonb in the normal function context */ val = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1); @@ -1689,24 +1625,6 @@ jsonb_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null) PG_RETURN_POINTER(state); } -/* - * jsonb_agg aggregate function - */ -Datum -jsonb_agg_transfn(PG_FUNCTION_ARGS) -{ - return jsonb_agg_transfn_worker(fcinfo, false); -} - -/* - * jsonb_agg_strict aggregate function - */ -Datum -jsonb_agg_strict_transfn(PG_FUNCTION_ARGS) -{ - return jsonb_agg_transfn_worker(fcinfo, true); -} - Datum jsonb_agg_finalfn(PG_FUNCTION_ARGS) { @@ -1739,9 +1657,11 @@ jsonb_agg_finalfn(PG_FUNCTION_ARGS) PG_RETURN_POINTER(out); } -static Datum -jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo, - bool absent_on_null, bool unique_keys) +/* + * jsonb_object_agg aggregate function + */ +Datum +jsonb_object_agg_transfn(PG_FUNCTION_ARGS) { MemoryContext oldcontext, aggcontext; @@ -1755,7 +1675,6 @@ jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo, *jbval; JsonbValue v; JsonbIteratorToken type; - bool skip; if (!AggCheckCallContext(fcinfo, &aggcontext)) { @@ -1775,9 +1694,6 @@ jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo, state->res = result; result->res = pushJsonbValue(&result->parseState, WJB_BEGIN_OBJECT, NULL); - result->parseState->unique_keys = unique_keys; - result->parseState->skip_nulls = absent_on_null; - MemoryContextSwitchTo(oldcontext); arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1); @@ -1813,15 +1729,6 @@ jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("field name must not be null"))); - /* - * Skip null values if absent_on_null unless key uniqueness check is - * needed (because we must save keys in this case). - */ - skip = absent_on_null && PG_ARGISNULL(2); - - if (skip && !unique_keys) - PG_RETURN_POINTER(state); - val = PG_GETARG_DATUM(1); memset(&elem, 0, sizeof(JsonbInState)); @@ -1877,16 +1784,6 @@ jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo, } result->res = pushJsonbValue(&result->parseState, WJB_KEY, &v); - - if (skip) - { - v.type = jbvNull; - result->res = pushJsonbValue(&result->parseState, - WJB_VALUE, &v); - MemoryContextSwitchTo(oldcontext); - PG_RETURN_POINTER(state); - } - break; case WJB_END_ARRAY: break; @@ -1959,43 +1856,6 @@ jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo, PG_RETURN_POINTER(state); } -/* - * jsonb_object_agg aggregate function - */ -Datum -jsonb_object_agg_transfn(PG_FUNCTION_ARGS) -{ - return jsonb_object_agg_transfn_worker(fcinfo, false, false); -} - - -/* - * jsonb_object_agg_strict aggregate function - */ -Datum -jsonb_object_agg_strict_transfn(PG_FUNCTION_ARGS) -{ - return jsonb_object_agg_transfn_worker(fcinfo, true, false); -} - -/* - * jsonb_object_agg_unique aggregate function - */ -Datum -jsonb_object_agg_unique_transfn(PG_FUNCTION_ARGS) -{ - return jsonb_object_agg_transfn_worker(fcinfo, false, true); -} - -/* - * jsonb_object_agg_unique_strict aggregate function - */ -Datum -jsonb_object_agg_unique_strict_transfn(PG_FUNCTION_ARGS) -{ - return jsonb_object_agg_transfn_worker(fcinfo, true, true); -} - Datum jsonb_object_agg_finalfn(PG_FUNCTION_ARGS) { @@ -2227,65 +2087,3 @@ jsonb_float8(PG_FUNCTION_ARGS) PG_RETURN_DATUM(retValue); } - -/* - * Construct an empty array jsonb. - */ -Jsonb * -JsonbMakeEmptyArray(void) -{ - JsonbValue jbv; - - jbv.type = jbvArray; - jbv.val.array.elems = NULL; - jbv.val.array.nElems = 0; - jbv.val.array.rawScalar = false; - - return JsonbValueToJsonb(&jbv); -} - -/* - * Construct an empty object jsonb. - */ -Jsonb * -JsonbMakeEmptyObject(void) -{ - JsonbValue jbv; - - jbv.type = jbvObject; - jbv.val.object.pairs = NULL; - jbv.val.object.nPairs = 0; - - return JsonbValueToJsonb(&jbv); -} - -/* - * Convert jsonb to a C-string stripping quotes from scalar strings. - */ -char * -JsonbUnquote(Jsonb *jb) -{ - if (JB_ROOT_IS_SCALAR(jb)) - { - JsonbValue v; - - (void) JsonbExtractScalar(&jb->root, &v); - - if (v.type == jbvString) - return pnstrdup(v.val.string.val, v.val.string.len); - else if (v.type == jbvBool) - return pstrdup(v.val.boolean ? "true" : "false"); - else if (v.type == jbvNumeric) - return DatumGetCString(DirectFunctionCall1(numeric_out, - PointerGetDatum(v.val.numeric))); - else if (v.type == jbvNull) - return pstrdup("null"); - else - { - elog(ERROR, "unrecognized jsonb value type %d", v.type); - return NULL; - } - } - else - return JsonbToCString(NULL, &jb->root, VARSIZE(jb)); -} diff --git a/src/backend/utils/adt/jsonb_util.c b/src/backend/utils/adt/jsonb_util.c index f8b61a95e7c..68057f1a74e 100644 --- a/src/backend/utils/adt/jsonb_util.c +++ b/src/backend/utils/adt/jsonb_util.c @@ -65,8 +65,7 @@ static int lengthCompareJsonbStringValue(const void *a, const void *b); static int lengthCompareJsonbString(const char *val1, int len1, const char *val2, int len2); static int lengthCompareJsonbPair(const void *a, const void *b, void *arg); -static void uniqueifyJsonbObject(JsonbValue *object, bool unique_keys, - bool skip_nulls); +static void uniqueifyJsonbObject(JsonbValue *object); static JsonbValue *pushJsonbValueScalar(JsonbParseState **pstate, JsonbIteratorToken seq, JsonbValue *scalarVal); @@ -774,9 +773,7 @@ pushJsonbValueScalar(JsonbParseState **pstate, JsonbIteratorToken seq, appendElement(*pstate, scalarVal); break; case WJB_END_OBJECT: - uniqueifyJsonbObject(&(*pstate)->contVal, - (*pstate)->unique_keys, - (*pstate)->skip_nulls); + uniqueifyJsonbObject(&(*pstate)->contVal); /* fall through! */ case WJB_END_ARRAY: /* Steps here common to WJB_END_OBJECT case */ @@ -819,9 +816,6 @@ pushState(JsonbParseState **pstate) JsonbParseState *ns = palloc(sizeof(JsonbParseState)); ns->next = *pstate; - ns->unique_keys = false; - ns->skip_nulls = false; - return ns; } @@ -2054,7 +2048,7 @@ tsqlLengthCompareJsonbPair(const void *a, const void *b, void *binequal) * Sort and unique-ify pairs in JsonbValue object */ static void -uniqueifyJsonbObject(JsonbValue *object, bool unique_keys, bool skip_nulls) +uniqueifyJsonbObject(JsonbValue *object) { bool hasNonUniq = false; @@ -2070,32 +2064,15 @@ uniqueifyJsonbObject(JsonbValue *object, bool unique_keys, bool skip_nulls) lengthCompareJsonbPair, &hasNonUniq); } - if (hasNonUniq && unique_keys) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_JSON_OBJECT_KEY_VALUE), - errmsg("duplicate JSON object key value"))); - - if ((hasNonUniq || skip_nulls) && sql_dialect != SQL_DIALECT_TSQL) + if (hasNonUniq && sql_dialect != SQL_DIALECT_TSQL) { - JsonbPair *ptr, - *res; - - while (skip_nulls && object->val.object.nPairs > 0 && - object->val.object.pairs->value.type == jbvNull) - { - /* If skip_nulls is true, remove leading items with null */ - object->val.object.pairs++; - object->val.object.nPairs--; - } - - ptr = object->val.object.pairs + 1; - res = object->val.object.pairs; + JsonbPair *ptr = object->val.object.pairs + 1, + *res = object->val.object.pairs; while (ptr - object->val.object.pairs < object->val.object.nPairs) { - /* Avoid copying over duplicate or null */ - if (lengthCompareJsonbStringValue(ptr, res) != 0 && - (!skip_nulls || ptr->value.type != jbvNull)) + /* Avoid copying over duplicate */ + if (lengthCompareJsonbStringValue(ptr, res) != 0) { res++; if (ptr != res) diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c index 9819e1a45ce..82c43617d85 100644 --- a/src/backend/utils/adt/jsonfuncs.c +++ b/src/backend/utils/adt/jsonfuncs.c @@ -2656,11 +2656,11 @@ populate_array_dim_jsonb(PopulateArrayContext *ctx, /* context */ check_stack_depth(); - if (jbv->type != jbvBinary || - !JsonContainerIsArray(jbc) || - JsonContainerIsScalar(jbc)) + if (jbv->type != jbvBinary || !JsonContainerIsArray(jbc)) populate_array_report_expected_array(ctx, ndim - 1); + Assert(!JsonContainerIsScalar(jbc)); + it = JsonbIteratorInit(jbc); tok = JsonbIteratorNext(&it, &val, true); @@ -3132,51 +3132,6 @@ populate_record_field(ColumnIOData *col, } } -/* recursively populate specified type from a json/jsonb value */ -Datum -json_populate_type(Datum json_val, Oid json_type, Oid typid, int32 typmod, - void **cache, MemoryContext mcxt, bool *isnull) -{ - JsValue jsv = {0}; - JsonbValue jbv; - - jsv.is_json = json_type == JSONOID; - - if (*isnull) - { - if (jsv.is_json) - jsv.val.json.str = NULL; - else - jsv.val.jsonb = NULL; - } - else if (jsv.is_json) - { - text *json = DatumGetTextPP(json_val); - - jsv.val.json.str = VARDATA_ANY(json); - jsv.val.json.len = VARSIZE_ANY_EXHDR(json); - jsv.val.json.type = JSON_TOKEN_INVALID; /* not used in - * populate_composite() */ - } - else - { - Jsonb *jsonb = DatumGetJsonbP(json_val); - - jsv.val.jsonb = &jbv; - - /* fill binary jsonb value pointing to jb */ - jbv.type = jbvBinary; - jbv.val.binary.data = &jsonb->root; - jbv.val.binary.len = VARSIZE(jsonb) - VARHDRSZ; - } - - if (!*cache) - *cache = MemoryContextAllocZero(mcxt, sizeof(ColumnIOData)); - - return populate_record_field(*cache, typid, typmod, NULL, mcxt, - PointerGetDatum(NULL), &jsv, isnull); -} - static RecordIOData * allocate_record_info(MemoryContext mcxt, int ncolumns) { @@ -5566,23 +5521,3 @@ transform_string_values_scalar(void *state, char *token, JsonTokenType tokentype else appendStringInfoString(_state->strval, token); } - -JsonTokenType -json_get_first_token(text *json, bool throw_error) -{ - JsonLexContext *lex; - JsonParseErrorType result; - - lex = makeJsonLexContext(json, false); - - /* Lex exactly one token from the input and check its type. */ - result = json_lex(lex); - - if (result == JSON_SUCCESS) - return lex->token_type; - - if (throw_error) - json_ereport_error(result, lex); - - return JSON_TOKEN_INVALID; /* invalid json */ -} diff --git a/src/backend/utils/adt/jsonpath.c b/src/backend/utils/adt/jsonpath.c index da9df4ae766..91af0300952 100644 --- a/src/backend/utils/adt/jsonpath.c +++ b/src/backend/utils/adt/jsonpath.c @@ -67,9 +67,7 @@ #include "lib/stringinfo.h" #include "libpq/pqformat.h" #include "miscadmin.h" -#include "nodes/nodeFuncs.h" #include "utils/builtins.h" -#include "utils/formatting.h" #include "utils/json.h" #include "utils/jsonpath.h" @@ -1079,258 +1077,3 @@ jspGetArraySubscript(JsonPathItem *v, JsonPathItem *from, JsonPathItem *to, return true; } - -/* SQL/JSON datatype status: */ -typedef enum JsonPathDatatypeStatus -{ - jpdsNonDateTime, /* null, bool, numeric, string, array, object */ - jpdsUnknownDateTime, /* unknown datetime type */ - jpdsDateTimeZoned, /* timetz, timestamptz */ - jpdsDateTimeNonZoned /* time, timestamp, date */ -} JsonPathDatatypeStatus; - -/* Context for jspIsMutableWalker() */ -typedef struct JsonPathMutableContext -{ - List *varnames; /* list of variable names */ - List *varexprs; /* list of variable expressions */ - JsonPathDatatypeStatus current; /* status of @ item */ - bool lax; /* jsonpath is lax or strict */ - bool mutable; /* resulting mutability status */ -} JsonPathMutableContext; - -/* - * Recursive walker for jspIsMutable() - */ -static JsonPathDatatypeStatus -jspIsMutableWalker(JsonPathItem *jpi, JsonPathMutableContext *cxt) -{ - JsonPathItem next; - JsonPathDatatypeStatus status = jpdsNonDateTime; - - while (!cxt->mutable) - { - JsonPathItem arg; - JsonPathDatatypeStatus leftStatus; - JsonPathDatatypeStatus rightStatus; - - switch (jpi->type) - { - case jpiRoot: - Assert(status == jpdsNonDateTime); - break; - - case jpiCurrent: - Assert(status == jpdsNonDateTime); - status = cxt->current; - break; - - case jpiFilter: - { - JsonPathDatatypeStatus prevStatus = cxt->current; - - cxt->current = status; - jspGetArg(jpi, &arg); - jspIsMutableWalker(&arg, cxt); - - cxt->current = prevStatus; - break; - } - - case jpiVariable: - { - int32 len; - const char *name = jspGetString(jpi, &len); - ListCell *lc1; - ListCell *lc2; - - Assert(status == jpdsNonDateTime); - - forboth(lc1, cxt->varnames, lc2, cxt->varexprs) - { - String *varname = lfirst_node(String, lc1); - Node *varexpr = lfirst(lc2); - - if (strncmp(varname->sval, name, len)) - continue; - - switch (exprType(varexpr)) - { - case DATEOID: - case TIMEOID: - case TIMESTAMPOID: - status = jpdsDateTimeNonZoned; - break; - - case TIMETZOID: - case TIMESTAMPTZOID: - status = jpdsDateTimeZoned; - break; - - default: - status = jpdsNonDateTime; - break; - } - - break; - } - break; - } - - case jpiEqual: - case jpiNotEqual: - case jpiLess: - case jpiGreater: - case jpiLessOrEqual: - case jpiGreaterOrEqual: - Assert(status == jpdsNonDateTime); - jspGetLeftArg(jpi, &arg); - leftStatus = jspIsMutableWalker(&arg, cxt); - - jspGetRightArg(jpi, &arg); - rightStatus = jspIsMutableWalker(&arg, cxt); - - /* - * Comparison of datetime type with different timezone status - * is mutable. - */ - if (leftStatus != jpdsNonDateTime && - rightStatus != jpdsNonDateTime && - (leftStatus == jpdsUnknownDateTime || - rightStatus == jpdsUnknownDateTime || - leftStatus != rightStatus)) - cxt->mutable = true; - break; - - case jpiNot: - case jpiIsUnknown: - case jpiExists: - case jpiPlus: - case jpiMinus: - Assert(status == jpdsNonDateTime); - jspGetArg(jpi, &arg); - jspIsMutableWalker(&arg, cxt); - break; - - case jpiAnd: - case jpiOr: - case jpiAdd: - case jpiSub: - case jpiMul: - case jpiDiv: - case jpiMod: - case jpiStartsWith: - Assert(status == jpdsNonDateTime); - jspGetLeftArg(jpi, &arg); - jspIsMutableWalker(&arg, cxt); - jspGetRightArg(jpi, &arg); - jspIsMutableWalker(&arg, cxt); - break; - - case jpiIndexArray: - for (int i = 0; i < jpi->content.array.nelems; i++) - { - JsonPathItem from; - JsonPathItem to; - - if (jspGetArraySubscript(jpi, &from, &to, i)) - jspIsMutableWalker(&to, cxt); - - jspIsMutableWalker(&from, cxt); - } - /* FALLTHROUGH */ - - case jpiAnyArray: - if (!cxt->lax) - status = jpdsNonDateTime; - break; - - case jpiAny: - if (jpi->content.anybounds.first > 0) - status = jpdsNonDateTime; - break; - - case jpiDatetime: - if (jpi->content.arg) - { - char *template; - int flags; - - jspGetArg(jpi, &arg); - if (arg.type != jpiString) - { - status = jpdsNonDateTime; - break; /* there will be runtime error */ - } - - template = jspGetString(&arg, NULL); - flags = datetime_format_flags(template, NULL); - if (flags & DCH_ZONED) - status = jpdsDateTimeZoned; - else - status = jpdsDateTimeNonZoned; - } - else - { - status = jpdsUnknownDateTime; - } - break; - - case jpiLikeRegex: - Assert(status == jpdsNonDateTime); - jspInitByBuffer(&arg, jpi->base, jpi->content.like_regex.expr); - jspIsMutableWalker(&arg, cxt); - break; - - /* literals */ - case jpiNull: - case jpiString: - case jpiNumeric: - case jpiBool: - /* accessors */ - case jpiKey: - case jpiAnyKey: - /* special items */ - case jpiSubscript: - case jpiLast: - /* item methods */ - case jpiType: - case jpiSize: - case jpiAbs: - case jpiFloor: - case jpiCeiling: - case jpiDouble: - case jpiKeyValue: - status = jpdsNonDateTime; - break; - } - - if (!jspGetNext(jpi, &next)) - break; - - jpi = &next; - } - - return status; -} - -/* - * Check whether jsonpath expression is immutable or not. - */ -bool -jspIsMutable(JsonPath *path, List *varnames, List *varexprs) -{ - JsonPathMutableContext cxt; - JsonPathItem jpi; - - cxt.varnames = varnames; - cxt.varexprs = varexprs; - cxt.current = jpdsNonDateTime; - cxt.lax = (path->header & JSONPATH_LAX) != 0; - cxt.mutable = false; - - jspInit(&jpi, path); - jspIsMutableWalker(&jpi, &cxt); - - return cxt.mutable; -} diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c index 4ebe3c5d5e7..96147fb0f4c 100644 --- a/src/backend/utils/adt/jsonpath_exec.c +++ b/src/backend/utils/adt/jsonpath_exec.c @@ -61,11 +61,9 @@ #include "catalog/pg_collation.h" #include "catalog/pg_type.h" -#include "executor/execExpr.h" #include "funcapi.h" #include "lib/stringinfo.h" #include "miscadmin.h" -#include "nodes/nodeFuncs.h" #include "parser/parser.h" #include "regex/regex.h" #include "utils/builtins.h" @@ -77,8 +75,6 @@ #include "utils/guc.h" #include "utils/json.h" #include "utils/jsonpath.h" -#include "utils/lsyscache.h" -#include "utils/memutils.h" #include "utils/timestamp.h" #include "utils/varlena.h" @@ -91,16 +87,12 @@ typedef struct JsonBaseObjectInfo int id; } JsonBaseObjectInfo; -typedef int (*JsonPathVarCallback) (void *vars, char *varName, int varNameLen, - JsonbValue *val, JsonbValue *baseObject); - /* * Context of jsonpath execution. */ typedef struct JsonPathExecContext { - void *vars; /* variables to substitute into jsonpath */ - JsonPathVarCallback getVar; + Jsonb *vars; /* variables to substitute into jsonpath */ JsonbValue *root; /* for $ evaluation */ JsonbValue *current; /* for @ evaluation */ JsonBaseObjectInfo baseObject; /* "base object" for .keyvalue() @@ -160,59 +152,6 @@ typedef struct JsonValueListIterator ListCell *next; } JsonValueListIterator; -/* Structures for JSON_TABLE execution */ -typedef struct JsonTableScanState JsonTableScanState; -typedef struct JsonTableJoinState JsonTableJoinState; - -struct JsonTableScanState -{ - JsonTableScanState *parent; - JsonTableJoinState *nested; - MemoryContext mcxt; - JsonPath *path; - List *args; - JsonValueList found; - JsonValueListIterator iter; - Datum current; - int ordinal; - bool currentIsNull; - bool outerJoin; - bool errorOnError; - bool advanceNested; - bool reset; -}; - -struct JsonTableJoinState -{ - union - { - struct - { - JsonTableJoinState *left; - JsonTableJoinState *right; - bool cross; - bool advanceRight; - } join; - JsonTableScanState scan; - } u; - bool is_join; -}; - -/* random number to identify JsonTableContext */ -#define JSON_TABLE_CONTEXT_MAGIC 418352867 - -typedef struct JsonTableContext -{ - int magic; - struct - { - ExprState *expr; - JsonTableScanState *scan; - } *colexprs; - JsonTableScanState root; - bool empty; -} JsonTableContext; - /* strict/lax flags is decomposed into four [un]wrap/error flags */ #define jspStrictAbsenseOfErrors(cxt) (!(cxt)->laxMode) #define jspAutoUnwrap(cxt) ((cxt)->laxMode) @@ -235,8 +174,7 @@ typedef JsonPathBool (*JsonPathPredicateCallback) (JsonPathItem *jsp, void *param); typedef Numeric (*BinaryArithmFunc) (Numeric num1, Numeric num2, bool *error); -static JsonPathExecResult executeJsonPath(JsonPath *path, void *vars, - JsonPathVarCallback getVar, +static JsonPathExecResult executeJsonPath(JsonPath *path, Jsonb *vars, Jsonb *json, bool throwErrors, JsonValueList *result, bool useTz); static JsonPathExecResult executeItem(JsonPathExecContext *cxt, @@ -288,10 +226,7 @@ static JsonPathExecResult appendBoolResult(JsonPathExecContext *cxt, static void getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item, JsonbValue *value); static void getJsonPathVariable(JsonPathExecContext *cxt, - JsonPathItem *variable, JsonbValue *value); -static int getJsonPathVariableFromJsonb(void *varsJsonb, char *varName, - int varNameLen, JsonbValue *val, - JsonbValue *baseObject); + JsonPathItem *variable, Jsonb *vars, JsonbValue *value); static int JsonbArraySize(JsonbValue *jb); static JsonPathBool executeComparison(JsonPathItem *cmp, JsonbValue *lv, JsonbValue *rv, void *p); @@ -303,7 +238,6 @@ static JsonPathExecResult getArrayIndex(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, int32 *index); static JsonBaseObjectInfo setBaseObject(JsonPathExecContext *cxt, JsonbValue *jbv, int32 id); -static void JsonValueListClear(JsonValueList *jvl); static void JsonValueListAppend(JsonValueList *jvl, JsonbValue *jbv); static int JsonValueListLength(const JsonValueList *jvl); static bool JsonValueListIsEmpty(JsonValueList *jvl); @@ -321,12 +255,6 @@ static JsonbValue *wrapItemsInArray(const JsonValueList *items); static int compareDatetime(Datum val1, Oid typid1, Datum val2, Oid typid2, bool useTz, bool *have_error); - -static JsonTableJoinState *JsonTableInitPlanState(JsonTableContext *cxt, - Node *plan, JsonTableScanState *parent); -static bool JsonTableNextRow(JsonTableScanState *scan); - - /****************** User interface to JsonPath executor ********************/ /* @@ -356,8 +284,7 @@ jsonb_path_exists_internal(FunctionCallInfo fcinfo, bool tz) silent = PG_GETARG_BOOL(3); } - res = executeJsonPath(jp, vars, getJsonPathVariableFromJsonb, - jb, !silent, NULL, tz); + res = executeJsonPath(jp, vars, jb, !silent, NULL, tz); PG_FREE_IF_COPY(jb, 0); PG_FREE_IF_COPY(jp, 1); @@ -412,8 +339,7 @@ jsonb_path_match_internal(FunctionCallInfo fcinfo, bool tz) silent = PG_GETARG_BOOL(3); } - (void) executeJsonPath(jp, vars, getJsonPathVariableFromJsonb, - jb, !silent, &found, tz); + (void) executeJsonPath(jp, vars, jb, !silent, &found, tz); PG_FREE_IF_COPY(jb, 0); PG_FREE_IF_COPY(jp, 1); @@ -491,8 +417,7 @@ jsonb_path_query_internal(FunctionCallInfo fcinfo, bool tz) vars = PG_GETARG_JSONB_P_COPY(2); silent = PG_GETARG_BOOL(3); - (void) executeJsonPath(jp, vars, getJsonPathVariableFromJsonb, - jb, !silent, &found, tz); + (void) executeJsonPath(jp, vars, jb, !silent, &found, tz); funcctx->user_fctx = JsonValueListGetList(&found); @@ -558,7 +483,7 @@ tsql_openjson_with_get_subjsonb(PG_FUNCTION_ARGS) /* retrieve sub_jb */ vars = (Jsonb *) DirectFunctionCall1(jsonb_in, CStringGetDatum("{}")); - (void) executeJsonPath(jp, vars, getJsonPathVariableFromJsonb, jb, false, &found, false); + (void) executeJsonPath(jp, vars, jb, false, &found, false); if (JsonValueListLength(&found) >= 1) sub_jb = JsonbValueToJsonb(JsonValueListHead(&found)); @@ -652,7 +577,7 @@ tsql_openjson_with_columnize(Jsonb *jb, char *col_info) /* get tuple set using executeJsonPath */ jp = DatumGetJsonPathP(DirectFunctionCall1(jsonpath_in, CStringGetDatum(col_path))); - (void) executeJsonPath(jp, vars, getJsonPathVariableFromJsonb, jb, false, &found, false); + (void) executeJsonPath(jp, vars, jb, false, &found, false); list = JsonValueListGetList(&found); /* go through found and convert values to strings. Truncate as necessary based on col_size */ @@ -722,8 +647,7 @@ jsonb_path_query_array_internal(FunctionCallInfo fcinfo, bool tz) Jsonb *vars = PG_GETARG_JSONB_P(2); bool silent = PG_GETARG_BOOL(3); - (void) executeJsonPath(jp, vars, getJsonPathVariableFromJsonb, - jb, !silent, &found, tz); + (void) executeJsonPath(jp, vars, jb, !silent, &found, tz); PG_RETURN_JSONB_P(JsonbValueToJsonb(wrapItemsInArray(&found))); } @@ -754,8 +678,7 @@ jsonb_path_query_first_internal(FunctionCallInfo fcinfo, bool tz) Jsonb *vars = PG_GETARG_JSONB_P(2); bool silent = PG_GETARG_BOOL(3); - (void) executeJsonPath(jp, vars, getJsonPathVariableFromJsonb, - jb, !silent, &found, tz); + (void) executeJsonPath(jp, vars, jb, !silent, &found, tz); if (JsonValueListLength(&found) >= 1) { @@ -802,9 +725,8 @@ jsonb_path_query_first_tz(PG_FUNCTION_ARGS) * In other case it tries to find all the satisfied result items. */ static JsonPathExecResult -executeJsonPath(JsonPath *path, void *vars, JsonPathVarCallback getVar, - Jsonb *json, bool throwErrors, JsonValueList *result, - bool useTz) +executeJsonPath(JsonPath *path, Jsonb *vars, Jsonb *json, bool throwErrors, + JsonValueList *result, bool useTz) { JsonPathExecContext cxt; JsonPathExecResult res; @@ -816,16 +738,22 @@ executeJsonPath(JsonPath *path, void *vars, JsonPathVarCallback getVar, if (!JsonbExtractScalar(&json->root, &jbv)) JsonbInitBinary(&jbv, json); + if (vars && !JsonContainerIsObject(&vars->root)) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("\"vars\" argument is not an object"), + errdetail("Jsonpath parameters should be encoded as key-value pairs of \"vars\" object."))); + } + cxt.vars = vars; - cxt.getVar = getVar; cxt.laxMode = (path->header & JSONPATH_LAX) != 0; cxt.ignoreStructuralErrors = cxt.laxMode; cxt.root = &jbv; cxt.current = &jbv; cxt.baseObject.jbc = NULL; cxt.baseObject.id = 0; - /* 1 + number of base objects in vars */ - cxt.lastGeneratedObjectId = 1 + getVar(vars, NULL, 0, NULL, NULL); + cxt.lastGeneratedObjectId = vars ? 2 : 1; cxt.innermostArraySize = -1; cxt.throwErrors = throwErrors; cxt.useTz = useTz; @@ -2377,7 +2305,7 @@ getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item, &value->val.string.len); break; case jpiVariable: - getJsonPathVariable(cxt, item, value); + getJsonPathVariable(cxt, item, cxt->vars, value); return; default: elog(ERROR, "unexpected jsonpath item type"); @@ -2389,63 +2317,42 @@ getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item, */ static void getJsonPathVariable(JsonPathExecContext *cxt, JsonPathItem *variable, - JsonbValue *value) + Jsonb *vars, JsonbValue *value) { char *varName; int varNameLength; - JsonbValue baseObject; - int baseObjectId; - - Assert(variable->type == jpiVariable); - varName = jspGetString(variable, &varNameLength); - - if (!cxt->vars || - (baseObjectId = cxt->getVar(cxt->vars, varName, varNameLength, value, - &baseObject)) < 0) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("could not find jsonpath variable \"%s\"", - pnstrdup(varName, varNameLength)))); - - if (baseObjectId > 0) - setBaseObject(cxt, &baseObject, baseObjectId); -} - -static int -getJsonPathVariableFromJsonb(void *varsJsonb, char *varName, int varNameLength, - JsonbValue *value, JsonbValue *baseObject) -{ - Jsonb *vars = varsJsonb; JsonbValue tmp; JsonbValue *v; - if (!varName) + if (!vars) { - if (vars && !JsonContainerIsObject(&vars->root)) - { - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("\"vars\" argument is not an object"), - errdetail("Jsonpath parameters should be encoded as key-value pairs of \"vars\" object."))); - } - - return vars ? 1 : 0; /* count of base objects */ + value->type = jbvNull; + return; } + Assert(variable->type == jpiVariable); + varName = jspGetString(variable, &varNameLength); tmp.type = jbvString; tmp.val.string.val = varName; tmp.val.string.len = varNameLength; v = findJsonbValueFromContainer(&vars->root, JB_FOBJECT, &tmp); - if (!v) - return -1; - - *value = *v; - pfree(v); + if (v) + { + *value = *v; + pfree(v); + } + else + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("could not find jsonpath variable \"%s\"", + pnstrdup(varName, varNameLength)))); + } - JsonbInitBinary(baseObject, vars); - return 1; + JsonbInitBinary(&tmp, vars); + setBaseObject(cxt, &tmp, 1); } /**************** Support functions for JsonPath execution *****************/ @@ -2734,13 +2641,6 @@ setBaseObject(JsonPathExecContext *cxt, JsonbValue *jbv, int32 id) return baseObject; } -static void -JsonValueListClear(JsonValueList *jvl) -{ - jvl->singleton = NULL; - jvl->list = NULL; -} - static void JsonValueListAppend(JsonValueList *jvl, JsonbValue *jbv) { @@ -3109,667 +3009,3 @@ compareDatetime(Datum val1, Oid typid1, Datum val2, Oid typid2, return DatumGetInt32(DirectFunctionCall2(cmpfunc, val1, val2)); } - -/********************Interface to pgsql's executor***************************/ - -bool -JsonPathExists(Datum jb, JsonPath *jp, List *vars, bool *error) -{ - JsonPathExecResult res = executeJsonPath(jp, vars, EvalJsonPathVar, - DatumGetJsonbP(jb), !error, NULL, - true); - - Assert(error || !jperIsError(res)); - - if (error && jperIsError(res)) - *error = true; - - return res == jperOk; -} - -Datum -JsonPathQuery(Datum jb, JsonPath *jp, JsonWrapper wrapper, bool *empty, - bool *error, List *vars) -{ - JsonbValue *first; - bool wrap; - JsonValueList found = {0}; - JsonPathExecResult res PG_USED_FOR_ASSERTS_ONLY; - int count; - - res = executeJsonPath(jp, vars, EvalJsonPathVar, DatumGetJsonbP(jb), !error, - &found, true); - - Assert(error || !jperIsError(res)); - - if (error && jperIsError(res)) - { - *error = true; - *empty = false; - return (Datum) 0; - } - - count = JsonValueListLength(&found); - - first = count ? JsonValueListHead(&found) : NULL; - - if (!first) - wrap = false; - else if (wrapper == JSW_NONE) - wrap = false; - else if (wrapper == JSW_UNCONDITIONAL) - wrap = true; - else if (wrapper == JSW_CONDITIONAL) - wrap = count > 1 || - IsAJsonbScalar(first) || - (first->type == jbvBinary && - JsonContainerIsScalar(first->val.binary.data)); - else - { - elog(ERROR, "unrecognized json wrapper %d", wrapper); - wrap = false; - } - - if (wrap) - return JsonbPGetDatum(JsonbValueToJsonb(wrapItemsInArray(&found))); - - if (count > 1) - { - if (error) - { - *error = true; - return (Datum) 0; - } - - ereport(ERROR, - (errcode(ERRCODE_MORE_THAN_ONE_SQL_JSON_ITEM), - errmsg("JSON path expression in JSON_QUERY should return " - "singleton item without wrapper"), - errhint("Use WITH WRAPPER clause to wrap SQL/JSON item " - "sequence into array."))); - } - - if (first) - return JsonbPGetDatum(JsonbValueToJsonb(first)); - - *empty = true; - return PointerGetDatum(NULL); -} - -JsonbValue * -JsonPathValue(Datum jb, JsonPath *jp, bool *empty, bool *error, List *vars) -{ - JsonbValue *res; - JsonValueList found = {0}; - JsonPathExecResult jper PG_USED_FOR_ASSERTS_ONLY; - int count; - - jper = executeJsonPath(jp, vars, EvalJsonPathVar, DatumGetJsonbP(jb), !error, - &found, true); - - Assert(error || !jperIsError(jper)); - - if (error && jperIsError(jper)) - { - *error = true; - *empty = false; - return NULL; - } - - count = JsonValueListLength(&found); - - *empty = !count; - - if (*empty) - return NULL; - - if (count > 1) - { - if (error) - { - *error = true; - return NULL; - } - - ereport(ERROR, - (errcode(ERRCODE_MORE_THAN_ONE_SQL_JSON_ITEM), - errmsg("JSON path expression in JSON_VALUE should return " - "singleton scalar item"))); - } - - res = JsonValueListHead(&found); - - if (res->type == jbvBinary && - JsonContainerIsScalar(res->val.binary.data)) - JsonbExtractScalar(res->val.binary.data, res); - - if (!IsAJsonbScalar(res)) - { - if (error) - { - *error = true; - return NULL; - } - - ereport(ERROR, - (errcode(ERRCODE_SQL_JSON_SCALAR_REQUIRED), - errmsg("JSON path expression in JSON_VALUE should return " - "singleton scalar item"))); - } - - if (res->type == jbvNull) - return NULL; - - return res; -} - -static void -JsonbValueInitNumericDatum(JsonbValue *jbv, Datum num) -{ - jbv->type = jbvNumeric; - jbv->val.numeric = DatumGetNumeric(num); -} - -void -JsonItemFromDatum(Datum val, Oid typid, int32 typmod, JsonbValue *res) -{ - switch (typid) - { - case BOOLOID: - res->type = jbvBool; - res->val.boolean = DatumGetBool(val); - break; - case NUMERICOID: - JsonbValueInitNumericDatum(res, val); - break; - case INT2OID: - JsonbValueInitNumericDatum(res, DirectFunctionCall1(int2_numeric, val)); - break; - case INT4OID: - JsonbValueInitNumericDatum(res, DirectFunctionCall1(int4_numeric, val)); - break; - case INT8OID: - JsonbValueInitNumericDatum(res, DirectFunctionCall1(int8_numeric, val)); - break; - case FLOAT4OID: - JsonbValueInitNumericDatum(res, DirectFunctionCall1(float4_numeric, val)); - break; - case FLOAT8OID: - JsonbValueInitNumericDatum(res, DirectFunctionCall1(float8_numeric, val)); - break; - case TEXTOID: - case VARCHAROID: - res->type = jbvString; - res->val.string.val = VARDATA_ANY(val); - res->val.string.len = VARSIZE_ANY_EXHDR(val); - break; - case DATEOID: - case TIMEOID: - case TIMETZOID: - case TIMESTAMPOID: - case TIMESTAMPTZOID: - res->type = jbvDatetime; - res->val.datetime.value = val; - res->val.datetime.typid = typid; - res->val.datetime.typmod = typmod; - res->val.datetime.tz = 0; - break; - case JSONBOID: - { - JsonbValue *jbv = res; - Jsonb *jb = DatumGetJsonbP(val); - - if (JsonContainerIsScalar(&jb->root)) - { - bool result PG_USED_FOR_ASSERTS_ONLY; - - result = JsonbExtractScalar(&jb->root, jbv); - Assert(result); - } - else - JsonbInitBinary(jbv, jb); - break; - } - case JSONOID: - { - text *txt = DatumGetTextP(val); - char *str = text_to_cstring(txt); - Jsonb *jb = - DatumGetJsonbP(DirectFunctionCall1(jsonb_in, - CStringGetDatum(str))); - - pfree(str); - - JsonItemFromDatum(JsonbPGetDatum(jb), JSONBOID, -1, res); - break; - } - default: - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("only bool, numeric, and text types could be " - "casted to supported jsonpath types."))); - } -} - -/************************ JSON_TABLE functions ***************************/ - -/* - * Returns private data from executor state. Ensure validity by check with - * MAGIC number. - */ -static inline JsonTableContext * -GetJsonTableContext(TableFuncScanState *state, const char *fname) -{ - JsonTableContext *result; - - if (!IsA(state, TableFuncScanState)) - elog(ERROR, "%s called with invalid TableFuncScanState", fname); - result = (JsonTableContext *) state->opaque; - if (result->magic != JSON_TABLE_CONTEXT_MAGIC) - elog(ERROR, "%s called with invalid TableFuncScanState", fname); - - return result; -} - -/* Recursively initialize JSON_TABLE scan state */ -static void -JsonTableInitScanState(JsonTableContext *cxt, JsonTableScanState *scan, - JsonTableParent *node, JsonTableScanState *parent, - List *args, MemoryContext mcxt) -{ - int i; - - scan->parent = parent; - scan->outerJoin = node->outerJoin; - scan->errorOnError = node->errorOnError; - scan->path = DatumGetJsonPathP(node->path->constvalue); - scan->args = args; - scan->mcxt = AllocSetContextCreate(mcxt, "JsonTableContext", - ALLOCSET_DEFAULT_SIZES); - scan->nested = node->child ? - JsonTableInitPlanState(cxt, node->child, scan) : NULL; - scan->current = PointerGetDatum(NULL); - scan->currentIsNull = true; - - for (i = node->colMin; i <= node->colMax; i++) - cxt->colexprs[i].scan = scan; -} - -/* Recursively initialize JSON_TABLE scan state */ -static JsonTableJoinState * -JsonTableInitPlanState(JsonTableContext *cxt, Node *plan, - JsonTableScanState *parent) -{ - JsonTableJoinState *state = palloc0(sizeof(*state)); - - if (IsA(plan, JsonTableSibling)) - { - JsonTableSibling *join = castNode(JsonTableSibling, plan); - - state->is_join = true; - state->u.join.cross = join->cross; - state->u.join.left = JsonTableInitPlanState(cxt, join->larg, parent); - state->u.join.right = JsonTableInitPlanState(cxt, join->rarg, parent); - } - else - { - JsonTableParent *node = castNode(JsonTableParent, plan); - - state->is_join = false; - - JsonTableInitScanState(cxt, &state->u.scan, node, parent, - parent->args, parent->mcxt); - } - - return state; -} - -/* - * JsonTableInitOpaque - * Fill in TableFuncScanState->opaque for JsonTable processor - */ -static void -JsonTableInitOpaque(TableFuncScanState *state, int natts) -{ - JsonTableContext *cxt; - PlanState *ps = &state->ss.ps; - TableFuncScan *tfs = castNode(TableFuncScan, ps->plan); - TableFunc *tf = tfs->tablefunc; - JsonExpr *ci = castNode(JsonExpr, tf->docexpr); - JsonTableParent *root = castNode(JsonTableParent, tf->plan); - List *args = NIL; - ListCell *lc; - int i; - - cxt = palloc0(sizeof(JsonTableContext)); - cxt->magic = JSON_TABLE_CONTEXT_MAGIC; - - if (ci->passing_values) - { - ListCell *exprlc; - ListCell *namelc; - - forboth(exprlc, ci->passing_values, - namelc, ci->passing_names) - { - Expr *expr = (Expr *) lfirst(exprlc); - String *name = lfirst_node(String, namelc); - JsonPathVariableEvalContext *var = palloc(sizeof(*var)); - - var->name = pstrdup(name->sval); - var->typid = exprType((Node *) expr); - var->typmod = exprTypmod((Node *) expr); - var->estate = ExecInitExpr(expr, ps); - var->econtext = ps->ps_ExprContext; - var->mcxt = CurrentMemoryContext; - var->evaluated = false; - var->value = (Datum) 0; - var->isnull = true; - - args = lappend(args, var); - } - } - - cxt->colexprs = palloc(sizeof(*cxt->colexprs) * - list_length(tf->colvalexprs)); - - JsonTableInitScanState(cxt, &cxt->root, root, NULL, args, - CurrentMemoryContext); - - i = 0; - - foreach(lc, tf->colvalexprs) - { - Expr *expr = lfirst(lc); - - cxt->colexprs[i].expr = - ExecInitExprWithCaseValue(expr, ps, - &cxt->colexprs[i].scan->current, - &cxt->colexprs[i].scan->currentIsNull); - - i++; - } - - state->opaque = cxt; -} - -/* Reset scan iterator to the beginning of the item list */ -static void -JsonTableRescan(JsonTableScanState *scan) -{ - JsonValueListInitIterator(&scan->found, &scan->iter); - scan->current = PointerGetDatum(NULL); - scan->currentIsNull = true; - scan->advanceNested = false; - scan->ordinal = 0; -} - -/* Reset context item of a scan, execute JSON path and reset a scan */ -static void -JsonTableResetContextItem(JsonTableScanState *scan, Datum item) -{ - MemoryContext oldcxt; - JsonPathExecResult res; - Jsonb *js = (Jsonb *) DatumGetJsonbP(item); - - JsonValueListClear(&scan->found); - - MemoryContextResetOnly(scan->mcxt); - - oldcxt = MemoryContextSwitchTo(scan->mcxt); - - res = executeJsonPath(scan->path, scan->args, EvalJsonPathVar, js, - scan->errorOnError, &scan->found, false /* FIXME */ ); - - MemoryContextSwitchTo(oldcxt); - - if (jperIsError(res)) - { - Assert(!scan->errorOnError); - JsonValueListClear(&scan->found); /* EMPTY ON ERROR case */ - } - - JsonTableRescan(scan); -} - -/* - * JsonTableSetDocument - * Install the input document - */ -static void -JsonTableSetDocument(TableFuncScanState *state, Datum value) -{ - JsonTableContext *cxt = GetJsonTableContext(state, "JsonTableSetDocument"); - - JsonTableResetContextItem(&cxt->root, value); -} - -/* Recursively reset scan and its child nodes */ -static void -JsonTableRescanRecursive(JsonTableJoinState *state) -{ - if (state->is_join) - { - JsonTableRescanRecursive(state->u.join.left); - JsonTableRescanRecursive(state->u.join.right); - state->u.join.advanceRight = false; - } - else - { - JsonTableRescan(&state->u.scan); - if (state->u.scan.nested) - JsonTableRescanRecursive(state->u.scan.nested); - } -} - -/* - * Fetch next row from a cross/union joined scan. - * - * Returns false at the end of a scan, true otherwise. - */ -static bool -JsonTableNextJoinRow(JsonTableJoinState *state) -{ - if (!state->is_join) - return JsonTableNextRow(&state->u.scan); - - if (state->u.join.advanceRight) - { - /* fetch next inner row */ - if (JsonTableNextJoinRow(state->u.join.right)) - return true; - - /* inner rows are exhausted */ - if (state->u.join.cross) - state->u.join.advanceRight = false; /* next outer row */ - else - return false; /* end of scan */ - } - - while (!state->u.join.advanceRight) - { - /* fetch next outer row */ - bool left = JsonTableNextJoinRow(state->u.join.left); - - if (state->u.join.cross) - { - if (!left) - return false; /* end of scan */ - - JsonTableRescanRecursive(state->u.join.right); - - if (!JsonTableNextJoinRow(state->u.join.right)) - continue; /* next outer row */ - - state->u.join.advanceRight = true; /* next inner row */ - } - else if (!left) - { - if (!JsonTableNextJoinRow(state->u.join.right)) - return false; /* end of scan */ - - state->u.join.advanceRight = true; /* next inner row */ - } - - break; - } - - return true; -} - -/* Recursively set 'reset' flag of scan and its child nodes */ -static void -JsonTableJoinReset(JsonTableJoinState *state) -{ - if (state->is_join) - { - JsonTableJoinReset(state->u.join.left); - JsonTableJoinReset(state->u.join.right); - state->u.join.advanceRight = false; - } - else - { - state->u.scan.reset = true; - state->u.scan.advanceNested = false; - - if (state->u.scan.nested) - JsonTableJoinReset(state->u.scan.nested); - } -} - -/* - * Fetch next row from a simple scan with outer/inner joined nested subscans. - * - * Returns false at the end of a scan, true otherwise. - */ -static bool -JsonTableNextRow(JsonTableScanState *scan) -{ - /* reset context item if requested */ - if (scan->reset) - { - Assert(!scan->parent->currentIsNull); - JsonTableResetContextItem(scan, scan->parent->current); - scan->reset = false; - } - - if (scan->advanceNested) - { - /* fetch next nested row */ - scan->advanceNested = JsonTableNextJoinRow(scan->nested); - - if (scan->advanceNested) - return true; - } - - for (;;) - { - /* fetch next row */ - JsonbValue *jbv = JsonValueListNext(&scan->found, &scan->iter); - MemoryContext oldcxt; - - if (!jbv) - { - scan->current = PointerGetDatum(NULL); - scan->currentIsNull = true; - return false; /* end of scan */ - } - - /* set current row item */ - oldcxt = MemoryContextSwitchTo(scan->mcxt); - scan->current = JsonbPGetDatum(JsonbValueToJsonb(jbv)); - scan->currentIsNull = false; - MemoryContextSwitchTo(oldcxt); - - scan->ordinal++; - - if (!scan->nested) - break; - - JsonTableJoinReset(scan->nested); - - scan->advanceNested = JsonTableNextJoinRow(scan->nested); - - if (scan->advanceNested || scan->outerJoin) - break; - } - - return true; -} - -/* - * JsonTableFetchRow - * Prepare the next "current" tuple for upcoming GetValue calls. - * Returns FALSE if the row-filter expression returned no more rows. - */ -static bool -JsonTableFetchRow(TableFuncScanState *state) -{ - JsonTableContext *cxt = GetJsonTableContext(state, "JsonTableFetchRow"); - - if (cxt->empty) - return false; - - return JsonTableNextRow(&cxt->root); -} - -/* - * JsonTableGetValue - * Return the value for column number 'colnum' for the current row. - * - * This leaks memory, so be sure to reset often the context in which it's - * called. - */ -static Datum -JsonTableGetValue(TableFuncScanState *state, int colnum, - Oid typid, int32 typmod, bool *isnull) -{ - JsonTableContext *cxt = GetJsonTableContext(state, "JsonTableGetValue"); - ExprContext *econtext = state->ss.ps.ps_ExprContext; - ExprState *estate = cxt->colexprs[colnum].expr; - JsonTableScanState *scan = cxt->colexprs[colnum].scan; - Datum result; - - if (scan->currentIsNull) /* NULL from outer/union join */ - { - result = (Datum) 0; - *isnull = true; - } - else if (estate) /* regular column */ - { - result = ExecEvalExpr(estate, econtext, isnull); - } - else - { - result = Int32GetDatum(scan->ordinal); /* ordinality column */ - *isnull = false; - } - - return result; -} - -/* - * JsonTableDestroyOpaque - */ -static void -JsonTableDestroyOpaque(TableFuncScanState *state) -{ - JsonTableContext *cxt = GetJsonTableContext(state, "JsonTableDestroyOpaque"); - - /* not valid anymore */ - cxt->magic = 0; - - state->opaque = NULL; -} - -const TableFuncRoutine JsonbTableRoutine = -{ - JsonTableInitOpaque, - JsonTableSetDocument, - NULL, - NULL, - NULL, - JsonTableFetchRow, - JsonTableGetValue, - JsonTableDestroyOpaque -}; diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index b7e40a936a0..68810f3bc6d 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -468,12 +468,6 @@ static void get_coercion_expr(Node *arg, deparse_context *context, Node *parentNode); static void get_const_expr(Const *constval, deparse_context *context, int showtype); -static void get_json_constructor(JsonConstructorExpr *ctor, - deparse_context *context, bool showimplicit); -static void get_json_agg_constructor(JsonConstructorExpr *ctor, - deparse_context *context, - const char *funcname, - bool is_json_objectagg); static void get_const_collation(Const *constval, deparse_context *context); static void simple_quote_literal(StringInfo buf, const char *val); static void get_sublink_expr(SubLink *sublink, deparse_context *context); @@ -507,10 +501,6 @@ static char *generate_qualified_type_name(Oid typid); static text *string_to_text(char *str); static char *flatten_reloptions(Oid relid); static void get_reloptions(StringInfo buf, Datum reloptions); -static void get_json_path_spec(Node *path_spec, deparse_context *context, - bool showimplicit); -static void get_json_table_columns(TableFunc *tf, JsonTableParent *node, - deparse_context *context, bool showimplicit); #define only_marker(rte) ((rte)->inh ? "" : "ONLY ") @@ -6345,8 +6335,7 @@ get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno, bool need_paren = (PRETTY_PAREN(context) || IsA(expr, FuncExpr) || IsA(expr, Aggref) - || IsA(expr, WindowFunc) - || IsA(expr, JsonConstructorExpr)); + || IsA(expr, WindowFunc)); if (need_paren) appendStringInfoChar(context->buf, '('); @@ -8205,8 +8194,6 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags) case T_GroupingFunc: case T_WindowFunc: case T_FuncExpr: - case T_JsonConstructorExpr: - case T_JsonExpr: /* function-like: name(..) or name[..] */ return true; @@ -8300,7 +8287,6 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags) case T_NullTest: case T_BooleanTest: case T_DistinctExpr: - case T_JsonIsPredicate: switch (nodeTag(parentNode)) { case T_FuncExpr: @@ -8325,7 +8311,6 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags) case T_GroupingFunc: /* own parentheses */ case T_WindowFunc: /* own parentheses */ case T_CaseExpr: /* other separators */ - case T_JsonExpr: /* own parentheses */ return true; default: return false; @@ -8382,11 +8367,6 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags) return false; } - case T_JsonValueExpr: - /* maybe simple, check args */ - return isSimpleNode((Node *) ((JsonValueExpr *) node)->raw_expr, - node, prettyFlags); - default: break; } @@ -8493,122 +8473,6 @@ get_rule_expr_paren(Node *node, deparse_context *context, } -/* - * get_json_path_spec - Parse back a JSON path specification - */ -static void -get_json_path_spec(Node *path_spec, deparse_context *context, bool showimplicit) -{ - if (IsA(path_spec, Const)) - get_const_expr((Const *) path_spec, context, -1); - else - get_rule_expr(path_spec, context, showimplicit); -} - -/* - * get_json_format - Parse back a JsonFormat node - */ -static void -get_json_format(JsonFormat *format, StringInfo buf) -{ - if (format->format_type == JS_FORMAT_DEFAULT) - return; - - appendStringInfoString(buf, - format->format_type == JS_FORMAT_JSONB ? - " FORMAT JSONB" : " FORMAT JSON"); - - if (format->encoding != JS_ENC_DEFAULT) - { - const char *encoding = - format->encoding == JS_ENC_UTF16 ? "UTF16" : - format->encoding == JS_ENC_UTF32 ? "UTF32" : "UTF8"; - - appendStringInfo(buf, " ENCODING %s", encoding); - } -} - -/* - * get_json_returning - Parse back a JsonReturning structure - */ -static void -get_json_returning(JsonReturning *returning, StringInfo buf, - bool json_format_by_default) -{ - if (!OidIsValid(returning->typid)) - return; - - appendStringInfo(buf, " RETURNING %s", - format_type_with_typemod(returning->typid, - returning->typmod)); - - if (!json_format_by_default || - returning->format->format_type != - (returning->typid == JSONBOID ? JS_FORMAT_JSONB : JS_FORMAT_JSON)) - get_json_format(returning->format, buf); -} - -static void -get_json_behavior(JsonBehavior *behavior, deparse_context *context, - const char *on) -{ - /* - * The order of array elements must correspond to the order of - * JsonBehaviorType members. - */ - const char *behavior_names[] = - { - " NULL", - " ERROR", - " EMPTY", - " TRUE", - " FALSE", - " UNKNOWN", - " EMPTY ARRAY", - " EMPTY OBJECT", - " DEFAULT " - }; - - if ((int) behavior->btype < 0 || behavior->btype >= lengthof(behavior_names)) - elog(ERROR, "invalid json behavior type: %d", behavior->btype); - - appendStringInfoString(context->buf, behavior_names[behavior->btype]); - - if (behavior->btype == JSON_BEHAVIOR_DEFAULT) - get_rule_expr(behavior->default_expr, context, false); - - appendStringInfo(context->buf, " ON %s", on); -} - -/* - * get_json_expr_options - * - * Parse back common options for JSON_QUERY, JSON_VALUE, JSON_EXISTS and - * JSON_TABLE columns. - */ -static void -get_json_expr_options(JsonExpr *jsexpr, deparse_context *context, - JsonBehaviorType default_behavior) -{ - if (jsexpr->op == JSON_QUERY_OP) - { - if (jsexpr->wrapper == JSW_CONDITIONAL) - appendStringInfo(context->buf, " WITH CONDITIONAL WRAPPER"); - else if (jsexpr->wrapper == JSW_UNCONDITIONAL) - appendStringInfo(context->buf, " WITH UNCONDITIONAL WRAPPER"); - - if (jsexpr->omit_quotes) - appendStringInfo(context->buf, " OMIT QUOTES"); - } - - if (jsexpr->op != JSON_EXISTS_OP && - jsexpr->on_empty->btype != default_behavior) - get_json_behavior(jsexpr->on_empty, context, "EMPTY"); - - if (jsexpr->on_error->btype != default_behavior) - get_json_behavior(jsexpr->on_error, context, "ERROR"); -} - /* ---------- * get_rule_expr - Parse back an expression * @@ -9767,116 +9631,6 @@ get_rule_expr(Node *node, deparse_context *context, } break; - - case T_JsonValueExpr: - { - JsonValueExpr *jve = (JsonValueExpr *) node; - - get_rule_expr((Node *) jve->raw_expr, context, false); - get_json_format(jve->format, context->buf); - } - break; - - case T_JsonConstructorExpr: - get_json_constructor((JsonConstructorExpr *) node, context, false); - break; - - case T_JsonIsPredicate: - { - JsonIsPredicate *pred = (JsonIsPredicate *) node; - - if (!PRETTY_PAREN(context)) - appendStringInfoChar(context->buf, '('); - - get_rule_expr_paren(pred->expr, context, true, node); - - appendStringInfoString(context->buf, " IS JSON"); - - /* TODO: handle FORMAT clause */ - - switch (pred->item_type) - { - case JS_TYPE_SCALAR: - appendStringInfoString(context->buf, " SCALAR"); - break; - case JS_TYPE_ARRAY: - appendStringInfoString(context->buf, " ARRAY"); - break; - case JS_TYPE_OBJECT: - appendStringInfoString(context->buf, " OBJECT"); - break; - default: - break; - } - - if (pred->unique_keys) - appendStringInfoString(context->buf, " WITH UNIQUE KEYS"); - - if (!PRETTY_PAREN(context)) - appendStringInfoChar(context->buf, ')'); - } - break; - - case T_JsonExpr: - { - JsonExpr *jexpr = (JsonExpr *) node; - - switch (jexpr->op) - { - case JSON_QUERY_OP: - appendStringInfoString(buf, "JSON_QUERY("); - break; - case JSON_VALUE_OP: - appendStringInfoString(buf, "JSON_VALUE("); - break; - case JSON_EXISTS_OP: - appendStringInfoString(buf, "JSON_EXISTS("); - break; - default: - elog(ERROR, "unexpected JsonExpr type: %d", jexpr->op); - break; - } - - get_rule_expr(jexpr->formatted_expr, context, showimplicit); - - appendStringInfoString(buf, ", "); - - get_json_path_spec(jexpr->path_spec, context, showimplicit); - - if (jexpr->passing_values) - { - ListCell *lc1, - *lc2; - bool needcomma = false; - - appendStringInfoString(buf, " PASSING "); - - forboth(lc1, jexpr->passing_names, - lc2, jexpr->passing_values) - { - if (needcomma) - appendStringInfoString(buf, ", "); - needcomma = true; - - get_rule_expr((Node *) lfirst(lc2), context, showimplicit); - appendStringInfo(buf, " AS %s", - ((String *) lfirst_node(String, lc1))->sval); - } - } - - if (jexpr->op != JSON_EXISTS_OP || - jexpr->returning->typid != BOOLOID) - get_json_returning(jexpr->returning, context->buf, - jexpr->op == JSON_QUERY_OP); - - get_json_expr_options(jexpr, context, - jexpr->op == JSON_EXISTS_OP ? - JSON_BEHAVIOR_FALSE : JSON_BEHAVIOR_NULL); - - appendStringInfoString(buf, ")"); - } - break; - case T_List: { char *sep; @@ -10000,7 +9754,6 @@ looks_like_function(Node *node) case T_MinMaxExpr: case T_SQLValueFunction: case T_XmlExpr: - case T_JsonExpr: /* these are all accepted by func_expr_common_subexpr */ return true; default: @@ -10146,103 +9899,17 @@ get_func_expr(FuncExpr *expr, deparse_context *context, appendStringInfoChar(buf, ')'); } -static void -get_json_constructor_options(JsonConstructorExpr *ctor, StringInfo buf) -{ - if (ctor->absent_on_null) - { - if (ctor->type == JSCTOR_JSON_OBJECT || - ctor->type == JSCTOR_JSON_OBJECTAGG) - appendStringInfoString(buf, " ABSENT ON NULL"); - } - else - { - if (ctor->type == JSCTOR_JSON_ARRAY || - ctor->type == JSCTOR_JSON_ARRAYAGG) - appendStringInfoString(buf, " NULL ON NULL"); - } - - if (ctor->unique) - appendStringInfoString(buf, " WITH UNIQUE KEYS"); - - if (!((ctor->type == JSCTOR_JSON_PARSE || - ctor->type == JSCTOR_JSON_SCALAR) && - ctor->returning->typid == JSONOID)) - get_json_returning(ctor->returning, buf, true); -} - -static void -get_json_constructor(JsonConstructorExpr *ctor, deparse_context *context, - bool showimplicit) -{ - StringInfo buf = context->buf; - const char *funcname; - int nargs; - ListCell *lc; - - switch (ctor->type) - { - case JSCTOR_JSON_PARSE: - funcname = "JSON"; - break; - case JSCTOR_JSON_SCALAR: - funcname = "JSON_SCALAR"; - break; - case JSCTOR_JSON_SERIALIZE: - funcname = "JSON_SERIALIZE"; - break; - case JSCTOR_JSON_OBJECT: - funcname = "JSON_OBJECT"; - break; - case JSCTOR_JSON_ARRAY: - funcname = "JSON_ARRAY"; - break; - case JSCTOR_JSON_OBJECTAGG: - get_json_agg_constructor(ctor, context, "JSON_OBJECTAGG", true); - return; - case JSCTOR_JSON_ARRAYAGG: - get_json_agg_constructor(ctor, context, "JSON_ARRAYAGG", false); - return; - default: - elog(ERROR, "invalid JsonConstructorExprType %d", ctor->type); - } - - appendStringInfo(buf, "%s(", funcname); - - nargs = 0; - foreach(lc, ctor->args) - { - if (nargs > 0) - { - const char *sep = ctor->type == JSCTOR_JSON_OBJECT && - (nargs % 2) != 0 ? " : " : ", "; - - appendStringInfoString(buf, sep); - } - - get_rule_expr((Node *) lfirst(lc), context, true); - - nargs++; - } - - get_json_constructor_options(ctor, buf); - - appendStringInfo(buf, ")"); -} - - /* - * get_agg_expr_helper - Parse back an Aggref node + * get_agg_expr - Parse back an Aggref node */ static void -get_agg_expr_helper(Aggref *aggref, deparse_context *context, - Aggref *original_aggref, const char *funcname, - const char *options, bool is_json_objectagg) +get_agg_expr(Aggref *aggref, deparse_context *context, + Aggref *original_aggref) { StringInfo buf = context->buf; Oid argtypes[FUNC_MAX_ARGS]; int nargs; - bool use_variadic = false; + bool use_variadic; /* * For a combining aggregate, we look up and deparse the corresponding @@ -10272,14 +9939,13 @@ get_agg_expr_helper(Aggref *aggref, deparse_context *context, /* Extract the argument types as seen by the parser */ nargs = get_aggregate_argtypes(aggref, argtypes); - if (!funcname) - funcname = generate_function_name(aggref->aggfnoid, nargs, NIL, - argtypes, aggref->aggvariadic, - &use_variadic, - context->special_exprkind); - /* Print the aggregate name, schema-qualified if needed */ - appendStringInfo(buf, "%s(%s", funcname, + appendStringInfo(buf, "%s(%s", + generate_function_name(aggref->aggfnoid, nargs, + NIL, argtypes, + aggref->aggvariadic, + &use_variadic, + context->special_exprkind), (aggref->aggdistinct != NIL) ? "DISTINCT " : ""); if (AGGKIND_IS_ORDERED_SET(aggref->aggkind)) @@ -10315,18 +9981,7 @@ get_agg_expr_helper(Aggref *aggref, deparse_context *context, if (tle->resjunk) continue; if (i++ > 0) - { - if (is_json_objectagg) - { - if (i > 2) - break; /* skip ABSENT ON NULL and WITH UNIQUE - * args */ - - appendStringInfoString(buf, " : "); - } - else - appendStringInfoString(buf, ", "); - } + appendStringInfoString(buf, ", "); if (use_variadic && i == nargs) appendStringInfoString(buf, "VARIADIC "); get_rule_expr(arg, context, true); @@ -10340,9 +9995,6 @@ get_agg_expr_helper(Aggref *aggref, deparse_context *context, } } - if (options) - appendStringInfoString(buf, options); - if (aggref->aggfilter != NULL) { appendStringInfoString(buf, ") FILTER (WHERE "); @@ -10352,16 +10004,6 @@ get_agg_expr_helper(Aggref *aggref, deparse_context *context, appendStringInfoChar(buf, ')'); } -/* - * get_agg_expr - Parse back an Aggref node - */ -static void -get_agg_expr(Aggref *aggref, deparse_context *context, Aggref *original_aggref) -{ - get_agg_expr_helper(aggref, context, original_aggref, NULL, NULL, - false); -} - /* * This is a helper function for get_agg_expr(). It's used when we deparse * a combining Aggref; resolve_special_varno locates the corresponding partial @@ -10381,12 +10023,10 @@ get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg) } /* - * get_windowfunc_expr_helper - Parse back a WindowFunc node + * get_windowfunc_expr - Parse back a WindowFunc node */ static void -get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context, - const char *funcname, const char *options, - bool is_json_objectagg) +get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context) { StringInfo buf = context->buf; Oid argtypes[FUNC_MAX_ARGS]; @@ -10410,30 +10050,16 @@ get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context, nargs++; } - if (!funcname) - funcname = generate_function_name(wfunc->winfnoid, nargs, argnames, - argtypes, false, NULL, - context->special_exprkind); - - appendStringInfo(buf, "%s(", funcname); - + appendStringInfo(buf, "%s(", + generate_function_name(wfunc->winfnoid, nargs, + argnames, argtypes, + false, NULL, + context->special_exprkind)); /* winstar can be set only in zero-argument aggregates */ if (wfunc->winstar) appendStringInfoChar(buf, '*'); else - { - if (is_json_objectagg) - { - get_rule_expr((Node *) linitial(wfunc->args), context, false); - appendStringInfoString(buf, " : "); - get_rule_expr((Node *) lsecond(wfunc->args), context, false); - } - else - get_rule_expr((Node *) wfunc->args, context, true); - } - - if (options) - appendStringInfoString(buf, options); + get_rule_expr((Node *) wfunc->args, context, true); if (wfunc->aggfilter != NULL) { @@ -10470,15 +10096,6 @@ get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context, } } -/* - * get_windowfunc_expr - Parse back a WindowFunc node - */ -static void -get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context) -{ - get_windowfunc_expr_helper(wfunc, context, NULL, NULL, false); -} - /* * get_func_sql_syntax - Parse back a SQL-syntax function call * @@ -10719,31 +10336,6 @@ get_func_sql_syntax(FuncExpr *expr, deparse_context *context) return false; } -/* - * get_json_agg_constructor - Parse back an aggregate JsonConstructorExpr node - */ -static void -get_json_agg_constructor(JsonConstructorExpr *ctor, deparse_context *context, - const char *funcname, bool is_json_objectagg) -{ - StringInfoData options; - - initStringInfo(&options); - get_json_constructor_options(ctor, &options); - - if (IsA(ctor->func, Aggref)) - get_agg_expr_helper((Aggref *) ctor->func, context, - (Aggref *) ctor->func, - funcname, options.data, is_json_objectagg); - else if (IsA(ctor->func, WindowFunc)) - get_windowfunc_expr_helper((WindowFunc *) ctor->func, context, - funcname, options.data, - is_json_objectagg); - else - elog(ERROR, "invalid JsonConstructorExpr underlying node type: %d", - nodeTag(ctor->func)); -} - /* ---------- * get_coercion_expr * @@ -11113,14 +10705,16 @@ get_sublink_expr(SubLink *sublink, deparse_context *context) /* ---------- - * get_xmltable - Parse back a XMLTABLE function + * get_tablefunc - Parse back a table function * ---------- */ static void -get_xmltable(TableFunc *tf, deparse_context *context, bool showimplicit) +get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit) { StringInfo buf = context->buf; + /* XMLTABLE is the only existing implementation. */ + appendStringInfoString(buf, "XMLTABLE("); if (tf->ns_uris != NIL) @@ -11211,271 +10805,6 @@ get_xmltable(TableFunc *tf, deparse_context *context, bool showimplicit) appendStringInfoChar(buf, ')'); } -/* - * get_json_nested_columns - Parse back nested JSON_TABLE columns - */ -static void -get_json_table_nested_columns(TableFunc *tf, Node *node, - deparse_context *context, bool showimplicit, - bool needcomma) -{ - if (IsA(node, JsonTableSibling)) - { - JsonTableSibling *n = (JsonTableSibling *) node; - - get_json_table_nested_columns(tf, n->larg, context, showimplicit, - needcomma); - get_json_table_nested_columns(tf, n->rarg, context, showimplicit, true); - } - else - { - JsonTableParent *n = castNode(JsonTableParent, node); - - if (needcomma) - appendStringInfoChar(context->buf, ','); - - appendStringInfoChar(context->buf, ' '); - appendContextKeyword(context, "NESTED PATH ", 0, 0, 0); - get_const_expr(n->path, context, -1); - appendStringInfo(context->buf, " AS %s", quote_identifier(n->name)); - get_json_table_columns(tf, n, context, showimplicit); - } -} - -/* - * get_json_table_plan - Parse back a JSON_TABLE plan - */ -static void -get_json_table_plan(TableFunc *tf, Node *node, deparse_context *context, - bool parenthesize) -{ - if (parenthesize) - appendStringInfoChar(context->buf, '('); - - if (IsA(node, JsonTableSibling)) - { - JsonTableSibling *n = (JsonTableSibling *) node; - - get_json_table_plan(tf, n->larg, context, - IsA(n->larg, JsonTableSibling) || - castNode(JsonTableParent, n->larg)->child); - - appendStringInfoString(context->buf, n->cross ? " CROSS " : " UNION "); - - get_json_table_plan(tf, n->rarg, context, - IsA(n->rarg, JsonTableSibling) || - castNode(JsonTableParent, n->rarg)->child); - } - else - { - JsonTableParent *n = castNode(JsonTableParent, node); - - appendStringInfoString(context->buf, quote_identifier(n->name)); - - if (n->child) - { - appendStringInfoString(context->buf, - n->outerJoin ? " OUTER " : " INNER "); - get_json_table_plan(tf, n->child, context, - IsA(n->child, JsonTableSibling)); - } - } - - if (parenthesize) - appendStringInfoChar(context->buf, ')'); -} - -/* - * get_json_table_columns - Parse back JSON_TABLE columns - */ -static void -get_json_table_columns(TableFunc *tf, JsonTableParent *node, - deparse_context *context, bool showimplicit) -{ - StringInfo buf = context->buf; - JsonExpr *jexpr = castNode(JsonExpr, tf->docexpr); - ListCell *lc_colname; - ListCell *lc_coltype; - ListCell *lc_coltypmod; - ListCell *lc_colvarexpr; - int colnum = 0; - - appendStringInfoChar(buf, ' '); - appendContextKeyword(context, "COLUMNS (", 0, 0, 0); - - if (PRETTY_INDENT(context)) - context->indentLevel += PRETTYINDENT_VAR; - - forfour(lc_colname, tf->colnames, - lc_coltype, tf->coltypes, - lc_coltypmod, tf->coltypmods, - lc_colvarexpr, tf->colvalexprs) - { - char *colname = strVal(lfirst(lc_colname)); - JsonExpr *colexpr; - Oid typid; - int32 typmod; - bool ordinality; - JsonBehaviorType default_behavior; - - typid = lfirst_oid(lc_coltype); - typmod = lfirst_int(lc_coltypmod); - colexpr = castNode(JsonExpr, lfirst(lc_colvarexpr)); - - if (colnum < node->colMin) - { - colnum++; - continue; - } - - if (colnum > node->colMax) - break; - - if (colnum > node->colMin) - appendStringInfoString(buf, ", "); - - colnum++; - - ordinality = !colexpr; - - appendContextKeyword(context, "", 0, 0, 0); - - appendStringInfo(buf, "%s %s", quote_identifier(colname), - ordinality ? "FOR ORDINALITY" : - format_type_with_typemod(typid, typmod)); - if (ordinality) - continue; - - if (colexpr->op == JSON_EXISTS_OP) - { - appendStringInfoString(buf, " EXISTS"); - default_behavior = JSON_BEHAVIOR_FALSE; - } - else - { - if (colexpr->op == JSON_QUERY_OP) - { - char typcategory; - bool typispreferred; - - get_type_category_preferred(typid, &typcategory, &typispreferred); - - if (typcategory == TYPCATEGORY_STRING) - appendStringInfoString(buf, - colexpr->format->format_type == JS_FORMAT_JSONB ? - " FORMAT JSONB" : " FORMAT JSON"); - } - - default_behavior = JSON_BEHAVIOR_NULL; - } - - if (jexpr->on_error->btype == JSON_BEHAVIOR_ERROR) - default_behavior = JSON_BEHAVIOR_ERROR; - - appendStringInfoString(buf, " PATH "); - - get_json_path_spec(colexpr->path_spec, context, showimplicit); - - get_json_expr_options(colexpr, context, default_behavior); - } - - if (node->child) - get_json_table_nested_columns(tf, node->child, context, showimplicit, - node->colMax >= node->colMin); - - if (PRETTY_INDENT(context)) - context->indentLevel -= PRETTYINDENT_VAR; - - appendContextKeyword(context, ")", 0, 0, 0); -} - -/* ---------- - * get_json_table - Parse back a JSON_TABLE function - * ---------- - */ -static void -get_json_table(TableFunc *tf, deparse_context *context, bool showimplicit) -{ - StringInfo buf = context->buf; - JsonExpr *jexpr = castNode(JsonExpr, tf->docexpr); - JsonTableParent *root = castNode(JsonTableParent, tf->plan); - - appendStringInfoString(buf, "JSON_TABLE("); - - if (PRETTY_INDENT(context)) - context->indentLevel += PRETTYINDENT_VAR; - - appendContextKeyword(context, "", 0, 0, 0); - - get_rule_expr(jexpr->formatted_expr, context, showimplicit); - - appendStringInfoString(buf, ", "); - - get_const_expr(root->path, context, -1); - - appendStringInfo(buf, " AS %s", quote_identifier(root->name)); - - if (jexpr->passing_values) - { - ListCell *lc1, - *lc2; - bool needcomma = false; - - appendStringInfoChar(buf, ' '); - appendContextKeyword(context, "PASSING ", 0, 0, 0); - - if (PRETTY_INDENT(context)) - context->indentLevel += PRETTYINDENT_VAR; - - forboth(lc1, jexpr->passing_names, - lc2, jexpr->passing_values) - { - if (needcomma) - appendStringInfoString(buf, ", "); - needcomma = true; - - appendContextKeyword(context, "", 0, 0, 0); - - get_rule_expr((Node *) lfirst(lc2), context, false); - appendStringInfo(buf, " AS %s", - quote_identifier((lfirst_node(String, lc1))->sval) - ); - } - - if (PRETTY_INDENT(context)) - context->indentLevel -= PRETTYINDENT_VAR; - } - - get_json_table_columns(tf, root, context, showimplicit); - - appendStringInfoChar(buf, ' '); - appendContextKeyword(context, "PLAN ", 0, 0, 0); - get_json_table_plan(tf, (Node *) root, context, true); - - if (jexpr->on_error->btype != JSON_BEHAVIOR_EMPTY) - get_json_behavior(jexpr->on_error, context, "ERROR"); - - if (PRETTY_INDENT(context)) - context->indentLevel -= PRETTYINDENT_VAR; - - appendContextKeyword(context, ")", 0, 0, 0); -} - -/* ---------- - * get_tablefunc - Parse back a table function - * ---------- - */ -static void -get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit) -{ - /* XMLTABLE and JSON_TABLE are the only existing implementations. */ - - if (tf->functype == TFT_XMLTABLE) - get_xmltable(tf, context, showimplicit); - else if (tf->functype == TFT_JSON_TABLE) - get_json_table(tf, context, showimplicit); -} - /* ---------- * get_from_clause - Parse back a FROM clause * diff --git a/src/backend/utils/misc/queryjumble.c b/src/backend/utils/misc/queryjumble.c index eeaa0b31fe2..a67487e5fe8 100644 --- a/src/backend/utils/misc/queryjumble.c +++ b/src/backend/utils/misc/queryjumble.c @@ -737,76 +737,6 @@ JumbleExpr(JumbleState *jstate, Node *node) JumbleExpr(jstate, (Node *) conf->exclRelTlist); } break; - case T_JsonFormat: - { - JsonFormat *format = (JsonFormat *) node; - - APP_JUMB(format->format_type); - APP_JUMB(format->encoding); - } - break; - case T_JsonReturning: - { - JsonReturning *returning = (JsonReturning *) node; - - JumbleExpr(jstate, (Node *) returning->format); - APP_JUMB(returning->typid); - APP_JUMB(returning->typmod); - } - break; - case T_JsonValueExpr: - { - JsonValueExpr *expr = (JsonValueExpr *) node; - - JumbleExpr(jstate, (Node *) expr->raw_expr); - JumbleExpr(jstate, (Node *) expr->formatted_expr); - JumbleExpr(jstate, (Node *) expr->format); - } - break; - case T_JsonConstructorExpr: - { - JsonConstructorExpr *ctor = (JsonConstructorExpr *) node; - - APP_JUMB(ctor->type); - JumbleExpr(jstate, (Node *) ctor->args); - JumbleExpr(jstate, (Node *) ctor->func); - JumbleExpr(jstate, (Node *) ctor->coercion); - JumbleExpr(jstate, (Node *) ctor->returning); - APP_JUMB(ctor->absent_on_null); - APP_JUMB(ctor->unique); - } - break; - case T_JsonIsPredicate: - { - JsonIsPredicate *pred = (JsonIsPredicate *) node; - - JumbleExpr(jstate, (Node *) pred->expr); - JumbleExpr(jstate, (Node *) pred->format); - APP_JUMB(pred->item_type); - APP_JUMB(pred->unique_keys); - } - break; - case T_JsonExpr: - { - JsonExpr *jexpr = (JsonExpr *) node; - - APP_JUMB(jexpr->op); - JumbleExpr(jstate, jexpr->formatted_expr); - JumbleExpr(jstate, jexpr->path_spec); - foreach(temp, jexpr->passing_names) - { - APP_JUMB_STRING(lfirst_node(String, temp)->sval); - } - JumbleExpr(jstate, (Node *) jexpr->passing_values); - if (jexpr->on_empty) - { - APP_JUMB(jexpr->on_empty->btype); - JumbleExpr(jstate, jexpr->on_empty->default_expr); - } - APP_JUMB(jexpr->on_error->btype); - JumbleExpr(jstate, jexpr->on_error->default_expr); - } - break; case T_List: foreach(temp, (List *) node) { @@ -879,11 +809,9 @@ JumbleExpr(JumbleState *jstate, Node *node) { TableFunc *tablefunc = (TableFunc *) node; - APP_JUMB(tablefunc->functype); JumbleExpr(jstate, tablefunc->docexpr); JumbleExpr(jstate, tablefunc->rowexpr); JumbleExpr(jstate, (Node *) tablefunc->colexprs); - JumbleExpr(jstate, (Node *) tablefunc->colvalexprs); } break; case T_TableSampleClause: diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 7482c85a86c..78d25036b35 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -57,6 +57,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202208251 +#define CATALOG_VERSION_NO 202209011 #endif diff --git a/src/include/catalog/pg_aggregate.dat b/src/include/catalog/pg_aggregate.dat index 86cc6507983..b9110a52985 100644 --- a/src/include/catalog/pg_aggregate.dat +++ b/src/include/catalog/pg_aggregate.dat @@ -571,36 +571,14 @@ # json { aggfnoid => 'json_agg', aggtransfn => 'json_agg_transfn', aggfinalfn => 'json_agg_finalfn', aggtranstype => 'internal' }, -{ aggfnoid => 'json_agg_strict', aggtransfn => 'json_agg_strict_transfn', - aggfinalfn => 'json_agg_finalfn', aggtranstype => 'internal' }, { aggfnoid => 'json_object_agg', aggtransfn => 'json_object_agg_transfn', aggfinalfn => 'json_object_agg_finalfn', aggtranstype => 'internal' }, -{ aggfnoid => 'json_object_agg_unique', - aggtransfn => 'json_object_agg_unique_transfn', - aggfinalfn => 'json_object_agg_finalfn', aggtranstype => 'internal' }, -{ aggfnoid => 'json_object_agg_strict', - aggtransfn => 'json_object_agg_strict_transfn', - aggfinalfn => 'json_object_agg_finalfn', aggtranstype => 'internal' }, -{ aggfnoid => 'json_object_agg_unique_strict', - aggtransfn => 'json_object_agg_unique_strict_transfn', - aggfinalfn => 'json_object_agg_finalfn', aggtranstype => 'internal' }, # jsonb { aggfnoid => 'jsonb_agg', aggtransfn => 'jsonb_agg_transfn', aggfinalfn => 'jsonb_agg_finalfn', aggtranstype => 'internal' }, -{ aggfnoid => 'jsonb_agg_strict', aggtransfn => 'jsonb_agg_strict_transfn', - aggfinalfn => 'jsonb_agg_finalfn', aggtranstype => 'internal' }, { aggfnoid => 'jsonb_object_agg', aggtransfn => 'jsonb_object_agg_transfn', aggfinalfn => 'jsonb_object_agg_finalfn', aggtranstype => 'internal' }, -{ aggfnoid => 'jsonb_object_agg_unique', - aggtransfn => 'jsonb_object_agg_unique_transfn', - aggfinalfn => 'jsonb_object_agg_finalfn', aggtranstype => 'internal' }, -{ aggfnoid => 'jsonb_object_agg_strict', - aggtransfn => 'jsonb_object_agg_strict_transfn', - aggfinalfn => 'jsonb_object_agg_finalfn', aggtranstype => 'internal' }, -{ aggfnoid => 'jsonb_object_agg_unique_strict', - aggtransfn => 'jsonb_object_agg_unique_strict_transfn', - aggfinalfn => 'jsonb_object_agg_finalfn', aggtranstype => 'internal' }, # ordered-set and hypothetical-set aggregates { aggfnoid => 'percentile_disc(float8,anyelement)', aggkind => 'o', diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index be47583122b..a07e737a337 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -8785,10 +8785,6 @@ proname => 'json_agg_transfn', proisstrict => 'f', provolatile => 's', prorettype => 'internal', proargtypes => 'internal anyelement', prosrc => 'json_agg_transfn' }, -{ oid => '6208', descr => 'json aggregate transition function', - proname => 'json_agg_strict_transfn', proisstrict => 'f', provolatile => 's', - prorettype => 'internal', proargtypes => 'internal anyelement', - prosrc => 'json_agg_strict_transfn' }, { oid => '3174', descr => 'json aggregate final function', proname => 'json_agg_finalfn', proisstrict => 'f', prorettype => 'json', proargtypes => 'internal', prosrc => 'json_agg_finalfn' }, @@ -8796,29 +8792,10 @@ proname => 'json_agg', prokind => 'a', proisstrict => 'f', provolatile => 's', prorettype => 'json', proargtypes => 'anyelement', prosrc => 'aggregate_dummy' }, -{ oid => '6209', descr => 'aggregate input into json', - proname => 'json_agg_strict', prokind => 'a', proisstrict => 'f', - provolatile => 's', prorettype => 'json', proargtypes => 'anyelement', - prosrc => 'aggregate_dummy' }, { oid => '3180', descr => 'json object aggregate transition function', proname => 'json_object_agg_transfn', proisstrict => 'f', provolatile => 's', prorettype => 'internal', proargtypes => 'internal any any', prosrc => 'json_object_agg_transfn' }, -{ oid => '6210', descr => 'json object aggregate transition function', - proname => 'json_object_agg_strict_transfn', proisstrict => 'f', - provolatile => 's', prorettype => 'internal', - proargtypes => 'internal any any', - prosrc => 'json_object_agg_strict_transfn' }, -{ oid => '6211', descr => 'json object aggregate transition function', - proname => 'json_object_agg_unique_transfn', proisstrict => 'f', - provolatile => 's', prorettype => 'internal', - proargtypes => 'internal any any', - prosrc => 'json_object_agg_unique_transfn' }, -{ oid => '6212', descr => 'json object aggregate transition function', - proname => 'json_object_agg_unique_strict_transfn', proisstrict => 'f', - provolatile => 's', prorettype => 'internal', - proargtypes => 'internal any any', - prosrc => 'json_object_agg_unique_strict_transfn' }, { oid => '3196', descr => 'json object aggregate final function', proname => 'json_object_agg_finalfn', proisstrict => 'f', prorettype => 'json', proargtypes => 'internal', @@ -8827,20 +8804,6 @@ proname => 'json_object_agg', prokind => 'a', proisstrict => 'f', provolatile => 's', prorettype => 'json', proargtypes => 'any any', prosrc => 'aggregate_dummy' }, -{ oid => '6213', descr => 'aggregate non-NULL input into a json object', - proname => 'json_object_agg_strict', prokind => 'a', proisstrict => 'f', - provolatile => 's', prorettype => 'json', proargtypes => 'any any', - prosrc => 'aggregate_dummy' }, -{ oid => '6214', - descr => 'aggregate input into a json object with unique keys', - proname => 'json_object_agg_unique', prokind => 'a', proisstrict => 'f', - provolatile => 's', prorettype => 'json', proargtypes => 'any any', - prosrc => 'aggregate_dummy' }, -{ oid => '6215', - descr => 'aggregate non-NULL input into a json object with unique keys', - proname => 'json_object_agg_unique_strict', prokind => 'a', - proisstrict => 'f', provolatile => 's', prorettype => 'json', - proargtypes => 'any any', prosrc => 'aggregate_dummy' }, { oid => '3198', descr => 'build a json array from any inputs', proname => 'json_build_array', provariadic => 'any', proisstrict => 'f', provolatile => 's', prorettype => 'json', proargtypes => 'any', @@ -9713,10 +9676,6 @@ proname => 'jsonb_agg_transfn', proisstrict => 'f', provolatile => 's', prorettype => 'internal', proargtypes => 'internal anyelement', prosrc => 'jsonb_agg_transfn' }, -{ oid => '6216', descr => 'jsonb aggregate transition function', - proname => 'jsonb_agg_strict_transfn', proisstrict => 'f', provolatile => 's', - prorettype => 'internal', proargtypes => 'internal anyelement', - prosrc => 'jsonb_agg_strict_transfn' }, { oid => '3266', descr => 'jsonb aggregate final function', proname => 'jsonb_agg_finalfn', proisstrict => 'f', provolatile => 's', prorettype => 'jsonb', proargtypes => 'internal', @@ -9725,29 +9684,10 @@ proname => 'jsonb_agg', prokind => 'a', proisstrict => 'f', provolatile => 's', prorettype => 'jsonb', proargtypes => 'anyelement', prosrc => 'aggregate_dummy' }, -{ oid => '6217', descr => 'aggregate input into jsonb skipping nulls', - proname => 'jsonb_agg_strict', prokind => 'a', proisstrict => 'f', - provolatile => 's', prorettype => 'jsonb', proargtypes => 'anyelement', - prosrc => 'aggregate_dummy' }, { oid => '3268', descr => 'jsonb object aggregate transition function', proname => 'jsonb_object_agg_transfn', proisstrict => 'f', provolatile => 's', prorettype => 'internal', proargtypes => 'internal any any', prosrc => 'jsonb_object_agg_transfn' }, -{ oid => '6218', descr => 'jsonb object aggregate transition function', - proname => 'jsonb_object_agg_strict_transfn', proisstrict => 'f', - provolatile => 's', prorettype => 'internal', - proargtypes => 'internal any any', - prosrc => 'jsonb_object_agg_strict_transfn' }, -{ oid => '6219', descr => 'jsonb object aggregate transition function', - proname => 'jsonb_object_agg_unique_transfn', proisstrict => 'f', - provolatile => 's', prorettype => 'internal', - proargtypes => 'internal any any', - prosrc => 'jsonb_object_agg_unique_transfn' }, -{ oid => '6220', descr => 'jsonb object aggregate transition function', - proname => 'jsonb_object_agg_unique_strict_transfn', proisstrict => 'f', - provolatile => 's', prorettype => 'internal', - proargtypes => 'internal any any', - prosrc => 'jsonb_object_agg_unique_strict_transfn' }, { oid => '3269', descr => 'jsonb object aggregate final function', proname => 'jsonb_object_agg_finalfn', proisstrict => 'f', provolatile => 's', prorettype => 'jsonb', proargtypes => 'internal', @@ -9756,20 +9696,6 @@ proname => 'jsonb_object_agg', prokind => 'a', proisstrict => 'f', prorettype => 'jsonb', proargtypes => 'any any', prosrc => 'aggregate_dummy' }, -{ oid => '6221', descr => 'aggregate non-NULL inputs into jsonb object', - proname => 'jsonb_object_agg_strict', prokind => 'a', proisstrict => 'f', - prorettype => 'jsonb', proargtypes => 'any any', - prosrc => 'aggregate_dummy' }, -{ oid => '6222', - descr => 'aggregate inputs into jsonb object checking key uniqueness', - proname => 'jsonb_object_agg_unique', prokind => 'a', proisstrict => 'f', - prorettype => 'jsonb', proargtypes => 'any any', - prosrc => 'aggregate_dummy' }, -{ oid => '6223', - descr => 'aggregate non-NULL inputs into jsonb object checking key uniqueness', - proname => 'jsonb_object_agg_unique_strict', prokind => 'a', - proisstrict => 'f', prorettype => 'jsonb', proargtypes => 'any any', - prosrc => 'aggregate_dummy' }, { oid => '3271', descr => 'build a jsonb array from any inputs', proname => 'jsonb_build_array', provariadic => 'any', proisstrict => 'f', provolatile => 's', prorettype => 'jsonb', proargtypes => 'any', diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h index c8ef917ffe0..e14f15d435b 100644 --- a/src/include/executor/execExpr.h +++ b/src/include/executor/execExpr.h @@ -21,9 +21,6 @@ struct ExprEvalStep; struct SubscriptingRefState; struct ScalarArrayOpExprHashTable; -struct JsonbValue; -struct JsonExprState; -struct JsonConstructorExprState; /* Bits in ExprState->flags (see also execnodes.h for public flag bits): */ /* expression's interpreter has been initialized */ @@ -242,9 +239,6 @@ typedef enum ExprEvalOp EEOP_GROUPING_FUNC, EEOP_WINDOW_FUNC, EEOP_SUBPLAN, - EEOP_JSON_CONSTRUCTOR, - EEOP_IS_JSON, - EEOP_JSONEXPR, /* aggregation related nodes */ EEOP_AGG_STRICT_DESERIALIZE, @@ -679,25 +673,6 @@ typedef struct ExprEvalStep int transno; int setoff; } agg_trans; - - /* for EEOP_JSON_CONSTRUCTOR */ - struct - { - struct JsonConstructorExprState *jcstate; - } json_constructor; - - /* for EEOP_IS_JSON */ - struct - { - JsonIsPredicate *pred; /* original expression node */ - } is_json; - - /* for EEOP_JSONEXPR */ - struct - { - struct JsonExprState *jsestate; - } jsonexpr; - } d; } ExprEvalStep; @@ -742,64 +717,6 @@ typedef struct SubscriptExecSteps ExecEvalSubroutine sbs_fetch_old; /* fetch old value for assignment */ } SubscriptExecSteps; -/* EEOP_JSON_CONSTRUCTOR state, too big to inline */ -typedef struct JsonConstructorExprState -{ - JsonConstructorExpr *constructor; - Datum *arg_values; - bool *arg_nulls; - Oid *arg_types; - struct - { - int category; - Oid outfuncid; - } *arg_type_cache; /* cache for datum_to_json[b]() */ - int nargs; -} JsonConstructorExprState; - -/* EEOP_JSONEXPR state, too big to inline */ -typedef struct JsonExprState -{ - JsonExpr *jsexpr; /* original expression node */ - - struct - { - FmgrInfo func; /* typinput function for output type */ - Oid typioparam; - } input; /* I/O info for output type */ - - NullableDatum - *formatted_expr, /* formatted context item value */ - *res_expr, /* result item */ - *coercion_expr, /* input for JSON item coercion */ - *pathspec; /* path specification value */ - - ExprState *result_expr; /* coerced to output type */ - ExprState *default_on_empty; /* ON EMPTY DEFAULT expression */ - ExprState *default_on_error; /* ON ERROR DEFAULT expression */ - List *args; /* passing arguments */ - - void *cache; /* cache for json_populate_type() */ - - struct JsonCoercionsState - { - struct JsonCoercionState - { - JsonCoercion *coercion; /* coercion expression */ - ExprState *estate; /* coercion expression state */ - } null, - string, - numeric , - boolean, - date, - time, - timetz, - timestamp, - timestamptz, - composite; - } coercions; /* states for coercion from SQL/JSON item - * types directly to the output type */ -} JsonExprState; /* functions in execExpr.c */ extern void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s); @@ -850,7 +767,6 @@ extern void ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, extern void ExecEvalConstraintNotNull(ExprState *state, ExprEvalStep *op); extern void ExecEvalConstraintCheck(ExprState *state, ExprEvalStep *op); extern void ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op); -extern void ExecEvalJsonIsPredicate(ExprState *state, ExprEvalStep *op); extern void ExecEvalGroupingFunc(ExprState *state, ExprEvalStep *op); extern void ExecEvalSubPlan(ExprState *state, ExprEvalStep *op, ExprContext *econtext); @@ -858,20 +774,6 @@ extern void ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext); extern void ExecEvalSysVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext, TupleTableSlot *slot); -extern void ExecEvalJsonConstructor(ExprState *state, ExprEvalStep *op, - ExprContext *econtext); -extern void ExecEvalJson(ExprState *state, ExprEvalStep *op, - ExprContext *econtext); -extern Datum ExecPrepareJsonItemCoercion(struct JsonbValue *item, - JsonReturning *returning, - struct JsonCoercionsState *coercions, - struct JsonCoercionState **pjcstate); -extern bool ExecEvalJsonNeedsSubTransaction(JsonExpr *jsexpr, - struct JsonCoercionsState *); -extern Datum ExecEvalExprPassingCaseValue(ExprState *estate, - ExprContext *econtext, bool *isnull, - Datum caseval_datum, - bool caseval_isnull); extern void ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroup, ExprContext *aggcontext); diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index dd0d519426e..b9f9c3e43fe 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -273,8 +273,6 @@ ExecProcNode(PlanState *node) */ extern ExprState *ExecInitExpr(Expr *node, PlanState *parent); extern ExprState *ExecInitExprWithParams(Expr *node, ParamListInfo ext_params); -extern ExprState *ExecInitExprWithCaseValue(Expr *node, PlanState *parent, - Datum *caseval, bool *casenull); extern ExprState *ExecInitQual(List *qual, PlanState *parent); extern ExprState *ExecInitCheck(List *qual, PlanState *parent); extern List *ExecInitExprList(List *nodes, PlanState *parent); diff --git a/src/include/nodes/makefuncs.h b/src/include/nodes/makefuncs.h index 06e6369026a..50de4c62af7 100644 --- a/src/include/nodes/makefuncs.h +++ b/src/include/nodes/makefuncs.h @@ -106,16 +106,4 @@ extern GroupingSet *makeGroupingSet(GroupingSetKind kind, List *content, int loc extern VacuumRelation *makeVacuumRelation(RangeVar *relation, Oid oid, List *va_cols); -extern JsonFormat *makeJsonFormat(JsonFormatType type, JsonEncoding encoding, - int location); -extern JsonValueExpr *makeJsonValueExpr(Expr *expr, JsonFormat *format); -extern JsonBehavior *makeJsonBehavior(JsonBehaviorType type, Node *expr); -extern Node *makeJsonTableJoinedPlan(JsonTablePlanJoinType type, - Node *plan1, Node *plan2, int location); -extern Node *makeJsonKeyValue(Node *key, Node *value); -extern Node *makeJsonIsPredicate(Node *expr, JsonFormat *format, - JsonValueType item_type, bool unique_keys, - int location); -extern JsonEncoding makeJsonEncoding(char *name); - #endif /* MAKEFUNC_H */ diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 2e49cf20f71..ff2c59011d3 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1608,293 +1608,6 @@ typedef struct TriggerTransition bool isTable; } TriggerTransition; -/* Nodes for SQL/JSON support */ - -/* - * JsonQuotes - - * representation of [KEEP|OMIT] QUOTES clause for JSON_QUERY() - */ -typedef enum JsonQuotes -{ - JS_QUOTES_UNSPEC, /* unspecified */ - JS_QUOTES_KEEP, /* KEEP QUOTES */ - JS_QUOTES_OMIT /* OMIT QUOTES */ -} JsonQuotes; - -/* - * JsonTableColumnType - - * enumeration of JSON_TABLE column types - */ -typedef enum JsonTableColumnType -{ - JTC_FOR_ORDINALITY, - JTC_REGULAR, - JTC_EXISTS, - JTC_FORMATTED, - JTC_NESTED, -} JsonTableColumnType; - -/* - * JsonOutput - - * representation of JSON output clause (RETURNING type [FORMAT format]) - */ -typedef struct JsonOutput -{ - NodeTag type; - TypeName *typeName; /* RETURNING type name, if specified */ - JsonReturning *returning; /* RETURNING FORMAT clause and type Oids */ -} JsonOutput; - -/* - * JsonArgument - - * representation of argument from JSON PASSING clause - */ -typedef struct JsonArgument -{ - NodeTag type; - JsonValueExpr *val; /* argument value expression */ - char *name; /* argument name */ -} JsonArgument; - -/* - * JsonCommon - - * representation of common syntax of functions using JSON path - */ -typedef struct JsonCommon -{ - NodeTag type; - JsonValueExpr *expr; /* context item expression */ - Node *pathspec; /* JSON path specification expression */ - char *pathname; /* path name, if any */ - List *passing; /* list of PASSING clause arguments, if any */ - int location; /* token location, or -1 if unknown */ -} JsonCommon; - -/* - * JsonFuncExpr - - * untransformed representation of JSON function expressions - */ -typedef struct JsonFuncExpr -{ - NodeTag type; - JsonExprOp op; /* expression type */ - JsonCommon *common; /* common syntax */ - JsonOutput *output; /* output clause, if specified */ - JsonBehavior *on_empty; /* ON EMPTY behavior, if specified */ - JsonBehavior *on_error; /* ON ERROR behavior, if specified */ - JsonWrapper wrapper; /* array wrapper behavior (JSON_QUERY only) */ - bool omit_quotes; /* omit or keep quotes? (JSON_QUERY only) */ - int location; /* token location, or -1 if unknown */ -} JsonFuncExpr; - -/* - * JsonTableColumn - - * untransformed representation of JSON_TABLE column - */ -typedef struct JsonTableColumn -{ - NodeTag type; - JsonTableColumnType coltype; /* column type */ - char *name; /* column name */ - TypeName *typeName; /* column type name */ - char *pathspec; /* path specification, if any */ - char *pathname; /* path name, if any */ - JsonFormat *format; /* JSON format clause, if specified */ - JsonWrapper wrapper; /* WRAPPER behavior for formatted columns */ - bool omit_quotes; /* omit or keep quotes on scalar strings? */ - List *columns; /* nested columns */ - JsonBehavior *on_empty; /* ON EMPTY behavior */ - JsonBehavior *on_error; /* ON ERROR behavior */ - int location; /* token location, or -1 if unknown */ -} JsonTableColumn; - -/* - * JsonTablePlanType - - * flags for JSON_TABLE plan node types representation - */ -typedef enum JsonTablePlanType -{ - JSTP_DEFAULT, - JSTP_SIMPLE, - JSTP_JOINED, -} JsonTablePlanType; - -/* - * JsonTablePlanJoinType - - * flags for JSON_TABLE join types representation - */ -typedef enum JsonTablePlanJoinType -{ - JSTPJ_INNER = 0x01, - JSTPJ_OUTER = 0x02, - JSTPJ_CROSS = 0x04, - JSTPJ_UNION = 0x08, -} JsonTablePlanJoinType; - -typedef struct JsonTablePlan JsonTablePlan; - -/* - * JsonTablePlan - - * untransformed representation of JSON_TABLE plan node - */ -struct JsonTablePlan -{ - NodeTag type; - JsonTablePlanType plan_type; /* plan type */ - JsonTablePlanJoinType join_type; /* join type (for joined plan only) */ - JsonTablePlan *plan1; /* first joined plan */ - JsonTablePlan *plan2; /* second joined plan */ - char *pathname; /* path name (for simple plan only) */ - int location; /* token location, or -1 if unknown */ -}; - -/* - * JsonTable - - * untransformed representation of JSON_TABLE - */ -typedef struct JsonTable -{ - NodeTag type; - JsonCommon *common; /* common JSON path syntax fields */ - List *columns; /* list of JsonTableColumn */ - JsonTablePlan *plan; /* join plan, if specified */ - JsonBehavior *on_error; /* ON ERROR behavior, if specified */ - Alias *alias; /* table alias in FROM clause */ - bool lateral; /* does it have LATERAL prefix? */ - int location; /* token location, or -1 if unknown */ -} JsonTable; - -/* - * JsonKeyValue - - * untransformed representation of JSON object key-value pair for - * JSON_OBJECT() and JSON_OBJECTAGG() - */ -typedef struct JsonKeyValue -{ - NodeTag type; - Expr *key; /* key expression */ - JsonValueExpr *value; /* JSON value expression */ -} JsonKeyValue; - -/* - * JsonParseExpr - - * untransformed representation of JSON() - */ -typedef struct JsonParseExpr -{ - NodeTag type; - JsonValueExpr *expr; /* string expression */ - JsonOutput *output; /* RETURNING clause, if specified */ - bool unique_keys; /* WITH UNIQUE KEYS? */ - int location; /* token location, or -1 if unknown */ -} JsonParseExpr; - -/* - * JsonScalarExpr - - * untransformed representation of JSON_SCALAR() - */ -typedef struct JsonScalarExpr -{ - NodeTag type; - Expr *expr; /* scalar expression */ - JsonOutput *output; /* RETURNING clause, if specified */ - int location; /* token location, or -1 if unknown */ -} JsonScalarExpr; - -/* - * JsonSerializeExpr - - * untransformed representation of JSON_SERIALIZE() function - */ -typedef struct JsonSerializeExpr -{ - NodeTag type; - JsonValueExpr *expr; /* json value expression */ - JsonOutput *output; /* RETURNING clause, if specified */ - int location; /* token location, or -1 if unknown */ -} JsonSerializeExpr; - -/* - * JsonObjectConstructor - - * untransformed representation of JSON_OBJECT() constructor - */ -typedef struct JsonObjectConstructor -{ - NodeTag type; - List *exprs; /* list of JsonKeyValue pairs */ - JsonOutput *output; /* RETURNING clause, if specified */ - bool absent_on_null; /* skip NULL values? */ - bool unique; /* check key uniqueness? */ - int location; /* token location, or -1 if unknown */ -} JsonObjectConstructor; - -/* - * JsonArrayConstructor - - * untransformed representation of JSON_ARRAY(element,...) constructor - */ -typedef struct JsonArrayConstructor -{ - NodeTag type; - List *exprs; /* list of JsonValueExpr elements */ - JsonOutput *output; /* RETURNING clause, if specified */ - bool absent_on_null; /* skip NULL elements? */ - int location; /* token location, or -1 if unknown */ -} JsonArrayConstructor; - -/* - * JsonArrayQueryConstructor - - * untransformed representation of JSON_ARRAY(subquery) constructor - */ -typedef struct JsonArrayQueryConstructor -{ - NodeTag type; - Node *query; /* subquery */ - JsonOutput *output; /* RETURNING clause, if specified */ - JsonFormat *format; /* FORMAT clause for subquery, if specified */ - bool absent_on_null; /* skip NULL elements? */ - int location; /* token location, or -1 if unknown */ -} JsonArrayQueryConstructor; - -/* - * JsonAggConstructor - - * common fields of untransformed representation of - * JSON_ARRAYAGG() and JSON_OBJECTAGG() - */ -typedef struct JsonAggConstructor -{ - NodeTag type; - JsonOutput *output; /* RETURNING clause, if any */ - Node *agg_filter; /* FILTER clause, if any */ - List *agg_order; /* ORDER BY clause, if any */ - struct WindowDef *over; /* OVER clause, if any */ - int location; /* token location, or -1 if unknown */ -} JsonAggConstructor; - -/* - * JsonObjectAgg - - * untransformed representation of JSON_OBJECTAGG() - */ -typedef struct JsonObjectAgg -{ - NodeTag type; - JsonAggConstructor *constructor; /* common fields */ - JsonKeyValue *arg; /* object key-value pair */ - bool absent_on_null; /* skip NULL values? */ - bool unique; /* check key uniqueness? */ -} JsonObjectAgg; - -/* - * JsonArrayAgg - - * untransformed representation of JSON_ARRRAYAGG() - */ -typedef struct JsonArrayAgg -{ - NodeTag type; - JsonAggConstructor *constructor; /* common fields */ - JsonValueExpr *arg; /* array element expression */ - bool absent_on_null; /* skip NULL elements? */ -} JsonArrayAgg; - - /***************************************************************************** * Raw Grammar Output Statements *****************************************************************************/ diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index 29ec26fe6d6..efc7ea7bee5 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -89,14 +89,8 @@ typedef struct RangeVar int location; } RangeVar; -typedef enum TableFuncType -{ - TFT_XMLTABLE, - TFT_JSON_TABLE -} TableFuncType; - /* - * TableFunc - node for a table function, such as XMLTABLE or JSON_TABLE. + * TableFunc - node for a table function, such as XMLTABLE. * * Entries in the ns_names list are either String nodes containing * literal namespace names, or NULL pointers to represent DEFAULT. @@ -104,7 +98,6 @@ typedef enum TableFuncType typedef struct TableFunc { NodeTag type; - TableFuncType functype; /* XMLTABLE or JSON_TABLE */ List *ns_uris; /* list of namespace URI expressions */ List *ns_names; /* list of namespace names or NULL */ Node *docexpr; /* input document expression */ @@ -115,9 +108,7 @@ typedef struct TableFunc List *colcollations; /* OID list of column collation OIDs */ List *colexprs; /* list of column filter expressions */ List *coldefexprs; /* list of column default expressions */ - List *colvalexprs; /* list of column value expressions */ Bitmapset *notnulls; /* nullability flag for each output column */ - Node *plan; /* JSON_TABLE plan */ int ordinalitycol; /* counts from 0; -1 if none specified */ int location; /* token location, or -1 if unknown */ } TableFunc; @@ -1384,260 +1375,6 @@ typedef struct XmlExpr int location; /* token location, or -1 if unknown */ } XmlExpr; -/* - * JsonExprOp - - * enumeration of JSON functions using JSON path - */ -typedef enum JsonExprOp -{ - JSON_VALUE_OP, /* JSON_VALUE() */ - JSON_QUERY_OP, /* JSON_QUERY() */ - JSON_EXISTS_OP, /* JSON_EXISTS() */ - JSON_TABLE_OP /* JSON_TABLE() */ -} JsonExprOp; - -/* - * JsonEncoding - - * representation of JSON ENCODING clause - */ -typedef enum JsonEncoding -{ - JS_ENC_DEFAULT, /* unspecified */ - JS_ENC_UTF8, - JS_ENC_UTF16, - JS_ENC_UTF32, -} JsonEncoding; - -/* - * JsonFormatType - - * enumeration of JSON formats used in JSON FORMAT clause - */ -typedef enum JsonFormatType -{ - JS_FORMAT_DEFAULT, /* unspecified */ - JS_FORMAT_JSON, /* FORMAT JSON [ENCODING ...] */ - JS_FORMAT_JSONB /* implicit internal format for RETURNING - * jsonb */ -} JsonFormatType; - -/* - * JsonBehaviorType - - * enumeration of behavior types used in JSON ON ... BEHAVIOR clause - * - * If enum members are reordered, get_json_behavior() from ruleutils.c - * must be updated accordingly. - */ -typedef enum JsonBehaviorType -{ - JSON_BEHAVIOR_NULL = 0, - JSON_BEHAVIOR_ERROR, - JSON_BEHAVIOR_EMPTY, - JSON_BEHAVIOR_TRUE, - JSON_BEHAVIOR_FALSE, - JSON_BEHAVIOR_UNKNOWN, - JSON_BEHAVIOR_EMPTY_ARRAY, - JSON_BEHAVIOR_EMPTY_OBJECT, - JSON_BEHAVIOR_DEFAULT -} JsonBehaviorType; - -/* - * JsonWrapper - - * representation of WRAPPER clause for JSON_QUERY() - */ -typedef enum JsonWrapper -{ - JSW_NONE, - JSW_CONDITIONAL, - JSW_UNCONDITIONAL, -} JsonWrapper; - -/* - * JsonFormat - - * representation of JSON FORMAT clause - */ -typedef struct JsonFormat -{ - NodeTag type; - JsonFormatType format_type; /* format type */ - JsonEncoding encoding; /* JSON encoding */ - int location; /* token location, or -1 if unknown */ -} JsonFormat; - -/* - * JsonReturning - - * transformed representation of JSON RETURNING clause - */ -typedef struct JsonReturning -{ - NodeTag type; - JsonFormat *format; /* output JSON format */ - Oid typid; /* target type Oid */ - int32 typmod; /* target type modifier */ -} JsonReturning; - -/* - * JsonValueExpr - - * representation of JSON value expression (expr [FORMAT json_format]) - */ -typedef struct JsonValueExpr -{ - NodeTag type; - Expr *raw_expr; /* raw expression */ - Expr *formatted_expr; /* formatted expression or NULL */ - JsonFormat *format; /* FORMAT clause, if specified */ -} JsonValueExpr; - -typedef enum JsonConstructorType -{ - JSCTOR_JSON_OBJECT = 1, - JSCTOR_JSON_ARRAY = 2, - JSCTOR_JSON_OBJECTAGG = 3, - JSCTOR_JSON_ARRAYAGG = 4, - JSCTOR_JSON_SCALAR = 5, - JSCTOR_JSON_SERIALIZE = 6, - JSCTOR_JSON_PARSE = 7 -} JsonConstructorType; - -/* - * JsonConstructorExpr - - * wrapper over FuncExpr/Aggref/WindowFunc for SQL/JSON constructors - */ -typedef struct JsonConstructorExpr -{ - Expr xpr; - JsonConstructorType type; /* constructor type */ - List *args; - Expr *func; /* underlying json[b]_xxx() function call */ - Expr *coercion; /* coercion to RETURNING type */ - JsonReturning *returning; /* RETURNING clause */ - bool absent_on_null; /* ABSENT ON NULL? */ - bool unique; /* WITH UNIQUE KEYS? (JSON_OBJECT[AGG] only) */ - int location; -} JsonConstructorExpr; - -/* - * JsonValueType - - * representation of JSON item type in IS JSON predicate - */ -typedef enum JsonValueType -{ - JS_TYPE_ANY, /* IS JSON [VALUE] */ - JS_TYPE_OBJECT, /* IS JSON OBJECT */ - JS_TYPE_ARRAY, /* IS JSON ARRAY */ - JS_TYPE_SCALAR /* IS JSON SCALAR */ -} JsonValueType; - -/* - * JsonIsPredicate - - * representation of IS JSON predicate - */ -typedef struct JsonIsPredicate -{ - NodeTag type; - Node *expr; /* subject expression */ - JsonFormat *format; /* FORMAT clause, if specified */ - JsonValueType item_type; /* JSON item type */ - bool unique_keys; /* check key uniqueness? */ - int location; /* token location, or -1 if unknown */ -} JsonIsPredicate; - -/* - * JsonBehavior - - * representation of JSON ON ... BEHAVIOR clause - */ -typedef struct JsonBehavior -{ - NodeTag type; - JsonBehaviorType btype; /* behavior type */ - Node *default_expr; /* default expression, if any */ -} JsonBehavior; - -/* - * JsonCoercion - - * coercion from SQL/JSON item types to SQL types - */ -typedef struct JsonCoercion -{ - NodeTag type; - Node *expr; /* resulting expression coerced to target type */ - bool via_populate; /* coerce result using json_populate_type()? */ - bool via_io; /* coerce result using type input function? */ - Oid collation; /* collation for coercion via I/O or populate */ -} JsonCoercion; - -/* - * JsonItemCoercions - - * expressions for coercion from SQL/JSON item types directly to the - * output SQL type - */ -typedef struct JsonItemCoercions -{ - NodeTag type; - JsonCoercion *null; - JsonCoercion *string; - JsonCoercion *numeric; - JsonCoercion *boolean; - JsonCoercion *date; - JsonCoercion *time; - JsonCoercion *timetz; - JsonCoercion *timestamp; - JsonCoercion *timestamptz; - JsonCoercion *composite; /* arrays and objects */ -} JsonItemCoercions; - -/* - * JsonExpr - - * transformed representation of JSON_VALUE(), JSON_QUERY(), JSON_EXISTS() - */ -typedef struct JsonExpr -{ - Expr xpr; - JsonExprOp op; /* json function ID */ - Node *formatted_expr; /* formatted context item expression */ - JsonCoercion *result_coercion; /* resulting coercion to RETURNING type */ - JsonFormat *format; /* context item format (JSON/JSONB) */ - Node *path_spec; /* JSON path specification expression */ - List *passing_names; /* PASSING argument names */ - List *passing_values; /* PASSING argument values */ - JsonReturning *returning; /* RETURNING clause type/format info */ - JsonBehavior *on_empty; /* ON EMPTY behavior */ - JsonBehavior *on_error; /* ON ERROR behavior */ - JsonItemCoercions *coercions; /* coercions for JSON_VALUE */ - JsonWrapper wrapper; /* WRAPPER for JSON_QUERY */ - bool omit_quotes; /* KEEP/OMIT QUOTES for JSON_QUERY */ - int location; /* token location, or -1 if unknown */ -} JsonExpr; - -/* - * JsonTableParent - - * transformed representation of parent JSON_TABLE plan node - */ -typedef struct JsonTableParent -{ - NodeTag type; - Const *path; /* jsonpath constant */ - char *name; /* path name */ - Node *child; /* nested columns, if any */ - bool outerJoin; /* outer or inner join for nested columns? */ - int colMin; /* min column index in the resulting column - * list */ - int colMax; /* max column index in the resulting column - * list */ - bool errorOnError; /* ERROR/EMPTY ON ERROR behavior */ -} JsonTableParent; - -/* - * JsonTableSibling - - * transformed representation of joined sibling JSON_TABLE plan node - */ -typedef struct JsonTableSibling -{ - NodeTag type; - Node *larg; /* left join node */ - Node *rarg; /* right join node */ - bool cross; /* cross or union join? */ -} JsonTableSibling; - /* ---------------- * NullTest * diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index 34e1a2b2be3..65ffa8979db 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -26,7 +26,6 @@ /* name, value, category, is-bare-label */ PG_KEYWORD("abort", ABORT_P, UNRESERVED_KEYWORD, BARE_LABEL) -PG_KEYWORD("absent", ABSENT, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("absolute", ABSOLUTE_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("access", ACCESS, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("action", ACTION, UNRESERVED_KEYWORD, BARE_LABEL) @@ -93,7 +92,6 @@ PG_KEYWORD("commit", COMMIT, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("committed", COMMITTED, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("compression", COMPRESSION, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("concurrently", CONCURRENTLY, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) -PG_KEYWORD("conditional", CONDITIONAL, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("configuration", CONFIGURATION, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("conflict", CONFLICT, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("connection", CONNECTION, UNRESERVED_KEYWORD, BARE_LABEL) @@ -148,13 +146,11 @@ PG_KEYWORD("double", DOUBLE_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("drop", DROP, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("each", EACH, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("else", ELSE, RESERVED_KEYWORD, BARE_LABEL) -PG_KEYWORD("empty", EMPTY_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("enable", ENABLE_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("encoding", ENCODING, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("encrypted", ENCRYPTED, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("end", END_P, RESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("enum", ENUM_P, UNRESERVED_KEYWORD, BARE_LABEL) -PG_KEYWORD("error", ERROR_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("escape", ESCAPE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("event", EVENT, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("except", EXCEPT, RESERVED_KEYWORD, AS_LABEL) @@ -179,7 +175,6 @@ PG_KEYWORD("following", FOLLOWING, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("for", FOR, RESERVED_KEYWORD, AS_LABEL) PG_KEYWORD("force", FORCE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("foreign", FOREIGN, RESERVED_KEYWORD, BARE_LABEL) -PG_KEYWORD("format", FORMAT, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("forward", FORWARD, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("freeze", FREEZE, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("from", FROM, RESERVED_KEYWORD, AS_LABEL) @@ -232,20 +227,7 @@ PG_KEYWORD("is", IS, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD, AS_LABEL) PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) -PG_KEYWORD("json", JSON, COL_NAME_KEYWORD, BARE_LABEL) -PG_KEYWORD("json_array", JSON_ARRAY, COL_NAME_KEYWORD, BARE_LABEL) -PG_KEYWORD("json_arrayagg", JSON_ARRAYAGG, COL_NAME_KEYWORD, BARE_LABEL) -PG_KEYWORD("json_exists", JSON_EXISTS, COL_NAME_KEYWORD, BARE_LABEL) -PG_KEYWORD("json_object", JSON_OBJECT, COL_NAME_KEYWORD, BARE_LABEL) -PG_KEYWORD("json_objectagg", JSON_OBJECTAGG, COL_NAME_KEYWORD, BARE_LABEL) -PG_KEYWORD("json_query", JSON_QUERY, COL_NAME_KEYWORD, BARE_LABEL) -PG_KEYWORD("json_scalar", JSON_SCALAR, COL_NAME_KEYWORD, BARE_LABEL) -PG_KEYWORD("json_serialize", JSON_SERIALIZE, COL_NAME_KEYWORD, BARE_LABEL) -PG_KEYWORD("json_table", JSON_TABLE, COL_NAME_KEYWORD, BARE_LABEL) -PG_KEYWORD("json_value", JSON_VALUE, COL_NAME_KEYWORD, BARE_LABEL) -PG_KEYWORD("keep", KEEP, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD, BARE_LABEL) -PG_KEYWORD("keys", KEYS, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD, BARE_LABEL) @@ -284,7 +266,6 @@ PG_KEYWORD("names", NAMES, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("national", NATIONAL, COL_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("natural", NATURAL, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("nchar", NCHAR, COL_NAME_KEYWORD, BARE_LABEL) -PG_KEYWORD("nested", NESTED, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("new", NEW, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("next", NEXT, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("nfc", NFC, UNRESERVED_KEYWORD, BARE_LABEL) @@ -310,7 +291,6 @@ PG_KEYWORD("off", OFF, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("offset", OFFSET, RESERVED_KEYWORD, AS_LABEL) PG_KEYWORD("oids", OIDS, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("old", OLD, UNRESERVED_KEYWORD, BARE_LABEL) -PG_KEYWORD("omit", OMIT, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("on", ON, RESERVED_KEYWORD, AS_LABEL) PG_KEYWORD("only", ONLY, RESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("operator", OPERATOR, UNRESERVED_KEYWORD, BARE_LABEL) @@ -335,9 +315,7 @@ PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD, BARE_LABEL) -PG_KEYWORD("path", PATH, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD, BARE_LABEL) -PG_KEYWORD("plan", PLAN, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("position", POSITION, COL_NAME_KEYWORD, BARE_LABEL) @@ -355,7 +333,6 @@ PG_KEYWORD("procedures", PROCEDURES, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("program", PROGRAM, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("publication", PUBLICATION, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("quote", QUOTE, UNRESERVED_KEYWORD, BARE_LABEL) -PG_KEYWORD("quotes", QUOTES, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("range", RANGE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("read", READ, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("real", REAL, COL_NAME_KEYWORD, BARE_LABEL) @@ -390,7 +367,6 @@ PG_KEYWORD("row", ROW, COL_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("savepoint", SAVEPOINT, UNRESERVED_KEYWORD, BARE_LABEL) -PG_KEYWORD("scalar", SCALAR, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("schema", SCHEMA, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("schemas", SCHEMAS, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD, BARE_LABEL) @@ -426,7 +402,6 @@ PG_KEYWORD("stdout", STDOUT, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("storage", STORAGE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("stored", STORED, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD, BARE_LABEL) -PG_KEYWORD("string", STRING, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD, BARE_LABEL) @@ -461,7 +436,6 @@ PG_KEYWORD("types", TYPES_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("uescape", UESCAPE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("unbounded", UNBOUNDED, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("uncommitted", UNCOMMITTED, UNRESERVED_KEYWORD, BARE_LABEL) -PG_KEYWORD("unconditional", UNCONDITIONAL, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("unencrypted", UNENCRYPTED, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("union", UNION, RESERVED_KEYWORD, AS_LABEL) PG_KEYWORD("unique", UNIQUE, RESERVED_KEYWORD, BARE_LABEL) diff --git a/src/include/parser/parse_clause.h b/src/include/parser/parse_clause.h index 3ec3d5876dc..01ff660bec8 100644 --- a/src/include/parser/parse_clause.h +++ b/src/include/parser/parse_clause.h @@ -51,9 +51,6 @@ extern List *addTargetToSortList(ParseState *pstate, TargetEntry *tle, extern Index assignSortGroupRef(TargetEntry *tle, List *tlist); extern bool targetIsInSortList(TargetEntry *tle, Oid sortop, List *sortList); -/* functions in parse_jsontable.c */ -extern ParseNamespaceItem *transformJsonTable(ParseState *pstate, JsonTable *jt); - typedef bool (*tle_name_comparison_hook_type)(const char *tlename, const char *identifier); extern PGDLLEXPORT tle_name_comparison_hook_type tle_name_comparison_hook; diff --git a/src/include/utils/formatting.h b/src/include/utils/formatting.h index f048eb0869d..851e787bfdb 100644 --- a/src/include/utils/formatting.h +++ b/src/include/utils/formatting.h @@ -17,9 +17,6 @@ #ifndef _FORMATTING_H_ #define _FORMATTING_H_ -#define DCH_DATED 0x01 -#define DCH_TIMED 0x02 -#define DCH_ZONED 0x04 extern char *str_tolower(const char *buff, size_t nbytes, Oid collid); extern char *str_toupper(const char *buff, size_t nbytes, Oid collid); @@ -32,6 +29,5 @@ extern char *asc_initcap(const char *buff, size_t nbytes); extern Datum parse_datetime(text *date_txt, text *fmt, Oid collid, bool strict, Oid *typid, int32 *typmod, int *tz, bool *have_error); -extern int datetime_format_flags(const char *fmt_str, bool *have_error); #endif diff --git a/src/include/utils/json.h b/src/include/utils/json.h index 403cc20bc6b..468be49d0a4 100644 --- a/src/include/utils/json.h +++ b/src/include/utils/json.h @@ -16,36 +16,9 @@ #include "lib/stringinfo.h" -typedef enum /* type categories for datum_to_json */ -{ - JSONTYPE_NULL, /* null, so we didn't bother to identify */ - JSONTYPE_BOOL, /* boolean (built-in types only) */ - JSONTYPE_NUMERIC, /* numeric (ditto) */ - JSONTYPE_DATE, /* we use special formatting for datetimes */ - JSONTYPE_TIMESTAMP, - JSONTYPE_TIMESTAMPTZ, - JSONTYPE_JSON, /* JSON itself (and JSONB) */ - JSONTYPE_ARRAY, /* array */ - JSONTYPE_COMPOSITE, /* composite */ - JSONTYPE_CAST, /* something with an explicit cast to JSON */ - JSONTYPE_OTHER /* all else */ -} JsonTypeCategory; - /* functions in json.c */ extern void escape_json(StringInfo buf, const char *str); extern char *JsonEncodeDateTime(char *buf, Datum value, Oid typid, const int *tzp); -extern bool to_json_is_immutable(Oid typoid); -extern void json_categorize_type(Oid typoid, JsonTypeCategory *tcategory, - Oid *outfuncoid); -extern Datum to_json_worker(Datum val, JsonTypeCategory tcategory, - Oid outfuncoid); -extern Datum json_build_object_worker(int nargs, Datum *args, bool *nulls, - Oid *types, bool absent_on_null, - bool unique_keys); -extern Datum json_build_array_worker(int nargs, Datum *args, bool *nulls, - Oid *types, bool absent_on_null); -extern bool json_validate(text *json, bool check_unique_keys, bool throw_error); extern void tsql_json_build_object(StringInfo result,Datum colname, Datum colval, Oid collation, bool is_null); - #endif /* JSON_H */ diff --git a/src/include/utils/jsonb.h b/src/include/utils/jsonb.h index c9e89052965..5fba94ec2e4 100644 --- a/src/include/utils/jsonb.h +++ b/src/include/utils/jsonb.h @@ -329,8 +329,6 @@ typedef struct JsonbParseState JsonbValue contVal; Size size; struct JsonbParseState *next; - bool unique_keys; /* Check object key uniqueness */ - bool skip_nulls; /* Skip null object fields */ } JsonbParseState; /* @@ -376,22 +374,6 @@ typedef struct JsonbIterator struct JsonbIterator *parent; } JsonbIterator; -/* unlike with json categories, we need to treat json and jsonb differently */ -typedef enum /* type categories for datum_to_jsonb */ -{ - JSONBTYPE_NULL, /* null, so we didn't bother to identify */ - JSONBTYPE_BOOL, /* boolean (built-in types only) */ - JSONBTYPE_NUMERIC, /* numeric (ditto) */ - JSONBTYPE_DATE, /* we use special formatting for datetimes */ - JSONBTYPE_TIMESTAMP, /* we use special formatting for timestamp */ - JSONBTYPE_TIMESTAMPTZ, /* ... and timestamptz */ - JSONBTYPE_JSON, /* JSON */ - JSONBTYPE_JSONB, /* JSONB */ - JSONBTYPE_ARRAY, /* array */ - JSONBTYPE_COMPOSITE, /* composite */ - JSONBTYPE_JSONCAST, /* something with an explicit cast to JSON */ - JSONBTYPE_OTHER /* all else */ -} JsonbTypeCategory; /* Support functions */ extern uint32 getJsonbOffset(const JsonbContainer *jc, int index); @@ -422,14 +404,10 @@ extern void JsonbHashScalarValueExtended(const JsonbValue *scalarVal, uint64 *hash, uint64 seed); /* jsonb.c support functions */ -extern Datum jsonb_from_text(text *js, bool unique_keys); extern char *JsonbToCString(StringInfo out, JsonbContainer *in, int estimated_len); extern char *JsonbToCStringIndent(StringInfo out, JsonbContainer *in, int estimated_len); -extern Jsonb *JsonbMakeEmptyArray(void); -extern Jsonb *JsonbMakeEmptyObject(void); -extern char *JsonbUnquote(Jsonb *jb); extern bool JsonbExtractScalar(JsonbContainer *jbc, JsonbValue *res); extern const char *JsonbTypeName(JsonbValue *jb); @@ -437,16 +415,5 @@ extern Datum jsonb_set_element(Jsonb *jb, Datum *path, int path_len, JsonbValue *newval); extern Datum jsonb_get_element(Jsonb *jb, Datum *path, int npath, bool *isnull, bool as_text); -extern bool to_jsonb_is_immutable(Oid typoid); -extern void jsonb_categorize_type(Oid typoid, JsonbTypeCategory *tcategory, - Oid *outfuncoid); -extern Datum to_jsonb_worker(Datum val, JsonbTypeCategory tcategory, - Oid outfuncoid); -extern Datum jsonb_build_object_worker(int nargs, Datum *args, bool *nulls, - Oid *types, bool absent_on_null, - bool unique_keys); -extern Datum jsonb_build_array_worker(int nargs, Datum *args, bool *nulls, - Oid *types, bool absent_on_null); - extern void jsonb_get_value(Datum val, bool is_null, JsonbValue *json, Oid val_type); #endif /* __JSONB_H__ */ diff --git a/src/include/utils/jsonfuncs.h b/src/include/utils/jsonfuncs.h index 62dc3d88a42..865b2ff7c11 100644 --- a/src/include/utils/jsonfuncs.h +++ b/src/include/utils/jsonfuncs.h @@ -45,9 +45,6 @@ extern void pg_parse_json_or_ereport(JsonLexContext *lex, JsonSemAction *sem); /* report an error during json lexing or parsing */ extern void json_ereport_error(JsonParseErrorType error, JsonLexContext *lex); -/* get first JSON token */ -extern JsonTokenType json_get_first_token(text *json, bool throw_error); - extern uint32 parse_jsonb_index_flags(Jsonb *jb); extern void iterate_jsonb_values(Jsonb *jb, uint32 flags, void *state, JsonIterateStringValuesAction action); @@ -58,8 +55,4 @@ extern Jsonb *transform_jsonb_string_values(Jsonb *jsonb, void *action_state, extern text *transform_json_string_values(text *json, void *action_state, JsonTransformStringValuesAction transform_action); -extern Datum json_populate_type(Datum json_val, Oid json_type, - Oid typid, int32 typmod, - void **cache, MemoryContext mcxt, bool *isnull); - #endif diff --git a/src/include/utils/jsonpath.h b/src/include/utils/jsonpath.h index 20ba71a949f..934da114342 100644 --- a/src/include/utils/jsonpath.h +++ b/src/include/utils/jsonpath.h @@ -15,11 +15,8 @@ #define JSONPATH_H #include "fmgr.h" -#include "executor/tablefunc.h" #include "nodes/pg_list.h" -#include "nodes/primnodes.h" #include "utils/jsonb.h" -#include "utils/jsonfuncs.h" typedef struct { @@ -177,7 +174,6 @@ extern bool jspGetBool(JsonPathItem *v); extern char *jspGetString(JsonPathItem *v, int32 *len); extern bool jspGetArraySubscript(JsonPathItem *v, JsonPathItem *from, JsonPathItem *to, int i); -extern bool jspIsMutable(JsonPath *path, List *varnames, List *varexprs); extern const char *jspOperationName(JsonPathItemType type); @@ -252,40 +248,6 @@ extern JsonPathParseResult *parsejsonpath(const char *str, int len); extern int jspConvertRegexFlags(uint32 xflags); -/* - * Evaluation of jsonpath - */ - -/* External variable passed into jsonpath. */ -typedef struct JsonPathVariableEvalContext -{ - char *name; - Oid typid; - int32 typmod; - struct ExprContext *econtext; - struct ExprState *estate; - MemoryContext mcxt; /* memory context for cached value */ - Datum value; - bool isnull; - bool evaluated; -} JsonPathVariableEvalContext; - -/* SQL/JSON item */ -extern void JsonItemFromDatum(Datum val, Oid typid, int32 typmod, - JsonbValue *res); - -extern bool JsonPathExists(Datum jb, JsonPath *path, List *vars, bool *error); -extern Datum JsonPathQuery(Datum jb, JsonPath *jp, JsonWrapper wrapper, - bool *empty, bool *error, List *vars); -extern JsonbValue *JsonPathValue(Datum jb, JsonPath *jp, bool *empty, - bool *error, List *vars); - -extern int EvalJsonPathVar(void *vars, char *varName, int varNameLen, - JsonbValue *val, JsonbValue *baseObject); - -extern PGDLLIMPORT const TableFuncRoutine JsonbTableRoutine; - extern Jsonb *tsql_openjson_with_get_subjsonb(PG_FUNCTION_ARGS); extern List *tsql_openjson_with_columnize(Jsonb *jb, char *col_info); - #endif diff --git a/src/interfaces/ecpg/preproc/ecpg.trailer b/src/interfaces/ecpg/preproc/ecpg.trailer index fba35f6be6a..0b100b9b043 100644 --- a/src/interfaces/ecpg/preproc/ecpg.trailer +++ b/src/interfaces/ecpg/preproc/ecpg.trailer @@ -657,34 +657,6 @@ var_type: simple_type $$.type_index = mm_strdup("-1"); $$.type_sizeof = NULL; } - | STRING - { - if (INFORMIX_MODE) - { - /* In Informix mode, "string" is automatically a typedef */ - $$.type_enum = ECPGt_string; - $$.type_str = mm_strdup("char"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); - $$.type_sizeof = NULL; - } - else - { - /* Otherwise, legal only if user typedef'ed it */ - struct typedefs *this = get_typedef("string", false); - - $$.type_str = (this->type->type_enum == ECPGt_varchar || this->type->type_enum == ECPGt_bytea) ? EMPTY : mm_strdup(this->name); - $$.type_enum = this->type->type_enum; - $$.type_dimension = this->type->type_dimension; - $$.type_index = this->type->type_index; - if (this->type->type_sizeof && strlen(this->type->type_sizeof) != 0) - $$.type_sizeof = this->type->type_sizeof; - else - $$.type_sizeof = cat_str(3, mm_strdup("sizeof("), mm_strdup(this->name), mm_strdup(")")); - - struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list); - } - } | IDENT ecpg_interval { /* diff --git a/src/interfaces/ecpg/preproc/parse.pl b/src/interfaces/ecpg/preproc/parse.pl index 8de5c4457b3..8925e24a301 100644 --- a/src/interfaces/ecpg/preproc/parse.pl +++ b/src/interfaces/ecpg/preproc/parse.pl @@ -58,8 +58,6 @@ 'NOT_LA' => 'not', 'NULLS_LA' => 'nulls', 'WITH_LA' => 'with', - 'WITH_LA_UNIQUE' => 'with', - 'WITHOUT_LA' => 'without', 'TYPECAST' => '::', 'DOT_DOT' => '..', 'COLON_EQUALS' => ':=', diff --git a/src/interfaces/ecpg/preproc/parser.c b/src/interfaces/ecpg/preproc/parser.c index 5e2b606f9ba..a44e07a17ab 100644 --- a/src/interfaces/ecpg/preproc/parser.c +++ b/src/interfaces/ecpg/preproc/parser.c @@ -83,7 +83,6 @@ filtered_base_yylex(void) case WITH: case UIDENT: case USCONST: - case WITHOUT: break; default: return cur_token; @@ -144,19 +143,6 @@ filtered_base_yylex(void) case ORDINALITY: cur_token = WITH_LA; break; - case UNIQUE: - cur_token = WITH_LA_UNIQUE; - break; - } - break; - - case WITHOUT: - /* Replace WITHOUT by WITHOUT_LA if it's followed by TIME */ - switch (next_token) - { - case TIME: - cur_token = WITHOUT_LA; - break; } break; case UIDENT: diff --git a/src/test/regress/expected/json_sqljson.out b/src/test/regress/expected/json_sqljson.out deleted file mode 100644 index 995f2674046..00000000000 --- a/src/test/regress/expected/json_sqljson.out +++ /dev/null @@ -1,24 +0,0 @@ --- JSON_EXISTS -SELECT JSON_EXISTS(NULL FORMAT JSON, '$'); -ERROR: JSON_EXISTS() is not yet implemented for the json type -LINE 1: SELECT JSON_EXISTS(NULL FORMAT JSON, '$'); - ^ -HINT: Try casting the argument to jsonb --- JSON_VALUE -SELECT JSON_VALUE(NULL FORMAT JSON, '$'); -ERROR: JSON_VALUE() is not yet implemented for the json type -LINE 1: SELECT JSON_VALUE(NULL FORMAT JSON, '$'); - ^ -HINT: Try casting the argument to jsonb --- JSON_QUERY -SELECT JSON_QUERY(NULL FORMAT JSON, '$'); -ERROR: JSON_QUERY() is not yet implemented for the json type -LINE 1: SELECT JSON_QUERY(NULL FORMAT JSON, '$'); - ^ -HINT: Try casting the argument to jsonb --- JSON_TABLE -SELECT * FROM JSON_TABLE(NULL FORMAT JSON, '$' COLUMNS (foo text)); -ERROR: JSON_TABLE() is not yet implemented for the json type -LINE 1: SELECT * FROM JSON_TABLE(NULL FORMAT JSON, '$' COLUMNS (foo ... - ^ -HINT: Try casting the argument to jsonb diff --git a/src/test/regress/expected/jsonb_sqljson.out b/src/test/regress/expected/jsonb_sqljson.out deleted file mode 100644 index ef496110af3..00000000000 --- a/src/test/regress/expected/jsonb_sqljson.out +++ /dev/null @@ -1,2135 +0,0 @@ --- JSON_EXISTS -SELECT JSON_EXISTS(NULL::jsonb, '$'); - json_exists -------------- - -(1 row) - -SELECT JSON_EXISTS(jsonb '[]', '$'); - json_exists -------------- - t -(1 row) - -SELECT JSON_EXISTS(JSON_OBJECT(RETURNING jsonb), '$'); - json_exists -------------- - t -(1 row) - -SELECT JSON_EXISTS(jsonb '1', '$'); - json_exists -------------- - t -(1 row) - -SELECT JSON_EXISTS(jsonb 'null', '$'); - json_exists -------------- - t -(1 row) - -SELECT JSON_EXISTS(jsonb '[]', '$'); - json_exists -------------- - t -(1 row) - -SELECT JSON_EXISTS(jsonb '1', '$.a'); - json_exists -------------- - f -(1 row) - -SELECT JSON_EXISTS(jsonb '1', 'strict $.a'); - json_exists -------------- - f -(1 row) - -SELECT JSON_EXISTS(jsonb '1', 'strict $.a' ERROR ON ERROR); -ERROR: jsonpath member accessor can only be applied to an object -SELECT JSON_EXISTS(jsonb 'null', '$.a'); - json_exists -------------- - f -(1 row) - -SELECT JSON_EXISTS(jsonb '[]', '$.a'); - json_exists -------------- - f -(1 row) - -SELECT JSON_EXISTS(jsonb '[1, "aaa", {"a": 1}]', 'strict $.a'); - json_exists -------------- - f -(1 row) - -SELECT JSON_EXISTS(jsonb '[1, "aaa", {"a": 1}]', 'lax $.a'); - json_exists -------------- - t -(1 row) - -SELECT JSON_EXISTS(jsonb '{}', '$.a'); - json_exists -------------- - f -(1 row) - -SELECT JSON_EXISTS(jsonb '{"b": 1, "a": 2}', '$.a'); - json_exists -------------- - t -(1 row) - -SELECT JSON_EXISTS(jsonb '1', '$.a.b'); - json_exists -------------- - f -(1 row) - -SELECT JSON_EXISTS(jsonb '{"a": {"b": 1}}', '$.a.b'); - json_exists -------------- - t -(1 row) - -SELECT JSON_EXISTS(jsonb '{"a": 1, "b": 2}', '$.a.b'); - json_exists -------------- - f -(1 row) - -SELECT JSON_EXISTS(jsonb '{"a": 1, "b": 2}', '$.* ? (@ > $x)' PASSING 1 AS x); - json_exists -------------- - t -(1 row) - -SELECT JSON_EXISTS(jsonb '{"a": 1, "b": 2}', '$.* ? (@ > $x)' PASSING '1' AS x); - json_exists -------------- - f -(1 row) - -SELECT JSON_EXISTS(jsonb '{"a": 1, "b": 2}', '$.* ? (@ > $x && @ < $y)' PASSING 0 AS x, 2 AS y); - json_exists -------------- - t -(1 row) - -SELECT JSON_EXISTS(jsonb '{"a": 1, "b": 2}', '$.* ? (@ > $x && @ < $y)' PASSING 0 AS x, 1 AS y); - json_exists -------------- - f -(1 row) - --- extension: boolean expressions -SELECT JSON_EXISTS(jsonb '1', '$ > 2'); - json_exists -------------- - t -(1 row) - -SELECT JSON_EXISTS(jsonb '1', '$.a > 2' ERROR ON ERROR); - json_exists -------------- - t -(1 row) - --- extension: RETURNING clause -SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING bool); - json_exists -------------- - t -(1 row) - -SELECT JSON_EXISTS(jsonb '1', '$[1]' RETURNING bool); - json_exists -------------- - f -(1 row) - -SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING int); - json_exists -------------- - 1 -(1 row) - -SELECT JSON_EXISTS(jsonb '1', '$[1]' RETURNING int); - json_exists -------------- - 0 -(1 row) - -SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING text); - json_exists -------------- - true -(1 row) - -SELECT JSON_EXISTS(jsonb '1', '$[1]' RETURNING text); - json_exists -------------- - false -(1 row) - -SELECT JSON_EXISTS(jsonb '1', 'strict $[1]' RETURNING text FALSE ON ERROR); - json_exists -------------- - false -(1 row) - -SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING jsonb); -ERROR: cannot cast type boolean to jsonb -LINE 1: SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING jsonb); - ^ -SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING float4); -ERROR: cannot cast type boolean to real -LINE 1: SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING float4); - ^ --- JSON_VALUE -SELECT JSON_VALUE(NULL::jsonb, '$'); - json_value ------------- - -(1 row) - -SELECT JSON_VALUE(jsonb 'null', '$'); - json_value ------------- - -(1 row) - -SELECT JSON_VALUE(jsonb 'null', '$' RETURNING int); - json_value ------------- - -(1 row) - -SELECT JSON_VALUE(jsonb 'true', '$'); - json_value ------------- - true -(1 row) - -SELECT JSON_VALUE(jsonb 'true', '$' RETURNING bool); - json_value ------------- - t -(1 row) - -SELECT JSON_VALUE(jsonb '123', '$'); - json_value ------------- - 123 -(1 row) - -SELECT JSON_VALUE(jsonb '123', '$' RETURNING int) + 234; - ?column? ----------- - 357 -(1 row) - -SELECT JSON_VALUE(jsonb '123', '$' RETURNING text); - json_value ------------- - 123 -(1 row) - -/* jsonb bytea ??? */ -SELECT JSON_VALUE(jsonb '123', '$' RETURNING bytea ERROR ON ERROR); -ERROR: SQL/JSON item cannot be cast to target type -SELECT JSON_VALUE(jsonb '1.23', '$'); - json_value ------------- - 1.23 -(1 row) - -SELECT JSON_VALUE(jsonb '1.23', '$' RETURNING int); - json_value ------------- - 1 -(1 row) - -SELECT JSON_VALUE(jsonb '"1.23"', '$' RETURNING numeric); - json_value ------------- - 1.23 -(1 row) - -SELECT JSON_VALUE(jsonb '"1.23"', '$' RETURNING int ERROR ON ERROR); -ERROR: invalid input syntax for type integer: "1.23" -SELECT JSON_VALUE(jsonb '"aaa"', '$'); - json_value ------------- - aaa -(1 row) - -SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING text); - json_value ------------- - aaa -(1 row) - -SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING char(5)); - json_value ------------- - aaa -(1 row) - -SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING char(2)); - json_value ------------- - aa -(1 row) - -SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING json); - json_value ------------- - "aaa" -(1 row) - -SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING jsonb); - json_value ------------- - "aaa" -(1 row) - -SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING json ERROR ON ERROR); - json_value ------------- - "aaa" -(1 row) - -SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING jsonb ERROR ON ERROR); - json_value ------------- - "aaa" -(1 row) - -SELECT JSON_VALUE(jsonb '"\"aaa\""', '$' RETURNING json); - json_value ------------- - "\"aaa\"" -(1 row) - -SELECT JSON_VALUE(jsonb '"\"aaa\""', '$' RETURNING jsonb); - json_value ------------- - "\"aaa\"" -(1 row) - -SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING int); - json_value ------------- - -(1 row) - -SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING int ERROR ON ERROR); -ERROR: invalid input syntax for type integer: "aaa" -SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING int DEFAULT 111 ON ERROR); - json_value ------------- - 111 -(1 row) - -SELECT JSON_VALUE(jsonb '"123"', '$' RETURNING int) + 234; - ?column? ----------- - 357 -(1 row) - -SELECT JSON_VALUE(jsonb '"2017-02-20"', '$' RETURNING date) + 9; - ?column? ------------- - 03-01-2017 -(1 row) - --- Test NULL checks execution in domain types -CREATE DOMAIN sqljsonb_int_not_null AS int NOT NULL; -SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null); -ERROR: domain sqljsonb_int_not_null does not allow null values -SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null NULL ON ERROR); -ERROR: domain sqljsonb_int_not_null does not allow null values -SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null DEFAULT NULL ON ERROR); -ERROR: domain sqljsonb_int_not_null does not allow null values -SELECT JSON_VALUE(jsonb '[]', '$'); - json_value ------------- - -(1 row) - -SELECT JSON_VALUE(jsonb '[]', '$' ERROR ON ERROR); -ERROR: JSON path expression in JSON_VALUE should return singleton scalar item -SELECT JSON_VALUE(jsonb '{}', '$'); - json_value ------------- - -(1 row) - -SELECT JSON_VALUE(jsonb '{}', '$' ERROR ON ERROR); -ERROR: JSON path expression in JSON_VALUE should return singleton scalar item -SELECT JSON_VALUE(jsonb '1', '$.a'); - json_value ------------- - -(1 row) - -SELECT JSON_VALUE(jsonb '1', 'strict $.a' ERROR ON ERROR); -ERROR: jsonpath member accessor can only be applied to an object -SELECT JSON_VALUE(jsonb '1', 'strict $.a' DEFAULT 'error' ON ERROR); - json_value ------------- - error -(1 row) - -SELECT JSON_VALUE(jsonb '1', 'lax $.a' ERROR ON ERROR); - json_value ------------- - -(1 row) - -SELECT JSON_VALUE(jsonb '1', 'lax $.a' ERROR ON EMPTY ERROR ON ERROR); -ERROR: no SQL/JSON item -SELECT JSON_VALUE(jsonb '1', 'strict $.a' DEFAULT 2 ON ERROR); - json_value ------------- - 2 -(1 row) - -SELECT JSON_VALUE(jsonb '1', 'lax $.a' DEFAULT 2 ON ERROR); - json_value ------------- - -(1 row) - -SELECT JSON_VALUE(jsonb '1', 'lax $.a' DEFAULT '2' ON ERROR); - json_value ------------- - -(1 row) - -SELECT JSON_VALUE(jsonb '1', 'lax $.a' NULL ON EMPTY DEFAULT '2' ON ERROR); - json_value ------------- - -(1 row) - -SELECT JSON_VALUE(jsonb '1', 'lax $.a' DEFAULT '2' ON EMPTY DEFAULT '3' ON ERROR); - json_value ------------- - 2 -(1 row) - -SELECT JSON_VALUE(jsonb '1', 'lax $.a' ERROR ON EMPTY DEFAULT '3' ON ERROR); - json_value ------------- - 3 -(1 row) - -SELECT JSON_VALUE(jsonb '[1,2]', '$[*]' ERROR ON ERROR); -ERROR: JSON path expression in JSON_VALUE should return singleton scalar item -SELECT JSON_VALUE(jsonb '[1,2]', '$[*]' DEFAULT '0' ON ERROR); - json_value ------------- - 0 -(1 row) - -SELECT JSON_VALUE(jsonb '[" "]', '$[*]' RETURNING int ERROR ON ERROR); -ERROR: invalid input syntax for type integer: " " -SELECT JSON_VALUE(jsonb '[" "]', '$[*]' RETURNING int DEFAULT 2 + 3 ON ERROR); - json_value ------------- - 5 -(1 row) - -SELECT JSON_VALUE(jsonb '["1"]', '$[*]' RETURNING int DEFAULT 2 + 3 ON ERROR); - json_value ------------- - 1 -(1 row) - -SELECT - x, - JSON_VALUE( - jsonb '{"a": 1, "b": 2}', - '$.* ? (@ > $x)' PASSING x AS x - RETURNING int - DEFAULT -1 ON EMPTY - DEFAULT -2 ON ERROR - ) y -FROM - generate_series(0, 2) x; - x | y ----+---- - 0 | -2 - 1 | 2 - 2 | -1 -(3 rows) - -SELECT JSON_VALUE(jsonb 'null', '$a' PASSING point ' (1, 2 )' AS a); - json_value ------------- - (1,2) -(1 row) - -SELECT JSON_VALUE(jsonb 'null', '$a' PASSING point ' (1, 2 )' AS a RETURNING point); - json_value ------------- - (1,2) -(1 row) - --- Test timestamptz passing and output -SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts); - json_value ------------------------------- - Tue Feb 20 18:34:56 2018 PST -(1 row) - -SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING timestamptz); - json_value ------------------------------- - Tue Feb 20 18:34:56 2018 PST -(1 row) - -SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING timestamp); - json_value --------------------------- - Tue Feb 20 18:34:56 2018 -(1 row) - -SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING json); - json_value ------------------------------ - "2018-02-21T02:34:56+00:00" -(1 row) - -SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING jsonb); - json_value ------------------------------ - "2018-02-21T02:34:56+00:00" -(1 row) - --- JSON_QUERY -SELECT - JSON_QUERY(js, '$'), - JSON_QUERY(js, '$' WITHOUT WRAPPER), - JSON_QUERY(js, '$' WITH CONDITIONAL WRAPPER), - JSON_QUERY(js, '$' WITH UNCONDITIONAL ARRAY WRAPPER), - JSON_QUERY(js, '$' WITH ARRAY WRAPPER) -FROM - (VALUES - (jsonb 'null'), - ('12.3'), - ('true'), - ('"aaa"'), - ('[1, null, "2"]'), - ('{"a": 1, "b": [2]}') - ) foo(js); - json_query | json_query | json_query | json_query | json_query ---------------------+--------------------+--------------------+----------------------+---------------------- - null | null | [null] | [null] | [null] - 12.3 | 12.3 | [12.3] | [12.3] | [12.3] - true | true | [true] | [true] | [true] - "aaa" | "aaa" | ["aaa"] | ["aaa"] | ["aaa"] - [1, null, "2"] | [1, null, "2"] | [1, null, "2"] | [[1, null, "2"]] | [[1, null, "2"]] - {"a": 1, "b": [2]} | {"a": 1, "b": [2]} | {"a": 1, "b": [2]} | [{"a": 1, "b": [2]}] | [{"a": 1, "b": [2]}] -(6 rows) - -SELECT - JSON_QUERY(js, 'strict $[*]') AS "unspec", - JSON_QUERY(js, 'strict $[*]' WITHOUT WRAPPER) AS "without", - JSON_QUERY(js, 'strict $[*]' WITH CONDITIONAL WRAPPER) AS "with cond", - JSON_QUERY(js, 'strict $[*]' WITH UNCONDITIONAL ARRAY WRAPPER) AS "with uncond", - JSON_QUERY(js, 'strict $[*]' WITH ARRAY WRAPPER) AS "with" -FROM - (VALUES - (jsonb '1'), - ('[]'), - ('[null]'), - ('[12.3]'), - ('[true]'), - ('["aaa"]'), - ('[[1, 2, 3]]'), - ('[{"a": 1, "b": [2]}]'), - ('[1, "2", null, [3]]') - ) foo(js); - unspec | without | with cond | with uncond | with ---------------------+--------------------+---------------------+----------------------+---------------------- - | | | | - | | | | - null | null | [null] | [null] | [null] - 12.3 | 12.3 | [12.3] | [12.3] | [12.3] - true | true | [true] | [true] | [true] - "aaa" | "aaa" | ["aaa"] | ["aaa"] | ["aaa"] - [1, 2, 3] | [1, 2, 3] | [1, 2, 3] | [[1, 2, 3]] | [[1, 2, 3]] - {"a": 1, "b": [2]} | {"a": 1, "b": [2]} | {"a": 1, "b": [2]} | [{"a": 1, "b": [2]}] | [{"a": 1, "b": [2]}] - | | [1, "2", null, [3]] | [1, "2", null, [3]] | [1, "2", null, [3]] -(9 rows) - -SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text); - json_query ------------- - "aaa" -(1 row) - -SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text KEEP QUOTES); - json_query ------------- - "aaa" -(1 row) - -SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text KEEP QUOTES ON SCALAR STRING); - json_query ------------- - "aaa" -(1 row) - -SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text OMIT QUOTES); - json_query ------------- - aaa -(1 row) - -SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text OMIT QUOTES ON SCALAR STRING); - json_query ------------- - aaa -(1 row) - -SELECT JSON_QUERY(jsonb '"aaa"', '$' OMIT QUOTES ERROR ON ERROR); -ERROR: invalid input syntax for type json -DETAIL: Token "aaa" is invalid. -CONTEXT: JSON data, line 1: aaa -SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING json OMIT QUOTES ERROR ON ERROR); -ERROR: invalid input syntax for type json -DETAIL: Token "aaa" is invalid. -CONTEXT: JSON data, line 1: aaa -SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING bytea FORMAT JSON OMIT QUOTES ERROR ON ERROR); - json_query ------------- - \x616161 -(1 row) - --- QUOTES behavior should not be specified when WITH WRAPPER used: --- Should fail -SELECT JSON_QUERY(jsonb '[1]', '$' WITH WRAPPER OMIT QUOTES); -ERROR: SQL/JSON QUOTES behavior must not be specified when WITH WRAPPER is used -LINE 1: SELECT JSON_QUERY(jsonb '[1]', '$' WITH WRAPPER OMIT QUOTES)... - ^ -SELECT JSON_QUERY(jsonb '[1]', '$' WITH WRAPPER KEEP QUOTES); -ERROR: SQL/JSON QUOTES behavior must not be specified when WITH WRAPPER is used -LINE 1: SELECT JSON_QUERY(jsonb '[1]', '$' WITH WRAPPER KEEP QUOTES)... - ^ -SELECT JSON_QUERY(jsonb '[1]', '$' WITH CONDITIONAL WRAPPER KEEP QUOTES); -ERROR: SQL/JSON QUOTES behavior must not be specified when WITH WRAPPER is used -LINE 1: ...N_QUERY(jsonb '[1]', '$' WITH CONDITIONAL WRAPPER KEEP QUOTE... - ^ -SELECT JSON_QUERY(jsonb '[1]', '$' WITH CONDITIONAL WRAPPER OMIT QUOTES); -ERROR: SQL/JSON QUOTES behavior must not be specified when WITH WRAPPER is used -LINE 1: ...N_QUERY(jsonb '[1]', '$' WITH CONDITIONAL WRAPPER OMIT QUOTE... - ^ --- Should succeed -SELECT JSON_QUERY(jsonb '[1]', '$' WITHOUT WRAPPER OMIT QUOTES); - json_query ------------- - [1] -(1 row) - -SELECT JSON_QUERY(jsonb '[1]', '$' WITHOUT WRAPPER KEEP QUOTES); - json_query ------------- - [1] -(1 row) - -SELECT JSON_QUERY(jsonb '[]', '$[*]'); - json_query ------------- - -(1 row) - -SELECT JSON_QUERY(jsonb '[]', '$[*]' NULL ON EMPTY); - json_query ------------- - -(1 row) - -SELECT JSON_QUERY(jsonb '[]', '$[*]' EMPTY ON EMPTY); - json_query ------------- - [] -(1 row) - -SELECT JSON_QUERY(jsonb '[]', '$[*]' EMPTY ARRAY ON EMPTY); - json_query ------------- - [] -(1 row) - -SELECT JSON_QUERY(jsonb '[]', '$[*]' EMPTY OBJECT ON EMPTY); - json_query ------------- - {} -(1 row) - -SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY); - json_query ------------- - -(1 row) - -SELECT JSON_QUERY(jsonb '[]', '$[*]' DEFAULT '"empty"' ON EMPTY); - json_query ------------- - "empty" -(1 row) - -SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY NULL ON ERROR); - json_query ------------- - -(1 row) - -SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY EMPTY ARRAY ON ERROR); - json_query ------------- - [] -(1 row) - -SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY EMPTY OBJECT ON ERROR); - json_query ------------- - {} -(1 row) - -SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY ERROR ON ERROR); -ERROR: no SQL/JSON item -SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON ERROR); - json_query ------------- - -(1 row) - -SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' ERROR ON ERROR); -ERROR: JSON path expression in JSON_QUERY should return singleton item without wrapper -HINT: Use WITH WRAPPER clause to wrap SQL/JSON item sequence into array. -SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' DEFAULT '"empty"' ON ERROR); - json_query ------------- - "empty" -(1 row) - -SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING json); - json_query ------------- - [1, 2] -(1 row) - -SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING json FORMAT JSON); - json_query ------------- - [1, 2] -(1 row) - -SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING jsonb); - json_query ------------- - [1, 2] -(1 row) - -SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING jsonb FORMAT JSON); - json_query ------------- - [1, 2] -(1 row) - -SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING text); - json_query ------------- - [1, 2] -(1 row) - -SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING char(10)); - json_query ------------- - [1, 2] -(1 row) - -SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING char(3)); - json_query ------------- - [1, -(1 row) - -SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING text FORMAT JSON); - json_query ------------- - [1, 2] -(1 row) - -SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING bytea); - json_query ----------------- - \x5b312c20325d -(1 row) - -SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING bytea FORMAT JSON); - json_query ----------------- - \x5b312c20325d -(1 row) - -SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' RETURNING bytea EMPTY OBJECT ON ERROR); - json_query ------------- - \x7b7d -(1 row) - -SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' RETURNING bytea FORMAT JSON EMPTY OBJECT ON ERROR); - json_query ------------- - \x7b7d -(1 row) - -SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' RETURNING json EMPTY OBJECT ON ERROR); - json_query ------------- - {} -(1 row) - -SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' RETURNING jsonb EMPTY OBJECT ON ERROR); - json_query ------------- - {} -(1 row) - -SELECT - x, y, - JSON_QUERY( - jsonb '[1,2,3,4,5,null]', - '$[*] ? (@ >= $x && @ <= $y)' - PASSING x AS x, y AS y - WITH CONDITIONAL WRAPPER - EMPTY ARRAY ON EMPTY - ) list -FROM - generate_series(0, 4) x, - generate_series(0, 4) y; - x | y | list ----+---+-------------- - 0 | 0 | [] - 0 | 1 | [1] - 0 | 2 | [1, 2] - 0 | 3 | [1, 2, 3] - 0 | 4 | [1, 2, 3, 4] - 1 | 0 | [] - 1 | 1 | [1] - 1 | 2 | [1, 2] - 1 | 3 | [1, 2, 3] - 1 | 4 | [1, 2, 3, 4] - 2 | 0 | [] - 2 | 1 | [] - 2 | 2 | [2] - 2 | 3 | [2, 3] - 2 | 4 | [2, 3, 4] - 3 | 0 | [] - 3 | 1 | [] - 3 | 2 | [] - 3 | 3 | [3] - 3 | 4 | [3, 4] - 4 | 0 | [] - 4 | 1 | [] - 4 | 2 | [] - 4 | 3 | [] - 4 | 4 | [4] -(25 rows) - --- Extension: record types returning -CREATE TYPE sqljsonb_rec AS (a int, t text, js json, jb jsonb, jsa json[]); -CREATE TYPE sqljsonb_reca AS (reca sqljsonb_rec[]); -SELECT JSON_QUERY(jsonb '[{"a": 1, "b": "foo", "t": "aaa", "js": [1, "2", {}], "jb": {"x": [1, "2", {}]}}, {"a": 2}]', '$[0]' RETURNING sqljsonb_rec); - json_query ------------------------------------------------------ - (1,aaa,"[1, ""2"", {}]","{""x"": [1, ""2"", {}]}",) -(1 row) - -SELECT * FROM unnest((JSON_QUERY(jsonb '{"jsa": [{"a": 1, "b": ["foo"]}, {"a": 2, "c": {}}, 123]}', '$' RETURNING sqljsonb_rec)).jsa); - unnest ------------------------- - {"a": 1, "b": ["foo"]} - {"a": 2, "c": {}} - 123 -(3 rows) - -SELECT * FROM unnest((JSON_QUERY(jsonb '{"reca": [{"a": 1, "t": ["foo", []]}, {"a": 2, "jb": [{}, true]}]}', '$' RETURNING sqljsonb_reca)).reca); - a | t | js | jb | jsa ----+-------------+----+------------+----- - 1 | ["foo", []] | | | - 2 | | | [{}, true] | -(2 rows) - --- Extension: array types returning -SELECT JSON_QUERY(jsonb '[1,2,null,"3"]', '$[*]' RETURNING int[] WITH WRAPPER); - json_query --------------- - {1,2,NULL,3} -(1 row) - -SELECT * FROM unnest(JSON_QUERY(jsonb '[{"a": 1, "t": ["foo", []]}, {"a": 2, "jb": [{}, true]}]', '$' RETURNING sqljsonb_rec[])); - a | t | js | jb | jsa ----+-------------+----+------------+----- - 1 | ["foo", []] | | | - 2 | | | [{}, true] | -(2 rows) - --- Extension: domain types returning -SELECT JSON_QUERY(jsonb '{"a": 1}', '$.a' RETURNING sqljsonb_int_not_null); - json_query ------------- - 1 -(1 row) - -SELECT JSON_QUERY(jsonb '{"a": 1}', '$.b' RETURNING sqljsonb_int_not_null); -ERROR: domain sqljsonb_int_not_null does not allow null values --- Test timestamptz passing and output -SELECT JSON_QUERY(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts); - json_query ------------------------------ - "2018-02-21T02:34:56+00:00" -(1 row) - -SELECT JSON_QUERY(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING json); - json_query ------------------------------ - "2018-02-21T02:34:56+00:00" -(1 row) - -SELECT JSON_QUERY(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING jsonb); - json_query ------------------------------ - "2018-02-21T02:34:56+00:00" -(1 row) - --- Test constraints -CREATE TABLE test_jsonb_constraints ( - js text, - i int, - x jsonb DEFAULT JSON_QUERY(jsonb '[1,2]', '$[*]' WITH WRAPPER) - CONSTRAINT test_jsonb_constraint1 - CHECK (js IS JSON) - CONSTRAINT test_jsonb_constraint2 - CHECK (JSON_EXISTS(js::jsonb, '$.a' PASSING i + 5 AS int, i::text AS txt, array[1,2,3] as arr)) - CONSTRAINT test_jsonb_constraint3 - CHECK (JSON_VALUE(js::jsonb, '$.a' RETURNING int DEFAULT ('12' || i)::int ON EMPTY ERROR ON ERROR) > i) - CONSTRAINT test_jsonb_constraint4 - CHECK (JSON_QUERY(js::jsonb, '$.a' WITH CONDITIONAL WRAPPER EMPTY OBJECT ON ERROR) < jsonb '[10]') - CONSTRAINT test_jsonb_constraint5 - CHECK (JSON_QUERY(js::jsonb, '$.a' RETURNING char(5) OMIT QUOTES EMPTY ARRAY ON EMPTY) > 'a' COLLATE "C") - CONSTRAINT test_jsonb_constraint6 - CHECK (JSON_EXISTS(js::jsonb, 'strict $.a' RETURNING int TRUE ON ERROR) < 2) -); -\d test_jsonb_constraints - Table "public.test_jsonb_constraints" - Column | Type | Collation | Nullable | Default ---------+---------+-----------+----------+-------------------------------------------------------------------------------- - js | text | | | - i | integer | | | - x | jsonb | | | JSON_QUERY('[1, 2]'::jsonb, '$[*]' RETURNING jsonb WITH UNCONDITIONAL WRAPPER) -Check constraints: - "test_jsonb_constraint1" CHECK (js IS JSON) - "test_jsonb_constraint2" CHECK (JSON_EXISTS(js::jsonb, '$."a"' PASSING i + 5 AS int, i::text AS txt, ARRAY[1, 2, 3] AS arr)) - "test_jsonb_constraint3" CHECK (JSON_VALUE(js::jsonb, '$."a"' RETURNING integer DEFAULT ('12'::text || i)::integer ON EMPTY ERROR ON ERROR) > i) - "test_jsonb_constraint4" CHECK (JSON_QUERY(js::jsonb, '$."a"' RETURNING jsonb WITH CONDITIONAL WRAPPER EMPTY OBJECT ON ERROR) < '[10]'::jsonb) - "test_jsonb_constraint5" CHECK (JSON_QUERY(js::jsonb, '$."a"' RETURNING character(5) OMIT QUOTES EMPTY ARRAY ON EMPTY) > ('a'::bpchar COLLATE "C")) - "test_jsonb_constraint6" CHECK (JSON_EXISTS(js::jsonb, 'strict $."a"' RETURNING integer TRUE ON ERROR) < 2) - -SELECT check_clause -FROM information_schema.check_constraints -WHERE constraint_name LIKE 'test_jsonb_constraint%' -ORDER BY 1; - check_clause --------------------------------------------------------------------------------------------------------------------------- - ((JSON_EXISTS((js)::jsonb, 'strict $."a"' RETURNING integer TRUE ON ERROR) < 2)) - ((JSON_QUERY((js)::jsonb, '$."a"' RETURNING character(5) OMIT QUOTES EMPTY ARRAY ON EMPTY) > ('a'::bpchar COLLATE "C"))) - ((JSON_QUERY((js)::jsonb, '$."a"' RETURNING jsonb WITH CONDITIONAL WRAPPER EMPTY OBJECT ON ERROR) < '[10]'::jsonb)) - ((JSON_VALUE((js)::jsonb, '$."a"' RETURNING integer DEFAULT (('12'::text || i))::integer ON EMPTY ERROR ON ERROR) > i)) - ((js IS JSON)) - (JSON_EXISTS((js)::jsonb, '$."a"' PASSING (i + 5) AS int, (i)::text AS txt, ARRAY[1, 2, 3] AS arr)) -(6 rows) - -SELECT pg_get_expr(adbin, adrelid) -FROM pg_attrdef -WHERE adrelid = 'test_jsonb_constraints'::regclass -ORDER BY 1; - pg_get_expr --------------------------------------------------------------------------------- - JSON_QUERY('[1, 2]'::jsonb, '$[*]' RETURNING jsonb WITH UNCONDITIONAL WRAPPER) -(1 row) - -INSERT INTO test_jsonb_constraints VALUES ('', 1); -ERROR: new row for relation "test_jsonb_constraints" violates check constraint "test_jsonb_constraint1" -DETAIL: Failing row contains (, 1, [1, 2]). -INSERT INTO test_jsonb_constraints VALUES ('1', 1); -ERROR: new row for relation "test_jsonb_constraints" violates check constraint "test_jsonb_constraint2" -DETAIL: Failing row contains (1, 1, [1, 2]). -INSERT INTO test_jsonb_constraints VALUES ('[]'); -ERROR: new row for relation "test_jsonb_constraints" violates check constraint "test_jsonb_constraint2" -DETAIL: Failing row contains ([], null, [1, 2]). -INSERT INTO test_jsonb_constraints VALUES ('{"b": 1}', 1); -ERROR: new row for relation "test_jsonb_constraints" violates check constraint "test_jsonb_constraint2" -DETAIL: Failing row contains ({"b": 1}, 1, [1, 2]). -INSERT INTO test_jsonb_constraints VALUES ('{"a": 1}', 1); -ERROR: new row for relation "test_jsonb_constraints" violates check constraint "test_jsonb_constraint3" -DETAIL: Failing row contains ({"a": 1}, 1, [1, 2]). -INSERT INTO test_jsonb_constraints VALUES ('{"a": 7}', 1); -ERROR: new row for relation "test_jsonb_constraints" violates check constraint "test_jsonb_constraint5" -DETAIL: Failing row contains ({"a": 7}, 1, [1, 2]). -INSERT INTO test_jsonb_constraints VALUES ('{"a": 10}', 1); -ERROR: new row for relation "test_jsonb_constraints" violates check constraint "test_jsonb_constraint4" -DETAIL: Failing row contains ({"a": 10}, 1, [1, 2]). -DROP TABLE test_jsonb_constraints; --- Test mutabilily od query functions -CREATE TABLE test_jsonb_mutability(js jsonb); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$')); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a[0]')); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime()')); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@ < $.datetime())')); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime() < $.datetime())')); -ERROR: functions in index expression must be marked IMMUTABLE -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime() < $.datetime("HH:MI TZH"))')); -ERROR: functions in index expression must be marked IMMUTABLE -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime("HH:MI TZH") < $.datetime("HH:MI TZH"))')); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime("HH:MI") < $.datetime("YY-MM-DD HH:MI"))')); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime("HH:MI TZH") < $.datetime("YY-MM-DD HH:MI"))')); -ERROR: functions in index expression must be marked IMMUTABLE -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime("HH:MI TZH") < $x' PASSING '12:34'::timetz AS x)); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime("HH:MI TZH") < $y' PASSING '12:34'::timetz AS x)); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime() < $x' PASSING '12:34'::timetz AS x)); -ERROR: functions in index expression must be marked IMMUTABLE -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime() < $x' PASSING '1234'::int AS x)); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime() ? (@ == $x)' PASSING '12:34'::time AS x)); -ERROR: functions in index expression must be marked IMMUTABLE -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime("YY-MM-DD") ? (@ == $x)' PASSING '2020-07-14'::date AS x)); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$[1, $.a ? (@.datetime() == $x)]' PASSING '12:34'::time AS x)); -ERROR: functions in index expression must be marked IMMUTABLE -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$[1, 0 to $.a ? (@.datetime() == $x)]' PASSING '12:34'::time AS x)); -ERROR: functions in index expression must be marked IMMUTABLE -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$[1, $.a ? (@.datetime("HH:MI") == $x)]' PASSING '12:34'::time AS x)); -DROP TABLE test_jsonb_mutability; --- JSON_TABLE --- Should fail (JSON_TABLE can be used only in FROM clause) -SELECT JSON_TABLE('[]', '$'); -ERROR: syntax error at or near "(" -LINE 1: SELECT JSON_TABLE('[]', '$'); - ^ --- Should fail (no columns) -SELECT * FROM JSON_TABLE(NULL, '$' COLUMNS ()); -ERROR: syntax error at or near ")" -LINE 1: SELECT * FROM JSON_TABLE(NULL, '$' COLUMNS ()); - ^ -SELECT * FROM JSON_TABLE (NULL::jsonb, '$' COLUMNS (v1 timestamp)) AS f (v1, v2); -ERROR: JSON_TABLE function has 1 columns available but 2 columns specified --- NULL => empty table -SELECT * FROM JSON_TABLE(NULL::jsonb, '$' COLUMNS (foo int)) bar; - foo ------ -(0 rows) - --- -SELECT * FROM JSON_TABLE(jsonb '123', '$' - COLUMNS (item int PATH '$', foo int)) bar; - item | foo -------+----- - 123 | -(1 row) - --- JSON_TABLE: basic functionality -CREATE DOMAIN jsonb_test_domain AS text CHECK (value <> 'foo'); -SELECT * -FROM - (VALUES - ('1'), - ('[]'), - ('{}'), - ('[1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""]') - ) vals(js) - LEFT OUTER JOIN --- JSON_TABLE is implicitly lateral - JSON_TABLE( - vals.js::jsonb, 'lax $[*]' - COLUMNS ( - id FOR ORDINALITY, - id2 FOR ORDINALITY, -- allowed additional ordinality columns - "int" int PATH '$', - "text" text PATH '$', - "char(4)" char(4) PATH '$', - "bool" bool PATH '$', - "numeric" numeric PATH '$', - "domain" jsonb_test_domain PATH '$', - js json PATH '$', - jb jsonb PATH '$', - jst text FORMAT JSON PATH '$', - jsc char(4) FORMAT JSON PATH '$', - jsv varchar(4) FORMAT JSON PATH '$', - jsb jsonb FORMAT JSON PATH '$', - jsbq jsonb FORMAT JSON PATH '$' OMIT QUOTES, - aaa int, -- implicit path '$."aaa"', - aaa1 int PATH '$.aaa', - exists1 bool EXISTS PATH '$.aaa', - exists2 int EXISTS PATH '$.aaa', - exists3 int EXISTS PATH 'strict $.aaa' UNKNOWN ON ERROR, - exists4 text EXISTS PATH 'strict $.aaa' FALSE ON ERROR, - js2 json PATH '$', - jsb2w jsonb PATH '$' WITH WRAPPER, - jsb2q jsonb PATH '$' OMIT QUOTES, - ia int[] PATH '$', - ta text[] PATH '$', - jba jsonb[] PATH '$' - ) - ) jt - ON true; - js | id | id2 | int | text | char(4) | bool | numeric | domain | js | jb | jst | jsc | jsv | jsb | jsbq | aaa | aaa1 | exists1 | exists2 | exists3 | exists4 | js2 | jsb2w | jsb2q | ia | ta | jba ----------------------------------------------------------------------------------------+----+-----+-----+---------+---------+------+---------+---------+--------------+--------------+--------------+------+------+--------------+--------------+-----+------+---------+---------+---------+---------+--------------+----------------+--------------+----+----+----- - 1 | 1 | 1 | 1 | 1 | 1 | | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | | | f | 0 | | false | 1 | [1] | 1 | | | - [] | | | | | | | | | | | | | | | | | | | | | | | | | | | - {} | 1 | 1 | | | | | | | {} | {} | {} | {} | {} | {} | {} | | | f | 0 | | false | {} | [{}] | {} | | | - [1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""] | 1 | 1 | 1 | 1 | 1 | | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | | | f | 0 | | false | 1 | [1] | 1 | | | - [1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""] | 2 | 2 | 1 | 1.23 | 1.23 | | 1.23 | 1.23 | 1.23 | 1.23 | 1.23 | 1.23 | 1.23 | 1.23 | 1.23 | | | f | 0 | | false | 1.23 | [1.23] | 1.23 | | | - [1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""] | 3 | 3 | 2 | 2 | 2 | | 2 | 2 | "2" | "2" | "2" | "2" | "2" | "2" | 2 | | | f | 0 | | false | "2" | ["2"] | 2 | | | - [1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""] | 4 | 4 | | aaaaaaa | aaaa | | | aaaaaaa | "aaaaaaa" | "aaaaaaa" | "aaaaaaa" | "aaa | "aaa | "aaaaaaa" | | | | f | 0 | | false | "aaaaaaa" | ["aaaaaaa"] | | | | - [1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""] | 5 | 5 | | foo | foo | | | | "foo" | "foo" | "foo" | "foo | "foo | "foo" | | | | f | 0 | | false | "foo" | ["foo"] | | | | - [1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""] | 6 | 6 | | | | | | | null | null | null | null | null | null | null | | | f | 0 | | false | null | [null] | null | | | - [1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""] | 7 | 7 | 0 | false | fals | f | | false | false | false | false | fals | fals | false | false | | | f | 0 | | false | false | [false] | false | | | - [1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""] | 8 | 8 | 1 | true | true | t | | true | true | true | true | true | true | true | true | | | f | 0 | | false | true | [true] | true | | | - [1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""] | 9 | 9 | | | | | | | {"aaa": 123} | {"aaa": 123} | {"aaa": 123} | {"aa | {"aa | {"aaa": 123} | {"aaa": 123} | 123 | 123 | t | 1 | 1 | true | {"aaa": 123} | [{"aaa": 123}] | {"aaa": 123} | | | - [1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""] | 10 | 10 | | [1,2] | [1,2 | | | [1,2] | "[1,2]" | "[1,2]" | "[1,2]" | "[1, | "[1, | "[1,2]" | [1, 2] | | | f | 0 | | false | "[1,2]" | ["[1,2]"] | [1, 2] | | | - [1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""] | 11 | 11 | | "str" | "str | | | "str" | "\"str\"" | "\"str\"" | "\"str\"" | "\"s | "\"s | "\"str\"" | "str" | | | f | 0 | | false | "\"str\"" | ["\"str\""] | "str" | | | -(14 rows) - --- JSON_TABLE: Test backward parsing -CREATE VIEW jsonb_table_view AS -SELECT * FROM - JSON_TABLE( - jsonb 'null', 'lax $[*]' PASSING 1 + 2 AS a, json '"foo"' AS "b c" - COLUMNS ( - id FOR ORDINALITY, - id2 FOR ORDINALITY, -- allowed additional ordinality columns - "int" int PATH '$', - "text" text PATH '$', - "char(4)" char(4) PATH '$', - "bool" bool PATH '$', - "numeric" numeric PATH '$', - "domain" jsonb_test_domain PATH '$', - js json PATH '$', - jb jsonb PATH '$', - jst text FORMAT JSON PATH '$', - jsc char(4) FORMAT JSON PATH '$', - jsv varchar(4) FORMAT JSON PATH '$', - jsb jsonb FORMAT JSON PATH '$', - jsbq jsonb FORMAT JSON PATH '$' OMIT QUOTES, - aaa int, -- implicit path '$."aaa"', - aaa1 int PATH '$.aaa', - exists1 bool EXISTS PATH '$.aaa', - exists2 int EXISTS PATH '$.aaa' TRUE ON ERROR, - exists3 text EXISTS PATH 'strict $.aaa' UNKNOWN ON ERROR, - js2 json PATH '$', - jsb2w jsonb PATH '$' WITH WRAPPER, - jsb2q jsonb PATH '$' OMIT QUOTES, - ia int[] PATH '$', - ta text[] PATH '$', - jba jsonb[] PATH '$', - NESTED PATH '$[1]' AS p1 COLUMNS ( - a1 int, - NESTED PATH '$[*]' AS "p1 1" COLUMNS ( - a11 text - ), - b1 text - ), - NESTED PATH '$[2]' AS p2 COLUMNS ( - NESTED PATH '$[*]' AS "p2:1" COLUMNS ( - a21 text - ), - NESTED PATH '$[*]' AS p22 COLUMNS ( - a22 text - ) - ) - ) - ); -\sv jsonb_table_view -CREATE OR REPLACE VIEW public.jsonb_table_view AS - SELECT "json_table".id, - "json_table".id2, - "json_table"."int", - "json_table".text, - "json_table"."char(4)", - "json_table".bool, - "json_table"."numeric", - "json_table".domain, - "json_table".js, - "json_table".jb, - "json_table".jst, - "json_table".jsc, - "json_table".jsv, - "json_table".jsb, - "json_table".jsbq, - "json_table".aaa, - "json_table".aaa1, - "json_table".exists1, - "json_table".exists2, - "json_table".exists3, - "json_table".js2, - "json_table".jsb2w, - "json_table".jsb2q, - "json_table".ia, - "json_table".ta, - "json_table".jba, - "json_table".a1, - "json_table".b1, - "json_table".a11, - "json_table".a21, - "json_table".a22 - FROM JSON_TABLE( - 'null'::jsonb, '$[*]' AS json_table_path_1 - PASSING - 1 + 2 AS a, - '"foo"'::json AS "b c" - COLUMNS ( - id FOR ORDINALITY, - id2 FOR ORDINALITY, - "int" integer PATH '$', - text text PATH '$', - "char(4)" character(4) PATH '$', - bool boolean PATH '$', - "numeric" numeric PATH '$', - domain jsonb_test_domain PATH '$', - js json PATH '$', - jb jsonb PATH '$', - jst text FORMAT JSON PATH '$', - jsc character(4) FORMAT JSON PATH '$', - jsv character varying(4) FORMAT JSON PATH '$', - jsb jsonb PATH '$', - jsbq jsonb PATH '$' OMIT QUOTES, - aaa integer PATH '$."aaa"', - aaa1 integer PATH '$."aaa"', - exists1 boolean EXISTS PATH '$."aaa"', - exists2 integer EXISTS PATH '$."aaa"' TRUE ON ERROR, - exists3 text EXISTS PATH 'strict $."aaa"' UNKNOWN ON ERROR, - js2 json PATH '$', - jsb2w jsonb PATH '$' WITH UNCONDITIONAL WRAPPER, - jsb2q jsonb PATH '$' OMIT QUOTES, - ia integer[] PATH '$', - ta text[] PATH '$', - jba jsonb[] PATH '$', - NESTED PATH '$[1]' AS p1 - COLUMNS ( - a1 integer PATH '$."a1"', - b1 text PATH '$."b1"', - NESTED PATH '$[*]' AS "p1 1" - COLUMNS ( - a11 text PATH '$."a11"' - ) - ), - NESTED PATH '$[2]' AS p2 - COLUMNS ( - NESTED PATH '$[*]' AS "p2:1" - COLUMNS ( - a21 text PATH '$."a21"' - ), - NESTED PATH '$[*]' AS p22 - COLUMNS ( - a22 text PATH '$."a22"' - ) - ) - ) - PLAN (json_table_path_1 OUTER ((p1 OUTER "p1 1") UNION (p2 OUTER ("p2:1" UNION p22)))) - ) -EXPLAIN (COSTS OFF, VERBOSE) SELECT * FROM jsonb_table_view; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Table Function Scan on "json_table" - Output: "json_table".id, "json_table".id2, "json_table"."int", "json_table".text, "json_table"."char(4)", "json_table".bool, "json_table"."numeric", "json_table".domain, "json_table".js, "json_table".jb, "json_table".jst, "json_table".jsc, "json_table".jsv, "json_table".jsb, "json_table".jsbq, "json_table".aaa, "json_table".aaa1, "json_table".exists1, "json_table".exists2, "json_table".exists3, "json_table".js2, "json_table".jsb2w, "json_table".jsb2q, "json_table".ia, "json_table".ta, "json_table".jba, "json_table".a1, "json_table".b1, "json_table".a11, "json_table".a21, "json_table".a22 - Table Function Call: JSON_TABLE('null'::jsonb, '$[*]' AS json_table_path_1 PASSING 3 AS a, '"foo"'::jsonb AS "b c" COLUMNS (id FOR ORDINALITY, id2 FOR ORDINALITY, "int" integer PATH '$', text text PATH '$', "char(4)" character(4) PATH '$', bool boolean PATH '$', "numeric" numeric PATH '$', domain jsonb_test_domain PATH '$', js json PATH '$', jb jsonb PATH '$', jst text FORMAT JSON PATH '$', jsc character(4) FORMAT JSON PATH '$', jsv character varying(4) FORMAT JSON PATH '$', jsb jsonb PATH '$', jsbq jsonb PATH '$' OMIT QUOTES, aaa integer PATH '$."aaa"', aaa1 integer PATH '$."aaa"', exists1 boolean EXISTS PATH '$."aaa"', exists2 integer EXISTS PATH '$."aaa"' TRUE ON ERROR, exists3 text EXISTS PATH 'strict $."aaa"' UNKNOWN ON ERROR, js2 json PATH '$', jsb2w jsonb PATH '$' WITH UNCONDITIONAL WRAPPER, jsb2q jsonb PATH '$' OMIT QUOTES, ia integer[] PATH '$', ta text[] PATH '$', jba jsonb[] PATH '$', NESTED PATH '$[1]' AS p1 COLUMNS (a1 integer PATH '$."a1"', b1 text PATH '$."b1"', NESTED PATH '$[*]' AS "p1 1" COLUMNS (a11 text PATH '$."a11"')), NESTED PATH '$[2]' AS p2 COLUMNS ( NESTED PATH '$[*]' AS "p2:1" COLUMNS (a21 text PATH '$."a21"'), NESTED PATH '$[*]' AS p22 COLUMNS (a22 text PATH '$."a22"'))) PLAN (json_table_path_1 OUTER ((p1 OUTER "p1 1") UNION (p2 OUTER ("p2:1" UNION p22))))) -(3 rows) - -DROP VIEW jsonb_table_view; -DROP DOMAIN jsonb_test_domain; --- JSON_TABLE: ON EMPTY/ON ERROR behavior -SELECT * -FROM - (VALUES ('1'), ('"err"')) vals(js), - JSON_TABLE(vals.js::jsonb, '$' COLUMNS (a int PATH '$')) jt; - js | a --------+--- - 1 | 1 - "err" | -(2 rows) - -SELECT * -FROM - (VALUES ('1'), ('"err"')) vals(js) - LEFT OUTER JOIN - JSON_TABLE(vals.js::jsonb, '$' COLUMNS (a int PATH '$') ERROR ON ERROR) jt - ON true; -ERROR: invalid input syntax for type integer: "err" -SELECT * -FROM - (VALUES ('1'), ('"err"')) vals(js) - LEFT OUTER JOIN - JSON_TABLE(vals.js::jsonb, '$' COLUMNS (a int PATH '$' ERROR ON ERROR)) jt - ON true; -ERROR: invalid input syntax for type integer: "err" -SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (a int PATH '$.a' ERROR ON EMPTY)) jt; - a ---- - -(1 row) - -SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (a int PATH 'strict $.a' ERROR ON EMPTY) ERROR ON ERROR) jt; -ERROR: jsonpath member accessor can only be applied to an object -SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (a int PATH 'lax $.a' ERROR ON EMPTY) ERROR ON ERROR) jt; -ERROR: no SQL/JSON item -SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int PATH '$' DEFAULT 1 ON EMPTY DEFAULT 2 ON ERROR)) jt; - a ---- - 2 -(1 row) - -SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int PATH 'strict $.a' DEFAULT 1 ON EMPTY DEFAULT 2 ON ERROR)) jt; - a ---- - 2 -(1 row) - -SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int PATH 'lax $.a' DEFAULT 1 ON EMPTY DEFAULT 2 ON ERROR)) jt; - a ---- - 1 -(1 row) - --- JSON_TABLE: EXISTS PATH types -SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int4 EXISTS PATH '$.a')); - a ---- - 0 -(1 row) - -SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int2 EXISTS PATH '$.a')); -ERROR: cannot cast type boolean to smallint -LINE 1: ...ELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int2 EXI... - ^ -SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int8 EXISTS PATH '$.a')); -ERROR: cannot cast type boolean to bigint -LINE 1: ...ELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int8 EXI... - ^ -SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a float4 EXISTS PATH '$.a')); -ERROR: cannot cast type boolean to real -LINE 1: ...ELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a float4 E... - ^ -SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a char(3) EXISTS PATH '$.a')); - a ------ - fal -(1 row) - -SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a json EXISTS PATH '$.a')); -ERROR: cannot cast type boolean to json -LINE 1: ...ELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a json EXI... - ^ -SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a jsonb EXISTS PATH '$.a')); -ERROR: cannot cast type boolean to jsonb -LINE 1: ...ELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a jsonb EX... - ^ --- JSON_TABLE: nested paths and plans --- Should fail (JSON_TABLE columns must contain explicit AS path --- specifications if explicit PLAN clause is used) -SELECT * FROM JSON_TABLE( - jsonb '[]', '$' -- AS required here - COLUMNS ( - foo int PATH '$' - ) - PLAN DEFAULT (UNION) -) jt; -ERROR: invalid JSON_TABLE expression -LINE 2: jsonb '[]', '$' -- AS required here - ^ -DETAIL: JSON_TABLE columns must contain explicit AS pathname specification if explicit PLAN clause is used -SELECT * FROM JSON_TABLE( - jsonb '[]', '$' AS path1 - COLUMNS ( - NESTED PATH '$' COLUMNS ( -- AS required here - foo int PATH '$' - ) - ) - PLAN DEFAULT (UNION) -) jt; -ERROR: invalid JSON_TABLE expression -LINE 4: NESTED PATH '$' COLUMNS ( -- AS required here - ^ -DETAIL: JSON_TABLE columns must contain explicit AS pathname specification if explicit PLAN clause is used --- Should fail (column names must be distinct) -SELECT * FROM JSON_TABLE( - jsonb '[]', '$' AS a - COLUMNS ( - a int - ) -) jt; -ERROR: duplicate JSON_TABLE column name: a -HINT: JSON_TABLE column names must be distinct from one another. -SELECT * FROM JSON_TABLE( - jsonb '[]', '$' AS a - COLUMNS ( - b int, - NESTED PATH '$' AS a - COLUMNS ( - c int - ) - ) -) jt; -ERROR: duplicate JSON_TABLE column name: a -HINT: JSON_TABLE column names must be distinct from one another. -SELECT * FROM JSON_TABLE( - jsonb '[]', '$' - COLUMNS ( - b int, - NESTED PATH '$' AS b - COLUMNS ( - c int - ) - ) -) jt; -ERROR: duplicate JSON_TABLE column name: b -HINT: JSON_TABLE column names must be distinct from one another. -SELECT * FROM JSON_TABLE( - jsonb '[]', '$' - COLUMNS ( - NESTED PATH '$' AS a - COLUMNS ( - b int - ), - NESTED PATH '$' - COLUMNS ( - NESTED PATH '$' AS a - COLUMNS ( - c int - ) - ) - ) -) jt; -ERROR: duplicate JSON_TABLE column name: a -HINT: JSON_TABLE column names must be distinct from one another. --- JSON_TABLE: plan validation -SELECT * FROM JSON_TABLE( - jsonb 'null', '$[*]' AS p0 - COLUMNS ( - NESTED PATH '$' AS p1 COLUMNS ( - NESTED PATH '$' AS p11 COLUMNS ( foo int ), - NESTED PATH '$' AS p12 COLUMNS ( bar int ) - ), - NESTED PATH '$' AS p2 COLUMNS ( - NESTED PATH '$' AS p21 COLUMNS ( baz int ) - ) - ) - PLAN (p1) -) jt; -ERROR: invalid JSON_TABLE plan -LINE 12: PLAN (p1) - ^ -DETAIL: Path name mismatch: expected p0 but p1 is given. -SELECT * FROM JSON_TABLE( - jsonb 'null', '$[*]' AS p0 - COLUMNS ( - NESTED PATH '$' AS p1 COLUMNS ( - NESTED PATH '$' AS p11 COLUMNS ( foo int ), - NESTED PATH '$' AS p12 COLUMNS ( bar int ) - ), - NESTED PATH '$' AS p2 COLUMNS ( - NESTED PATH '$' AS p21 COLUMNS ( baz int ) - ) - ) - PLAN (p0) -) jt; -ERROR: invalid JSON_TABLE plan -LINE 4: NESTED PATH '$' AS p1 COLUMNS ( - ^ -DETAIL: Plan node for nested path p1 was not found in plan. -SELECT * FROM JSON_TABLE( - jsonb 'null', '$[*]' AS p0 - COLUMNS ( - NESTED PATH '$' AS p1 COLUMNS ( - NESTED PATH '$' AS p11 COLUMNS ( foo int ), - NESTED PATH '$' AS p12 COLUMNS ( bar int ) - ), - NESTED PATH '$' AS p2 COLUMNS ( - NESTED PATH '$' AS p21 COLUMNS ( baz int ) - ) - ) - PLAN (p0 OUTER p3) -) jt; -ERROR: invalid JSON_TABLE plan -LINE 4: NESTED PATH '$' AS p1 COLUMNS ( - ^ -DETAIL: Plan node for nested path p1 was not found in plan. -SELECT * FROM JSON_TABLE( - jsonb 'null', '$[*]' AS p0 - COLUMNS ( - NESTED PATH '$' AS p1 COLUMNS ( - NESTED PATH '$' AS p11 COLUMNS ( foo int ), - NESTED PATH '$' AS p12 COLUMNS ( bar int ) - ), - NESTED PATH '$' AS p2 COLUMNS ( - NESTED PATH '$' AS p21 COLUMNS ( baz int ) - ) - ) - PLAN (p0 UNION p1 UNION p11) -) jt; -ERROR: invalid JSON_TABLE plan -LINE 12: PLAN (p0 UNION p1 UNION p11) - ^ -DETAIL: Expected INNER or OUTER JSON_TABLE plan node. -SELECT * FROM JSON_TABLE( - jsonb 'null', '$[*]' AS p0 - COLUMNS ( - NESTED PATH '$' AS p1 COLUMNS ( - NESTED PATH '$' AS p11 COLUMNS ( foo int ), - NESTED PATH '$' AS p12 COLUMNS ( bar int ) - ), - NESTED PATH '$' AS p2 COLUMNS ( - NESTED PATH '$' AS p21 COLUMNS ( baz int ) - ) - ) - PLAN (p0 OUTER (p1 CROSS p13)) -) jt; -ERROR: invalid JSON_TABLE plan -LINE 8: NESTED PATH '$' AS p2 COLUMNS ( - ^ -DETAIL: Plan node for nested path p2 was not found in plan. -SELECT * FROM JSON_TABLE( - jsonb 'null', '$[*]' AS p0 - COLUMNS ( - NESTED PATH '$' AS p1 COLUMNS ( - NESTED PATH '$' AS p11 COLUMNS ( foo int ), - NESTED PATH '$' AS p12 COLUMNS ( bar int ) - ), - NESTED PATH '$' AS p2 COLUMNS ( - NESTED PATH '$' AS p21 COLUMNS ( baz int ) - ) - ) - PLAN (p0 OUTER (p1 CROSS p2)) -) jt; -ERROR: invalid JSON_TABLE plan -LINE 5: NESTED PATH '$' AS p11 COLUMNS ( foo int ), - ^ -DETAIL: Plan node for nested path p11 was not found in plan. -SELECT * FROM JSON_TABLE( - jsonb 'null', '$[*]' AS p0 - COLUMNS ( - NESTED PATH '$' AS p1 COLUMNS ( - NESTED PATH '$' AS p11 COLUMNS ( foo int ), - NESTED PATH '$' AS p12 COLUMNS ( bar int ) - ), - NESTED PATH '$' AS p2 COLUMNS ( - NESTED PATH '$' AS p21 COLUMNS ( baz int ) - ) - ) - PLAN (p0 OUTER ((p1 UNION p11) CROSS p2)) -) jt; -ERROR: invalid JSON_TABLE plan -LINE 12: PLAN (p0 OUTER ((p1 UNION p11) CROSS p2)) - ^ -DETAIL: Plan node contains some extra or duplicate sibling nodes. -SELECT * FROM JSON_TABLE( - jsonb 'null', '$[*]' AS p0 - COLUMNS ( - NESTED PATH '$' AS p1 COLUMNS ( - NESTED PATH '$' AS p11 COLUMNS ( foo int ), - NESTED PATH '$' AS p12 COLUMNS ( bar int ) - ), - NESTED PATH '$' AS p2 COLUMNS ( - NESTED PATH '$' AS p21 COLUMNS ( baz int ) - ) - ) - PLAN (p0 OUTER ((p1 INNER p11) CROSS p2)) -) jt; -ERROR: invalid JSON_TABLE plan -LINE 6: NESTED PATH '$' AS p12 COLUMNS ( bar int ) - ^ -DETAIL: Plan node for nested path p12 was not found in plan. -SELECT * FROM JSON_TABLE( - jsonb 'null', '$[*]' AS p0 - COLUMNS ( - NESTED PATH '$' AS p1 COLUMNS ( - NESTED PATH '$' AS p11 COLUMNS ( foo int ), - NESTED PATH '$' AS p12 COLUMNS ( bar int ) - ), - NESTED PATH '$' AS p2 COLUMNS ( - NESTED PATH '$' AS p21 COLUMNS ( baz int ) - ) - ) - PLAN (p0 OUTER ((p1 INNER (p12 CROSS p11)) CROSS p2)) -) jt; -ERROR: invalid JSON_TABLE plan -LINE 9: NESTED PATH '$' AS p21 COLUMNS ( baz int ) - ^ -DETAIL: Plan node for nested path p21 was not found in plan. -SELECT * FROM JSON_TABLE( - jsonb 'null', 'strict $[*]' AS p0 - COLUMNS ( - NESTED PATH '$' AS p1 COLUMNS ( - NESTED PATH '$' AS p11 COLUMNS ( foo int ), - NESTED PATH '$' AS p12 COLUMNS ( bar int ) - ), - NESTED PATH '$' AS p2 COLUMNS ( - NESTED PATH '$' AS p21 COLUMNS ( baz int ) - ) - ) - PLAN (p0 OUTER ((p1 INNER (p12 CROSS p11)) CROSS (p2 INNER p21))) -) jt; - bar | foo | baz ------+-----+----- -(0 rows) - -SELECT * FROM JSON_TABLE( - jsonb 'null', 'strict $[*]' -- without root path name - COLUMNS ( - NESTED PATH '$' AS p1 COLUMNS ( - NESTED PATH '$' AS p11 COLUMNS ( foo int ), - NESTED PATH '$' AS p12 COLUMNS ( bar int ) - ), - NESTED PATH '$' AS p2 COLUMNS ( - NESTED PATH '$' AS p21 COLUMNS ( baz int ) - ) - ) - PLAN ((p1 INNER (p12 CROSS p11)) CROSS (p2 INNER p21)) -) jt; -ERROR: invalid JSON_TABLE expression -LINE 2: jsonb 'null', 'strict $[*]' -- without root path name - ^ -DETAIL: JSON_TABLE columns must contain explicit AS pathname specification if explicit PLAN clause is used --- JSON_TABLE: plan execution -CREATE TEMP TABLE jsonb_table_test (js jsonb); -INSERT INTO jsonb_table_test -VALUES ( - '[ - {"a": 1, "b": [], "c": []}, - {"a": 2, "b": [1, 2, 3], "c": [10, null, 20]}, - {"a": 3, "b": [1, 2], "c": []}, - {"x": "4", "b": [1, 2], "c": 123} - ]' -); --- unspecified plan (outer, union) -select - jt.* -from - jsonb_table_test jtt, - json_table ( - jtt.js,'strict $[*]' as p - columns ( - n for ordinality, - a int path 'lax $.a' default -1 on empty, - nested path 'strict $.b[*]' as pb columns ( b int path '$' ), - nested path 'strict $.c[*]' as pc columns ( c int path '$' ) - ) - ) jt; - n | a | b | c ----+----+---+---- - 1 | 1 | | - 2 | 2 | 1 | - 2 | 2 | 2 | - 2 | 2 | 3 | - 2 | 2 | | 10 - 2 | 2 | | - 2 | 2 | | 20 - 3 | 3 | 1 | - 3 | 3 | 2 | - 4 | -1 | 1 | - 4 | -1 | 2 | -(11 rows) - --- default plan (outer, union) -select - jt.* -from - jsonb_table_test jtt, - json_table ( - jtt.js,'strict $[*]' as p - columns ( - n for ordinality, - a int path 'lax $.a' default -1 on empty, - nested path 'strict $.b[*]' as pb columns ( b int path '$' ), - nested path 'strict $.c[*]' as pc columns ( c int path '$' ) - ) - plan default (outer, union) - ) jt; - n | a | b | c ----+----+---+---- - 1 | 1 | | - 2 | 2 | 1 | - 2 | 2 | 2 | - 2 | 2 | 3 | - 2 | 2 | | 10 - 2 | 2 | | - 2 | 2 | | 20 - 3 | 3 | 1 | - 3 | 3 | 2 | - 4 | -1 | 1 | - 4 | -1 | 2 | -(11 rows) - --- specific plan (p outer (pb union pc)) -select - jt.* -from - jsonb_table_test jtt, - json_table ( - jtt.js,'strict $[*]' as p - columns ( - n for ordinality, - a int path 'lax $.a' default -1 on empty, - nested path 'strict $.b[*]' as pb columns ( b int path '$' ), - nested path 'strict $.c[*]' as pc columns ( c int path '$' ) - ) - plan (p outer (pb union pc)) - ) jt; - n | a | b | c ----+----+---+---- - 1 | 1 | | - 2 | 2 | 1 | - 2 | 2 | 2 | - 2 | 2 | 3 | - 2 | 2 | | 10 - 2 | 2 | | - 2 | 2 | | 20 - 3 | 3 | 1 | - 3 | 3 | 2 | - 4 | -1 | 1 | - 4 | -1 | 2 | -(11 rows) - --- specific plan (p outer (pc union pb)) -select - jt.* -from - jsonb_table_test jtt, - json_table ( - jtt.js,'strict $[*]' as p - columns ( - n for ordinality, - a int path 'lax $.a' default -1 on empty, - nested path 'strict $.b[*]' as pb columns ( b int path '$' ), - nested path 'strict $.c[*]' as pc columns ( c int path '$' ) - ) - plan (p outer (pc union pb)) - ) jt; - n | a | c | b ----+----+----+--- - 1 | 1 | | - 2 | 2 | 10 | - 2 | 2 | | - 2 | 2 | 20 | - 2 | 2 | | 1 - 2 | 2 | | 2 - 2 | 2 | | 3 - 3 | 3 | | 1 - 3 | 3 | | 2 - 4 | -1 | | 1 - 4 | -1 | | 2 -(11 rows) - --- default plan (inner, union) -select - jt.* -from - jsonb_table_test jtt, - json_table ( - jtt.js,'strict $[*]' as p - columns ( - n for ordinality, - a int path 'lax $.a' default -1 on empty, - nested path 'strict $.b[*]' as pb columns ( b int path '$' ), - nested path 'strict $.c[*]' as pc columns ( c int path '$' ) - ) - plan default (inner) - ) jt; - n | a | b | c ----+----+---+---- - 2 | 2 | 1 | - 2 | 2 | 2 | - 2 | 2 | 3 | - 2 | 2 | | 10 - 2 | 2 | | - 2 | 2 | | 20 - 3 | 3 | 1 | - 3 | 3 | 2 | - 4 | -1 | 1 | - 4 | -1 | 2 | -(10 rows) - --- specific plan (p inner (pb union pc)) -select - jt.* -from - jsonb_table_test jtt, - json_table ( - jtt.js,'strict $[*]' as p - columns ( - n for ordinality, - a int path 'lax $.a' default -1 on empty, - nested path 'strict $.b[*]' as pb columns ( b int path '$' ), - nested path 'strict $.c[*]' as pc columns ( c int path '$' ) - ) - plan (p inner (pb union pc)) - ) jt; - n | a | b | c ----+----+---+---- - 2 | 2 | 1 | - 2 | 2 | 2 | - 2 | 2 | 3 | - 2 | 2 | | 10 - 2 | 2 | | - 2 | 2 | | 20 - 3 | 3 | 1 | - 3 | 3 | 2 | - 4 | -1 | 1 | - 4 | -1 | 2 | -(10 rows) - --- default plan (inner, cross) -select - jt.* -from - jsonb_table_test jtt, - json_table ( - jtt.js,'strict $[*]' as p - columns ( - n for ordinality, - a int path 'lax $.a' default -1 on empty, - nested path 'strict $.b[*]' as pb columns ( b int path '$' ), - nested path 'strict $.c[*]' as pc columns ( c int path '$' ) - ) - plan default (cross, inner) - ) jt; - n | a | b | c ----+---+---+---- - 2 | 2 | 1 | 10 - 2 | 2 | 1 | - 2 | 2 | 1 | 20 - 2 | 2 | 2 | 10 - 2 | 2 | 2 | - 2 | 2 | 2 | 20 - 2 | 2 | 3 | 10 - 2 | 2 | 3 | - 2 | 2 | 3 | 20 -(9 rows) - --- specific plan (p inner (pb cross pc)) -select - jt.* -from - jsonb_table_test jtt, - json_table ( - jtt.js,'strict $[*]' as p - columns ( - n for ordinality, - a int path 'lax $.a' default -1 on empty, - nested path 'strict $.b[*]' as pb columns ( b int path '$' ), - nested path 'strict $.c[*]' as pc columns ( c int path '$' ) - ) - plan (p inner (pb cross pc)) - ) jt; - n | a | b | c ----+---+---+---- - 2 | 2 | 1 | 10 - 2 | 2 | 1 | - 2 | 2 | 1 | 20 - 2 | 2 | 2 | 10 - 2 | 2 | 2 | - 2 | 2 | 2 | 20 - 2 | 2 | 3 | 10 - 2 | 2 | 3 | - 2 | 2 | 3 | 20 -(9 rows) - --- default plan (outer, cross) -select - jt.* -from - jsonb_table_test jtt, - json_table ( - jtt.js,'strict $[*]' as p - columns ( - n for ordinality, - a int path 'lax $.a' default -1 on empty, - nested path 'strict $.b[*]' as pb columns ( b int path '$' ), - nested path 'strict $.c[*]' as pc columns ( c int path '$' ) - ) - plan default (outer, cross) - ) jt; - n | a | b | c ----+----+---+---- - 1 | 1 | | - 2 | 2 | 1 | 10 - 2 | 2 | 1 | - 2 | 2 | 1 | 20 - 2 | 2 | 2 | 10 - 2 | 2 | 2 | - 2 | 2 | 2 | 20 - 2 | 2 | 3 | 10 - 2 | 2 | 3 | - 2 | 2 | 3 | 20 - 3 | 3 | | - 4 | -1 | | -(12 rows) - --- specific plan (p outer (pb cross pc)) -select - jt.* -from - jsonb_table_test jtt, - json_table ( - jtt.js,'strict $[*]' as p - columns ( - n for ordinality, - a int path 'lax $.a' default -1 on empty, - nested path 'strict $.b[*]' as pb columns ( b int path '$' ), - nested path 'strict $.c[*]' as pc columns ( c int path '$' ) - ) - plan (p outer (pb cross pc)) - ) jt; - n | a | b | c ----+----+---+---- - 1 | 1 | | - 2 | 2 | 1 | 10 - 2 | 2 | 1 | - 2 | 2 | 1 | 20 - 2 | 2 | 2 | 10 - 2 | 2 | 2 | - 2 | 2 | 2 | 20 - 2 | 2 | 3 | 10 - 2 | 2 | 3 | - 2 | 2 | 3 | 20 - 3 | 3 | | - 4 | -1 | | -(12 rows) - -select - jt.*, b1 + 100 as b -from - json_table (jsonb - '[ - {"a": 1, "b": [[1, 10], [2], [3, 30, 300]], "c": [1, null, 2]}, - {"a": 2, "b": [10, 20], "c": [1, null, 2]}, - {"x": "3", "b": [11, 22, 33, 44]} - ]', - '$[*]' as p - columns ( - n for ordinality, - a int path 'lax $.a' default -1 on error, - nested path 'strict $.b[*]' as pb columns ( - b text format json path '$', - nested path 'strict $[*]' as pb1 columns ( - b1 int path '$' - ) - ), - nested path 'strict $.c[*]' as pc columns ( - c text format json path '$', - nested path 'strict $[*]' as pc1 columns ( - c1 int path '$' - ) - ) - ) - --plan default(outer, cross) - plan(p outer ((pb inner pb1) cross (pc outer pc1))) - ) jt; - n | a | b | b1 | c | c1 | b ----+---+--------------+-----+------+----+----- - 1 | 1 | [1, 10] | 1 | 1 | | 101 - 1 | 1 | [1, 10] | 1 | null | | 101 - 1 | 1 | [1, 10] | 1 | 2 | | 101 - 1 | 1 | [1, 10] | 10 | 1 | | 110 - 1 | 1 | [1, 10] | 10 | null | | 110 - 1 | 1 | [1, 10] | 10 | 2 | | 110 - 1 | 1 | [2] | 2 | 1 | | 102 - 1 | 1 | [2] | 2 | null | | 102 - 1 | 1 | [2] | 2 | 2 | | 102 - 1 | 1 | [3, 30, 300] | 3 | 1 | | 103 - 1 | 1 | [3, 30, 300] | 3 | null | | 103 - 1 | 1 | [3, 30, 300] | 3 | 2 | | 103 - 1 | 1 | [3, 30, 300] | 30 | 1 | | 130 - 1 | 1 | [3, 30, 300] | 30 | null | | 130 - 1 | 1 | [3, 30, 300] | 30 | 2 | | 130 - 1 | 1 | [3, 30, 300] | 300 | 1 | | 400 - 1 | 1 | [3, 30, 300] | 300 | null | | 400 - 1 | 1 | [3, 30, 300] | 300 | 2 | | 400 - 2 | 2 | | | | | - 3 | | | | | | -(20 rows) - --- Should succeed (JSON arguments are passed to root and nested paths) -SELECT * -FROM - generate_series(1, 4) x, - generate_series(1, 3) y, - JSON_TABLE(jsonb - '[[1,2,3],[2,3,4,5],[3,4,5,6]]', - 'strict $[*] ? (@[*] < $x)' - PASSING x AS x, y AS y - COLUMNS ( - y text FORMAT JSON PATH '$', - NESTED PATH 'strict $[*] ? (@ >= $y)' - COLUMNS ( - z int PATH '$' - ) - ) - ) jt; - x | y | y | z ----+---+--------------+--- - 2 | 1 | [1, 2, 3] | 1 - 2 | 1 | [1, 2, 3] | 2 - 2 | 1 | [1, 2, 3] | 3 - 3 | 1 | [1, 2, 3] | 1 - 3 | 1 | [1, 2, 3] | 2 - 3 | 1 | [1, 2, 3] | 3 - 3 | 1 | [2, 3, 4, 5] | 2 - 3 | 1 | [2, 3, 4, 5] | 3 - 3 | 1 | [2, 3, 4, 5] | 4 - 3 | 1 | [2, 3, 4, 5] | 5 - 4 | 1 | [1, 2, 3] | 1 - 4 | 1 | [1, 2, 3] | 2 - 4 | 1 | [1, 2, 3] | 3 - 4 | 1 | [2, 3, 4, 5] | 2 - 4 | 1 | [2, 3, 4, 5] | 3 - 4 | 1 | [2, 3, 4, 5] | 4 - 4 | 1 | [2, 3, 4, 5] | 5 - 4 | 1 | [3, 4, 5, 6] | 3 - 4 | 1 | [3, 4, 5, 6] | 4 - 4 | 1 | [3, 4, 5, 6] | 5 - 4 | 1 | [3, 4, 5, 6] | 6 - 2 | 2 | [1, 2, 3] | 2 - 2 | 2 | [1, 2, 3] | 3 - 3 | 2 | [1, 2, 3] | 2 - 3 | 2 | [1, 2, 3] | 3 - 3 | 2 | [2, 3, 4, 5] | 2 - 3 | 2 | [2, 3, 4, 5] | 3 - 3 | 2 | [2, 3, 4, 5] | 4 - 3 | 2 | [2, 3, 4, 5] | 5 - 4 | 2 | [1, 2, 3] | 2 - 4 | 2 | [1, 2, 3] | 3 - 4 | 2 | [2, 3, 4, 5] | 2 - 4 | 2 | [2, 3, 4, 5] | 3 - 4 | 2 | [2, 3, 4, 5] | 4 - 4 | 2 | [2, 3, 4, 5] | 5 - 4 | 2 | [3, 4, 5, 6] | 3 - 4 | 2 | [3, 4, 5, 6] | 4 - 4 | 2 | [3, 4, 5, 6] | 5 - 4 | 2 | [3, 4, 5, 6] | 6 - 2 | 3 | [1, 2, 3] | 3 - 3 | 3 | [1, 2, 3] | 3 - 3 | 3 | [2, 3, 4, 5] | 3 - 3 | 3 | [2, 3, 4, 5] | 4 - 3 | 3 | [2, 3, 4, 5] | 5 - 4 | 3 | [1, 2, 3] | 3 - 4 | 3 | [2, 3, 4, 5] | 3 - 4 | 3 | [2, 3, 4, 5] | 4 - 4 | 3 | [2, 3, 4, 5] | 5 - 4 | 3 | [3, 4, 5, 6] | 3 - 4 | 3 | [3, 4, 5, 6] | 4 - 4 | 3 | [3, 4, 5, 6] | 5 - 4 | 3 | [3, 4, 5, 6] | 6 -(52 rows) - --- Should fail (JSON arguments are not passed to column paths) -SELECT * -FROM JSON_TABLE( - jsonb '[1,2,3]', - '$[*] ? (@ < $x)' - PASSING 10 AS x - COLUMNS (y text FORMAT JSON PATH '$ ? (@ < $x)') - ) jt; -ERROR: could not find jsonpath variable "x" --- Extension: non-constant JSON path -SELECT JSON_EXISTS(jsonb '{"a": 123}', '$' || '.' || 'a'); - json_exists -------------- - t -(1 row) - -SELECT JSON_VALUE(jsonb '{"a": 123}', '$' || '.' || 'a'); - json_value ------------- - 123 -(1 row) - -SELECT JSON_VALUE(jsonb '{"a": 123}', '$' || '.' || 'b' DEFAULT 'foo' ON EMPTY); - json_value ------------- - foo -(1 row) - -SELECT JSON_QUERY(jsonb '{"a": 123}', '$' || '.' || 'a'); - json_query ------------- - 123 -(1 row) - -SELECT JSON_QUERY(jsonb '{"a": 123}', '$' || '.' || 'a' WITH WRAPPER); - json_query ------------- - [123] -(1 row) - --- Should fail (invalid path) -SELECT JSON_QUERY(jsonb '{"a": 123}', 'error' || ' ' || 'error'); -ERROR: syntax error at or near " " of jsonpath input --- Should fail (not supported) -SELECT * FROM JSON_TABLE(jsonb '{"a": 123}', '$' || '.' || 'a' COLUMNS (foo int)); -ERROR: only string constants supported in JSON_TABLE path specification -LINE 1: SELECT * FROM JSON_TABLE(jsonb '{"a": 123}', '$' || '.' || '... - ^ --- Test parallel JSON_VALUE() -CREATE UNLOGGED TABLE test_parallel_jsonb_value AS -SELECT i::text::jsonb AS js -FROM generate_series(1, 50000) i; --- encourage use of parallel plans -set parallel_setup_cost=0; -set parallel_tuple_cost=0; -set min_parallel_table_scan_size=0; -set max_parallel_workers_per_gather=4; -set parallel_leader_participation = off; --- Should be non-parallel due to subtransactions -EXPLAIN (COSTS OFF) -SELECT sum(JSON_VALUE(js, '$' RETURNING numeric)) FROM test_parallel_jsonb_value; - QUERY PLAN ---------------------------------------------- - Aggregate - -> Seq Scan on test_parallel_jsonb_value -(2 rows) - -SELECT sum(JSON_VALUE(js, '$' RETURNING numeric)) FROM test_parallel_jsonb_value; - sum ------------- - 1250025000 -(1 row) - --- Should be parallel -EXPLAIN (COSTS OFF) -SELECT sum(JSON_VALUE(js, '$' RETURNING numeric ERROR ON ERROR)) FROM test_parallel_jsonb_value; - QUERY PLAN ------------------------------------------------------------------- - Finalize Aggregate - -> Gather - Workers Planned: 4 - -> Partial Aggregate - -> Parallel Seq Scan on test_parallel_jsonb_value -(5 rows) - -SELECT sum(JSON_VALUE(js, '$' RETURNING numeric ERROR ON ERROR)) FROM test_parallel_jsonb_value; - sum ------------- - 1250025000 -(1 row) - -DROP TABLE test_parallel_jsonb_value; diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index 86d755aa443..330eb0f7656 100644 --- a/src/test/regress/expected/opr_sanity.out +++ b/src/test/regress/expected/opr_sanity.out @@ -1474,10 +1474,8 @@ WHERE a.aggfnoid = p.oid AND NOT binary_coercible(p.proargtypes[1], ptr.proargtypes[2])) OR (p.pronargs > 2 AND NOT binary_coercible(p.proargtypes[2], ptr.proargtypes[3])) - OR (p.pronargs > 3 AND - NOT binary_coercible(p.proargtypes[3], ptr.proargtypes[4])) - -- we could carry the check further, but 4 args is enough for now - OR (p.pronargs > 4) + -- we could carry the check further, but 3 args is enough for now + OR (p.pronargs > 3) ); aggfnoid | proname | oid | proname ----------+---------+-----+--------- diff --git a/src/test/regress/expected/sqljson.out b/src/test/regress/expected/sqljson.out deleted file mode 100644 index 748dfdb04d4..00000000000 --- a/src/test/regress/expected/sqljson.out +++ /dev/null @@ -1,1320 +0,0 @@ --- JSON() -SELECT JSON(); -ERROR: syntax error at or near ")" -LINE 1: SELECT JSON(); - ^ -SELECT JSON(NULL); - json ------- - -(1 row) - -SELECT JSON('{ "a" : 1 } '); - json --------------- - { "a" : 1 } -(1 row) - -SELECT JSON('{ "a" : 1 } ' FORMAT JSON); - json --------------- - { "a" : 1 } -(1 row) - -SELECT JSON('{ "a" : 1 } ' FORMAT JSON ENCODING UTF8); -ERROR: JSON ENCODING clause is only allowed for bytea input type -LINE 1: SELECT JSON('{ "a" : 1 } ' FORMAT JSON ENCODING UTF8); - ^ -SELECT JSON('{ "a" : 1 } '::bytea FORMAT JSON ENCODING UTF8); - json --------------- - { "a" : 1 } -(1 row) - -SELECT pg_typeof(JSON('{ "a" : 1 } ')); - pg_typeof ------------ - json -(1 row) - -SELECT JSON(' 1 '::json); - json ---------- - 1 -(1 row) - -SELECT JSON(' 1 '::jsonb); - json ------- - 1 -(1 row) - -SELECT JSON(' 1 '::json WITH UNIQUE KEYS); -ERROR: cannot use non-string types with WITH UNIQUE KEYS clause -LINE 1: SELECT JSON(' 1 '::json WITH UNIQUE KEYS); - ^ -SELECT JSON(123); -ERROR: cannot cast type integer to json -LINE 1: SELECT JSON(123); - ^ -SELECT JSON('{"a": 1, "a": 2}'); - json ------------------- - {"a": 1, "a": 2} -(1 row) - -SELECT JSON('{"a": 1, "a": 2}' WITH UNIQUE KEYS); -ERROR: duplicate JSON object key value -SELECT JSON('{"a": 1, "a": 2}' WITHOUT UNIQUE KEYS); - json ------------------- - {"a": 1, "a": 2} -(1 row) - -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123'); - QUERY PLAN ------------------------------ - Result - Output: JSON('123'::json) -(2 rows) - -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' FORMAT JSON); - QUERY PLAN ------------------------------ - Result - Output: JSON('123'::json) -(2 rows) - -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123'::bytea FORMAT JSON); - QUERY PLAN ------------------------------------------------ - Result - Output: JSON('\x313233'::bytea FORMAT JSON) -(2 rows) - -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123'::bytea FORMAT JSON ENCODING UTF8); - QUERY PLAN -------------------------------------------------------------- - Result - Output: JSON('\x313233'::bytea FORMAT JSON ENCODING UTF8) -(2 rows) - -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' WITH UNIQUE KEYS); - QUERY PLAN ----------------------------------------------- - Result - Output: JSON('123'::text WITH UNIQUE KEYS) -(2 rows) - -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' WITHOUT UNIQUE KEYS); - QUERY PLAN ------------------------------ - Result - Output: JSON('123'::json) -(2 rows) - -SELECT JSON('123' RETURNING text); -ERROR: cannot use RETURNING type text in JSON() -LINE 1: SELECT JSON('123' RETURNING text); - ^ -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123'); - QUERY PLAN ------------------------------ - Result - Output: JSON('123'::json) -(2 rows) - -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' RETURNING json); - QUERY PLAN ------------------------------ - Result - Output: JSON('123'::json) -(2 rows) - -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' RETURNING jsonb); - QUERY PLAN ----------------------------------------------- - Result - Output: JSON('123'::jsonb RETURNING jsonb) -(2 rows) - -SELECT pg_typeof(JSON('123')); - pg_typeof ------------ - json -(1 row) - -SELECT pg_typeof(JSON('123' RETURNING json)); - pg_typeof ------------ - json -(1 row) - -SELECT pg_typeof(JSON('123' RETURNING jsonb)); - pg_typeof ------------ - jsonb -(1 row) - --- JSON_SCALAR() -SELECT JSON_SCALAR(); -ERROR: syntax error at or near ")" -LINE 1: SELECT JSON_SCALAR(); - ^ -SELECT JSON_SCALAR(NULL); - json_scalar -------------- - -(1 row) - -SELECT JSON_SCALAR(NULL::int); - json_scalar -------------- - -(1 row) - -SELECT JSON_SCALAR(123); - json_scalar -------------- - 123 -(1 row) - -SELECT JSON_SCALAR(123.45); - json_scalar -------------- - 123.45 -(1 row) - -SELECT JSON_SCALAR(123.45::numeric); - json_scalar -------------- - 123.45 -(1 row) - -SELECT JSON_SCALAR(true); - json_scalar -------------- - true -(1 row) - -SELECT JSON_SCALAR(false); - json_scalar -------------- - false -(1 row) - -SELECT JSON_SCALAR(' 123.45'); - json_scalar -------------- - " 123.45" -(1 row) - -SELECT JSON_SCALAR('2020-06-07'::date); - json_scalar --------------- - "2020-06-07" -(1 row) - -SELECT JSON_SCALAR('2020-06-07 01:02:03'::timestamp); - json_scalar ------------------------ - "2020-06-07T01:02:03" -(1 row) - -SELECT JSON_SCALAR('{}'::json); - json_scalar -------------- - {} -(1 row) - -SELECT JSON_SCALAR('{}'::jsonb); - json_scalar -------------- - {} -(1 row) - -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR(123); - QUERY PLAN ----------------------------- - Result - Output: JSON_SCALAR(123) -(2 rows) - -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR('123'); - QUERY PLAN ------------------------------------- - Result - Output: JSON_SCALAR('123'::text) -(2 rows) - -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR(123 RETURNING json); - QUERY PLAN ----------------------------- - Result - Output: JSON_SCALAR(123) -(2 rows) - -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR(123 RETURNING jsonb); - QUERY PLAN --------------------------------------------- - Result - Output: JSON_SCALAR(123 RETURNING jsonb) -(2 rows) - --- JSON_SERIALIZE() -SELECT JSON_SERIALIZE(); -ERROR: syntax error at or near ")" -LINE 1: SELECT JSON_SERIALIZE(); - ^ -SELECT JSON_SERIALIZE(NULL); - json_serialize ----------------- - -(1 row) - -SELECT JSON_SERIALIZE(JSON('{ "a" : 1 } ')); - json_serialize ----------------- - { "a" : 1 } -(1 row) - -SELECT JSON_SERIALIZE('{ "a" : 1 } '); - json_serialize ----------------- - { "a" : 1 } -(1 row) - -SELECT JSON_SERIALIZE('1'); - json_serialize ----------------- - 1 -(1 row) - -SELECT JSON_SERIALIZE('1' FORMAT JSON); - json_serialize ----------------- - 1 -(1 row) - -SELECT JSON_SERIALIZE('{ "a" : 1 } ' RETURNING bytea); - json_serialize ----------------------------- - \x7b20226122203a2031207d20 -(1 row) - -SELECT JSON_SERIALIZE('{ "a" : 1 } ' RETURNING varchar); - json_serialize ----------------- - { "a" : 1 } -(1 row) - -SELECT pg_typeof(JSON_SERIALIZE(NULL)); - pg_typeof ------------ - text -(1 row) - --- only string types or bytea allowed -SELECT JSON_SERIALIZE('{ "a" : 1 } ' RETURNING jsonb); -ERROR: cannot use RETURNING type jsonb in JSON_SERIALIZE() -HINT: Try returning a string type or bytea. -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SERIALIZE('{}'); - QUERY PLAN ------------------------------------------------------ - Result - Output: JSON_SERIALIZE('{}'::json RETURNING text) -(2 rows) - -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SERIALIZE('{}' RETURNING bytea); - QUERY PLAN ------------------------------------------------------- - Result - Output: JSON_SERIALIZE('{}'::json RETURNING bytea) -(2 rows) - --- JSON_OBJECT() -SELECT JSON_OBJECT(); - json_object -------------- - {} -(1 row) - -SELECT JSON_OBJECT(RETURNING json); - json_object -------------- - {} -(1 row) - -SELECT JSON_OBJECT(RETURNING json FORMAT JSON); - json_object -------------- - {} -(1 row) - -SELECT JSON_OBJECT(RETURNING jsonb); - json_object -------------- - {} -(1 row) - -SELECT JSON_OBJECT(RETURNING jsonb FORMAT JSON); - json_object -------------- - {} -(1 row) - -SELECT JSON_OBJECT(RETURNING text); - json_object -------------- - {} -(1 row) - -SELECT JSON_OBJECT(RETURNING text FORMAT JSON); - json_object -------------- - {} -(1 row) - -SELECT JSON_OBJECT(RETURNING text FORMAT JSON ENCODING UTF8); -ERROR: cannot set JSON encoding for non-bytea output types -LINE 1: SELECT JSON_OBJECT(RETURNING text FORMAT JSON ENCODING UTF8)... - ^ -SELECT JSON_OBJECT(RETURNING text FORMAT JSON ENCODING INVALID_ENCODING); -ERROR: unrecognized JSON encoding: invalid_encoding -SELECT JSON_OBJECT(RETURNING bytea); - json_object -------------- - \x7b7d -(1 row) - -SELECT JSON_OBJECT(RETURNING bytea FORMAT JSON); - json_object -------------- - \x7b7d -(1 row) - -SELECT JSON_OBJECT(RETURNING bytea FORMAT JSON ENCODING UTF8); - json_object -------------- - \x7b7d -(1 row) - -SELECT JSON_OBJECT(RETURNING bytea FORMAT JSON ENCODING UTF16); -ERROR: unsupported JSON encoding -LINE 1: SELECT JSON_OBJECT(RETURNING bytea FORMAT JSON ENCODING UTF1... - ^ -HINT: Only UTF8 JSON encoding is supported. -SELECT JSON_OBJECT(RETURNING bytea FORMAT JSON ENCODING UTF32); -ERROR: unsupported JSON encoding -LINE 1: SELECT JSON_OBJECT(RETURNING bytea FORMAT JSON ENCODING UTF3... - ^ -HINT: Only UTF8 JSON encoding is supported. -SELECT JSON_OBJECT('foo': NULL::int FORMAT JSON); -ERROR: cannot use non-string types with explicit FORMAT JSON clause -LINE 1: SELECT JSON_OBJECT('foo': NULL::int FORMAT JSON); - ^ -SELECT JSON_OBJECT('foo': NULL::int FORMAT JSON ENCODING UTF8); -ERROR: JSON ENCODING clause is only allowed for bytea input type -LINE 1: SELECT JSON_OBJECT('foo': NULL::int FORMAT JSON ENCODING UTF... - ^ -SELECT JSON_OBJECT('foo': NULL::json FORMAT JSON); -WARNING: FORMAT JSON has no effect for json and jsonb types -LINE 1: SELECT JSON_OBJECT('foo': NULL::json FORMAT JSON); - ^ - json_object ----------------- - {"foo" : null} -(1 row) - -SELECT JSON_OBJECT('foo': NULL::json FORMAT JSON ENCODING UTF8); -ERROR: JSON ENCODING clause is only allowed for bytea input type -LINE 1: SELECT JSON_OBJECT('foo': NULL::json FORMAT JSON ENCODING UT... - ^ -SELECT JSON_OBJECT('foo': NULL::jsonb FORMAT JSON); -WARNING: FORMAT JSON has no effect for json and jsonb types -LINE 1: SELECT JSON_OBJECT('foo': NULL::jsonb FORMAT JSON); - ^ - json_object ---------------- - {"foo": null} -(1 row) - -SELECT JSON_OBJECT('foo': NULL::jsonb FORMAT JSON ENCODING UTF8); -ERROR: JSON ENCODING clause is only allowed for bytea input type -LINE 1: SELECT JSON_OBJECT('foo': NULL::jsonb FORMAT JSON ENCODING U... - ^ -SELECT JSON_OBJECT(NULL: 1); -ERROR: argument 1 cannot be null -HINT: Object keys should be text. -SELECT JSON_OBJECT('a': 2 + 3); - json_object -------------- - {"a" : 5} -(1 row) - -SELECT JSON_OBJECT('a' VALUE 2 + 3); - json_object -------------- - {"a" : 5} -(1 row) - ---SELECT JSON_OBJECT(KEY 'a' VALUE 2 + 3); -SELECT JSON_OBJECT('a' || 2: 1); - json_object -------------- - {"a2" : 1} -(1 row) - -SELECT JSON_OBJECT(('a' || 2) VALUE 1); - json_object -------------- - {"a2" : 1} -(1 row) - ---SELECT JSON_OBJECT('a' || 2 VALUE 1); ---SELECT JSON_OBJECT(KEY 'a' || 2 VALUE 1); -SELECT JSON_OBJECT('a': 2::text); - json_object -------------- - {"a" : "2"} -(1 row) - -SELECT JSON_OBJECT('a' VALUE 2::text); - json_object -------------- - {"a" : "2"} -(1 row) - ---SELECT JSON_OBJECT(KEY 'a' VALUE 2::text); -SELECT JSON_OBJECT(1::text: 2); - json_object -------------- - {"1" : 2} -(1 row) - -SELECT JSON_OBJECT((1::text) VALUE 2); - json_object -------------- - {"1" : 2} -(1 row) - ---SELECT JSON_OBJECT(1::text VALUE 2); ---SELECT JSON_OBJECT(KEY 1::text VALUE 2); -SELECT JSON_OBJECT(json '[1]': 123); -ERROR: key value must be scalar, not array, composite, or json -SELECT JSON_OBJECT(ARRAY[1,2,3]: 'aaa'); -ERROR: key value must be scalar, not array, composite, or json -SELECT JSON_OBJECT( - 'a': '123', - 1.23: 123, - 'c': json '[ 1,true,{ } ]', - 'd': jsonb '{ "x" : 123.45 }' -); - json_object -------------------------------------------------------------------- - {"a": "123", "c": [1, true, {}], "d": {"x": 123.45}, "1.23": 123} -(1 row) - -SELECT JSON_OBJECT( - 'a': '123', - 1.23: 123, - 'c': json '[ 1,true,{ } ]', - 'd': jsonb '{ "x" : 123.45 }' - RETURNING jsonb -); - json_object -------------------------------------------------------------------- - {"a": "123", "c": [1, true, {}], "d": {"x": 123.45}, "1.23": 123} -(1 row) - -/* -SELECT JSON_OBJECT( - 'a': '123', - KEY 1.23 VALUE 123, - 'c' VALUE json '[1, true, {}]' -); -*/ -SELECT JSON_OBJECT('a': '123', 'b': JSON_OBJECT('a': 111, 'b': 'aaa')); - json_object ------------------------------------------------ - {"a" : "123", "b" : {"a" : 111, "b" : "aaa"}} -(1 row) - -SELECT JSON_OBJECT('a': '123', 'b': JSON_OBJECT('a': 111, 'b': 'aaa' RETURNING jsonb)); - json_object -------------------------------------------- - {"a": "123", "b": {"a": 111, "b": "aaa"}} -(1 row) - -SELECT JSON_OBJECT('a': JSON_OBJECT('b': 1 RETURNING text)); - json_object ------------------------ - {"a" : "{\"b\" : 1}"} -(1 row) - -SELECT JSON_OBJECT('a': JSON_OBJECT('b': 1 RETURNING text) FORMAT JSON); - json_object -------------------- - {"a" : {"b" : 1}} -(1 row) - -SELECT JSON_OBJECT('a': JSON_OBJECT('b': 1 RETURNING bytea)); - json_object ---------------------------------- - {"a" : "\\x7b226222203a20317d"} -(1 row) - -SELECT JSON_OBJECT('a': JSON_OBJECT('b': 1 RETURNING bytea) FORMAT JSON); - json_object -------------------- - {"a" : {"b" : 1}} -(1 row) - -SELECT JSON_OBJECT('a': '1', 'b': NULL, 'c': 2); - json_object ----------------------------------- - {"a" : "1", "b" : null, "c" : 2} -(1 row) - -SELECT JSON_OBJECT('a': '1', 'b': NULL, 'c': 2 NULL ON NULL); - json_object ----------------------------------- - {"a" : "1", "b" : null, "c" : 2} -(1 row) - -SELECT JSON_OBJECT('a': '1', 'b': NULL, 'c': 2 ABSENT ON NULL); - json_object ----------------------- - {"a" : "1", "c" : 2} -(1 row) - -SELECT JSON_OBJECT(1: 1, '1': NULL WITH UNIQUE); -ERROR: duplicate JSON key "1" -SELECT JSON_OBJECT(1: 1, '1': NULL ABSENT ON NULL WITH UNIQUE); -ERROR: duplicate JSON key "1" -SELECT JSON_OBJECT(1: 1, '1': NULL NULL ON NULL WITH UNIQUE RETURNING jsonb); -ERROR: duplicate JSON object key value -SELECT JSON_OBJECT(1: 1, '1': NULL ABSENT ON NULL WITH UNIQUE RETURNING jsonb); -ERROR: duplicate JSON object key value -SELECT JSON_OBJECT(1: 1, '2': NULL, '1': 1 NULL ON NULL WITH UNIQUE); -ERROR: duplicate JSON key "1" -SELECT JSON_OBJECT(1: 1, '2': NULL, '1': 1 ABSENT ON NULL WITH UNIQUE); -ERROR: duplicate JSON key "1" -SELECT JSON_OBJECT(1: 1, '2': NULL, '1': 1 ABSENT ON NULL WITHOUT UNIQUE); - json_object --------------------- - {"1" : 1, "1" : 1} -(1 row) - -SELECT JSON_OBJECT(1: 1, '2': NULL, '1': 1 ABSENT ON NULL WITH UNIQUE RETURNING jsonb); -ERROR: duplicate JSON object key value -SELECT JSON_OBJECT(1: 1, '2': NULL, '1': 1 ABSENT ON NULL WITHOUT UNIQUE RETURNING jsonb); - json_object -------------- - {"1": 1} -(1 row) - -SELECT JSON_OBJECT(1: 1, '2': NULL, '3': 1, 4: NULL, '5': 'a' ABSENT ON NULL WITH UNIQUE RETURNING jsonb); - json_object ----------------------------- - {"1": 1, "3": 1, "5": "a"} -(1 row) - --- JSON_ARRAY() -SELECT JSON_ARRAY(); - json_array ------------- - [] -(1 row) - -SELECT JSON_ARRAY(RETURNING json); - json_array ------------- - [] -(1 row) - -SELECT JSON_ARRAY(RETURNING json FORMAT JSON); - json_array ------------- - [] -(1 row) - -SELECT JSON_ARRAY(RETURNING jsonb); - json_array ------------- - [] -(1 row) - -SELECT JSON_ARRAY(RETURNING jsonb FORMAT JSON); - json_array ------------- - [] -(1 row) - -SELECT JSON_ARRAY(RETURNING text); - json_array ------------- - [] -(1 row) - -SELECT JSON_ARRAY(RETURNING text FORMAT JSON); - json_array ------------- - [] -(1 row) - -SELECT JSON_ARRAY(RETURNING text FORMAT JSON ENCODING UTF8); -ERROR: cannot set JSON encoding for non-bytea output types -LINE 1: SELECT JSON_ARRAY(RETURNING text FORMAT JSON ENCODING UTF8); - ^ -SELECT JSON_ARRAY(RETURNING text FORMAT JSON ENCODING INVALID_ENCODING); -ERROR: unrecognized JSON encoding: invalid_encoding -SELECT JSON_ARRAY(RETURNING bytea); - json_array ------------- - \x5b5d -(1 row) - -SELECT JSON_ARRAY(RETURNING bytea FORMAT JSON); - json_array ------------- - \x5b5d -(1 row) - -SELECT JSON_ARRAY(RETURNING bytea FORMAT JSON ENCODING UTF8); - json_array ------------- - \x5b5d -(1 row) - -SELECT JSON_ARRAY(RETURNING bytea FORMAT JSON ENCODING UTF16); -ERROR: unsupported JSON encoding -LINE 1: SELECT JSON_ARRAY(RETURNING bytea FORMAT JSON ENCODING UTF16... - ^ -HINT: Only UTF8 JSON encoding is supported. -SELECT JSON_ARRAY(RETURNING bytea FORMAT JSON ENCODING UTF32); -ERROR: unsupported JSON encoding -LINE 1: SELECT JSON_ARRAY(RETURNING bytea FORMAT JSON ENCODING UTF32... - ^ -HINT: Only UTF8 JSON encoding is supported. -SELECT JSON_ARRAY('aaa', 111, true, array[1,2,3], NULL, json '{"a": [1]}', jsonb '["a",3]'); - json_array ------------------------------------------------------ - ["aaa", 111, true, [1, 2, 3], {"a": [1]}, ["a", 3]] -(1 row) - -SELECT JSON_ARRAY('a', NULL, 'b' NULL ON NULL); - json_array ------------------- - ["a", null, "b"] -(1 row) - -SELECT JSON_ARRAY('a', NULL, 'b' ABSENT ON NULL); - json_array ------------- - ["a", "b"] -(1 row) - -SELECT JSON_ARRAY(NULL, NULL, 'b' ABSENT ON NULL); - json_array ------------- - ["b"] -(1 row) - -SELECT JSON_ARRAY('a', NULL, 'b' NULL ON NULL RETURNING jsonb); - json_array ------------------- - ["a", null, "b"] -(1 row) - -SELECT JSON_ARRAY('a', NULL, 'b' ABSENT ON NULL RETURNING jsonb); - json_array ------------- - ["a", "b"] -(1 row) - -SELECT JSON_ARRAY(NULL, NULL, 'b' ABSENT ON NULL RETURNING jsonb); - json_array ------------- - ["b"] -(1 row) - -SELECT JSON_ARRAY(JSON_ARRAY('{ "a" : 123 }' RETURNING text)); - json_array -------------------------------- - ["[\"{ \\\"a\\\" : 123 }\"]"] -(1 row) - -SELECT JSON_ARRAY(JSON_ARRAY('{ "a" : 123 }' FORMAT JSON RETURNING text)); - json_array ------------------------ - ["[{ \"a\" : 123 }]"] -(1 row) - -SELECT JSON_ARRAY(JSON_ARRAY('{ "a" : 123 }' FORMAT JSON RETURNING text) FORMAT JSON); - json_array -------------------- - [[{ "a" : 123 }]] -(1 row) - -SELECT JSON_ARRAY(SELECT i FROM (VALUES (1), (2), (NULL), (4)) foo(i)); - json_array ------------- - [1, 2, 4] -(1 row) - -SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i)); - json_array ------------- - [[1,2], + - [3,4]] -(1 row) - -SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) RETURNING jsonb); - json_array ------------------- - [[1, 2], [3, 4]] -(1 row) - ---SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) NULL ON NULL); ---SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) NULL ON NULL RETURNING jsonb); -SELECT JSON_ARRAY(SELECT i FROM (VALUES (3), (1), (NULL), (2)) foo(i) ORDER BY i); - json_array ------------- - [1, 2, 3] -(1 row) - --- Should fail -SELECT JSON_ARRAY(SELECT FROM (VALUES (1)) foo(i)); -ERROR: subquery must return only one column -LINE 1: SELECT JSON_ARRAY(SELECT FROM (VALUES (1)) foo(i)); - ^ -SELECT JSON_ARRAY(SELECT i, i FROM (VALUES (1)) foo(i)); -ERROR: subquery must return only one column -LINE 1: SELECT JSON_ARRAY(SELECT i, i FROM (VALUES (1)) foo(i)); - ^ -SELECT JSON_ARRAY(SELECT * FROM (VALUES (1, 2)) foo(i, j)); -ERROR: subquery must return only one column -LINE 1: SELECT JSON_ARRAY(SELECT * FROM (VALUES (1, 2)) foo(i, j)); - ^ --- JSON_ARRAYAGG() -SELECT JSON_ARRAYAGG(i) IS NULL, - JSON_ARRAYAGG(i RETURNING jsonb) IS NULL -FROM generate_series(1, 0) i; - ?column? | ?column? -----------+---------- - t | t -(1 row) - -SELECT JSON_ARRAYAGG(i), - JSON_ARRAYAGG(i RETURNING jsonb) -FROM generate_series(1, 5) i; - json_arrayagg | json_arrayagg ------------------+----------------- - [1, 2, 3, 4, 5] | [1, 2, 3, 4, 5] -(1 row) - -SELECT JSON_ARRAYAGG(i ORDER BY i DESC) -FROM generate_series(1, 5) i; - json_arrayagg ------------------ - [5, 4, 3, 2, 1] -(1 row) - -SELECT JSON_ARRAYAGG(i::text::json) -FROM generate_series(1, 5) i; - json_arrayagg ------------------ - [1, 2, 3, 4, 5] -(1 row) - -SELECT JSON_ARRAYAGG(JSON_ARRAY(i, i + 1 RETURNING text) FORMAT JSON) -FROM generate_series(1, 5) i; - json_arrayagg ------------------------------------------- - [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6]] -(1 row) - -SELECT JSON_ARRAYAGG(NULL), - JSON_ARRAYAGG(NULL RETURNING jsonb) -FROM generate_series(1, 5); - json_arrayagg | json_arrayagg ----------------+--------------- - [] | [] -(1 row) - -SELECT JSON_ARRAYAGG(NULL NULL ON NULL), - JSON_ARRAYAGG(NULL NULL ON NULL RETURNING jsonb) -FROM generate_series(1, 5); - json_arrayagg | json_arrayagg ---------------------------------+-------------------------------- - [null, null, null, null, null] | [null, null, null, null, null] -(1 row) - -SELECT - JSON_ARRAYAGG(bar), - JSON_ARRAYAGG(bar RETURNING jsonb), - JSON_ARRAYAGG(bar ABSENT ON NULL), - JSON_ARRAYAGG(bar ABSENT ON NULL RETURNING jsonb), - JSON_ARRAYAGG(bar NULL ON NULL), - JSON_ARRAYAGG(bar NULL ON NULL RETURNING jsonb), - JSON_ARRAYAGG(foo), - JSON_ARRAYAGG(foo RETURNING jsonb), - JSON_ARRAYAGG(foo ORDER BY bar) FILTER (WHERE bar > 2), - JSON_ARRAYAGG(foo ORDER BY bar RETURNING jsonb) FILTER (WHERE bar > 2) -FROM - (VALUES (NULL), (3), (1), (NULL), (NULL), (5), (2), (4), (NULL)) foo(bar); - json_arrayagg | json_arrayagg | json_arrayagg | json_arrayagg | json_arrayagg | json_arrayagg | json_arrayagg | json_arrayagg | json_arrayagg | json_arrayagg ------------------+-----------------+-----------------+-----------------+-----------------------------------------+-----------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------------------+---------------+-------------------------------------- - [1, 2, 3, 4, 5] | [1, 2, 3, 4, 5] | [1, 2, 3, 4, 5] | [1, 2, 3, 4, 5] | [1, 2, 3, 4, 5, null, null, null, null] | [1, 2, 3, 4, 5, null, null, null, null] | [{"bar":1}, +| [{"bar": 1}, {"bar": 2}, {"bar": 3}, {"bar": 4}, {"bar": 5}, {"bar": null}, {"bar": null}, {"bar": null}, {"bar": null}] | [{"bar":3}, +| [{"bar": 3}, {"bar": 4}, {"bar": 5}] - | | | | | | {"bar":2}, +| | {"bar":4}, +| - | | | | | | {"bar":3}, +| | {"bar":5}] | - | | | | | | {"bar":4}, +| | | - | | | | | | {"bar":5}, +| | | - | | | | | | {"bar":null}, +| | | - | | | | | | {"bar":null}, +| | | - | | | | | | {"bar":null}, +| | | - | | | | | | {"bar":null}] | | | -(1 row) - -SELECT - bar, JSON_ARRAYAGG(bar) FILTER (WHERE bar > 2) OVER (PARTITION BY foo.bar % 2) -FROM - (VALUES (NULL), (3), (1), (NULL), (NULL), (5), (2), (4), (NULL), (5), (4)) foo(bar); - bar | json_arrayagg ------+--------------- - 4 | [4, 4] - 4 | [4, 4] - 2 | [4, 4] - 5 | [5, 3, 5] - 3 | [5, 3, 5] - 1 | [5, 3, 5] - 5 | [5, 3, 5] - | - | - | - | -(11 rows) - --- JSON_OBJECTAGG() -SELECT JSON_OBJECTAGG('key': 1) IS NULL, - JSON_OBJECTAGG('key': 1 RETURNING jsonb) IS NULL -WHERE FALSE; - ?column? | ?column? -----------+---------- - t | t -(1 row) - -SELECT JSON_OBJECTAGG(NULL: 1); -ERROR: field name must not be null -SELECT JSON_OBJECTAGG(NULL: 1 RETURNING jsonb); -ERROR: field name must not be null -SELECT - JSON_OBJECTAGG(i: i), --- JSON_OBJECTAGG(i VALUE i), --- JSON_OBJECTAGG(KEY i VALUE i), - JSON_OBJECTAGG(i: i RETURNING jsonb) -FROM - generate_series(1, 5) i; - json_objectagg | json_objectagg --------------------------------------------------+------------------------------------------ - { "1" : 1, "2" : 2, "3" : 3, "4" : 4, "5" : 5 } | {"1": 1, "2": 2, "3": 3, "4": 4, "5": 5} -(1 row) - -SELECT - JSON_OBJECTAGG(k: v), - JSON_OBJECTAGG(k: v NULL ON NULL), - JSON_OBJECTAGG(k: v ABSENT ON NULL), - JSON_OBJECTAGG(k: v RETURNING jsonb), - JSON_OBJECTAGG(k: v NULL ON NULL RETURNING jsonb), - JSON_OBJECTAGG(k: v ABSENT ON NULL RETURNING jsonb) -FROM - (VALUES (1, 1), (1, NULL), (2, NULL), (3, 3)) foo(k, v); - json_objectagg | json_objectagg | json_objectagg | json_objectagg | json_objectagg | json_objectagg -----------------------------------------------+----------------------------------------------+----------------------+--------------------------------+--------------------------------+------------------ - { "1" : 1, "1" : null, "2" : null, "3" : 3 } | { "1" : 1, "1" : null, "2" : null, "3" : 3 } | { "1" : 1, "3" : 3 } | {"1": null, "2": null, "3": 3} | {"1": null, "2": null, "3": 3} | {"1": 1, "3": 3} -(1 row) - -SELECT JSON_OBJECTAGG(k: v WITH UNIQUE KEYS) -FROM (VALUES (1, 1), (1, NULL), (2, 2)) foo(k, v); -ERROR: duplicate JSON key "1" -SELECT JSON_OBJECTAGG(k: v ABSENT ON NULL WITH UNIQUE KEYS) -FROM (VALUES (1, 1), (1, NULL), (2, 2)) foo(k, v); -ERROR: duplicate JSON key "1" -SELECT JSON_OBJECTAGG(k: v ABSENT ON NULL WITH UNIQUE KEYS) -FROM (VALUES (1, 1), (0, NULL), (3, NULL), (2, 2), (4, NULL)) foo(k, v); - json_objectagg ----------------------- - { "1" : 1, "2" : 2 } -(1 row) - -SELECT JSON_OBJECTAGG(k: v WITH UNIQUE KEYS RETURNING jsonb) -FROM (VALUES (1, 1), (1, NULL), (2, 2)) foo(k, v); -ERROR: duplicate JSON object key value -SELECT JSON_OBJECTAGG(k: v ABSENT ON NULL WITH UNIQUE KEYS RETURNING jsonb) -FROM (VALUES (1, 1), (1, NULL), (2, 2)) foo(k, v); -ERROR: duplicate JSON object key value -SELECT JSON_OBJECTAGG(k: v ABSENT ON NULL WITH UNIQUE KEYS RETURNING jsonb) -FROM (VALUES (1, 1), (0, NULL),(4, null), (5, null),(6, null),(2, 2)) foo(k, v); - json_objectagg ------------------- - {"1": 1, "2": 2} -(1 row) - --- Test JSON_OBJECT deparsing -EXPLAIN (VERBOSE, COSTS OFF) -SELECT JSON_OBJECT('foo' : '1' FORMAT JSON, 'bar' : 'baz' RETURNING json); - QUERY PLAN ------------------------------------------------------------------------------- - Result - Output: JSON_OBJECT('foo' : '1'::json, 'bar' : 'baz'::text RETURNING json) -(2 rows) - -CREATE VIEW json_object_view AS -SELECT JSON_OBJECT('foo' : '1' FORMAT JSON, 'bar' : 'baz' RETURNING json); -\sv json_object_view -CREATE OR REPLACE VIEW public.json_object_view AS - SELECT JSON_OBJECT('foo' : '1'::text FORMAT JSON, 'bar' : 'baz'::text RETURNING json) AS "json_object" -DROP VIEW json_object_view; -SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v WITH UNIQUE KEYS) OVER (ORDER BY k) -FROM (VALUES (1,1), (2,2)) a(k,v); - a | json_objectagg ----------------+---------------------- - {"k":1,"v":1} | { "1" : 1 } - {"k":2,"v":2} | { "1" : 1, "2" : 2 } -(2 rows) - -SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v WITH UNIQUE KEYS) OVER (ORDER BY k) -FROM (VALUES (1,1), (1,2), (2,2)) a(k,v); -ERROR: duplicate JSON key "1" -SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v ABSENT ON NULL WITH UNIQUE KEYS) - OVER (ORDER BY k) -FROM (VALUES (1,1), (1,null), (2,2)) a(k,v); -ERROR: duplicate JSON key "1" -SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v ABSENT ON NULL) -OVER (ORDER BY k) -FROM (VALUES (1,1), (1,null), (2,2)) a(k,v); - a | json_objectagg -------------------+---------------------- - {"k":1,"v":1} | { "1" : 1 } - {"k":1,"v":null} | { "1" : 1 } - {"k":2,"v":2} | { "1" : 1, "2" : 2 } -(3 rows) - -SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v ABSENT ON NULL) -OVER (ORDER BY k RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) -FROM (VALUES (1,1), (1,null), (2,2)) a(k,v); - a | json_objectagg -------------------+---------------------- - {"k":1,"v":1} | { "1" : 1, "2" : 2 } - {"k":1,"v":null} | { "1" : 1, "2" : 2 } - {"k":2,"v":2} | { "1" : 1, "2" : 2 } -(3 rows) - --- Test JSON_ARRAY deparsing -EXPLAIN (VERBOSE, COSTS OFF) -SELECT JSON_ARRAY('1' FORMAT JSON, 2 RETURNING json); - QUERY PLAN ---------------------------------------------------- - Result - Output: JSON_ARRAY('1'::json, 2 RETURNING json) -(2 rows) - -CREATE VIEW json_array_view AS -SELECT JSON_ARRAY('1' FORMAT JSON, 2 RETURNING json); -\sv json_array_view -CREATE OR REPLACE VIEW public.json_array_view AS - SELECT JSON_ARRAY('1'::text FORMAT JSON, 2 RETURNING json) AS "json_array" -DROP VIEW json_array_view; --- Test JSON_OBJECTAGG deparsing -EXPLAIN (VERBOSE, COSTS OFF) -SELECT JSON_OBJECTAGG(i: ('111' || i)::bytea FORMAT JSON WITH UNIQUE RETURNING text) FILTER (WHERE i > 3) -FROM generate_series(1,5) i; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------- - Aggregate - Output: JSON_OBJECTAGG(i : (('111'::text || (i)::text))::bytea FORMAT JSON WITH UNIQUE KEYS RETURNING text) FILTER (WHERE (i > 3)) - -> Function Scan on pg_catalog.generate_series i - Output: i - Function Call: generate_series(1, 5) -(5 rows) - -EXPLAIN (VERBOSE, COSTS OFF) -SELECT JSON_OBJECTAGG(i: ('111' || i)::bytea FORMAT JSON WITH UNIQUE RETURNING text) OVER (PARTITION BY i % 2) -FROM generate_series(1,5) i; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------ - WindowAgg - Output: JSON_OBJECTAGG(i : (('111'::text || (i)::text))::bytea FORMAT JSON WITH UNIQUE KEYS RETURNING text) OVER (?), ((i % 2)) - -> Sort - Output: ((i % 2)), i - Sort Key: ((i.i % 2)) - -> Function Scan on pg_catalog.generate_series i - Output: (i % 2), i - Function Call: generate_series(1, 5) -(8 rows) - -CREATE VIEW json_objectagg_view AS -SELECT JSON_OBJECTAGG(i: ('111' || i)::bytea FORMAT JSON WITH UNIQUE RETURNING text) FILTER (WHERE i > 3) -FROM generate_series(1,5) i; -\sv json_objectagg_view -CREATE OR REPLACE VIEW public.json_objectagg_view AS - SELECT JSON_OBJECTAGG(i.i : ('111'::text || i.i)::bytea FORMAT JSON WITH UNIQUE KEYS RETURNING text) FILTER (WHERE i.i > 3) AS "json_objectagg" - FROM generate_series(1, 5) i(i) -DROP VIEW json_objectagg_view; --- Test JSON_ARRAYAGG deparsing -EXPLAIN (VERBOSE, COSTS OFF) -SELECT JSON_ARRAYAGG(('111' || i)::bytea FORMAT JSON NULL ON NULL RETURNING text) FILTER (WHERE i > 3) -FROM generate_series(1,5) i; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------ - Aggregate - Output: JSON_ARRAYAGG((('111'::text || (i)::text))::bytea FORMAT JSON NULL ON NULL RETURNING text) FILTER (WHERE (i > 3)) - -> Function Scan on pg_catalog.generate_series i - Output: i - Function Call: generate_series(1, 5) -(5 rows) - -EXPLAIN (VERBOSE, COSTS OFF) -SELECT JSON_ARRAYAGG(('111' || i)::bytea FORMAT JSON NULL ON NULL RETURNING text) OVER (PARTITION BY i % 2) -FROM generate_series(1,5) i; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------- - WindowAgg - Output: JSON_ARRAYAGG((('111'::text || (i)::text))::bytea FORMAT JSON NULL ON NULL RETURNING text) OVER (?), ((i % 2)) - -> Sort - Output: ((i % 2)), i - Sort Key: ((i.i % 2)) - -> Function Scan on pg_catalog.generate_series i - Output: (i % 2), i - Function Call: generate_series(1, 5) -(8 rows) - -CREATE VIEW json_arrayagg_view AS -SELECT JSON_ARRAYAGG(('111' || i)::bytea FORMAT JSON NULL ON NULL RETURNING text) FILTER (WHERE i > 3) -FROM generate_series(1,5) i; -\sv json_arrayagg_view -CREATE OR REPLACE VIEW public.json_arrayagg_view AS - SELECT JSON_ARRAYAGG(('111'::text || i.i)::bytea FORMAT JSON NULL ON NULL RETURNING text) FILTER (WHERE i.i > 3) AS "json_arrayagg" - FROM generate_series(1, 5) i(i) -DROP VIEW json_arrayagg_view; --- Test JSON_ARRAY(subquery) deparsing -EXPLAIN (VERBOSE, COSTS OFF) -SELECT JSON_ARRAY(SELECT i FROM (VALUES (1), (2), (NULL), (4)) foo(i) RETURNING jsonb); - QUERY PLAN ---------------------------------------------------------------------- - Result - Output: $0 - InitPlan 1 (returns $0) - -> Aggregate - Output: JSON_ARRAYAGG("*VALUES*".column1 RETURNING jsonb) - -> Values Scan on "*VALUES*" - Output: "*VALUES*".column1 -(7 rows) - -CREATE VIEW json_array_subquery_view AS -SELECT JSON_ARRAY(SELECT i FROM (VALUES (1), (2), (NULL), (4)) foo(i) RETURNING jsonb); -\sv json_array_subquery_view -CREATE OR REPLACE VIEW public.json_array_subquery_view AS - SELECT ( SELECT JSON_ARRAYAGG(q.a RETURNING jsonb) AS "json_arrayagg" - FROM ( SELECT foo.i - FROM ( VALUES (1), (2), (NULL::integer), (4)) foo(i)) q(a)) AS "json_array" -DROP VIEW json_array_subquery_view; --- 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.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; diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index 102c1981edd..8e699a8281e 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -111,7 +111,7 @@ test: select_views portals_p2 foreign_key cluster dependency guc bitmapops combo # ---------- # Another group of parallel tests (JSON related) # ---------- -test: json jsonb json_encoding jsonpath jsonpath_encoding jsonb_jsonpath sqljson json_sqljson jsonb_sqljson +test: json jsonb json_encoding jsonpath jsonpath_encoding jsonb_jsonpath # ---------- # Another group of parallel tests diff --git a/src/test/regress/sql/json_sqljson.sql b/src/test/regress/sql/json_sqljson.sql deleted file mode 100644 index df4a430d885..00000000000 --- a/src/test/regress/sql/json_sqljson.sql +++ /dev/null @@ -1,15 +0,0 @@ --- JSON_EXISTS - -SELECT JSON_EXISTS(NULL FORMAT JSON, '$'); - --- JSON_VALUE - -SELECT JSON_VALUE(NULL FORMAT JSON, '$'); - --- JSON_QUERY - -SELECT JSON_QUERY(NULL FORMAT JSON, '$'); - --- JSON_TABLE - -SELECT * FROM JSON_TABLE(NULL FORMAT JSON, '$' COLUMNS (foo text)); diff --git a/src/test/regress/sql/jsonb_sqljson.sql b/src/test/regress/sql/jsonb_sqljson.sql deleted file mode 100644 index fff25374808..00000000000 --- a/src/test/regress/sql/jsonb_sqljson.sql +++ /dev/null @@ -1,977 +0,0 @@ --- JSON_EXISTS - -SELECT JSON_EXISTS(NULL::jsonb, '$'); - -SELECT JSON_EXISTS(jsonb '[]', '$'); -SELECT JSON_EXISTS(JSON_OBJECT(RETURNING jsonb), '$'); - -SELECT JSON_EXISTS(jsonb '1', '$'); -SELECT JSON_EXISTS(jsonb 'null', '$'); -SELECT JSON_EXISTS(jsonb '[]', '$'); - -SELECT JSON_EXISTS(jsonb '1', '$.a'); -SELECT JSON_EXISTS(jsonb '1', 'strict $.a'); -SELECT JSON_EXISTS(jsonb '1', 'strict $.a' ERROR ON ERROR); -SELECT JSON_EXISTS(jsonb 'null', '$.a'); -SELECT JSON_EXISTS(jsonb '[]', '$.a'); -SELECT JSON_EXISTS(jsonb '[1, "aaa", {"a": 1}]', 'strict $.a'); -SELECT JSON_EXISTS(jsonb '[1, "aaa", {"a": 1}]', 'lax $.a'); -SELECT JSON_EXISTS(jsonb '{}', '$.a'); -SELECT JSON_EXISTS(jsonb '{"b": 1, "a": 2}', '$.a'); - -SELECT JSON_EXISTS(jsonb '1', '$.a.b'); -SELECT JSON_EXISTS(jsonb '{"a": {"b": 1}}', '$.a.b'); -SELECT JSON_EXISTS(jsonb '{"a": 1, "b": 2}', '$.a.b'); - -SELECT JSON_EXISTS(jsonb '{"a": 1, "b": 2}', '$.* ? (@ > $x)' PASSING 1 AS x); -SELECT JSON_EXISTS(jsonb '{"a": 1, "b": 2}', '$.* ? (@ > $x)' PASSING '1' AS x); -SELECT JSON_EXISTS(jsonb '{"a": 1, "b": 2}', '$.* ? (@ > $x && @ < $y)' PASSING 0 AS x, 2 AS y); -SELECT JSON_EXISTS(jsonb '{"a": 1, "b": 2}', '$.* ? (@ > $x && @ < $y)' PASSING 0 AS x, 1 AS y); - --- extension: boolean expressions -SELECT JSON_EXISTS(jsonb '1', '$ > 2'); -SELECT JSON_EXISTS(jsonb '1', '$.a > 2' ERROR ON ERROR); - --- extension: RETURNING clause -SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING bool); -SELECT JSON_EXISTS(jsonb '1', '$[1]' RETURNING bool); -SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING int); -SELECT JSON_EXISTS(jsonb '1', '$[1]' RETURNING int); -SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING text); -SELECT JSON_EXISTS(jsonb '1', '$[1]' RETURNING text); -SELECT JSON_EXISTS(jsonb '1', 'strict $[1]' RETURNING text FALSE ON ERROR); -SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING jsonb); -SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING float4); - - --- JSON_VALUE - -SELECT JSON_VALUE(NULL::jsonb, '$'); - -SELECT JSON_VALUE(jsonb 'null', '$'); -SELECT JSON_VALUE(jsonb 'null', '$' RETURNING int); - -SELECT JSON_VALUE(jsonb 'true', '$'); -SELECT JSON_VALUE(jsonb 'true', '$' RETURNING bool); - -SELECT JSON_VALUE(jsonb '123', '$'); -SELECT JSON_VALUE(jsonb '123', '$' RETURNING int) + 234; -SELECT JSON_VALUE(jsonb '123', '$' RETURNING text); -/* jsonb bytea ??? */ -SELECT JSON_VALUE(jsonb '123', '$' RETURNING bytea ERROR ON ERROR); - -SELECT JSON_VALUE(jsonb '1.23', '$'); -SELECT JSON_VALUE(jsonb '1.23', '$' RETURNING int); -SELECT JSON_VALUE(jsonb '"1.23"', '$' RETURNING numeric); -SELECT JSON_VALUE(jsonb '"1.23"', '$' RETURNING int ERROR ON ERROR); - -SELECT JSON_VALUE(jsonb '"aaa"', '$'); -SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING text); -SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING char(5)); -SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING char(2)); -SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING json); -SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING jsonb); -SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING json ERROR ON ERROR); -SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING jsonb ERROR ON ERROR); -SELECT JSON_VALUE(jsonb '"\"aaa\""', '$' RETURNING json); -SELECT JSON_VALUE(jsonb '"\"aaa\""', '$' RETURNING jsonb); -SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING int); -SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING int ERROR ON ERROR); -SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING int DEFAULT 111 ON ERROR); -SELECT JSON_VALUE(jsonb '"123"', '$' RETURNING int) + 234; - -SELECT JSON_VALUE(jsonb '"2017-02-20"', '$' RETURNING date) + 9; - --- Test NULL checks execution in domain types -CREATE DOMAIN sqljsonb_int_not_null AS int NOT NULL; -SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null); -SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null NULL ON ERROR); -SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null DEFAULT NULL ON ERROR); - -SELECT JSON_VALUE(jsonb '[]', '$'); -SELECT JSON_VALUE(jsonb '[]', '$' ERROR ON ERROR); -SELECT JSON_VALUE(jsonb '{}', '$'); -SELECT JSON_VALUE(jsonb '{}', '$' ERROR ON ERROR); - -SELECT JSON_VALUE(jsonb '1', '$.a'); -SELECT JSON_VALUE(jsonb '1', 'strict $.a' ERROR ON ERROR); -SELECT JSON_VALUE(jsonb '1', 'strict $.a' DEFAULT 'error' ON ERROR); -SELECT JSON_VALUE(jsonb '1', 'lax $.a' ERROR ON ERROR); -SELECT JSON_VALUE(jsonb '1', 'lax $.a' ERROR ON EMPTY ERROR ON ERROR); -SELECT JSON_VALUE(jsonb '1', 'strict $.a' DEFAULT 2 ON ERROR); -SELECT JSON_VALUE(jsonb '1', 'lax $.a' DEFAULT 2 ON ERROR); -SELECT JSON_VALUE(jsonb '1', 'lax $.a' DEFAULT '2' ON ERROR); -SELECT JSON_VALUE(jsonb '1', 'lax $.a' NULL ON EMPTY DEFAULT '2' ON ERROR); -SELECT JSON_VALUE(jsonb '1', 'lax $.a' DEFAULT '2' ON EMPTY DEFAULT '3' ON ERROR); -SELECT JSON_VALUE(jsonb '1', 'lax $.a' ERROR ON EMPTY DEFAULT '3' ON ERROR); - -SELECT JSON_VALUE(jsonb '[1,2]', '$[*]' ERROR ON ERROR); -SELECT JSON_VALUE(jsonb '[1,2]', '$[*]' DEFAULT '0' ON ERROR); -SELECT JSON_VALUE(jsonb '[" "]', '$[*]' RETURNING int ERROR ON ERROR); -SELECT JSON_VALUE(jsonb '[" "]', '$[*]' RETURNING int DEFAULT 2 + 3 ON ERROR); -SELECT JSON_VALUE(jsonb '["1"]', '$[*]' RETURNING int DEFAULT 2 + 3 ON ERROR); - -SELECT - x, - JSON_VALUE( - jsonb '{"a": 1, "b": 2}', - '$.* ? (@ > $x)' PASSING x AS x - RETURNING int - DEFAULT -1 ON EMPTY - DEFAULT -2 ON ERROR - ) y -FROM - generate_series(0, 2) x; - -SELECT JSON_VALUE(jsonb 'null', '$a' PASSING point ' (1, 2 )' AS a); -SELECT JSON_VALUE(jsonb 'null', '$a' PASSING point ' (1, 2 )' AS a RETURNING point); - --- Test timestamptz passing and output -SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts); -SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING timestamptz); -SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING timestamp); -SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING json); -SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING jsonb); - --- JSON_QUERY - -SELECT - JSON_QUERY(js, '$'), - JSON_QUERY(js, '$' WITHOUT WRAPPER), - JSON_QUERY(js, '$' WITH CONDITIONAL WRAPPER), - JSON_QUERY(js, '$' WITH UNCONDITIONAL ARRAY WRAPPER), - JSON_QUERY(js, '$' WITH ARRAY WRAPPER) -FROM - (VALUES - (jsonb 'null'), - ('12.3'), - ('true'), - ('"aaa"'), - ('[1, null, "2"]'), - ('{"a": 1, "b": [2]}') - ) foo(js); - -SELECT - JSON_QUERY(js, 'strict $[*]') AS "unspec", - JSON_QUERY(js, 'strict $[*]' WITHOUT WRAPPER) AS "without", - JSON_QUERY(js, 'strict $[*]' WITH CONDITIONAL WRAPPER) AS "with cond", - JSON_QUERY(js, 'strict $[*]' WITH UNCONDITIONAL ARRAY WRAPPER) AS "with uncond", - JSON_QUERY(js, 'strict $[*]' WITH ARRAY WRAPPER) AS "with" -FROM - (VALUES - (jsonb '1'), - ('[]'), - ('[null]'), - ('[12.3]'), - ('[true]'), - ('["aaa"]'), - ('[[1, 2, 3]]'), - ('[{"a": 1, "b": [2]}]'), - ('[1, "2", null, [3]]') - ) foo(js); - -SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text); -SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text KEEP QUOTES); -SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text KEEP QUOTES ON SCALAR STRING); -SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text OMIT QUOTES); -SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text OMIT QUOTES ON SCALAR STRING); -SELECT JSON_QUERY(jsonb '"aaa"', '$' OMIT QUOTES ERROR ON ERROR); -SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING json OMIT QUOTES ERROR ON ERROR); -SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING bytea FORMAT JSON OMIT QUOTES ERROR ON ERROR); - --- QUOTES behavior should not be specified when WITH WRAPPER used: --- Should fail -SELECT JSON_QUERY(jsonb '[1]', '$' WITH WRAPPER OMIT QUOTES); -SELECT JSON_QUERY(jsonb '[1]', '$' WITH WRAPPER KEEP QUOTES); -SELECT JSON_QUERY(jsonb '[1]', '$' WITH CONDITIONAL WRAPPER KEEP QUOTES); -SELECT JSON_QUERY(jsonb '[1]', '$' WITH CONDITIONAL WRAPPER OMIT QUOTES); --- Should succeed -SELECT JSON_QUERY(jsonb '[1]', '$' WITHOUT WRAPPER OMIT QUOTES); -SELECT JSON_QUERY(jsonb '[1]', '$' WITHOUT WRAPPER KEEP QUOTES); - -SELECT JSON_QUERY(jsonb '[]', '$[*]'); -SELECT JSON_QUERY(jsonb '[]', '$[*]' NULL ON EMPTY); -SELECT JSON_QUERY(jsonb '[]', '$[*]' EMPTY ON EMPTY); -SELECT JSON_QUERY(jsonb '[]', '$[*]' EMPTY ARRAY ON EMPTY); -SELECT JSON_QUERY(jsonb '[]', '$[*]' EMPTY OBJECT ON EMPTY); -SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY); -SELECT JSON_QUERY(jsonb '[]', '$[*]' DEFAULT '"empty"' ON EMPTY); - -SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY NULL ON ERROR); -SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY EMPTY ARRAY ON ERROR); -SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY EMPTY OBJECT ON ERROR); -SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY ERROR ON ERROR); -SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON ERROR); - -SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' ERROR ON ERROR); -SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' DEFAULT '"empty"' ON ERROR); - -SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING json); -SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING json FORMAT JSON); -SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING jsonb); -SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING jsonb FORMAT JSON); -SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING text); -SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING char(10)); -SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING char(3)); -SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING text FORMAT JSON); -SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING bytea); -SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING bytea FORMAT JSON); - -SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' RETURNING bytea EMPTY OBJECT ON ERROR); -SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' RETURNING bytea FORMAT JSON EMPTY OBJECT ON ERROR); -SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' RETURNING json EMPTY OBJECT ON ERROR); -SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' RETURNING jsonb EMPTY OBJECT ON ERROR); - -SELECT - x, y, - JSON_QUERY( - jsonb '[1,2,3,4,5,null]', - '$[*] ? (@ >= $x && @ <= $y)' - PASSING x AS x, y AS y - WITH CONDITIONAL WRAPPER - EMPTY ARRAY ON EMPTY - ) list -FROM - generate_series(0, 4) x, - generate_series(0, 4) y; - --- Extension: record types returning -CREATE TYPE sqljsonb_rec AS (a int, t text, js json, jb jsonb, jsa json[]); -CREATE TYPE sqljsonb_reca AS (reca sqljsonb_rec[]); - -SELECT JSON_QUERY(jsonb '[{"a": 1, "b": "foo", "t": "aaa", "js": [1, "2", {}], "jb": {"x": [1, "2", {}]}}, {"a": 2}]', '$[0]' RETURNING sqljsonb_rec); -SELECT * FROM unnest((JSON_QUERY(jsonb '{"jsa": [{"a": 1, "b": ["foo"]}, {"a": 2, "c": {}}, 123]}', '$' RETURNING sqljsonb_rec)).jsa); -SELECT * FROM unnest((JSON_QUERY(jsonb '{"reca": [{"a": 1, "t": ["foo", []]}, {"a": 2, "jb": [{}, true]}]}', '$' RETURNING sqljsonb_reca)).reca); - --- Extension: array types returning -SELECT JSON_QUERY(jsonb '[1,2,null,"3"]', '$[*]' RETURNING int[] WITH WRAPPER); -SELECT * FROM unnest(JSON_QUERY(jsonb '[{"a": 1, "t": ["foo", []]}, {"a": 2, "jb": [{}, true]}]', '$' RETURNING sqljsonb_rec[])); - --- Extension: domain types returning -SELECT JSON_QUERY(jsonb '{"a": 1}', '$.a' RETURNING sqljsonb_int_not_null); -SELECT JSON_QUERY(jsonb '{"a": 1}', '$.b' RETURNING sqljsonb_int_not_null); - --- Test timestamptz passing and output -SELECT JSON_QUERY(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts); -SELECT JSON_QUERY(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING json); -SELECT JSON_QUERY(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING jsonb); - --- Test constraints - -CREATE TABLE test_jsonb_constraints ( - js text, - i int, - x jsonb DEFAULT JSON_QUERY(jsonb '[1,2]', '$[*]' WITH WRAPPER) - CONSTRAINT test_jsonb_constraint1 - CHECK (js IS JSON) - CONSTRAINT test_jsonb_constraint2 - CHECK (JSON_EXISTS(js::jsonb, '$.a' PASSING i + 5 AS int, i::text AS txt, array[1,2,3] as arr)) - CONSTRAINT test_jsonb_constraint3 - CHECK (JSON_VALUE(js::jsonb, '$.a' RETURNING int DEFAULT ('12' || i)::int ON EMPTY ERROR ON ERROR) > i) - CONSTRAINT test_jsonb_constraint4 - CHECK (JSON_QUERY(js::jsonb, '$.a' WITH CONDITIONAL WRAPPER EMPTY OBJECT ON ERROR) < jsonb '[10]') - CONSTRAINT test_jsonb_constraint5 - CHECK (JSON_QUERY(js::jsonb, '$.a' RETURNING char(5) OMIT QUOTES EMPTY ARRAY ON EMPTY) > 'a' COLLATE "C") - CONSTRAINT test_jsonb_constraint6 - CHECK (JSON_EXISTS(js::jsonb, 'strict $.a' RETURNING int TRUE ON ERROR) < 2) -); - -\d test_jsonb_constraints - -SELECT check_clause -FROM information_schema.check_constraints -WHERE constraint_name LIKE 'test_jsonb_constraint%' -ORDER BY 1; - -SELECT pg_get_expr(adbin, adrelid) -FROM pg_attrdef -WHERE adrelid = 'test_jsonb_constraints'::regclass -ORDER BY 1; - -INSERT INTO test_jsonb_constraints VALUES ('', 1); -INSERT INTO test_jsonb_constraints VALUES ('1', 1); -INSERT INTO test_jsonb_constraints VALUES ('[]'); -INSERT INTO test_jsonb_constraints VALUES ('{"b": 1}', 1); -INSERT INTO test_jsonb_constraints VALUES ('{"a": 1}', 1); -INSERT INTO test_jsonb_constraints VALUES ('{"a": 7}', 1); -INSERT INTO test_jsonb_constraints VALUES ('{"a": 10}', 1); - -DROP TABLE test_jsonb_constraints; - --- Test mutabilily od query functions -CREATE TABLE test_jsonb_mutability(js jsonb); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$')); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a[0]')); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime()')); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@ < $.datetime())')); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime() < $.datetime())')); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime() < $.datetime("HH:MI TZH"))')); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime("HH:MI TZH") < $.datetime("HH:MI TZH"))')); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime("HH:MI") < $.datetime("YY-MM-DD HH:MI"))')); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime("HH:MI TZH") < $.datetime("YY-MM-DD HH:MI"))')); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime("HH:MI TZH") < $x' PASSING '12:34'::timetz AS x)); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime("HH:MI TZH") < $y' PASSING '12:34'::timetz AS x)); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime() < $x' PASSING '12:34'::timetz AS x)); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime() < $x' PASSING '1234'::int AS x)); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime() ? (@ == $x)' PASSING '12:34'::time AS x)); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime("YY-MM-DD") ? (@ == $x)' PASSING '2020-07-14'::date AS x)); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$[1, $.a ? (@.datetime() == $x)]' PASSING '12:34'::time AS x)); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$[1, 0 to $.a ? (@.datetime() == $x)]' PASSING '12:34'::time AS x)); -CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$[1, $.a ? (@.datetime("HH:MI") == $x)]' PASSING '12:34'::time AS x)); -DROP TABLE test_jsonb_mutability; - --- JSON_TABLE - --- Should fail (JSON_TABLE can be used only in FROM clause) -SELECT JSON_TABLE('[]', '$'); - --- Should fail (no columns) -SELECT * FROM JSON_TABLE(NULL, '$' COLUMNS ()); - -SELECT * FROM JSON_TABLE (NULL::jsonb, '$' COLUMNS (v1 timestamp)) AS f (v1, v2); - --- NULL => empty table -SELECT * FROM JSON_TABLE(NULL::jsonb, '$' COLUMNS (foo int)) bar; - --- -SELECT * FROM JSON_TABLE(jsonb '123', '$' - COLUMNS (item int PATH '$', foo int)) bar; - --- JSON_TABLE: basic functionality -CREATE DOMAIN jsonb_test_domain AS text CHECK (value <> 'foo'); - -SELECT * -FROM - (VALUES - ('1'), - ('[]'), - ('{}'), - ('[1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""]') - ) vals(js) - LEFT OUTER JOIN --- JSON_TABLE is implicitly lateral - JSON_TABLE( - vals.js::jsonb, 'lax $[*]' - COLUMNS ( - id FOR ORDINALITY, - id2 FOR ORDINALITY, -- allowed additional ordinality columns - "int" int PATH '$', - "text" text PATH '$', - "char(4)" char(4) PATH '$', - "bool" bool PATH '$', - "numeric" numeric PATH '$', - "domain" jsonb_test_domain PATH '$', - js json PATH '$', - jb jsonb PATH '$', - jst text FORMAT JSON PATH '$', - jsc char(4) FORMAT JSON PATH '$', - jsv varchar(4) FORMAT JSON PATH '$', - jsb jsonb FORMAT JSON PATH '$', - jsbq jsonb FORMAT JSON PATH '$' OMIT QUOTES, - aaa int, -- implicit path '$."aaa"', - aaa1 int PATH '$.aaa', - exists1 bool EXISTS PATH '$.aaa', - exists2 int EXISTS PATH '$.aaa', - exists3 int EXISTS PATH 'strict $.aaa' UNKNOWN ON ERROR, - exists4 text EXISTS PATH 'strict $.aaa' FALSE ON ERROR, - - js2 json PATH '$', - jsb2w jsonb PATH '$' WITH WRAPPER, - jsb2q jsonb PATH '$' OMIT QUOTES, - ia int[] PATH '$', - ta text[] PATH '$', - jba jsonb[] PATH '$' - ) - ) jt - ON true; - --- JSON_TABLE: Test backward parsing - -CREATE VIEW jsonb_table_view AS -SELECT * FROM - JSON_TABLE( - jsonb 'null', 'lax $[*]' PASSING 1 + 2 AS a, json '"foo"' AS "b c" - COLUMNS ( - id FOR ORDINALITY, - id2 FOR ORDINALITY, -- allowed additional ordinality columns - "int" int PATH '$', - "text" text PATH '$', - "char(4)" char(4) PATH '$', - "bool" bool PATH '$', - "numeric" numeric PATH '$', - "domain" jsonb_test_domain PATH '$', - js json PATH '$', - jb jsonb PATH '$', - jst text FORMAT JSON PATH '$', - jsc char(4) FORMAT JSON PATH '$', - jsv varchar(4) FORMAT JSON PATH '$', - jsb jsonb FORMAT JSON PATH '$', - jsbq jsonb FORMAT JSON PATH '$' OMIT QUOTES, - aaa int, -- implicit path '$."aaa"', - aaa1 int PATH '$.aaa', - exists1 bool EXISTS PATH '$.aaa', - exists2 int EXISTS PATH '$.aaa' TRUE ON ERROR, - exists3 text EXISTS PATH 'strict $.aaa' UNKNOWN ON ERROR, - - js2 json PATH '$', - jsb2w jsonb PATH '$' WITH WRAPPER, - jsb2q jsonb PATH '$' OMIT QUOTES, - ia int[] PATH '$', - ta text[] PATH '$', - jba jsonb[] PATH '$', - - NESTED PATH '$[1]' AS p1 COLUMNS ( - a1 int, - NESTED PATH '$[*]' AS "p1 1" COLUMNS ( - a11 text - ), - b1 text - ), - NESTED PATH '$[2]' AS p2 COLUMNS ( - NESTED PATH '$[*]' AS "p2:1" COLUMNS ( - a21 text - ), - NESTED PATH '$[*]' AS p22 COLUMNS ( - a22 text - ) - ) - ) - ); - -\sv jsonb_table_view - -EXPLAIN (COSTS OFF, VERBOSE) SELECT * FROM jsonb_table_view; - -DROP VIEW jsonb_table_view; -DROP DOMAIN jsonb_test_domain; - --- JSON_TABLE: ON EMPTY/ON ERROR behavior -SELECT * -FROM - (VALUES ('1'), ('"err"')) vals(js), - JSON_TABLE(vals.js::jsonb, '$' COLUMNS (a int PATH '$')) jt; - -SELECT * -FROM - (VALUES ('1'), ('"err"')) vals(js) - LEFT OUTER JOIN - JSON_TABLE(vals.js::jsonb, '$' COLUMNS (a int PATH '$') ERROR ON ERROR) jt - ON true; - -SELECT * -FROM - (VALUES ('1'), ('"err"')) vals(js) - LEFT OUTER JOIN - JSON_TABLE(vals.js::jsonb, '$' COLUMNS (a int PATH '$' ERROR ON ERROR)) jt - ON true; - -SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (a int PATH '$.a' ERROR ON EMPTY)) jt; -SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (a int PATH 'strict $.a' ERROR ON EMPTY) ERROR ON ERROR) jt; -SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (a int PATH 'lax $.a' ERROR ON EMPTY) ERROR ON ERROR) jt; - -SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int PATH '$' DEFAULT 1 ON EMPTY DEFAULT 2 ON ERROR)) jt; -SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int PATH 'strict $.a' DEFAULT 1 ON EMPTY DEFAULT 2 ON ERROR)) jt; -SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int PATH 'lax $.a' DEFAULT 1 ON EMPTY DEFAULT 2 ON ERROR)) jt; - --- JSON_TABLE: EXISTS PATH types -SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int4 EXISTS PATH '$.a')); -SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int2 EXISTS PATH '$.a')); -SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int8 EXISTS PATH '$.a')); -SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a float4 EXISTS PATH '$.a')); -SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a char(3) EXISTS PATH '$.a')); -SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a json EXISTS PATH '$.a')); -SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a jsonb EXISTS PATH '$.a')); - --- JSON_TABLE: nested paths and plans - --- Should fail (JSON_TABLE columns must contain explicit AS path --- specifications if explicit PLAN clause is used) -SELECT * FROM JSON_TABLE( - jsonb '[]', '$' -- AS required here - COLUMNS ( - foo int PATH '$' - ) - PLAN DEFAULT (UNION) -) jt; - -SELECT * FROM JSON_TABLE( - jsonb '[]', '$' AS path1 - COLUMNS ( - NESTED PATH '$' COLUMNS ( -- AS required here - foo int PATH '$' - ) - ) - PLAN DEFAULT (UNION) -) jt; - --- Should fail (column names must be distinct) -SELECT * FROM JSON_TABLE( - jsonb '[]', '$' AS a - COLUMNS ( - a int - ) -) jt; - -SELECT * FROM JSON_TABLE( - jsonb '[]', '$' AS a - COLUMNS ( - b int, - NESTED PATH '$' AS a - COLUMNS ( - c int - ) - ) -) jt; - -SELECT * FROM JSON_TABLE( - jsonb '[]', '$' - COLUMNS ( - b int, - NESTED PATH '$' AS b - COLUMNS ( - c int - ) - ) -) jt; - -SELECT * FROM JSON_TABLE( - jsonb '[]', '$' - COLUMNS ( - NESTED PATH '$' AS a - COLUMNS ( - b int - ), - NESTED PATH '$' - COLUMNS ( - NESTED PATH '$' AS a - COLUMNS ( - c int - ) - ) - ) -) jt; - --- JSON_TABLE: plan validation - -SELECT * FROM JSON_TABLE( - jsonb 'null', '$[*]' AS p0 - COLUMNS ( - NESTED PATH '$' AS p1 COLUMNS ( - NESTED PATH '$' AS p11 COLUMNS ( foo int ), - NESTED PATH '$' AS p12 COLUMNS ( bar int ) - ), - NESTED PATH '$' AS p2 COLUMNS ( - NESTED PATH '$' AS p21 COLUMNS ( baz int ) - ) - ) - PLAN (p1) -) jt; - -SELECT * FROM JSON_TABLE( - jsonb 'null', '$[*]' AS p0 - COLUMNS ( - NESTED PATH '$' AS p1 COLUMNS ( - NESTED PATH '$' AS p11 COLUMNS ( foo int ), - NESTED PATH '$' AS p12 COLUMNS ( bar int ) - ), - NESTED PATH '$' AS p2 COLUMNS ( - NESTED PATH '$' AS p21 COLUMNS ( baz int ) - ) - ) - PLAN (p0) -) jt; - -SELECT * FROM JSON_TABLE( - jsonb 'null', '$[*]' AS p0 - COLUMNS ( - NESTED PATH '$' AS p1 COLUMNS ( - NESTED PATH '$' AS p11 COLUMNS ( foo int ), - NESTED PATH '$' AS p12 COLUMNS ( bar int ) - ), - NESTED PATH '$' AS p2 COLUMNS ( - NESTED PATH '$' AS p21 COLUMNS ( baz int ) - ) - ) - PLAN (p0 OUTER p3) -) jt; - -SELECT * FROM JSON_TABLE( - jsonb 'null', '$[*]' AS p0 - COLUMNS ( - NESTED PATH '$' AS p1 COLUMNS ( - NESTED PATH '$' AS p11 COLUMNS ( foo int ), - NESTED PATH '$' AS p12 COLUMNS ( bar int ) - ), - NESTED PATH '$' AS p2 COLUMNS ( - NESTED PATH '$' AS p21 COLUMNS ( baz int ) - ) - ) - PLAN (p0 UNION p1 UNION p11) -) jt; - -SELECT * FROM JSON_TABLE( - jsonb 'null', '$[*]' AS p0 - COLUMNS ( - NESTED PATH '$' AS p1 COLUMNS ( - NESTED PATH '$' AS p11 COLUMNS ( foo int ), - NESTED PATH '$' AS p12 COLUMNS ( bar int ) - ), - NESTED PATH '$' AS p2 COLUMNS ( - NESTED PATH '$' AS p21 COLUMNS ( baz int ) - ) - ) - PLAN (p0 OUTER (p1 CROSS p13)) -) jt; - -SELECT * FROM JSON_TABLE( - jsonb 'null', '$[*]' AS p0 - COLUMNS ( - NESTED PATH '$' AS p1 COLUMNS ( - NESTED PATH '$' AS p11 COLUMNS ( foo int ), - NESTED PATH '$' AS p12 COLUMNS ( bar int ) - ), - NESTED PATH '$' AS p2 COLUMNS ( - NESTED PATH '$' AS p21 COLUMNS ( baz int ) - ) - ) - PLAN (p0 OUTER (p1 CROSS p2)) -) jt; - -SELECT * FROM JSON_TABLE( - jsonb 'null', '$[*]' AS p0 - COLUMNS ( - NESTED PATH '$' AS p1 COLUMNS ( - NESTED PATH '$' AS p11 COLUMNS ( foo int ), - NESTED PATH '$' AS p12 COLUMNS ( bar int ) - ), - NESTED PATH '$' AS p2 COLUMNS ( - NESTED PATH '$' AS p21 COLUMNS ( baz int ) - ) - ) - PLAN (p0 OUTER ((p1 UNION p11) CROSS p2)) -) jt; - -SELECT * FROM JSON_TABLE( - jsonb 'null', '$[*]' AS p0 - COLUMNS ( - NESTED PATH '$' AS p1 COLUMNS ( - NESTED PATH '$' AS p11 COLUMNS ( foo int ), - NESTED PATH '$' AS p12 COLUMNS ( bar int ) - ), - NESTED PATH '$' AS p2 COLUMNS ( - NESTED PATH '$' AS p21 COLUMNS ( baz int ) - ) - ) - PLAN (p0 OUTER ((p1 INNER p11) CROSS p2)) -) jt; - -SELECT * FROM JSON_TABLE( - jsonb 'null', '$[*]' AS p0 - COLUMNS ( - NESTED PATH '$' AS p1 COLUMNS ( - NESTED PATH '$' AS p11 COLUMNS ( foo int ), - NESTED PATH '$' AS p12 COLUMNS ( bar int ) - ), - NESTED PATH '$' AS p2 COLUMNS ( - NESTED PATH '$' AS p21 COLUMNS ( baz int ) - ) - ) - PLAN (p0 OUTER ((p1 INNER (p12 CROSS p11)) CROSS p2)) -) jt; - -SELECT * FROM JSON_TABLE( - jsonb 'null', 'strict $[*]' AS p0 - COLUMNS ( - NESTED PATH '$' AS p1 COLUMNS ( - NESTED PATH '$' AS p11 COLUMNS ( foo int ), - NESTED PATH '$' AS p12 COLUMNS ( bar int ) - ), - NESTED PATH '$' AS p2 COLUMNS ( - NESTED PATH '$' AS p21 COLUMNS ( baz int ) - ) - ) - PLAN (p0 OUTER ((p1 INNER (p12 CROSS p11)) CROSS (p2 INNER p21))) -) jt; - -SELECT * FROM JSON_TABLE( - jsonb 'null', 'strict $[*]' -- without root path name - COLUMNS ( - NESTED PATH '$' AS p1 COLUMNS ( - NESTED PATH '$' AS p11 COLUMNS ( foo int ), - NESTED PATH '$' AS p12 COLUMNS ( bar int ) - ), - NESTED PATH '$' AS p2 COLUMNS ( - NESTED PATH '$' AS p21 COLUMNS ( baz int ) - ) - ) - PLAN ((p1 INNER (p12 CROSS p11)) CROSS (p2 INNER p21)) -) jt; - --- JSON_TABLE: plan execution - -CREATE TEMP TABLE jsonb_table_test (js jsonb); - -INSERT INTO jsonb_table_test -VALUES ( - '[ - {"a": 1, "b": [], "c": []}, - {"a": 2, "b": [1, 2, 3], "c": [10, null, 20]}, - {"a": 3, "b": [1, 2], "c": []}, - {"x": "4", "b": [1, 2], "c": 123} - ]' -); - --- unspecified plan (outer, union) -select - jt.* -from - jsonb_table_test jtt, - json_table ( - jtt.js,'strict $[*]' as p - columns ( - n for ordinality, - a int path 'lax $.a' default -1 on empty, - nested path 'strict $.b[*]' as pb columns ( b int path '$' ), - nested path 'strict $.c[*]' as pc columns ( c int path '$' ) - ) - ) jt; - --- default plan (outer, union) -select - jt.* -from - jsonb_table_test jtt, - json_table ( - jtt.js,'strict $[*]' as p - columns ( - n for ordinality, - a int path 'lax $.a' default -1 on empty, - nested path 'strict $.b[*]' as pb columns ( b int path '$' ), - nested path 'strict $.c[*]' as pc columns ( c int path '$' ) - ) - plan default (outer, union) - ) jt; - --- specific plan (p outer (pb union pc)) -select - jt.* -from - jsonb_table_test jtt, - json_table ( - jtt.js,'strict $[*]' as p - columns ( - n for ordinality, - a int path 'lax $.a' default -1 on empty, - nested path 'strict $.b[*]' as pb columns ( b int path '$' ), - nested path 'strict $.c[*]' as pc columns ( c int path '$' ) - ) - plan (p outer (pb union pc)) - ) jt; - --- specific plan (p outer (pc union pb)) -select - jt.* -from - jsonb_table_test jtt, - json_table ( - jtt.js,'strict $[*]' as p - columns ( - n for ordinality, - a int path 'lax $.a' default -1 on empty, - nested path 'strict $.b[*]' as pb columns ( b int path '$' ), - nested path 'strict $.c[*]' as pc columns ( c int path '$' ) - ) - plan (p outer (pc union pb)) - ) jt; - --- default plan (inner, union) -select - jt.* -from - jsonb_table_test jtt, - json_table ( - jtt.js,'strict $[*]' as p - columns ( - n for ordinality, - a int path 'lax $.a' default -1 on empty, - nested path 'strict $.b[*]' as pb columns ( b int path '$' ), - nested path 'strict $.c[*]' as pc columns ( c int path '$' ) - ) - plan default (inner) - ) jt; - --- specific plan (p inner (pb union pc)) -select - jt.* -from - jsonb_table_test jtt, - json_table ( - jtt.js,'strict $[*]' as p - columns ( - n for ordinality, - a int path 'lax $.a' default -1 on empty, - nested path 'strict $.b[*]' as pb columns ( b int path '$' ), - nested path 'strict $.c[*]' as pc columns ( c int path '$' ) - ) - plan (p inner (pb union pc)) - ) jt; - --- default plan (inner, cross) -select - jt.* -from - jsonb_table_test jtt, - json_table ( - jtt.js,'strict $[*]' as p - columns ( - n for ordinality, - a int path 'lax $.a' default -1 on empty, - nested path 'strict $.b[*]' as pb columns ( b int path '$' ), - nested path 'strict $.c[*]' as pc columns ( c int path '$' ) - ) - plan default (cross, inner) - ) jt; - --- specific plan (p inner (pb cross pc)) -select - jt.* -from - jsonb_table_test jtt, - json_table ( - jtt.js,'strict $[*]' as p - columns ( - n for ordinality, - a int path 'lax $.a' default -1 on empty, - nested path 'strict $.b[*]' as pb columns ( b int path '$' ), - nested path 'strict $.c[*]' as pc columns ( c int path '$' ) - ) - plan (p inner (pb cross pc)) - ) jt; - --- default plan (outer, cross) -select - jt.* -from - jsonb_table_test jtt, - json_table ( - jtt.js,'strict $[*]' as p - columns ( - n for ordinality, - a int path 'lax $.a' default -1 on empty, - nested path 'strict $.b[*]' as pb columns ( b int path '$' ), - nested path 'strict $.c[*]' as pc columns ( c int path '$' ) - ) - plan default (outer, cross) - ) jt; - --- specific plan (p outer (pb cross pc)) -select - jt.* -from - jsonb_table_test jtt, - json_table ( - jtt.js,'strict $[*]' as p - columns ( - n for ordinality, - a int path 'lax $.a' default -1 on empty, - nested path 'strict $.b[*]' as pb columns ( b int path '$' ), - nested path 'strict $.c[*]' as pc columns ( c int path '$' ) - ) - plan (p outer (pb cross pc)) - ) jt; - - -select - jt.*, b1 + 100 as b -from - json_table (jsonb - '[ - {"a": 1, "b": [[1, 10], [2], [3, 30, 300]], "c": [1, null, 2]}, - {"a": 2, "b": [10, 20], "c": [1, null, 2]}, - {"x": "3", "b": [11, 22, 33, 44]} - ]', - '$[*]' as p - columns ( - n for ordinality, - a int path 'lax $.a' default -1 on error, - nested path 'strict $.b[*]' as pb columns ( - b text format json path '$', - nested path 'strict $[*]' as pb1 columns ( - b1 int path '$' - ) - ), - nested path 'strict $.c[*]' as pc columns ( - c text format json path '$', - nested path 'strict $[*]' as pc1 columns ( - c1 int path '$' - ) - ) - ) - --plan default(outer, cross) - plan(p outer ((pb inner pb1) cross (pc outer pc1))) - ) jt; - --- Should succeed (JSON arguments are passed to root and nested paths) -SELECT * -FROM - generate_series(1, 4) x, - generate_series(1, 3) y, - JSON_TABLE(jsonb - '[[1,2,3],[2,3,4,5],[3,4,5,6]]', - 'strict $[*] ? (@[*] < $x)' - PASSING x AS x, y AS y - COLUMNS ( - y text FORMAT JSON PATH '$', - NESTED PATH 'strict $[*] ? (@ >= $y)' - COLUMNS ( - z int PATH '$' - ) - ) - ) jt; - --- Should fail (JSON arguments are not passed to column paths) -SELECT * -FROM JSON_TABLE( - jsonb '[1,2,3]', - '$[*] ? (@ < $x)' - PASSING 10 AS x - COLUMNS (y text FORMAT JSON PATH '$ ? (@ < $x)') - ) jt; - --- Extension: non-constant JSON path -SELECT JSON_EXISTS(jsonb '{"a": 123}', '$' || '.' || 'a'); -SELECT JSON_VALUE(jsonb '{"a": 123}', '$' || '.' || 'a'); -SELECT JSON_VALUE(jsonb '{"a": 123}', '$' || '.' || 'b' DEFAULT 'foo' ON EMPTY); -SELECT JSON_QUERY(jsonb '{"a": 123}', '$' || '.' || 'a'); -SELECT JSON_QUERY(jsonb '{"a": 123}', '$' || '.' || 'a' WITH WRAPPER); --- Should fail (invalid path) -SELECT JSON_QUERY(jsonb '{"a": 123}', 'error' || ' ' || 'error'); --- Should fail (not supported) -SELECT * FROM JSON_TABLE(jsonb '{"a": 123}', '$' || '.' || 'a' COLUMNS (foo int)); - --- Test parallel JSON_VALUE() - - -CREATE UNLOGGED TABLE test_parallel_jsonb_value AS -SELECT i::text::jsonb AS js -FROM generate_series(1, 50000) i; - - --- encourage use of parallel plans -set parallel_setup_cost=0; -set parallel_tuple_cost=0; -set min_parallel_table_scan_size=0; -set max_parallel_workers_per_gather=4; -set parallel_leader_participation = off; - --- Should be non-parallel due to subtransactions -EXPLAIN (COSTS OFF) -SELECT sum(JSON_VALUE(js, '$' RETURNING numeric)) FROM test_parallel_jsonb_value; -SELECT sum(JSON_VALUE(js, '$' RETURNING numeric)) FROM test_parallel_jsonb_value; - --- Should be parallel -EXPLAIN (COSTS OFF) -SELECT sum(JSON_VALUE(js, '$' RETURNING numeric ERROR ON ERROR)) FROM test_parallel_jsonb_value; -SELECT sum(JSON_VALUE(js, '$' RETURNING numeric ERROR ON ERROR)) FROM test_parallel_jsonb_value; - -DROP TABLE test_parallel_jsonb_value; diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql index 63fe114fedd..2b292851e3a 100644 --- a/src/test/regress/sql/opr_sanity.sql +++ b/src/test/regress/sql/opr_sanity.sql @@ -854,10 +854,8 @@ WHERE a.aggfnoid = p.oid AND NOT binary_coercible(p.proargtypes[1], ptr.proargtypes[2])) OR (p.pronargs > 2 AND NOT binary_coercible(p.proargtypes[2], ptr.proargtypes[3])) - OR (p.pronargs > 3 AND - NOT binary_coercible(p.proargtypes[3], ptr.proargtypes[4])) - -- we could carry the check further, but 4 args is enough for now - OR (p.pronargs > 4) + -- we could carry the check further, but 3 args is enough for now + OR (p.pronargs > 3) ); -- Cross-check finalfn (if present) against its entry in pg_proc. diff --git a/src/test/regress/sql/sqljson.sql b/src/test/regress/sql/sqljson.sql deleted file mode 100644 index c2742b40f1d..00000000000 --- a/src/test/regress/sql/sqljson.sql +++ /dev/null @@ -1,471 +0,0 @@ --- JSON() -SELECT JSON(); -SELECT JSON(NULL); -SELECT JSON('{ "a" : 1 } '); -SELECT JSON('{ "a" : 1 } ' FORMAT JSON); -SELECT JSON('{ "a" : 1 } ' FORMAT JSON ENCODING UTF8); -SELECT JSON('{ "a" : 1 } '::bytea FORMAT JSON ENCODING UTF8); -SELECT pg_typeof(JSON('{ "a" : 1 } ')); - -SELECT JSON(' 1 '::json); -SELECT JSON(' 1 '::jsonb); -SELECT JSON(' 1 '::json WITH UNIQUE KEYS); -SELECT JSON(123); - -SELECT JSON('{"a": 1, "a": 2}'); -SELECT JSON('{"a": 1, "a": 2}' WITH UNIQUE KEYS); -SELECT JSON('{"a": 1, "a": 2}' WITHOUT UNIQUE KEYS); - -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123'); -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' FORMAT JSON); -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123'::bytea FORMAT JSON); -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123'::bytea FORMAT JSON ENCODING UTF8); -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' WITH UNIQUE KEYS); -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' WITHOUT UNIQUE KEYS); - -SELECT JSON('123' RETURNING text); - -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123'); -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' RETURNING json); -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' RETURNING jsonb); -SELECT pg_typeof(JSON('123')); -SELECT pg_typeof(JSON('123' RETURNING json)); -SELECT pg_typeof(JSON('123' RETURNING jsonb)); - --- JSON_SCALAR() -SELECT JSON_SCALAR(); -SELECT JSON_SCALAR(NULL); -SELECT JSON_SCALAR(NULL::int); -SELECT JSON_SCALAR(123); -SELECT JSON_SCALAR(123.45); -SELECT JSON_SCALAR(123.45::numeric); -SELECT JSON_SCALAR(true); -SELECT JSON_SCALAR(false); -SELECT JSON_SCALAR(' 123.45'); -SELECT JSON_SCALAR('2020-06-07'::date); -SELECT JSON_SCALAR('2020-06-07 01:02:03'::timestamp); -SELECT JSON_SCALAR('{}'::json); -SELECT JSON_SCALAR('{}'::jsonb); - -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR(123); -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR('123'); -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR(123 RETURNING json); -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR(123 RETURNING jsonb); - --- JSON_SERIALIZE() -SELECT JSON_SERIALIZE(); -SELECT JSON_SERIALIZE(NULL); -SELECT JSON_SERIALIZE(JSON('{ "a" : 1 } ')); -SELECT JSON_SERIALIZE('{ "a" : 1 } '); -SELECT JSON_SERIALIZE('1'); -SELECT JSON_SERIALIZE('1' FORMAT JSON); -SELECT JSON_SERIALIZE('{ "a" : 1 } ' RETURNING bytea); -SELECT JSON_SERIALIZE('{ "a" : 1 } ' RETURNING varchar); -SELECT pg_typeof(JSON_SERIALIZE(NULL)); - --- only string types or bytea allowed -SELECT JSON_SERIALIZE('{ "a" : 1 } ' RETURNING jsonb); - - -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SERIALIZE('{}'); -EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SERIALIZE('{}' RETURNING bytea); - --- JSON_OBJECT() -SELECT JSON_OBJECT(); -SELECT JSON_OBJECT(RETURNING json); -SELECT JSON_OBJECT(RETURNING json FORMAT JSON); -SELECT JSON_OBJECT(RETURNING jsonb); -SELECT JSON_OBJECT(RETURNING jsonb FORMAT JSON); -SELECT JSON_OBJECT(RETURNING text); -SELECT JSON_OBJECT(RETURNING text FORMAT JSON); -SELECT JSON_OBJECT(RETURNING text FORMAT JSON ENCODING UTF8); -SELECT JSON_OBJECT(RETURNING text FORMAT JSON ENCODING INVALID_ENCODING); -SELECT JSON_OBJECT(RETURNING bytea); -SELECT JSON_OBJECT(RETURNING bytea FORMAT JSON); -SELECT JSON_OBJECT(RETURNING bytea FORMAT JSON ENCODING UTF8); -SELECT JSON_OBJECT(RETURNING bytea FORMAT JSON ENCODING UTF16); -SELECT JSON_OBJECT(RETURNING bytea FORMAT JSON ENCODING UTF32); - -SELECT JSON_OBJECT('foo': NULL::int FORMAT JSON); -SELECT JSON_OBJECT('foo': NULL::int FORMAT JSON ENCODING UTF8); -SELECT JSON_OBJECT('foo': NULL::json FORMAT JSON); -SELECT JSON_OBJECT('foo': NULL::json FORMAT JSON ENCODING UTF8); -SELECT JSON_OBJECT('foo': NULL::jsonb FORMAT JSON); -SELECT JSON_OBJECT('foo': NULL::jsonb FORMAT JSON ENCODING UTF8); - -SELECT JSON_OBJECT(NULL: 1); -SELECT JSON_OBJECT('a': 2 + 3); -SELECT JSON_OBJECT('a' VALUE 2 + 3); ---SELECT JSON_OBJECT(KEY 'a' VALUE 2 + 3); -SELECT JSON_OBJECT('a' || 2: 1); -SELECT JSON_OBJECT(('a' || 2) VALUE 1); ---SELECT JSON_OBJECT('a' || 2 VALUE 1); ---SELECT JSON_OBJECT(KEY 'a' || 2 VALUE 1); -SELECT JSON_OBJECT('a': 2::text); -SELECT JSON_OBJECT('a' VALUE 2::text); ---SELECT JSON_OBJECT(KEY 'a' VALUE 2::text); -SELECT JSON_OBJECT(1::text: 2); -SELECT JSON_OBJECT((1::text) VALUE 2); ---SELECT JSON_OBJECT(1::text VALUE 2); ---SELECT JSON_OBJECT(KEY 1::text VALUE 2); -SELECT JSON_OBJECT(json '[1]': 123); -SELECT JSON_OBJECT(ARRAY[1,2,3]: 'aaa'); - -SELECT JSON_OBJECT( - 'a': '123', - 1.23: 123, - 'c': json '[ 1,true,{ } ]', - 'd': jsonb '{ "x" : 123.45 }' -); - -SELECT JSON_OBJECT( - 'a': '123', - 1.23: 123, - 'c': json '[ 1,true,{ } ]', - 'd': jsonb '{ "x" : 123.45 }' - RETURNING jsonb -); - -/* -SELECT JSON_OBJECT( - 'a': '123', - KEY 1.23 VALUE 123, - 'c' VALUE json '[1, true, {}]' -); -*/ - -SELECT JSON_OBJECT('a': '123', 'b': JSON_OBJECT('a': 111, 'b': 'aaa')); -SELECT JSON_OBJECT('a': '123', 'b': JSON_OBJECT('a': 111, 'b': 'aaa' RETURNING jsonb)); - -SELECT JSON_OBJECT('a': JSON_OBJECT('b': 1 RETURNING text)); -SELECT JSON_OBJECT('a': JSON_OBJECT('b': 1 RETURNING text) FORMAT JSON); -SELECT JSON_OBJECT('a': JSON_OBJECT('b': 1 RETURNING bytea)); -SELECT JSON_OBJECT('a': JSON_OBJECT('b': 1 RETURNING bytea) FORMAT JSON); - -SELECT JSON_OBJECT('a': '1', 'b': NULL, 'c': 2); -SELECT JSON_OBJECT('a': '1', 'b': NULL, 'c': 2 NULL ON NULL); -SELECT JSON_OBJECT('a': '1', 'b': NULL, 'c': 2 ABSENT ON NULL); - -SELECT JSON_OBJECT(1: 1, '1': NULL WITH UNIQUE); -SELECT JSON_OBJECT(1: 1, '1': NULL ABSENT ON NULL WITH UNIQUE); -SELECT JSON_OBJECT(1: 1, '1': NULL NULL ON NULL WITH UNIQUE RETURNING jsonb); -SELECT JSON_OBJECT(1: 1, '1': NULL ABSENT ON NULL WITH UNIQUE RETURNING jsonb); - -SELECT JSON_OBJECT(1: 1, '2': NULL, '1': 1 NULL ON NULL WITH UNIQUE); -SELECT JSON_OBJECT(1: 1, '2': NULL, '1': 1 ABSENT ON NULL WITH UNIQUE); -SELECT JSON_OBJECT(1: 1, '2': NULL, '1': 1 ABSENT ON NULL WITHOUT UNIQUE); -SELECT JSON_OBJECT(1: 1, '2': NULL, '1': 1 ABSENT ON NULL WITH UNIQUE RETURNING jsonb); -SELECT JSON_OBJECT(1: 1, '2': NULL, '1': 1 ABSENT ON NULL WITHOUT UNIQUE RETURNING jsonb); -SELECT JSON_OBJECT(1: 1, '2': NULL, '3': 1, 4: NULL, '5': 'a' ABSENT ON NULL WITH UNIQUE RETURNING jsonb); - - --- JSON_ARRAY() -SELECT JSON_ARRAY(); -SELECT JSON_ARRAY(RETURNING json); -SELECT JSON_ARRAY(RETURNING json FORMAT JSON); -SELECT JSON_ARRAY(RETURNING jsonb); -SELECT JSON_ARRAY(RETURNING jsonb FORMAT JSON); -SELECT JSON_ARRAY(RETURNING text); -SELECT JSON_ARRAY(RETURNING text FORMAT JSON); -SELECT JSON_ARRAY(RETURNING text FORMAT JSON ENCODING UTF8); -SELECT JSON_ARRAY(RETURNING text FORMAT JSON ENCODING INVALID_ENCODING); -SELECT JSON_ARRAY(RETURNING bytea); -SELECT JSON_ARRAY(RETURNING bytea FORMAT JSON); -SELECT JSON_ARRAY(RETURNING bytea FORMAT JSON ENCODING UTF8); -SELECT JSON_ARRAY(RETURNING bytea FORMAT JSON ENCODING UTF16); -SELECT JSON_ARRAY(RETURNING bytea FORMAT JSON ENCODING UTF32); - -SELECT JSON_ARRAY('aaa', 111, true, array[1,2,3], NULL, json '{"a": [1]}', jsonb '["a",3]'); - -SELECT JSON_ARRAY('a', NULL, 'b' NULL ON NULL); -SELECT JSON_ARRAY('a', NULL, 'b' ABSENT ON NULL); -SELECT JSON_ARRAY(NULL, NULL, 'b' ABSENT ON NULL); -SELECT JSON_ARRAY('a', NULL, 'b' NULL ON NULL RETURNING jsonb); -SELECT JSON_ARRAY('a', NULL, 'b' ABSENT ON NULL RETURNING jsonb); -SELECT JSON_ARRAY(NULL, NULL, 'b' ABSENT ON NULL RETURNING jsonb); - -SELECT JSON_ARRAY(JSON_ARRAY('{ "a" : 123 }' RETURNING text)); -SELECT JSON_ARRAY(JSON_ARRAY('{ "a" : 123 }' FORMAT JSON RETURNING text)); -SELECT JSON_ARRAY(JSON_ARRAY('{ "a" : 123 }' FORMAT JSON RETURNING text) FORMAT JSON); - -SELECT JSON_ARRAY(SELECT i FROM (VALUES (1), (2), (NULL), (4)) foo(i)); -SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i)); -SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) RETURNING jsonb); ---SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) NULL ON NULL); ---SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) NULL ON NULL RETURNING jsonb); -SELECT JSON_ARRAY(SELECT i FROM (VALUES (3), (1), (NULL), (2)) foo(i) ORDER BY i); --- Should fail -SELECT JSON_ARRAY(SELECT FROM (VALUES (1)) foo(i)); -SELECT JSON_ARRAY(SELECT i, i FROM (VALUES (1)) foo(i)); -SELECT JSON_ARRAY(SELECT * FROM (VALUES (1, 2)) foo(i, j)); - --- JSON_ARRAYAGG() -SELECT JSON_ARRAYAGG(i) IS NULL, - JSON_ARRAYAGG(i RETURNING jsonb) IS NULL -FROM generate_series(1, 0) i; - -SELECT JSON_ARRAYAGG(i), - JSON_ARRAYAGG(i RETURNING jsonb) -FROM generate_series(1, 5) i; - -SELECT JSON_ARRAYAGG(i ORDER BY i DESC) -FROM generate_series(1, 5) i; - -SELECT JSON_ARRAYAGG(i::text::json) -FROM generate_series(1, 5) i; - -SELECT JSON_ARRAYAGG(JSON_ARRAY(i, i + 1 RETURNING text) FORMAT JSON) -FROM generate_series(1, 5) i; - -SELECT JSON_ARRAYAGG(NULL), - JSON_ARRAYAGG(NULL RETURNING jsonb) -FROM generate_series(1, 5); - -SELECT JSON_ARRAYAGG(NULL NULL ON NULL), - JSON_ARRAYAGG(NULL NULL ON NULL RETURNING jsonb) -FROM generate_series(1, 5); - -SELECT - JSON_ARRAYAGG(bar), - JSON_ARRAYAGG(bar RETURNING jsonb), - JSON_ARRAYAGG(bar ABSENT ON NULL), - JSON_ARRAYAGG(bar ABSENT ON NULL RETURNING jsonb), - JSON_ARRAYAGG(bar NULL ON NULL), - JSON_ARRAYAGG(bar NULL ON NULL RETURNING jsonb), - JSON_ARRAYAGG(foo), - JSON_ARRAYAGG(foo RETURNING jsonb), - JSON_ARRAYAGG(foo ORDER BY bar) FILTER (WHERE bar > 2), - JSON_ARRAYAGG(foo ORDER BY bar RETURNING jsonb) FILTER (WHERE bar > 2) -FROM - (VALUES (NULL), (3), (1), (NULL), (NULL), (5), (2), (4), (NULL)) foo(bar); - -SELECT - bar, JSON_ARRAYAGG(bar) FILTER (WHERE bar > 2) OVER (PARTITION BY foo.bar % 2) -FROM - (VALUES (NULL), (3), (1), (NULL), (NULL), (5), (2), (4), (NULL), (5), (4)) foo(bar); - --- JSON_OBJECTAGG() -SELECT JSON_OBJECTAGG('key': 1) IS NULL, - JSON_OBJECTAGG('key': 1 RETURNING jsonb) IS NULL -WHERE FALSE; - -SELECT JSON_OBJECTAGG(NULL: 1); - -SELECT JSON_OBJECTAGG(NULL: 1 RETURNING jsonb); - -SELECT - JSON_OBJECTAGG(i: i), --- JSON_OBJECTAGG(i VALUE i), --- JSON_OBJECTAGG(KEY i VALUE i), - JSON_OBJECTAGG(i: i RETURNING jsonb) -FROM - generate_series(1, 5) i; - -SELECT - JSON_OBJECTAGG(k: v), - JSON_OBJECTAGG(k: v NULL ON NULL), - JSON_OBJECTAGG(k: v ABSENT ON NULL), - JSON_OBJECTAGG(k: v RETURNING jsonb), - JSON_OBJECTAGG(k: v NULL ON NULL RETURNING jsonb), - JSON_OBJECTAGG(k: v ABSENT ON NULL RETURNING jsonb) -FROM - (VALUES (1, 1), (1, NULL), (2, NULL), (3, 3)) foo(k, v); - -SELECT JSON_OBJECTAGG(k: v WITH UNIQUE KEYS) -FROM (VALUES (1, 1), (1, NULL), (2, 2)) foo(k, v); - -SELECT JSON_OBJECTAGG(k: v ABSENT ON NULL WITH UNIQUE KEYS) -FROM (VALUES (1, 1), (1, NULL), (2, 2)) foo(k, v); - -SELECT JSON_OBJECTAGG(k: v ABSENT ON NULL WITH UNIQUE KEYS) -FROM (VALUES (1, 1), (0, NULL), (3, NULL), (2, 2), (4, NULL)) foo(k, v); - -SELECT JSON_OBJECTAGG(k: v WITH UNIQUE KEYS RETURNING jsonb) -FROM (VALUES (1, 1), (1, NULL), (2, 2)) foo(k, v); - -SELECT JSON_OBJECTAGG(k: v ABSENT ON NULL WITH UNIQUE KEYS RETURNING jsonb) -FROM (VALUES (1, 1), (1, NULL), (2, 2)) foo(k, v); - -SELECT JSON_OBJECTAGG(k: v ABSENT ON NULL WITH UNIQUE KEYS RETURNING jsonb) -FROM (VALUES (1, 1), (0, NULL),(4, null), (5, null),(6, null),(2, 2)) foo(k, v); - --- Test JSON_OBJECT deparsing -EXPLAIN (VERBOSE, COSTS OFF) -SELECT JSON_OBJECT('foo' : '1' FORMAT JSON, 'bar' : 'baz' RETURNING json); - -CREATE VIEW json_object_view AS -SELECT JSON_OBJECT('foo' : '1' FORMAT JSON, 'bar' : 'baz' RETURNING json); - -\sv json_object_view - -DROP VIEW json_object_view; - -SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v WITH UNIQUE KEYS) OVER (ORDER BY k) -FROM (VALUES (1,1), (2,2)) a(k,v); - -SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v WITH UNIQUE KEYS) OVER (ORDER BY k) -FROM (VALUES (1,1), (1,2), (2,2)) a(k,v); - -SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v ABSENT ON NULL WITH UNIQUE KEYS) - OVER (ORDER BY k) -FROM (VALUES (1,1), (1,null), (2,2)) a(k,v); - -SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v ABSENT ON NULL) -OVER (ORDER BY k) -FROM (VALUES (1,1), (1,null), (2,2)) a(k,v); - -SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v ABSENT ON NULL) -OVER (ORDER BY k RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) -FROM (VALUES (1,1), (1,null), (2,2)) a(k,v); - --- Test JSON_ARRAY deparsing -EXPLAIN (VERBOSE, COSTS OFF) -SELECT JSON_ARRAY('1' FORMAT JSON, 2 RETURNING json); - -CREATE VIEW json_array_view AS -SELECT JSON_ARRAY('1' FORMAT JSON, 2 RETURNING json); - -\sv json_array_view - -DROP VIEW json_array_view; - --- Test JSON_OBJECTAGG deparsing -EXPLAIN (VERBOSE, COSTS OFF) -SELECT JSON_OBJECTAGG(i: ('111' || i)::bytea FORMAT JSON WITH UNIQUE RETURNING text) FILTER (WHERE i > 3) -FROM generate_series(1,5) i; - -EXPLAIN (VERBOSE, COSTS OFF) -SELECT JSON_OBJECTAGG(i: ('111' || i)::bytea FORMAT JSON WITH UNIQUE RETURNING text) OVER (PARTITION BY i % 2) -FROM generate_series(1,5) i; - -CREATE VIEW json_objectagg_view AS -SELECT JSON_OBJECTAGG(i: ('111' || i)::bytea FORMAT JSON WITH UNIQUE RETURNING text) FILTER (WHERE i > 3) -FROM generate_series(1,5) i; - -\sv json_objectagg_view - -DROP VIEW json_objectagg_view; - --- Test JSON_ARRAYAGG deparsing -EXPLAIN (VERBOSE, COSTS OFF) -SELECT JSON_ARRAYAGG(('111' || i)::bytea FORMAT JSON NULL ON NULL RETURNING text) FILTER (WHERE i > 3) -FROM generate_series(1,5) i; - -EXPLAIN (VERBOSE, COSTS OFF) -SELECT JSON_ARRAYAGG(('111' || i)::bytea FORMAT JSON NULL ON NULL RETURNING text) OVER (PARTITION BY i % 2) -FROM generate_series(1,5) i; - -CREATE VIEW json_arrayagg_view AS -SELECT JSON_ARRAYAGG(('111' || i)::bytea FORMAT JSON NULL ON NULL RETURNING text) FILTER (WHERE i > 3) -FROM generate_series(1,5) i; - -\sv json_arrayagg_view - -DROP VIEW json_arrayagg_view; - --- Test JSON_ARRAY(subquery) deparsing -EXPLAIN (VERBOSE, COSTS OFF) -SELECT JSON_ARRAY(SELECT i FROM (VALUES (1), (2), (NULL), (4)) foo(i) RETURNING jsonb); - -CREATE VIEW json_array_subquery_view AS -SELECT JSON_ARRAY(SELECT i FROM (VALUES (1), (2), (NULL), (4)) foo(i) RETURNING jsonb); - -\sv json_array_subquery_view - -DROP VIEW json_array_subquery_view; - --- IS JSON predicate -SELECT NULL IS JSON; -SELECT NULL IS NOT JSON; -SELECT NULL::json IS JSON; -SELECT NULL::jsonb IS JSON; -SELECT NULL::text IS JSON; -SELECT NULL::bytea IS JSON; -SELECT NULL::int IS JSON; - -SELECT '' IS JSON; - -SELECT bytea '\x00' IS JSON; - -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; - -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); - -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); - -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); - --- 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; - -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 - -DROP VIEW is_json_view; diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 6b17e5748ba..b9a2624a5d0 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -1238,12 +1238,10 @@ JsonBehaviorType JsonCoercion JsonCommon JsonConstructorExpr -JsonConstructorExprState JsonConstructorType JsonEncoding JsonExpr JsonExprOp -JsonExprState JsonFormat JsonFormatType JsonFunc @@ -1292,18 +1290,6 @@ JsonQuotes JsonReturning JsonScalarExpr JsonSemAction -JsonSerializeExpr -JsonTable -JsonTableColumn -JsonTableColumnType -JsonTableContext -JsonTableJoinState -JsonTableParent -JsonTablePlan -JsonTablePlanJoinType -JsonTablePlanType -JsonTableScanState -JsonTableSibling JsonTokenType JsonTransformStringValuesAction JsonTypeCategory @@ -2725,7 +2711,6 @@ TableFunc TableFuncRoutine TableFuncScan TableFuncScanState -TableFuncType TableInfo TableLikeClause TableSampleClause