</para>
<para>
<literal>jsonb_set_lax('[{"f1":1,"f2":null},2,null,3]', '{0,f1}', null)</literal>
- <returnvalue>[{"f1": null, "f2": null}, 2, null, 3]</returnvalue>
+ <returnvalue>[{"f1":null,"f2":null},2,null,3]</returnvalue>
</para>
<para>
<literal>jsonb_set_lax('[{"f1":99,"f2":null},2]', '{0,f3}', null, true, 'return_target')</literal>
comparisons.
</para>
<para>
- <literal>jsonb_path_exists_tz('["2015-08-01 12:00:00-05"]', '$[*] ? (@.datetime() < "2015-08-02".datetime())')</literal>
+ <literal>jsonb_path_exists_tz('["2015-08-01 12:00:00 -05"]', '$[*] ? (@.datetime() < "2015-08-02".datetime())')</literal>
<returnvalue>t</returnvalue>
</para></entry>
</row>
</programlisting>
</para>
</sect3>
- </sect2>
-
- <sect2 id="functions-sqljson">
- <title>SQL/JSON Functions and Expressions</title>
- <indexterm zone="functions-json">
- <primary>SQL/JSON</primary>
- <secondary>functions and expressions</secondary>
- </indexterm>
-
- <para>
- To provide native support for JSON data types within the SQL environment,
- <productname>PostgreSQL</productname> implements the
- <firstterm>SQL/JSON data model</firstterm>.
- 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
- <ulink url="https://tools.ietf.org/html/rfc7159">RFC 7159</ulink>.
- </para>
-
- <para>
- SQL/JSON allows you to handle JSON data alongside regular SQL data,
- with transaction support, including:
- </para>
-
- <itemizedlist>
- <listitem>
- <para>
- Uploading JSON data into the database and storing it in
- regular SQL columns as character or binary strings.
- </para>
- </listitem>
- <listitem>
- <para>
- Generating JSON objects and arrays from relational data.
- </para>
- </listitem>
- <listitem>
- <para>
- Querying JSON data using SQL/JSON query functions and
- SQL/JSON path language expressions.
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- There are two groups of SQL/JSON functions.
- <link linkend="functions-sqljson-producing">Constructor functions</link>
- generate JSON data from values of SQL types.
- <link linkend="functions-sqljson-querying">Query functions</link>
- evaluate SQL/JSON path language expressions against JSON values
- and produce values of SQL/JSON types, which are converted to SQL types.
- </para>
-
- <para>
- Many SQL/JSON functions have an optional <literal>FORMAT</literal>
- clause. This is provided to conform with the SQL standard, but has no
- effect except where noted otherwise.
- </para>
-
- <para>
- <xref linkend="functions-sqljson-producing" /> lists the SQL/JSON
- Constructor functions. Each function has a <literal>RETURNING</literal>
- clause specifying the data type returned. For the <function>json</function> and
- <function>json_scalar</function> functions, this needs to be either <type>json</type> or
- <type>jsonb</type>. For the other constructor functions it must be one of <type>json</type>,
- <type>jsonb</type>, <type>bytea</type>, a character string type (<type>text</type>, <type>char</type>,
- <type>varchar</type>, or <type>nchar</type>), or a type for which there is a cast
- from <type>json</type> to that type.
- By default, the <type>json</type> type is returned.
- </para>
-
- <note>
- <para>
- Many of the results that can be obtained from the SQL/JSON Constructor
- functions can also be obtained by calling
- <productname>PostgreSQL</productname>-specific functions detailed in
- <xref linkend="functions-json-creation-table" /> and
- <xref linkend="functions-aggregate-table"/>.
- </para>
- </note>
-
- <table id="functions-sqljson-producing">
- <title>SQL/JSON Constructor Functions</title>
- <tgroup cols="1">
- <thead>
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- Function signature
- </para>
- <para>
- Description
- </para>
- <para>
- Example(s)
- </para></entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm><primary>json constructor</primary></indexterm>
- <function>json</function> (
- <parameter>expression</parameter>
- <optional> <literal>FORMAT JSON</literal> <optional> <literal>ENCODING UTF8</literal> </optional></optional>
- <optional> { <literal>WITH</literal> | <literal>WITHOUT</literal> } <literal>UNIQUE</literal> <optional> <literal>KEYS</literal> </optional></optional>
- <optional> <literal>RETURNING</literal> <replaceable>json_data_type</replaceable> </optional>)
- </para>
- <para>
- The <parameter>expression</parameter> can be any text type or a
- <type>bytea</type> in UTF8 encoding. If the
- <parameter>expression</parameter> is NULL, an
- <acronym>SQL</acronym> null value is returned.
- If <literal>WITH UNIQUE</literal> is specified, the
- <parameter>expression</parameter> must not contain any duplicate
- object keys.
- </para>
- <para>
- <literal>json('{"a":123, "b":[true,"foo"], "a":"bar"}')</literal>
- <returnvalue>{"a":123, "b":[true,"foo"], "a":"bar"}</returnvalue>
- </para>
- <para>
- <literal>json('{"a":123,"b":[true,"foo"],"a":"bar"}' returning jsonb)</literal>
- <returnvalue>{"a": "bar", "b": [true, "foo"]}</returnvalue>
- </para></entry>
- </row>
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm><primary>json_scalar</primary></indexterm>
- <function>json_scalar</function> (<parameter>expression</parameter>
- <optional> <literal>RETURNING</literal> <replaceable>json_data_type</replaceable> </optional>)
- </para>
- <para>
- Returns a JSON scalar value representing
- <parameter>expression</parameter>.
- 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.
- </para>
- <para>
- <literal>json_scalar(123.45)</literal>
- <returnvalue>123.45</returnvalue>
- </para>
- <para>
- <literal>json_scalar(CURRENT_TIMESTAMP)</literal>
- <returnvalue>"2022-05-10T10:51:04.62128-04:00"</returnvalue>
- </para></entry>
- </row>
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm><primary>json_object</primary></indexterm>
- <function>json_object</function> (
- <optional> { <parameter>key_expression</parameter> { <literal>VALUE</literal> | ':' }
- <parameter>value_expression</parameter> <optional> <literal>FORMAT JSON</literal> <optional> <literal>ENCODING UTF8</literal> </optional> </optional> }<optional>, ...</optional> </optional>
- <optional> { <literal>NULL</literal> | <literal>ABSENT</literal> } <literal>ON NULL</literal> </optional>
- <optional> { <literal>WITH</literal> | <literal>WITHOUT</literal> } <literal>UNIQUE</literal> <optional> <literal>KEYS</literal> </optional> </optional>
- <optional> <literal>RETURNING</literal> <replaceable>data_type</replaceable> <optional> <literal>FORMAT JSON</literal> <optional> <literal>ENCODING UTF8</literal> </optional> </optional> </optional>)
- </para>
- <para>
- Constructs a JSON object of all the key value pairs given,
- or an empty object if none are given.
- <parameter>key_expression</parameter> is a scalar expression
- defining the <acronym>JSON</acronym> key, which is
- converted to the <type>text</type> type.
- It cannot be <literal>NULL</literal> nor can it
- belong to a type that has a cast to the <type>json</type>.
- If <literal>WITH UNIQUE</literal> is specified, there must not
- be any duplicate <parameter>key_expression</parameter>.
- If <literal>ABSENT ON NULL</literal> is specified, the entire
- pair is omitted if the <parameter>value_expression</parameter>
- is <literal>NULL</literal>.
- </para>
- <para>
- <literal>json_object('code' VALUE 'P123', 'title': 'Jaws')</literal>
- <returnvalue>{"code" : "P123", "title" : "Jaws"}</returnvalue>
- </para></entry>
- </row>
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm><primary>json_objectagg</primary></indexterm>
- <function>json_objectagg</function> (
- <optional> { <parameter>key_expression</parameter> { <literal>VALUE</literal> | ':' } <parameter>value_expression</parameter> } </optional>
- <optional> { <literal>NULL</literal> | <literal>ABSENT</literal> } <literal>ON NULL</literal> </optional>
- <optional> { <literal>WITH</literal> | <literal>WITHOUT</literal> } <literal>UNIQUE</literal> <optional> <literal>KEYS</literal> </optional> </optional>
- <optional> <literal>RETURNING</literal> <replaceable>data_type</replaceable> <optional> <literal>FORMAT JSON</literal> <optional> <literal>ENCODING UTF8</literal> </optional> </optional> </optional>)
- </para>
- <para>
- Behaves like <function>json_object</function> above, but as an
- aggregate function, so it only takes one
- <parameter>key_expression</parameter> and one
- <parameter>value_expression</parameter> parameter.
- </para>
- <para>
- <literal>SELECT json_objectagg(k:v) FROM (VALUES ('a'::text,current_date),('b',current_date + 1)) AS t(k,v)</literal>
- <returnvalue>{ "a" : "2022-05-10", "b" : "2022-05-11" }</returnvalue>
- </para></entry>
- </row>
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm><primary>json_array</primary></indexterm>
- <function>json_array</function> (
- <optional> { <parameter>value_expression</parameter> <optional> <literal>FORMAT JSON</literal> </optional> } <optional>, ...</optional> </optional>
- <optional> { <literal>NULL</literal> | <literal>ABSENT</literal> } <literal>ON NULL</literal> </optional>
- <optional> <literal>RETURNING</literal> <replaceable>data_type</replaceable> <optional> <literal>FORMAT JSON</literal> <optional> <literal>ENCODING UTF8</literal> </optional> </optional> </optional>)
- </para>
- <para role="func_signature">
- <function>json_array</function> (
- <optional> <replaceable>query_expression</replaceable> </optional>
- <optional> <literal>RETURNING</literal> <replaceable>data_type</replaceable> <optional> <literal>FORMAT JSON</literal> <optional> <literal>ENCODING UTF8</literal> </optional> </optional> </optional>)
- </para>
- <para>
- Constructs a JSON array from either a series of
- <parameter>value_expression</parameter> parameters or from the results
- of <replaceable>query_expression</replaceable>,
- which must be a SELECT query returning a single column. If
- <literal>ABSENT ON NULL</literal> is specified, NULL values are ignored.
- This is always the case if a
- <replaceable>query_expression</replaceable> is used.
- </para>
- <para>
- <literal>json_array(1,true,json '{"a":null}')</literal>
- <returnvalue>[1, true, {"a":null}]</returnvalue>
- </para>
- <para>
- <literal>json_array(SELECT * FROM (VALUES(1),(2)) t)</literal>
- <returnvalue>[1, 2]</returnvalue>
- </para></entry>
- </row>
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm><primary>json_arrayagg</primary></indexterm>
- <function>json_arrayagg</function> (
- <optional> <parameter>value_expression</parameter> </optional>
- <optional> <literal>ORDER BY</literal> <replaceable>sort_expression</replaceable> </optional>
- <optional> { <literal>NULL</literal> | <literal>ABSENT</literal> } <literal>ON NULL</literal> </optional>
- <optional> <literal>RETURNING</literal> <replaceable>data_type</replaceable> <optional> <literal>FORMAT JSON</literal> <optional> <literal>ENCODING UTF8</literal> </optional> </optional> </optional>)
- </para>
- <para>
- Behaves in the same way as <function>json_array</function>
- but as an aggregate function so it only takes one
- <parameter>value_expression</parameter> parameter.
- If <literal>ABSENT ON NULL</literal> is specified, any NULL
- values are omitted.
- If <literal>ORDER BY</literal> is specified, the elements will
- appear in the array in that order rather than in the input order.
- </para>
- <para>
- <literal>SELECT json_arrayagg(v) FROM (VALUES(2),(1)) t(v)</literal>
- <returnvalue>[2, 1]</returnvalue>
- </para></entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <para>
- <xref linkend="functions-sqljson-misc" /> details SQL/JSON
- facilities for testing and serializing JSON.
- </para>
-
- <table id="functions-sqljson-misc">
- <title>SQL/JSON Testing and Serializing Functions</title>
- <tgroup cols="1">
- <thead>
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- Function signature
- </para>
- <para>
- Description
- </para>
- <para>
- Example(s)
- </para></entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm><primary>IS JSON</primary></indexterm>
- <parameter>expression</parameter> <literal>IS</literal> <optional> <literal>NOT</literal> </optional> <literal>JSON</literal>
- <optional> { <literal>VALUE</literal> | <literal>SCALAR</literal> | <literal>ARRAY</literal> | <literal>OBJECT</literal> } </optional>
- <optional> { <literal>WITH</literal> | <literal>WITHOUT</literal> } <literal>UNIQUE</literal> <optional> <literal>KEYS</literal> </optional> </optional>
- </para>
- <para>
- This predicate tests whether <parameter>expression</parameter> can be
- parsed as JSON, possibly of a specified type.
- If <literal>SCALAR</literal> or <literal>ARRAY</literal> or
- <literal>OBJECT</literal> is specified, the
- test is whether or not the JSON is of that particular type. If
- <literal>WITH UNIQUE</literal> is specified, then an any object in the
- <parameter>expression</parameter> is also tested to see if it
- has duplicate keys.
- </para>
- <para>
-<screen>
-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
-</screen>
- </para></entry>
- </row>
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <function>json_serialize</function> (
- <parameter>expression</parameter> <optional> <literal>FORMAT JSON</literal> <optional> <literal>ENCODING UTF8</literal> </optional> </optional>
- <optional> <literal>RETURNING</literal> <parameter>data_type</parameter> <optional> <literal>FORMAT JSON</literal> <optional> <literal>ENCODING UTF8</literal> </optional> </optional> </optional>)
- </para>
- <para>
- Transforms an SQL/JSON value into a character or binary string. The
- <parameter>expression</parameter> can be of any JSON type, any
- character string type, or <type>bytea</type> in UTF8 encoding.
- The returned type can be any character string type or
- <type>bytea</type>. The default is <type>text</type>.
- </para>
- <para>
- <literal>json_serialize('{ "a" : 1 } ' RETURNING bytea)</literal>
- <returnvalue>\x7b20226122203a2031207d20</returnvalue>
- </para></entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <para>
- <xref linkend="functions-sqljson-querying"/> details the SQL/JSON
- functions that can be used to query JSON data, except
- for <function>json_table</function>.
- </para>
-
- <note>
- <para>
- SQL/JSON paths can only be applied to the <type>jsonb</type> type, so it
- might be necessary to cast the <parameter>context_item</parameter>
- argument of these functions to <type>jsonb</type>.
- </para>
- </note>
-
- <table id="functions-sqljson-querying">
- <title>SQL/JSON Query Functions</title>
- <tgroup cols="1">
- <thead>
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- Function signature
- </para>
- <para>
- Description
- </para>
- <para>
- Example(s)
- </para></entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm><primary>json_exists</primary></indexterm>
- <function>json_exists</function> (
- <parameter>context_item</parameter>, <parameter>path_expression</parameter> <optional> <literal>PASSING</literal> { <parameter>value</parameter> <literal>AS</literal> <replaceable>varname</replaceable> } <optional>, ...</optional></optional>
- <optional> <literal>RETURNING</literal> <replaceable>data_type</replaceable> </optional>
- <optional> { <literal>TRUE</literal> | <literal>FALSE</literal> |<literal> UNKNOWN</literal> | <literal>ERROR</literal> } <literal>ON ERROR</literal> </optional>)
- </para>
- <para>
- Returns true if the SQL/JSON <parameter>path_expression</parameter>
- applied to the <parameter>context_item</parameter> using the
- <parameter>value</parameter>s yields any items.
- The <literal>ON ERROR</literal> clause specifies what is returned if
- an error occurs. Note that if the <parameter>path_expression</parameter>
- is <literal>strict</literal>, an error is generated if it yields no items.
- The default value is <literal>UNKNOWN</literal> which causes a NULL
- result.
- </para>
- <para>
- <literal>json_exists(jsonb '{"key1": [1,2,3]}', 'strict $.key1[*] ? (@ > 2)')</literal>
- <returnvalue>t</returnvalue>
- </para>
- <para>
- <literal>json_exists(jsonb '{"a": [1,2,3]}', 'lax $.a[5]' ERROR ON ERROR)</literal>
- <returnvalue>f</returnvalue>
- </para>
- <para>
- <literal>json_exists(jsonb '{"a": [1,2,3]}', 'strict $.a[5]' ERROR ON ERROR)</literal>
- <returnvalue>ERROR: jsonpath array subscript is out of bounds</returnvalue>
- </para></entry>
- </row>
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm><primary>json_value</primary></indexterm>
- <function>json_value</function> (
- <parameter>context_item</parameter>, <parameter>path_expression</parameter>
- <optional> <literal>PASSING</literal> { <parameter>value</parameter> <literal>AS</literal> <parameter>varname</parameter> } <optional>, ...</optional></optional>
- <optional> <literal>RETURNING</literal> <parameter>data_type</parameter> </optional>
- <optional> { <literal>ERROR</literal> | <literal>NULL</literal> | <literal>DEFAULT</literal> <parameter>expression</parameter> } <literal>ON EMPTY</literal> </optional>
- <optional> { <literal>ERROR</literal> | <literal>NULL</literal> | <literal>DEFAULT</literal> <parameter>expression</parameter> } <literal>ON ERROR</literal> </optional>)
- </para>
- <para>
- Returns the result of applying the
- <parameter>path_expression</parameter> to the
- <parameter>context_item</parameter> using the
- <parameter>value</parameter>s. The extracted value must be
- a single <acronym>SQL/JSON</acronym> scalar item. For results that
- are objects or arrays, use the <function>json_query</function>
- instead.
- The returned <parameter>data_type</parameter> has the same semantics
- as for constructor functions like <function>json_objectagg</function>.
- The default returned type is <type>text</type>.
- The <literal>ON EMPTY</literal> clause specifies the behavior if the
- <parameter>path_expression</parameter> yields no value at all.
- The <literal>ON ERROR</literal> clause specifies the behavior if an
- error occurs, as a result of either the evaluation or the application
- of the <literal>ON EMPTY</literal> clause.
- </para>
- <para>
- <literal>json_value(jsonb '"123.45"', '$' RETURNING float)</literal>
- <returnvalue>123.45</returnvalue>
- </para>
- <para>
- <literal>json_value(jsonb '"03:04 2015-02-01"', '$.datetime("HH24:MI YYYY-MM-DD")' RETURNING date)</literal>
- <returnvalue>2015-02-01</returnvalue>
- </para>
- <para>
- <literal>json_value(jsonb '[1,2]', 'strict $[*]' DEFAULT 9 ON ERROR)</literal>
- <returnvalue>9</returnvalue>
- </para></entry>
- </row>
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm><primary>json_query</primary></indexterm>
- <function>json_query</function> (
- <parameter>context_item</parameter>, <parameter>path_expression</parameter> <optional> <literal>PASSING</literal> { <parameter>value</parameter> <literal>AS</literal> <parameter>varname</parameter> } <optional>, ...</optional></optional>
- <optional> <literal>RETURNING</literal> <parameter>data_type</parameter> <optional> <literal>FORMAT JSON</literal> <optional> <literal>ENCODING UTF8</literal> </optional> </optional> </optional>
- <optional> { <literal>WITHOUT</literal> | <literal>WITH</literal> { <literal>CONDITIONAL</literal> | <optional><literal>UNCONDITIONAL</literal></optional> } } <optional> <literal>ARRAY</literal> </optional> <literal>WRAPPER</literal> </optional>
- <optional> { <literal>KEEP</literal> | <literal>OMIT</literal> } <literal>QUOTES</literal> <optional> <literal>ON SCALAR STRING</literal> </optional> </optional>
- <optional> { <literal>ERROR</literal> | <literal>NULL</literal> | <literal>EMPTY</literal> { <optional> <literal>ARRAY</literal> </optional> | <literal>OBJECT</literal> } | <literal>DEFAULT</literal> <parameter>expression</parameter> } <literal>ON EMPTY</literal> </optional>
- <optional> { <literal>ERROR</literal> | <literal>NULL</literal> | <literal>EMPTY</literal> { <optional> <literal>ARRAY</literal> </optional> | <literal>OBJECT</literal> } | <literal>DEFAULT</literal> <parameter>expression</parameter> } <literal>ON ERROR</literal> </optional>)
- </para>
- <para>
- Returns the result of applying the
- <parameter>path_expression</parameter> to the
- <parameter>context_item</parameter> using the
- <parameter>value</parameter>s.
- This function must return a JSON string, so if the path expression
- returns multiple SQL/JSON items, you must wrap the result using the
- <literal>WITH WRAPPER</literal> clause. If the wrapper is
- <literal>UNCONDITIONAL</literal>, an array wrapper will always
- be applied, even if the returned value is already a single JSON object
- or array, but if it is <literal>CONDITIONAL</literal> it will not be
- applied to a single array or object. <literal>UNCONDITIONAL</literal>
- 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 <literal>OMIT QUOTES</literal> is specified.
- The <literal>ON ERROR</literal> and <literal>ON EMPTY</literal>
- clauses have similar semantics to those clauses for
- <function>json_value</function>.
- The returned <parameter>data_type</parameter> has the same semantics
- as for constructor functions like <function>json_objectagg</function>.
- The default returned type is <type>text</type>.
- </para>
- <para>
- <literal>json_query(jsonb '[1,[2,3],null]', 'lax $[*][1]' WITH CONDITIONAL WRAPPER)</literal>
- <returnvalue>[3]</returnvalue>
- </para></entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- </sect2>
-
- <sect2 id="functions-sqljson-table">
- <title>JSON_TABLE</title>
- <indexterm>
- <primary>json_table</primary>
- </indexterm>
-
- <para>
- <function>json_table</function> is an SQL/JSON function which
- queries <acronym>JSON</acronym> data
- and presents the results as a relational view, which can be accessed as a
- regular SQL table. You can only use <function>json_table</function> inside the
- <literal>FROM</literal> clause of a <literal>SELECT</literal> statement.
- </para>
-
- <para>
- Taking JSON data as input, <function>json_table</function> uses
- a path expression to extract a part of the provided data that
- will be used as a <firstterm>row pattern</firstterm> 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.
- </para>
-
- <para>
- To split the row pattern into columns, <function>json_table</function>
- provides the <literal>COLUMNS</literal> 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 <literal>NESTED PATH</literal> subclause. Joining the
- columns returned by <literal>NESTED PATH</literal> can add multiple
- new rows to the constructed view. Such rows are called
- <firstterm>child rows</firstterm>, as opposed to the <firstterm>parent row</firstterm>
- that generates them.
- </para>
-
- <para>
- The rows produced by <function>JSON_TABLE</function> 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 <acronym>JSON</acronym>
- data. Optionally, you can specify how to join the columns returned
- by <literal>NESTED PATH</literal> using the <literal>PLAN</literal> clause.
- </para>
-
- <para>
- Each <literal>NESTED PATH</literal> clause can generate one or more
- columns. Columns produced by <literal>NESTED PATH</literal>s at the
- same level are considered to be <firstterm>siblings</firstterm>,
- while a column produced by a <literal>NESTED PATH</literal> is
- considered to be a child of the column produced by and
- <literal>NESTED PATH</literal> 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.
- </para>
-
- <variablelist>
- <varlistentry>
- <term>
- <literal><parameter>context_item</parameter>, <parameter>path_expression</parameter> <optional> <literal>AS</literal> <parameter>json_path_name</parameter> </optional> <optional> <literal>PASSING</literal> { <parameter>value</parameter> <literal>AS</literal> <parameter>varname</parameter> } <optional>, ...</optional></optional></literal>
- </term>
- <listitem>
- <para>
- The input data to query, the JSON path expression defining the query,
- and an optional <literal>PASSING</literal> clause, which can provide data
- values to the <parameter>path_expression</parameter>.
- The result of the input data
- evaluation is called the <firstterm>row pattern</firstterm>. The row
- pattern is used as the source for row values in the constructed view.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- <literal>COLUMNS</literal>( <parameter>json_table_column</parameter> <optional>, ...</optional> )
- </term>
- <listitem>
-
- <para>
- The <literal>COLUMNS</literal> 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 <parameter>json_table_column</parameter>
- expression has the following syntax variants:
- </para>
-
- <variablelist>
- <varlistentry>
- <term>
- <literal><parameter>name</parameter> <parameter>type</parameter>
- <optional> <literal>PATH</literal> <parameter>json_path_specification</parameter> </optional></literal>
- </term>
- <listitem>
-
- <para>
- Inserts a single SQL/JSON item into each row of
- the specified column.
- </para>
- <para>
- The provided <literal>PATH</literal> expression parses the
- row pattern defined by <parameter>json_api_common_syntax</parameter>
- and fills the column with produced SQL/JSON items, one for each row.
- If the <literal>PATH</literal> expression is omitted,
- <function>JSON_TABLE</function> uses the
- <literal>$.<replaceable>name</replaceable></literal> path expression,
- where <replaceable>name</replaceable> 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.
- </para>
- <para>
- Optionally, you can add <literal>ON EMPTY</literal> and
- <literal>ON ERROR</literal> clauses to define how to handle missing values
- or structural errors.
- <literal>WRAPPER</literal> and <literal>QUOTES</literal> clauses can only
- be used with JSON, array, and composite types.
- These clauses have the same syntax and semantics as for
- <function>json_value</function> and <function>json_query</function>.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- <parameter>name</parameter> <parameter>type</parameter> <literal>FORMAT</literal> <parameter>json_representation</parameter>
- <optional> <literal>PATH</literal> <parameter>json_path_specification</parameter> </optional>
- </term>
- <listitem>
-
- <para>
- Generates a column and inserts a composite SQL/JSON
- item into each row of this column.
- </para>
- <para>
- The provided <literal>PATH</literal> expression parses the
- row pattern defined by <parameter>json_api_common_syntax</parameter>
- and fills the column with produced SQL/JSON items, one for each row.
- If the <literal>PATH</literal> expression is omitted,
- <function>JSON_TABLE</function> uses the
- <literal>$.<parameter>name</parameter></literal> path expression,
- where <parameter>name</parameter> 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.
- </para>
- <para>
- Optionally, you can add <literal>WRAPPER</literal>, <literal>QUOTES</literal>,
- <literal>ON EMPTY</literal> and <literal>ON ERROR</literal> clauses
- to define additional settings for the returned SQL/JSON items.
- These clauses have the same syntax and semantics as
- for <function>json_query</function>.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- <parameter>name</parameter> <parameter>type</parameter>
- <literal>EXISTS</literal> <optional> <literal>PATH</literal> <parameter>json_path_specification</parameter> </optional>
- </term>
- <listitem>
-
- <para>
- Generates a column and inserts a boolean item into each row of this column.
- </para>
- <para>
- The provided <literal>PATH</literal> expression parses the
- row pattern defined by <parameter>json_api_common_syntax</parameter>,
- checks whether any SQL/JSON items were returned, and fills the column with
- resulting boolean value, one for each row.
- The specified <parameter>type</parameter> should have cast from
- <type>boolean</type>.
- If the <literal>PATH</literal> expression is omitted,
- <function>JSON_TABLE</function> uses the
- <literal>$.<replaceable>name</replaceable></literal> path expression,
- where <replaceable>name</replaceable> is the provided column name.
- </para>
- <para>
- Optionally, you can add <literal>ON ERROR</literal> clause to define
- error behavior. This clause has the same syntax and semantics as
- for <function>json_exists</function>.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- <literal>NESTED PATH</literal> <parameter>json_path_specification</parameter> <optional> <literal>AS</literal> <parameter>json_path_name</parameter> </optional>
- <literal>COLUMNS</literal> ( <parameter>json_table_column</parameter> <optional>, ...</optional> )
- </term>
- <listitem>
-
- <para>
- Extracts SQL/JSON items from nested levels of the row pattern,
- generates one or more columns as defined by the <literal>COLUMNS</literal>
- subclause, and inserts the extracted SQL/JSON items into each row of these columns.
- The <parameter>json_table_column</parameter> expression in the
- <literal>COLUMNS</literal> subclause uses the same syntax as in the
- parent <literal>COLUMNS</literal> clause.
- </para>
-
- <para>
- The <literal>NESTED PATH</literal> syntax is recursive,
- so you can go down multiple nested levels by specifying several
- <literal>NESTED PATH</literal> subclauses within each other.
- It allows to unnest the hierarchy of JSON objects and arrays
- in a single function invocation rather than chaining several
- <function>JSON_TABLE</function> expressions in an SQL statement.
- </para>
-
- <para>
- You can use the <literal>PLAN</literal> clause to define how
- to join the columns returned by <parameter>NESTED PATH</parameter> clauses.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- <parameter>name</parameter> <literal>FOR ORDINALITY</literal>
- </term>
- <listitem>
-
- <para>
- 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 <literal>NESTED PATH</literal>
- clauses, the parent row number is repeated.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
-
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- <literal>AS</literal> <parameter>json_path_name</parameter>
- </term>
- <listitem>
-
- <para>
- The optional <parameter>json_path_name</parameter> serves as an
- identifier of the provided <parameter>json_path_specification</parameter>.
- The path name must be unique and distinct from the column names.
- When using the <literal>PLAN</literal> clause, you must specify the names
- for all the paths, including the row pattern. Each path name can appear in
- the <literal>PLAN</literal> clause only once.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- <literal>PLAN</literal> ( <parameter>json_table_plan</parameter> )
- </term>
- <listitem>
-
- <para>
- Defines how to join the data returned by <literal>NESTED PATH</literal>
- clauses to the constructed view.
- </para>
- <para>
- To join columns with parent/child relationship, you can use:
- </para>
- <variablelist>
- <varlistentry>
- <term>
- <literal>INNER</literal>
- </term>
- <listitem>
-
- <para>
- Use <literal>INNER JOIN</literal>, so that the parent row
- is omitted from the output if it does not have any child rows
- after joining the data returned by <literal>NESTED PATH</literal>.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- <literal>OUTER</literal>
- </term>
- <listitem>
-
- <para>
- Use <literal>LEFT OUTER JOIN</literal>, 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 <literal>NESTED PATH</literal>, with NULL values
- inserted into the child columns if the corresponding
- values are missing.
- </para>
- <para>
- This is the default option for joining columns with parent/child relationship.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
-
- <para>
- To join sibling columns, you can use:
- </para>
-
- <variablelist>
- <varlistentry>
- <term>
- <literal>UNION</literal>
- </term>
- <listitem>
-
- <para>
- Generate one row for each value produced by each of the sibling
- columns. The columns from the other siblings are set to null.
- </para>
- <para>
- This is the default option for joining sibling columns.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- <literal>CROSS</literal>
- </term>
- <listitem>
-
- <para>
- Generate one row for each combination of values from the sibling columns.
- </para>
- </listitem>
- </varlistentry>
-
- </variablelist>
-
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- <literal>PLAN DEFAULT</literal> ( <replaceable>OUTER | INNER</replaceable> <optional>, <replaceable>UNION | CROSS</replaceable> </optional> )
- </term>
- <listitem>
- <para>
- The terms can also be specified in reverse order. The
- <literal>INNER</literal> or <literal>OUTER</literal> option defines the
- joining plan for parent/child columns, while <literal>UNION</literal> or
- <literal>CROSS</literal> affects joins of sibling columns. This form
- of <literal>PLAN</literal> overrides the default plan for
- all columns at once. Even though the path names are not included in the
- <literal>PLAN DEFAULT</literal> form, to conform to the SQL/JSON standard
- they must be provided for all the paths if the <literal>PLAN</literal>
- clause is used.
- </para>
- <para>
- <literal>PLAN DEFAULT</literal> is simpler than specifying a complete
- <literal>PLAN</literal>, and is often all that is required to get the desired
- output.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
-
- <para>Examples</para>
-
- <para>
- In these examples the following small table storing some JSON data will be used:
-<programlisting>
-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" } ] }
- ] }');
-</programlisting>
- </para>
- <para>
- Query the <structname>my_films</structname> table holding
- some JSON data about the films and create a view that
- distributes the film genre, title, and director between separate columns:
-<screen>
-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)
-</screen>
- </para>
-
- <para>
- Find a director that has done films in two different genres:
-<screen>
-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)
-</screen>
- </para>
- </sect2>
-
+ </sect2>
</sect1>
<sect1 id="functions-sequence">
<entry>No</entry>
</row>
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm>
- <primary>json_agg_strict</primary>
- </indexterm>
- <function>json_agg_strict</function> ( <type>anyelement</type> )
- <returnvalue>json</returnvalue>
- </para>
- <para role="func_signature">
- <indexterm>
- <primary>jsonb_agg_strict</primary>
- </indexterm>
- <function>jsonb_agg_strict</function> ( <type>anyelement</type> )
- <returnvalue>jsonb</returnvalue>
- </para>
- <para>
- Collects all the input values, skipping nulls, into a JSON array.
- Values are converted to JSON as per <function>to_json</function>
- or <function>to_jsonb</function>.
- </para></entry>
- <entry>No</entry>
- </row>
-
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
</para>
<para>
Collects all the key/value pairs into a JSON object. Key arguments
- are coerced to text; value arguments are converted as per
- <function>to_json</function> or <function>to_jsonb</function>
- Values can be null, but keys cannot.
- </para></entry>
- <entry>No</entry>
- </row>
-
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm>
- <primary>json_object_agg_strict</primary>
- </indexterm>
- <function>json_object_agg_strict</function> (
- <parameter>key</parameter> <type>"any"</type>,
- <parameter>value</parameter> <type>"any"</type> )
- <returnvalue>json</returnvalue>
- </para>
- <para role="func_signature">
- <indexterm>
- <primary>jsonb_object_agg_strict</primary>
- </indexterm>
- <function>jsonb_object_agg_strict</function> (
- <parameter>key</parameter> <type>"any"</type>,
- <parameter>value</parameter> <type>"any"</type> )
- <returnvalue>jsonb</returnvalue>
- </para>
- <para>
- Collects all the key/value pairs into a JSON object. Key arguments
- are coerced to text; value arguments are converted as per
- <function>to_json</function> or <function>to_jsonb</function>.
- The <parameter>key</parameter> can not be null. If the
- <parameter>value</parameter> is null then the entry is skipped,
- </para></entry>
- <entry>No</entry>
- </row>
-
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm>
- <primary>json_object_agg_unique</primary>
- </indexterm>
- <function>json_object_agg_unique</function> (
- <parameter>key</parameter> <type>"any"</type>,
- <parameter>value</parameter> <type>"any"</type> )
- <returnvalue>json</returnvalue>
- </para>
- <para role="func_signature">
- <indexterm>
- <primary>jsonb_object_agg_unique</primary>
- </indexterm>
- <function>jsonb_object_agg_unique</function> (
- <parameter>key</parameter> <type>"any"</type>,
- <parameter>value</parameter> <type>"any"</type> )
- <returnvalue>jsonb</returnvalue>
- </para>
- <para>
- Collects all the key/value pairs into a JSON object. Key arguments
- are coerced to text; value arguments are converted as per
- <function>to_json</function> or <function>to_jsonb</function>.
- Values can be null, but keys cannot.
- If there is a duplicate key an error is thrown.
- </para></entry>
- <entry>No</entry>
- </row>
-
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm>
- <primary>json_object_agg_unique_strict</primary>
- </indexterm>
- <function>json_object_agg_unique_strict</function> (
- <parameter>key</parameter> <type>"any"</type>,
- <parameter>value</parameter> <type>"any"</type> )
- <returnvalue>json</returnvalue>
- </para>
- <para role="func_signature">
- <indexterm>
- <primary>jsonb_object_agg_unique_strict</primary>
- </indexterm>
- <function>jsonb_object_agg_unique_strict</function> (
- <parameter>key</parameter> <type>"any"</type>,
- <parameter>value</parameter> <type>"any"</type> )
- <returnvalue>jsonb</returnvalue>
- </para>
- <para>
- Collects all the key/value pairs into a JSON object. Key arguments
- are coerced to text; value arguments are converted as per
- <function>to_json</function> or <function>to_jsonb</function>.
- The <parameter>key</parameter> can not be null. If the
- <parameter>value</parameter> 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 <function>to_json</function> or <function>to_jsonb</function>.
+ Values can be null, but not keys.
</para></entry>
<entry>No</entry>
</row>
<para>
The aggregate functions <function>array_agg</function>,
<function>json_agg</function>, <function>jsonb_agg</function>,
- <function>json_agg_strict</function>, <function>jsonb_agg_strict</function>,
<function>json_object_agg</function>, <function>jsonb_object_agg</function>,
- <function>json_object_agg_strict</function>, <function>jsonb_object_agg_strict</function>,
- <function>json_object_agg_unique</function>, <function>jsonb_object_agg_unique</function>,
- <function>json_object_agg_unique_strict</function>,
- <function>jsonb_object_agg_unique_strict</function>,
<function>string_agg</function>,
and <function>xmlagg</function>, as well as similar user-defined
aggregate functions, produce meaningfully different result values
subquery's output to be reordered before the aggregate is computed.
</para>
- <note>
- <para>
- In addition to the JSON aggregates shown here, see the <function>json_objectagg</function>
- and <function>json_arrayagg</function> constructors in <xref linkend="functions-sqljson"/>.
- </para>
- </note>
-
<note>
<indexterm>
<primary>ANY</primary>
INTO
IS
JOIN
-JSON
JSON_ARRAY
JSON_ARRAYAGG
JSON_EXISTS
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
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
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:
#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"
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
*
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;
}
/*
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;
}
/*
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));
#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"
&&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,
{
/* 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();
}
}
}
-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
*
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;
-}
#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"
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,
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.
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;
ExecEvalSysVar,
ExecEvalWholeRowVar,
ExecEvalXmlExpr,
- ExecEvalJsonConstructor,
- ExecEvalJsonIsPredicate,
- ExecEvalJson,
MakeExpandedObjectReadOnlyInternal,
slot_getmissingattrs,
slot_getsomeattrs_int,
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
-#include "utils/errcodes.h"
#include "utils/lsyscache.h"
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;
-}
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 */
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;
}
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 */
/* 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;
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;
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:
case T_RangeTblRef:
case T_SortGroupClause:
case T_CTESearchClause:
- case T_JsonFormat:
return (Node *) copyObject(node);
case T_WithCheckOption:
{
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;
case T_ParamRef:
case T_A_Const:
case T_A_Star:
- case T_JsonFormat:
/* primitive node types with no subnodes */
break;
case T_Alias:
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));
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;
#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"
#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"
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 */
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,
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;
}
parse_enr.o \
parse_expr.o \
parse_func.o \
- parse_jsontable.o \
parse_merge.o \
parse_node.o \
parse_oper.o \
MergeWhenClause *mergewhen;
struct KeyActions *keyactions;
struct KeyAction *keyaction;
- JsonBehavior *jsbehavior;
- struct
- {
- JsonBehavior *on_empty;
- JsonBehavior *on_error;
- } on_behavior;
- JsonQuotes js_quotes;
}
%type <node> stmt toplevel_stmt schema_stmt routine_body_stmt
%type <list> copy_options
%type <typnam> Typename SimpleTypename ConstTypename
- GenericType Numeric opt_float JsonType
+ GenericType Numeric opt_float
Character ConstCharacter
CharacterWithLength CharacterWithoutLength
ConstDatetime ConstInterval
%type <defelt> hash_partbound_elem
-%type <node> 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 <list> 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 <str> json_table_path_name
- json_as_path_name_clause_opt
- json_table_column_path_specification_clause_opt
-
-%type <ival> 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 <jsbehavior> 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 <on_behavior> json_value_on_behavior_clause_opt
- json_query_on_behavior_clause_opt
-
-%type <js_quotes> json_quotes_behavior
- json_quotes_clause_opt
-
-%type <boolean> 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
*/
/* ordinary key words in alphabetical order */
-%token <keyword> ABORT_P ABSENT ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER
+%token <keyword> 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
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
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
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
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 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
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
* 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
/* Precedence: lowest to highest */
%nonassoc SET /* see relation_expr_opt_alias */
-%right FORMAT
%left UNION EXCEPT
%left INTERSECT
%left OR
* 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
%left Op OPERATOR /* multi-character ops and user-defined operators */
%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
*/
%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
-
%%
/*
$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;
- }
;
{ $$ = 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:
$$->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1),
makeIntConst($3, @3));
}
- | JsonType { $$ = $1; }
;
/* We have a separate ConstTypename to allow defaulting fixed-length
| ConstBit { $$ = $1; }
| ConstCharacter { $$ = $1; }
| ConstDatetime { $$ = $1; }
- | JsonType { $$ = $1; }
;
/*
opt_timezone:
WITH_LA TIME ZONE { $$ = true; }
- | WITHOUT_LA TIME ZONE { $$ = false; }
+ | WITHOUT TIME ZONE { $$ = false; }
| /*EMPTY*/ { $$ = false; }
;
}
;
-JsonType:
- JSON
- {
- $$ = SystemTypeName("json");
- $$->location = @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
{
/*
}
;
-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.
*
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; }
;
func_expr_windowless:
func_application { $$ = $1; }
| func_expr_common_subexpr { $$ = $1; }
- | json_aggregate_func { $$ = $1; }
;
/*
n->location = @1;
$$ = (Node *) n;
}
- | json_func_expr
- { $$ = $1; }
;
/*
| /*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; }
- ;
/*****************************************************************************
*
*/
unreserved_keyword:
ABORT_P
- | ABSENT
| ABSOLUTE_P
| ACCESS
| ACTION
| COMMIT
| COMMITTED
| COMPRESSION
- | CONDITIONAL
| CONFIGURATION
| CONFLICT
| CONNECTION
| DOUBLE_P
| DROP
| EACH
- | EMPTY_P
| ENABLE_P
| ENCODING
| ENCRYPTED
| ENUM_P
- | ERROR_P
| ESCAPE
| EVENT
| EXCLUDE
| FIRST_P
| FOLLOWING
| FORCE
- | FORMAT
| FORWARD
| FUNCTION
| FUNCTIONS
| INSTEAD
| INVOKER
| ISOLATION
- | KEEP
| KEY
- | KEYS
| LABEL
| LANGUAGE
| LARGE_P
| MOVE
| NAME_P
| NAMES
- | NESTED
| NEW
| NEXT
| NFC
| OFF
| OIDS
| OLD
- | OMIT
| OPERATOR
| OPTION
| OPTIONS
| PARTITION
| PASSING
| PASSWORD
- | PATH
- | PLAN
| PLANS
| POLICY
| PRECEDING
| PROGRAM
| PUBLICATION
| QUOTE
- | QUOTES
| RANGE
| READ
| REASSIGN
| ROWS
| RULE
| SAVEPOINT
- | SCALAR
| SCHEMA
| SCHEMAS
| SCROLL
| STORAGE
| STORED
| STRICT_P
- | STRING
| STRIP_P
| SUBSCRIPTION
| SUPPORT
| UESCAPE
| UNBOUNDED
| UNCOMMITTED
- | UNCONDITIONAL
| UNENCRYPTED
| UNKNOWN
| UNLISTEN
| 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
*/
bare_label_keyword:
ABORT_P
- | ABSENT
| ABSOLUTE_P
| ACCESS
| ACTION
| COMMITTED
| COMPRESSION
| CONCURRENTLY
- | CONDITIONAL
| CONFIGURATION
| CONFLICT
| CONNECTION
| DROP
| EACH
| ELSE
- | EMPTY_P
| ENABLE_P
| ENCODING
| ENCRYPTED
| END_P
| ENUM_P
- | ERROR_P
| ESCAPE
| EVENT
| EXCLUDE
| FOLLOWING
| FORCE
| FOREIGN
- | FORMAT
| FORWARD
| FREEZE
| FULL
| 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
| NATIONAL
| NATURAL
| NCHAR
- | NESTED
| NEW
| NEXT
| NFC
| OFF
| OIDS
| OLD
- | OMIT
| ONLY
| OPERATOR
| OPTION
| PARTITION
| PASSING
| PASSWORD
- | PATH
| PLACING
- | PLAN
| PLANS
| POLICY
| POSITION
| PROGRAM
| PUBLICATION
| QUOTE
- | QUOTES
| RANGE
| READ
| REAL
| ROWS
| RULE
| SAVEPOINT
- | SCALAR
| SCHEMA
| SCHEMAS
| SCROLL
| STORAGE
| STORED
| STRICT_P
- | STRING
| STRIP_P
| SUBSCRIPTION
| SUBSTRING
| UESCAPE
| UNBOUNDED
| UNCOMMITTED
- | UNCONDITIONAL
| UNENCRYPTED
| UNIQUE
| UNKNOWN
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;
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);
&loccontext);
}
break;
- case T_JsonExpr:
-
- /*
- * Context item and PASSING arguments are already
- * marked with collations in parse_expr.c.
- */
- break;
default:
/*
#include "postgres.h"
-#include "catalog/pg_aggregate.h"
-#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/dbcommands.h"
#include "miscadmin.h"
#include "parser/parse_type.h"
#include "utils/builtins.h"
#include "utils/date.h"
-#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/timestamp.h"
#include "utils/xml.h"
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,
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));
}
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);
-}
+++ /dev/null
-/*-------------------------------------------------------------------------
- *
- * 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);
- &