</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);
- }
- else
- elog(ERROR, "invalid JSON_TABLE join type %d",
- plan->join_type);
- }
-}
-
-/*
- * Validate child JSON_TABLE plan by checking that:
- * - all nested columns have path names specified
- * - all nested columns have corresponding node in the sibling plan
- * - plan does not contain duplicate or extra nodes
- */
-static void
-validateJsonTableChildPlan(ParseState *pstate, JsonTablePlan *plan,
- List *columns)
-{
- ListCell *lc1;
- List *siblings = NIL;
- int nchildren = 0;
-
- if (plan)
- collectSiblingPathsInJsonTablePlan(plan, &siblings);
-
- foreach(lc1, columns)
- {
- JsonTableColumn *jtc = castNode(JsonTableColumn, lfirst(lc1));
-
- if (jtc->coltype == JTC_NESTED)
- {
- ListCell *lc2;
- bool found = false;
-
- if (!jtc->pathname)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("nested JSON_TABLE columns must contain an explicit AS pathname specification if an explicit PLAN clause is used"),
- parser_errposition(pstate, jtc->location)));
-
- /* find nested path name in the list of sibling path names */
- foreach(lc2, siblings)
- {
- if ((found = !strcmp(jtc->pathname, lfirst(lc2))))
- break;
- }
-
- if (!found)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("invalid JSON_TABLE plan"),
- errdetail("Plan node for nested path %s was not found in plan.", jtc->pathname),
- parser_errposition(pstate, jtc->location)));
-
- nchildren++;
- }
- }
-
- if (list_length(siblings) > nchildren)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("invalid JSON_TABLE plan"),
- errdetail("Plan node contains some extra or duplicate sibling nodes."),
- parser_errposition(pstate, plan ? plan->location : -1)));
-}
-
-static JsonTableColumn *
-findNestedJsonTableColumn(List *columns, const char *pathname)
-{
- ListCell *lc;
-
- foreach(lc, columns)
- {
- JsonTableColumn *jtc = castNode(JsonTableColumn, lfirst(lc));
-
- if (jtc->coltype == JTC_NESTED &&
- jtc->pathname &&
- !strcmp(jtc->pathname, pathname))
- return jtc;
- }
-
- return NULL;
-}
-
-static Node *
-transformNestedJsonTableColumn(JsonTableContext *cxt, JsonTableColumn *jtc,
- JsonTablePlan *plan)
-{
- JsonTableParent *node;
- char *pathname = jtc->pathname;
-
- node = transformJsonTableColumns(cxt, plan, jtc->columns, jtc->pathspec,
- &pathname, jtc->location);
- node->name = pstrdup(pathname);
-
- return (Node *) node;
-}
-
-static Node *
-makeJsonTableSiblingJoin(bool cross, Node *lnode, Node *rnode)
-{
- JsonTableSibling *join = makeNode(JsonTableSibling);
-
- join->larg = lnode;
- join->rarg = rnode;
- join->cross = cross;
-
- return (Node *) join;
-}
-
-/*
- * Recursively transform child JSON_TABLE plan.
- *
- * Default plan is transformed into a cross/union join of its nested columns.
- * Simple and outer/inner plans are transformed into a JsonTableParent by
- * finding and transforming corresponding nested column.
- * Sibling plans are recursively transformed into a JsonTableSibling.
- */
-static Node *
-transformJsonTableChildPlan(JsonTableContext *cxt, JsonTablePlan *plan,
- List *columns)
-{
- JsonTableColumn *jtc = NULL;
-
- if (!plan || plan->plan_type == JSTP_DEFAULT)
- {
- /* unspecified or default plan */
- Node *res = NULL;
- ListCell *lc;
- bool cross = plan && (plan->join_type & JSTPJ_CROSS);
-
- /* transform all nested columns into cross/union join */
- foreach(lc, columns)
- {
- JsonTableColumn *col = castNode(JsonTableColumn, lfirst(lc));
- Node *node;
-
- if (col->coltype != JTC_NESTED)
- continue;
-
- node = transformNestedJsonTableColumn(cxt, col, plan);
-
- /* join transformed node with previous sibling nodes */
- res = res ? makeJsonTableSiblingJoin(cross, res, node) : node;
- }
-
- return res;
- }
- else if (plan->plan_type == JSTP_SIMPLE)
- {
- jtc = findNestedJsonTableColumn(columns, plan->pathname);
- }
- else if (plan->plan_type == JSTP_JOINED)
- {
- if (plan->join_type == JSTPJ_INNER ||
- plan->join_type == JSTPJ_OUTER)
- {
- Assert(plan->plan1->plan_type == JSTP_SIMPLE);
- jtc = findNestedJsonTableColumn(columns, plan->plan1->pathname);
- }
- else
- {
- Node *node1 = transformJsonTableChildPlan(cxt, plan->plan1,
- columns);
- Node *node2 = transformJsonTableChildPlan(cxt, plan->plan2,
- columns);
-
- return makeJsonTableSiblingJoin(plan->join_type == JSTPJ_CROSS,
- node1, node2);
- }
- }
- else
- elog(ERROR, "invalid JSON_TABLE plan type %d", plan->plan_type);
-
- if (!jtc)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("invalid JSON_TABLE plan"),
- errdetail("Path name was %s not found in nested columns list.",
- plan->pathname),
- parser_errposition(cxt->pstate, plan->location)));
-
- return transformNestedJsonTableColumn(cxt, jtc, plan);
-}
-
-/* Check whether type is json/jsonb, array, or record. */
-static bool
-typeIsComposite(Oid typid)
-{
- char typtype;
-
- if (typid == JSONOID ||
- typid == JSONBOID ||
- typid == RECORDOID ||
- type_is_array(typid))
- return true;
-
- typtype = get_typtype(typid);
-
- if (typtype == TYPTYPE_COMPOSITE)
- return true;
-
- if (typtype == TYPTYPE_DOMAIN)
- return typeIsComposite(getBaseType(typid));
-
- return false;
-}
-
-/* Append transformed non-nested JSON_TABLE columns to the TableFunc node */
-static void
-appendJsonTableColumns(JsonTableContext *cxt, List *columns)
-{
- ListCell *col;
- ParseState *pstate = cxt->pstate;
- JsonTable *jt = cxt->table;
- TableFunc *tf = cxt->tablefunc;
- bool errorOnError = jt->on_error &&
- jt->on_error->btype == JSON_BEHAVIOR_ERROR;
-
- foreach(col, columns)
- {
- JsonTableColumn *rawc = castNode(JsonTableColumn, lfirst(col));
- Oid typid;
- int32 typmod;
- Node *colexpr;
-
- if (rawc->name)
- {
- /* make sure column names are unique */
- ListCell *colname;
-
- foreach(colname, tf->colnames)
- if (!strcmp((const char *) colname, rawc->name))
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("column name \"%s\" is not unique",
- rawc->name),
- parser_errposition(pstate, rawc->location)));
-
- tf->colnames = lappend(tf->colnames,
- makeString(pstrdup(rawc->name)));
- }
-
- /*
- * Determine the type and typmod for the new column. FOR ORDINALITY
- * columns are INTEGER by standard; the others are user-specified.
- */
- switch (rawc->coltype)
- {
- case JTC_FOR_ORDINALITY:
- colexpr = NULL;
- typid = INT4OID;
- typmod = -1;
- break;
-
- case JTC_REGULAR:
- typenameTypeIdAndMod(pstate, rawc->typeName, &typid, &typmod);
-
- /*
- * Use implicit FORMAT JSON for composite types (arrays and
- * records)
- */
- if (typeIsComposite(typid))
- rawc->coltype = JTC_FORMATTED;
- else if (rawc->wrapper != JSW_NONE)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("cannot use WITH WRAPPER clause with scalar columns"),
- parser_errposition(pstate, rawc->location)));
- else if (rawc->omit_quotes)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("cannot use OMIT QUOTES clause with scalar columns"),
- parser_errposition(pstate, rawc->location)));
-
- /* FALLTHROUGH */
- case JTC_EXISTS:
- case JTC_FORMATTED:
- {
- Node *je;
- CaseTestExpr *param = makeNode(CaseTestExpr);
-
- param->collation = InvalidOid;
- param->typeId = cxt->contextItemTypid;
- param->typeMod = -1;
-
- je = transformJsonTableColumn(rawc, (Node *) param,
- NIL, errorOnError);
-
- colexpr = transformExpr(pstate, je, EXPR_KIND_FROM_FUNCTION);
- assign_expr_collations(pstate, colexpr);
-
- typid = exprType(colexpr);
- typmod = exprTypmod(colexpr);
- break;
- }
-
- case JTC_NESTED:
- continue;
-
- default:
- elog(ERROR, "unknown JSON_TABLE column type: %d", rawc->coltype);
- break;
- }
-
- tf->coltypes = lappend_oid(tf->coltypes, typid);
- tf->coltypmods = lappend_int(tf->coltypmods, typmod);
- tf->colcollations = lappend_oid(tf->colcollations, get_typcollation(typid));
- tf->colvalexprs = lappend(tf->colvalexprs, colexpr);
- }
-}
-
-/*
- * Create transformed JSON_TABLE parent plan node by appending all non-nested
- * columns to the TableFunc node and remembering their indices in the
- * colvalexprs list.
- */
-static JsonTableParent *
-makeParentJsonTableNode(JsonTableContext *cxt, char *pathSpec, List *columns)
-{
- JsonTableParent *node = makeNode(JsonTableParent);
-
- node->path = makeConst(JSONPATHOID, -1, InvalidOid, -1,
- DirectFunctionCall1(jsonpath_in,
- CStringGetDatum(pathSpec)),
- false, false);
-
- /* save start of column range */
- node->colMin = list_length(cxt->tablefunc->colvalexprs);
-
- appendJsonTableColumns(cxt, columns);
-
- /* save end of column range */
- node->colMax = list_length(cxt->tablefunc->colvalexprs) - 1;
-
- node->errorOnError =
- cxt->table->on_error &&
- cxt->table->on_error->btype == JSON_BEHAVIOR_ERROR;
-
- return node;
-}
-
-static JsonTableParent *
-transformJsonTableColumns(JsonTableContext *cxt, JsonTablePlan *plan,
- List *columns, char *pathSpec, char **pathName,
- int location)
-{
- JsonTableParent *node;
- JsonTablePlan *childPlan;
- bool defaultPlan = !plan || plan->plan_type == JSTP_DEFAULT;
-
- if (!*pathName)
- {
- if (cxt->table->plan)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("invalid JSON_TABLE expression"),
- errdetail("JSON_TABLE columns must contain "
- "explicit AS pathname specification if "
- "explicit PLAN clause is used"),
- parser_errposition(cxt->pstate, location)));
-
- *pathName = generateJsonTablePathName(cxt);
- }
-
- if (defaultPlan)
- childPlan = plan;
- else
- {
- /* validate parent and child plans */
- JsonTablePlan *parentPlan;
-
- if (plan->plan_type == JSTP_JOINED)
- {
- if (plan->join_type != JSTPJ_INNER &&
- plan->join_type != JSTPJ_OUTER)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("invalid JSON_TABLE plan"),
- errdetail("Expected INNER or OUTER JSON_TABLE plan node."),
- parser_errposition(cxt->pstate, plan->location)));
-
- parentPlan = plan->plan1;
- childPlan = plan->plan2;
-
- Assert(parentPlan->plan_type != JSTP_JOINED);
- Assert(parentPlan->pathname);
- }
- else
- {
- parentPlan = plan;
- childPlan = NULL;
- }
-
- if (strcmp(parentPlan->pathname, *pathName))
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("invalid JSON_TABLE plan"),
- errdetail("Path name mismatch: expected %s but %s is given.",
- *pathName, parentPlan->pathname),
- parser_errposition(cxt->pstate, plan->location)));
-
- validateJsonTableChildPlan(cxt->pstate, childPlan, columns);
- }
-
- /* transform only non-nested columns */
- node = makeParentJsonTableNode(cxt, pathSpec, columns);
- node->name = pstrdup(*pathName);
-
- if (childPlan || defaultPlan)
- {
- /* transform recursively nested columns */
- node->child = transformJsonTableChildPlan(cxt, childPlan, columns);
- if (node->child)
- node->outerJoin = !plan || (plan->join_type & JSTPJ_OUTER);
- /* else: default plan case, no children found */
- }
-
- return node;
-}
-
-/*
- * transformJsonTable -
- * Transform a raw JsonTable into TableFunc.
- *
- * Transform the document-generating expression, the row-generating expression,
- * the column-generating expressions, and the default value expressions.
- */
-ParseNamespaceItem *
-transformJsonTable(ParseState *pstate, JsonTable *jt)
-{
- JsonTableContext cxt;
- TableFunc *tf = makeNode(TableFunc);
- JsonFuncExpr *jfe = makeNode(JsonFuncExpr);
- JsonTablePlan *plan = jt->plan;
- JsonCommon *jscommon;
- char *rootPathName = jt->common->pathname;
- char *rootPath;
- bool is_lateral;
-
- cxt.pstate = pstate;
- cxt.table = jt;
- cxt.tablefunc = tf;
- cxt.pathNames = NIL;
- cxt.pathNameId = 0;
-
- if (rootPathName)
- registerJsonTableColumn(&cxt, rootPathName);
-
- registerAllJsonTableColumns(&cxt, jt->columns);
-
-#if 0 /* XXX it' unclear from the standard whether
- * root path name is mandatory or not */
- if (plan && plan->plan_type != JSTP_DEFAULT && !rootPathName)
- {
- /* Assign root path name and create corresponding plan node */
- JsonTablePlan *rootNode = makeNode(JsonTablePlan);
- JsonTablePlan *rootPlan = (JsonTablePlan *)
- makeJsonTableJoinedPlan(JSTPJ_OUTER, (Node *) rootNode,
- (Node *) plan, jt->location);
-
- rootPathName = generateJsonTablePathName(&cxt);
-
- rootNode->plan_type = JSTP_SIMPLE;
- rootNode->pathname = rootPathName;
-
- plan = rootPlan;
- }
-#endif
-
- jscommon = copyObject(jt->common);
- jscommon->pathspec = makeStringConst(pstrdup("$"), -1);
-
- jfe->op = JSON_TABLE_OP;
- jfe->common = jscommon;
- jfe->on_error = jt->on_error;
- jfe->location = jt->common->location;
-
- /*
- * We make lateral_only names of this level visible, whether or not the
- * RangeTableFunc is explicitly marked LATERAL. This is needed for SQL
- * spec compliance and seems useful on convenience grounds for all
- * functions in FROM.
- *
- * (LATERAL can't nest within a single pstate level, so we don't need
- * save/restore logic here.)
- */
- Assert(!pstate->p_lateral_active);
- pstate->p_lateral_active = true;
-
- tf->functype = TFT_JSON_TABLE;
- tf->docexpr = transformExpr(pstate, (Node *) jfe, EXPR_KIND_FROM_FUNCTION);
-
- cxt.contextItemTypid = exprType(tf->docexpr);
-
- if (!IsA(jt->common->pathspec, A_Const) ||
- castNode(A_Const, jt->common->pathspec)->val.node.type != T_String)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("only string constants supported in JSON_TABLE path specification"),
- parser_errposition(pstate,
- exprLocation(jt->common->pathspec))));
-
- rootPath = castNode(A_Const, jt->common->pathspec)->val.sval.sval;
-
- tf->plan = (Node *) transformJsonTableColumns(&cxt, plan, jt->columns,
- rootPath, &rootPathName,
- jt->common->location);
-
- tf->ordinalitycol = -1; /* undefine ordinality column number */
- tf->location = jt->location;
-
- pstate->p_lateral_active = false;
-
- /*
- * Mark the RTE as LATERAL if the user said LATERAL explicitly, or if
- * there are any lateral cross-references in it.
- */
- is_lateral = jt->lateral || contain_vars_of_level((Node *) tf, 0);
-
- return addRangeTableEntryForTableFunc(pstate,
- tf, jt->alias, is_lateral, true);
-}
bool inFromCl)
{
RangeTblEntry *rte = makeNode(RangeTblEntry);
- char *refname;
+ char *refname = alias ? alias->aliasname : pstrdup("xmltable");
Alias *eref;
int numaliases;
Assert(list_length(tf->coltypmods) == list_length(tf->colnames));
Assert(list_length(tf->colcollations) == list_length(tf->colnames));
- refname = alias ? alias->aliasname :
- pstrdup(tf->functype == TFT_XMLTABLE ? "xmltable" : "json_table");
+ refname = alias ? alias->aliasname : pstrdup("xmltable");
rte->rtekind = RTE_TABLEFUNC;
rte->relid = InvalidOid;
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("%s function has %d columns available but %d columns specified",
- tf->functype == TFT_XMLTABLE ? "XMLTABLE" : "JSON_TABLE",
+ "XMLTABLE",
list_length(tf->colnames), numaliases)));
rte->eref = eref;
case T_XmlSerialize:
*name = "xmlserialize";
return 2;
- case T_JsonParseExpr:
- *name = "json";
- return 2;
- case T_JsonScalarExpr:
- *name = "json_scalar";
- return 2;
- case T_JsonSerializeExpr:
- *name = "json_serialize";
- return 2;
- case T_JsonObjectConstructor:
- *name = "json_object";
- return 2;
- case T_JsonArrayConstructor:
- case T_JsonArrayQueryConstructor:
- *name = "json_array";
- return 2;
- case T_JsonObjectAgg:
- *name = "json_objectagg";
- return 2;
- case T_JsonArrayAgg:
- *name = "json_arrayagg";
- return 2;
- case T_JsonFuncExpr:
- /* make SQL/JSON functions act like a regular function */
- switch (((JsonFuncExpr *) node)->op)
- {
- case JSON_QUERY_OP:
- *name = "json_query";
- return 2;
- case JSON_VALUE_OP:
- *name = "json_value";
- return 2;
- case JSON_EXISTS_OP:
- *name = "json_exists";
- return 2;
- case JSON_TABLE_OP:
- *name = "json_table";
- return 2;
- }
- break;
default:
break;
}
case USCONST:
cur_token_length = strlen(yyextra->core_yy_extra.scanbuf + *llocp);
break;
- case WITHOUT:
- cur_token_length = 7;
- break;
default:
return cur_token;
}
case ORDINALITY:
cur_token = WITH_LA;
break;
- case UNIQUE:
- cur_token = WITH_LA_UNIQUE;
- break;
- }
- break;
-
- case WITHOUT:
- /* Replace WITHOUT by WITHOUT_LA if it's followed by TIME */
- switch (next_token)
- {
- case TIME:
- cur_token = WITHOUT_LA;
- break;
}
break;
else
buf = pstrdup("character varying");
break;
-
- case JSONOID:
- buf = pstrdup("json");
- break;
}
if (buf == NULL)
*L_currency_symbol;
} NUMProc;
+/* Return flags for DCH_from_char() */
+#define DCH_DATED 0x01
+#define DCH_TIMED 0x02
+#define DCH_ZONED 0x04
+
/* ----------
* Functions
* ----------
NUM_TOCHAR_finish;
PG_RETURN_TEXT_P(result);
}
-
-int
-datetime_format_flags(const char *fmt_str, bool *have_error)
-{
- bool incache;
- int fmt_len = strlen(fmt_str);
- int result;
- FormatNode *format;
-
- if (fmt_len > DCH_CACHE_SIZE)
- {
- /*
- * Allocate new memory if format picture is bigger than static cache
- * and do not use cache (call parser always)
- */
- incache = false;
-
- format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
-
- parse_format(format, fmt_str, DCH_keywords,
- DCH_suff, DCH_index, DCH_FLAG, NULL);
- }
- else
- {
- /*
- * Use cache buffers
- */
- DCHCacheEntry *ent = DCH_cache_fetch(fmt_str, false);
-
- incache = true;
- format = ent->format;
- }
-
- result = DCH_datetime_type(format, have_error);
-
- if (!incache)
- pfree(format);
-
- return result;
-}
*/
#include "postgres.h"
-#include "access/hash.h"
-#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
-#include "common/hashfn.h"
#include "funcapi.h"
#include "libpq/pqformat.h"
#include "miscadmin.h"
#include "utils/lsyscache.h"
#include "utils/typcache.h"
-/* Common context for key uniqueness check */
-typedef struct HTAB *JsonUniqueCheckState; /* hash table for key names */
-
-/* Hash entry for JsonUniqueCheckState */
-typedef struct JsonUniqueHashEntry
-{
- const char *key;
- int key_len;
- int object_id;
-} JsonUniqueHashEntry;
-
-/* Context for key uniqueness check in builder functions */
-typedef struct JsonUniqueBuilderState
-{
- JsonUniqueCheckState check; /* unique check */
- StringInfoData skipped_keys; /* skipped keys with NULL values */
- MemoryContext mcxt; /* context for saving skipped keys */
-} JsonUniqueBuilderState;
-
-/* Element of object stack for key uniqueness check during json parsing */
-typedef struct JsonUniqueStackEntry
+typedef enum /* type categories for datum_to_json */
{
- struct JsonUniqueStackEntry *parent;
- int object_id;
-} JsonUniqueStackEntry;
-
-/* State for key uniqueness check during json parsing */
-typedef struct JsonUniqueParsingState
-{
- JsonLexContext *lex;
- JsonUniqueCheckState check;
- JsonUniqueStackEntry *stack;
- int id_counter;
- bool unique;
-} JsonUniqueParsingState;
+ JSONTYPE_NULL, /* null, so we didn't bother to identify */
+ JSONTYPE_BOOL, /* boolean (built-in types only) */
+ JSONTYPE_NUMERIC, /* numeric (ditto) */
+ JSONTYPE_DATE, /* we use special formatting for datetimes */
+ JSONTYPE_TIMESTAMP,
+ JSONTYPE_TIMESTAMPTZ,
+ JSONTYPE_JSON, /* JSON itself (and JSONB) */
+ JSONTYPE_ARRAY, /* array */
+ JSONTYPE_COMPOSITE, /* composite */
+ JSONTYPE_CAST, /* something with an explicit cast to JSON */
+ JSONTYPE_OTHER /* all else */
+} JsonTypeCategory;
typedef struct JsonAggState
{
Oid key_output_func;
JsonTypeCategory val_category;
Oid val_output_func;
- JsonUniqueBuilderState unique_check;
} JsonAggState;
static void composite_to_json(Datum composite, StringInfo result,
bool use_line_feeds);
static void array_to_json_internal(Datum array, StringInfo result,
bool use_line_feeds);
+static void json_categorize_type(Oid typoid,
+ JsonTypeCategory *tcategory,
+ Oid *outfuncoid);
static void datum_to_json(Datum val, bool is_null, StringInfo result,
JsonTypeCategory tcategory, Oid outfuncoid,
bool key_scalar);
* output function OID. If the returned category is JSONTYPE_CAST, we
* return the OID of the type->JSON cast function instead.
*/
-void
+static void
json_categorize_type(Oid typoid,
JsonTypeCategory *tcategory,
Oid *outfuncoid)
PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
}
-Datum
-to_json_worker(Datum val, JsonTypeCategory tcategory, Oid outfuncoid)
-{
- StringInfo result = makeStringInfo();
-
- datum_to_json(val, false, result, tcategory, outfuncoid, false);
-
- return PointerGetDatum(cstring_to_text_with_len(result->data, result->len));
-}
-
-bool
-to_json_is_immutable(Oid typoid)
-{
- JsonTypeCategory tcategory;
- Oid outfuncoid;
-
- json_categorize_type(typoid, &tcategory, &outfuncoid);
-
- switch (tcategory)
- {
- case JSONTYPE_BOOL:
- case JSONTYPE_JSON:
- return true;
-
- case JSONTYPE_DATE:
- case JSONTYPE_TIMESTAMP:
- case JSONTYPE_TIMESTAMPTZ:
- return false;
-
- case JSONTYPE_ARRAY:
- return false; /* TODO recurse into elements */
-
- case JSONTYPE_COMPOSITE:
- return false; /* TODO recurse into fields */
-
- case JSONTYPE_NUMERIC:
- case JSONTYPE_CAST:
- default:
- return func_volatile(outfuncoid) == PROVOLATILE_IMMUTABLE;
- }
-}
-
/*
* SQL function to_json(anyvalue)
*/
{
Datum val = PG_GETARG_DATUM(0);
Oid val_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
+ StringInfo result;
JsonTypeCategory tcategory;
Oid outfuncoid;
json_categorize_type(val_type,
&tcategory, &outfuncoid);
- PG_RETURN_DATUM(to_json_worker(val, tcategory, outfuncoid));
+ result = makeStringInfo();
+
+ datum_to_json(val, false, result, tcategory, outfuncoid, false);
+
+ PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
}
/*
*
* aggregate input column as a json array value.
*/
-static Datum
-json_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null)
+Datum
+json_agg_transfn(PG_FUNCTION_ARGS)
{
MemoryContext aggcontext,
oldcontext;
else
{
state = (JsonAggState *) PG_GETARG_POINTER(0);
- }
-
- if (absent_on_null && PG_ARGISNULL(1))
- PG_RETURN_POINTER(state);
-
- if (state->str->len > 1)
appendStringInfoString(state->str, ", ");
+ }
/* fast path for NULLs */
if (PG_ARGISNULL(1))
val = PG_GETARG_DATUM(1);
/* add some whitespace if structured type and not first item */
- if (!PG_ARGISNULL(0) && state->str->len > 1 &&
+ if (!PG_ARGISNULL(0) &&
(state->val_category == JSONTYPE_ARRAY ||
state->val_category == JSONTYPE_COMPOSITE))
{
PG_RETURN_POINTER(state);
}
-
-/*
- * json_agg aggregate function
- */
-Datum
-json_agg_transfn(PG_FUNCTION_ARGS)
-{
- return json_agg_transfn_worker(fcinfo, false);
-}
-
-/*
- * json_agg_strict aggregate function
- */
-Datum
-json_agg_strict_transfn(PG_FUNCTION_ARGS)
-{
- return json_agg_transfn_worker(fcinfo, true);
-}
-
/*
* json_agg final function
*/
PG_RETURN_TEXT_P(catenate_stringinfo_string(state->str, "]"));
}
-/* Functions implementing hash table for key uniqueness check */
-static uint32
-json_unique_hash(const void *key, Size keysize)
-{
- const JsonUniqueHashEntry *entry = (JsonUniqueHashEntry *) key;
- uint32 hash = hash_bytes_uint32(entry->object_id);
-
- hash ^= hash_bytes((const unsigned char *) entry->key, entry->key_len);
-
- return DatumGetUInt32(hash);
-}
-
-static int
-json_unique_hash_match(const void *key1, const void *key2, Size keysize)
-{
- const JsonUniqueHashEntry *entry1 = (const JsonUniqueHashEntry *) key1;
- const JsonUniqueHashEntry *entry2 = (const JsonUniqueHashEntry *) key2;
-
- if (entry1->object_id != entry2->object_id)
- return entry1->object_id > entry2->object_id ? 1 : -1;
-
- if (entry1->key_len != entry2->key_len)
- return entry1->key_len > entry2->key_len ? 1 : -1;
-
- return strncmp(entry1->key, entry2->key, entry1->key_len);
-}
-
-/* Functions implementing object key uniqueness check */
-static void
-json_unique_check_init(JsonUniqueCheckState *cxt)
-{
- HASHCTL ctl;
-
- memset(&ctl, 0, sizeof(ctl));
- ctl.keysize = sizeof(JsonUniqueHashEntry);
- ctl.entrysize = sizeof(JsonUniqueHashEntry);
- ctl.hcxt = CurrentMemoryContext;
- ctl.hash = json_unique_hash;
- ctl.match = json_unique_hash_match;
-
- *cxt = hash_create("json object hashtable",
- 32,
- &ctl,
- HASH_ELEM | HASH_CONTEXT | HASH_FUNCTION | HASH_COMPARE);
-}
-
-static bool
-json_unique_check_key(JsonUniqueCheckState *cxt, const char *key, int object_id)
-{
- JsonUniqueHashEntry entry;
- bool found;
-
- entry.key = key;
- entry.key_len = strlen(key);
- entry.object_id = object_id;
-
- (void) hash_search(*cxt, &entry, HASH_ENTER, &found);
-
- return !found;
-}
-
-static void
-json_unique_builder_init(JsonUniqueBuilderState *cxt)
-{
- json_unique_check_init(&cxt->check);
- cxt->mcxt = CurrentMemoryContext;
- cxt->skipped_keys.data = NULL;
-}
-
-/* On-demand initialization of skipped_keys StringInfo structure */
-static StringInfo
-json_unique_builder_get_skipped_keys(JsonUniqueBuilderState *cxt)
-{
- StringInfo out = &cxt->skipped_keys;
-
- if (!out->data)
- {
- MemoryContext oldcxt = MemoryContextSwitchTo(cxt->mcxt);
-
- initStringInfo(out);
- MemoryContextSwitchTo(oldcxt);
- }
-
- return out;
-}
-
/*
* json_object_agg transition function.
*
* aggregate two input columns as a single json object value.
*/
-static Datum
-json_object_agg_transfn_worker(FunctionCallInfo fcinfo,
- bool absent_on_null, bool unique_keys)
+Datum
+json_object_agg_transfn(PG_FUNCTION_ARGS)
{
MemoryContext aggcontext,
oldcontext;
JsonAggState *state;
- StringInfo out;
Datum arg;
- bool skip;
- int key_offset;
if (!AggCheckCallContext(fcinfo, &aggcontext))
{
oldcontext = MemoryContextSwitchTo(aggcontext);
state = (JsonAggState *) palloc(sizeof(JsonAggState));
state->str = makeStringInfo();
- if (unique_keys)
- json_unique_builder_init(&state->unique_check);
- else
- memset(&state->unique_check, 0, sizeof(state->unique_check));
MemoryContextSwitchTo(oldcontext);
arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
else
{
state = (JsonAggState *) PG_GETARG_POINTER(0);
+ appendStringInfoString(state->str, ", ");
}
/*
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("field name must not be null")));
- /* Skip null values if absent_on_null */
- skip = absent_on_null && PG_ARGISNULL(2);
-
- if (skip)
- {
- /* If key uniqueness check is needed we must save skipped keys */
- if (!unique_keys)
- PG_RETURN_POINTER(state);
-
- out = json_unique_builder_get_skipped_keys(&state->unique_check);
- }
- else
- {
- out = state->str;
-
- /*
- * Append comma delimiter only if we have already outputted some
- * fields after the initial string "{ ".
- */
- if (out->len > 2)
- appendStringInfoString(out, ", ");
- }
-
arg = PG_GETARG_DATUM(1);
- key_offset = out->len;
-
- datum_to_json(arg, false, out, state->key_category,
+ datum_to_json(arg, false, state->str, state->key_category,
state->key_output_func, true);
- if (unique_keys)
- {
- const char *key = &out->data[key_offset];
-
- if (!json_unique_check_key(&state->unique_check.check, key, 0))
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_JSON_OBJECT_KEY_VALUE),
- errmsg("duplicate JSON key %s", key)));
-
- if (skip)
- PG_RETURN_POINTER(state);
- }
-
appendStringInfoString(state->str, " : ");
if (PG_ARGISNULL(2))
PG_RETURN_POINTER(state);
}
-/*
- * json_object_agg aggregate function
- */
-Datum
-json_object_agg_transfn(PG_FUNCTION_ARGS)
-{
- return json_object_agg_transfn_worker(fcinfo, false, false);
-}
-
-/*
- * json_object_agg_strict aggregate function
- */
-Datum
-json_object_agg_strict_transfn(PG_FUNCTION_ARGS)
-{
- return json_object_agg_transfn_worker(fcinfo, true, false);
-}
-
-/*
- * json_object_agg_unique aggregate function
- */
-Datum
-json_object_agg_unique_transfn(PG_FUNCTION_ARGS)
-{
- return json_object_agg_transfn_worker(fcinfo, false, true);
-}
-
-/*
- * json_object_agg_unique_strict aggregate function
- */
-Datum
-json_object_agg_unique_strict_transfn(PG_FUNCTION_ARGS)
-{
- return json_object_agg_transfn_worker(fcinfo, true, true);
-}
-
/*
* json_object_agg final function.
*/
return result;
}
+/*
+ * SQL function json_build_object(variadic "any")
+ */
Datum
-json_build_object_worker(int nargs, Datum *args, bool *nulls, Oid *types,
- bool absent_on_null, bool unique_keys)
+json_build_object(PG_FUNCTION_ARGS)
{
+ int nargs;
int i;
const char *sep = "";
StringInfo result;
- JsonUniqueBuilderState unique_check;
+ Datum *args;
+ bool *nulls;
+ Oid *types;
+
+ /* fetch argument values to build the object */
+ nargs = extract_variadic_args(fcinfo, 0, false, &args, &types, &nulls);
+
+ if (nargs < 0)
+ PG_RETURN_NULL();
if (nargs % 2 != 0)
ereport(ERROR,
appendStringInfoChar(result, '{');
- if (unique_keys)
- json_unique_builder_init(&unique_check);
-
for (i = 0; i < nargs; i += 2)
{
- StringInfo out;
- bool skip;
- int key_offset;
-
- /* Skip null values if absent_on_null */
- skip = absent_on_null && nulls[i + 1];
-
- if (skip)
- {
- /* If key uniqueness check is needed we must save skipped keys */
- if (!unique_keys)
- continue;
-
- out = json_unique_builder_get_skipped_keys(&unique_check);
- }
- else
- {
- appendStringInfoString(result, sep);
- sep = ", ";
- out = result;
- }
+ appendStringInfoString(result, sep);
+ sep = ", ";
/* process key */
if (nulls[i])
errmsg("argument %d cannot be null", i + 1),
errhint("Object keys should be text.")));
- /* save key offset before key appending */
- key_offset = out->len;
-
- add_json(args[i], false, out, types[i], true);
-
- if (unique_keys)
- {
- /* check key uniqueness after key appending */
- const char *key = &out->data[key_offset];
-
- if (!json_unique_check_key(&unique_check.check, key, 0))
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_JSON_OBJECT_KEY_VALUE),
- errmsg("duplicate JSON key %s", key)));
-
- if (skip)
- continue;
- }
+ add_json(args[i], false, result, types[i], true);
appendStringInfoString(result, " : ");
appendStringInfoChar(result, '}');
- return PointerGetDatum(cstring_to_text_with_len(result->data, result->len));
-}
-
-/*
- * SQL function json_build_object(variadic "any")
- */
-Datum
-json_build_object(PG_FUNCTION_ARGS)
-{
- Datum *args;
- bool *nulls;
- Oid *types;
-
- /* build argument values to build the object */
- int nargs = extract_variadic_args(fcinfo, 0, true,
- &args, &types, &nulls);
-
- if (nargs < 0)
- PG_RETURN_NULL();
-
- PG_RETURN_DATUM(json_build_object_worker(nargs, args, nulls, types, false, false));
+ PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
}
/*
PG_RETURN_TEXT_P(cstring_to_text_with_len("{}", 2));
}
+/*
+ * SQL function json_build_array(variadic "any")
+ */
Datum
-json_build_array_worker(int nargs, Datum *args, bool *nulls, Oid *types,
- bool absent_on_null)
+json_build_array(PG_FUNCTION_ARGS)
{
+ int nargs;
int i;
const char *sep = "";
StringInfo result;
+ Datum *args;
+ bool *nulls;
+ Oid *types;
+
+ /* fetch argument values to build the array */
+ nargs = extract_variadic_args(fcinfo, 0, false, &args, &types, &nulls);
+
+ if (nargs < 0)
+ PG_RETURN_NULL();
result = makeStringInfo();
for (i = 0; i < nargs; i++)
{
- if (absent_on_null && nulls[i])
- continue;
-
appendStringInfoString(result, sep);
sep = ", ";
add_json(args[i], nulls[i], result, types[i], false);
appendStringInfoChar(result, ']');
- return PointerGetDatum(cstring_to_text_with_len(result->data, result->len));
-}
-
-/*
- * SQL function json_build_array(variadic "any")
- */
-Datum
-json_build_array(PG_FUNCTION_ARGS)
-{
- Datum *args;
- bool *nulls;
- Oid *types;
-
- /* build argument values to build the object */
- int nargs = extract_variadic_args(fcinfo, 0, true,
- &args, &types, &nulls);
-
- if (nargs < 0)
- PG_RETURN_NULL();
-
- PG_RETURN_DATUM(json_build_array_worker(nargs, args, nulls, types, false));
+ PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
}
/*
appendStringInfoCharMacro(buf, '"');
}
-/* Semantic actions for key uniqueness check */
-static void
-json_unique_object_start(void *_state)
-{
- JsonUniqueParsingState *state = _state;
- JsonUniqueStackEntry *entry;
-
- if (!state->unique)
- return;
-
- /* push object entry to stack */
- entry = palloc(sizeof(*entry));
- entry->object_id = state->id_counter++;
- entry->parent = state->stack;
- state->stack = entry;
-}
-
-static void
-json_unique_object_end(void *_state)
-{
- JsonUniqueParsingState *state = _state;
- JsonUniqueStackEntry *entry;
-
- if (!state->unique)
- return;
-
- entry = state->stack;
- state->stack = entry->parent; /* pop object from stack */
- pfree(entry);
-}
-
-static void
-json_unique_object_field_start(void *_state, char *field, bool isnull)
-{
- JsonUniqueParsingState *state = _state;
- JsonUniqueStackEntry *entry;
-
- if (!state->unique)
- return;
-
- /* find key collision in the current object */
- if (json_unique_check_key(&state->check, field, state->stack->object_id))
- return;
-
- state->unique = false;
-
- /* pop all objects entries */
- while ((entry = state->stack))
- {
- state->stack = entry->parent;
- pfree(entry);
- }
-}
-
-/* Validate JSON text and additionally check key uniqueness */
-bool
-json_validate(text *json, bool check_unique_keys, bool throw_error)
-{
- JsonLexContext *lex = makeJsonLexContext(json, check_unique_keys);
- JsonSemAction uniqueSemAction = {0};
- JsonUniqueParsingState state;
- JsonParseErrorType result;
-
- if (check_unique_keys)
- {
- state.lex = lex;
- state.stack = NULL;
- state.id_counter = 0;
- state.unique = true;
- json_unique_check_init(&state.check);
-
- uniqueSemAction.semstate = &state;
- uniqueSemAction.object_start = json_unique_object_start;
- uniqueSemAction.object_field_start = json_unique_object_field_start;
- uniqueSemAction.object_end = json_unique_object_end;
- }
-
- result = pg_parse_json(lex, check_unique_keys ? &uniqueSemAction : &nullSemAction);
-
- if (result != JSON_SUCCESS)
- {
- if (throw_error)
- json_ereport_error(result, lex);
-
- return false; /* invalid json */
- }
-
- if (check_unique_keys && !state.unique)
- {
- if (throw_error)
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_JSON_OBJECT_KEY_VALUE),
- errmsg("duplicate JSON object key value")));
-
- return false; /* not unique keys */
- }
-
- return true; /* ok */
-}
-
/*
* SQL function json_typeof(json) -> text
*
Datum
json_typeof(PG_FUNCTION_ARGS)
{
- text *json = PG_GETARG_TEXT_PP(0);
- char *type;
+ text *json;
+
+ JsonLexContext *lex;
JsonTokenType tok;
+ char *type;
+ JsonParseErrorType result;
- /* Lex exactly one token from the input and check its type. */
- tok = json_get_first_token(json, true);
+ json = PG_GETARG_TEXT_PP(0);
+ lex = makeJsonLexContext(json, false);
+ /* Lex exactly one token from the input and check its type. */
+ result = json_lex(lex);
+ if (result != JSON_SUCCESS)
+ json_ereport_error(result, lex);
+ tok = lex->token_type;
switch (tok)
{
case JSON_TOKEN_OBJECT_START:
#include "access/htup_details.h"
#include "access/transam.h"
-#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "libpq/pqformat.h"
{
JsonbParseState *parseState;
JsonbValue *res;
- bool unique_keys;
} JsonbInState;
+/* unlike with json categories, we need to treat json and jsonb differently */
+typedef enum /* type categories for datum_to_jsonb */
+{
+ JSONBTYPE_NULL, /* null, so we didn't bother to identify */
+ JSONBTYPE_BOOL, /* boolean (built-in types only) */
+ JSONBTYPE_NUMERIC, /* numeric (ditto) */
+ JSONBTYPE_DATE, /* we use special formatting for datetimes */
+ JSONBTYPE_TIMESTAMP, /* we use special formatting for timestamp */
+ JSONBTYPE_TIMESTAMPTZ, /* ... and timestamptz */
+ JSONBTYPE_JSON, /* JSON */
+ JSONBTYPE_JSONB, /* JSONB */
+ JSONBTYPE_ARRAY, /* array */
+ JSONBTYPE_COMPOSITE, /* composite */
+ JSONBTYPE_JSONCAST, /* something with an explicit cast to JSON */
+ JSONBTYPE_OTHER /* all else */
+} JsonbTypeCategory;
+
typedef struct JsonbAggState
{
JsonbInState *res;
Oid val_output_func;
} JsonbAggState;
-static inline Datum jsonb_from_cstring(char *json, int len, bool unique_keys);
+static inline Datum jsonb_from_cstring(char *json, int len);
static size_t checkStringLen(size_t len);
static void jsonb_in_object_start(void *pstate);
static void jsonb_in_object_end(void *pstate);
static void jsonb_in_object_field_start(void *pstate, char *fname, bool isnull);
static void jsonb_put_escaped_value(StringInfo out, JsonbValue *scalarVal);
static void jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype);
+static void jsonb_categorize_type(Oid typoid,
+ JsonbTypeCategory *tcategory,
+ Oid *outfuncoid);
static void composite_to_jsonb(Datum composite, JsonbInState *result);
static void array_dim_to_jsonb(JsonbInState *result, int dim, int ndims, int *dims,
Datum *vals, bool *nulls, int *valcount,
JsonbTypeCategory tcategory, Oid outfuncoid);
static void array_to_jsonb_internal(Datum array, JsonbInState *result);
+static void jsonb_categorize_type(Oid typoid,
+ JsonbTypeCategory *tcategory,
+ Oid *outfuncoid);
static void datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
JsonbTypeCategory tcategory, Oid outfuncoid,
bool key_scalar);
{
char *json = PG_GETARG_CSTRING(0);
- return jsonb_from_cstring(json, strlen(json), false);
+ return jsonb_from_cstring(json, strlen(json));
}
/*
else
elog(ERROR, "unsupported jsonb version number %d", version);
- return jsonb_from_cstring(str, nbytes, false);
+ return jsonb_from_cstring(str, nbytes);
}
/*
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}
-Datum
-jsonb_from_text(text *js, bool unique_keys)
-{
- return jsonb_from_cstring(VARDATA_ANY(js),
- VARSIZE_ANY_EXHDR(js),
- unique_keys);
-}
-
/*
* Get the type name of a jsonb container.
*/
* Uses the json parser (with hooks) to construct a jsonb.
*/
static inline Datum
-jsonb_from_cstring(char *json, int len, bool unique_keys)
+jsonb_from_cstring(char *json, int len)
{
JsonLexContext *lex;
JsonbInState state;
memset(&sem, 0, sizeof(sem));
lex = makeJsonLexContextCstringLen(json, len, GetDatabaseEncoding(), true);
- state.unique_keys = unique_keys;
-
sem.semstate = (void *) &state;
sem.object_start = jsonb_in_object_start;
JsonbInState *_state = (JsonbInState *) pstate;
_state->res = pushJsonbValue(&_state->parseState, WJB_BEGIN_OBJECT, NULL);
- _state->parseState->unique_keys = _state->unique_keys;
}
static void
* output function OID. If the returned category is JSONBTYPE_JSONCAST,
* we return the OID of the relevant cast function instead.
*/
-void
+static void
jsonb_categorize_type(Oid typoid,
JsonbTypeCategory *tcategory,
Oid *outfuncoid)
datum_to_jsonb(val, is_null, result, tcategory, outfuncoid, key_scalar);
}
-Datum
-to_jsonb_worker(Datum val, JsonbTypeCategory tcategory, Oid outfuncoid)
-{
- JsonbInState result;
-
- memset(&result, 0, sizeof(JsonbInState));
-
- datum_to_jsonb(val, false, &result, tcategory, outfuncoid, false);
-
- return JsonbPGetDatum(JsonbValueToJsonb(result.res));
-}
-
-bool
-to_jsonb_is_immutable(Oid typoid)
-{
- JsonbTypeCategory tcategory;
- Oid outfuncoid;
-
- jsonb_categorize_type(typoid, &tcategory, &outfuncoid);
-
- switch (tcategory)
- {
- case JSONBTYPE_BOOL:
- case JSONBTYPE_JSON:
- case JSONBTYPE_JSONB:
- return true;
-
- case JSONBTYPE_DATE:
- case JSONBTYPE_TIMESTAMP:
- case JSONBTYPE_TIMESTAMPTZ:
- return false;
-
- case JSONBTYPE_ARRAY:
- return false; /* TODO recurse into elements */
-
- case JSONBTYPE_COMPOSITE:
- return false; /* TODO recurse into fields */
-
- case JSONBTYPE_NUMERIC:
- case JSONBTYPE_JSONCAST:
- default:
- return func_volatile(outfuncoid) == PROVOLATILE_IMMUTABLE;
- }
-}
-
/*
* SQL function to_jsonb(anyvalue)
*/
{
Datum val = PG_GETARG_DATUM(0);
Oid val_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
+ JsonbInState result;
JsonbTypeCategory tcategory;
Oid outfuncoid;
jsonb_categorize_type(val_type,
&tcategory, &outfuncoid);
- PG_RETURN_DATUM(to_jsonb_worker(val, tcategory, outfuncoid));
+ memset(&result, 0, sizeof(JsonbInState));
+
+ datum_to_jsonb(val, false, &result, tcategory, outfuncoid, false);
+
+ PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
}
+/*
+ * SQL function jsonb_build_object(variadic "any")
+ */
Datum
-jsonb_build_object_worker(int nargs, Datum *args, bool *nulls, Oid *types,
- bool absent_on_null, bool unique_keys)
+jsonb_build_object(PG_FUNCTION_ARGS)
{
+ int nargs;
int i;
JsonbInState result;
+ Datum *args;
+ bool *nulls;
+ Oid *types;
+
+ /* build argument values to build the object */
+ nargs = extract_variadic_args(fcinfo, 0, true, &args, &types, &nulls);
+
+ if (nargs < 0)
+ PG_RETURN_NULL();
if (nargs % 2 != 0)
ereport(ERROR,
memset(&result, 0, sizeof(JsonbInState));
result.res = pushJsonbValue(&result.parseState, WJB_BEGIN_OBJECT, NULL);
- result.parseState->unique_keys = unique_keys;
- result.parseState->skip_nulls = absent_on_null;
for (i = 0; i < nargs; i += 2)
{
/* process key */
- bool skip;
-
if (nulls[i])
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("argument %d: key must not be null", i + 1)));
- /* skip null values if absent_on_null */
- skip = absent_on_null && nulls[i + 1];
-
- /* we need to save skipped keys for the key uniqueness check */
- if (skip && !unique_keys)
- continue;
-
add_jsonb(args[i], false, &result, types[i], true);
/* process value */
result.res = pushJsonbValue(&result.parseState, WJB_END_OBJECT, NULL);
- return JsonbPGetDatum(JsonbValueToJsonb(result.res));
-}
-
-/*
- * SQL function jsonb_build_object(variadic "any")
- */
-Datum
-jsonb_build_object(PG_FUNCTION_ARGS)
-{
- Datum *args;
- bool *nulls;
- Oid *types;
-
- /* build argument values to build the object */
- int nargs = extract_variadic_args(fcinfo, 0, true,
- &args, &types, &nulls);
-
- if (nargs < 0)
- PG_RETURN_NULL();
-
- PG_RETURN_DATUM(jsonb_build_object_worker(nargs, args, nulls, types, false, false));
+ PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
}
/*
PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
}
-Datum
-jsonb_build_array_worker(int nargs, Datum *args, bool *nulls, Oid *types,
- bool absent_on_null)
-{
- int i;
- JsonbInState result;
-
- memset(&result, 0, sizeof(JsonbInState));
-
- result.res = pushJsonbValue(&result.parseState, WJB_BEGIN_ARRAY, NULL);
-
- for (i = 0; i < nargs; i++)
- {
- if (absent_on_null && nulls[i])
- continue;
-
- add_jsonb(args[i], nulls[i], &result, types[i], false);
- }
-
- result.res = pushJsonbValue(&result.parseState, WJB_END_ARRAY, NULL);
-
- return JsonbPGetDatum(JsonbValueToJsonb(result.res));
-}
-
/*
* SQL function jsonb_build_array(variadic "any")
*/
Datum
jsonb_build_array(PG_FUNCTION_ARGS)
{
+ int nargs;
+ int i;
+ JsonbInState result;
Datum *args;
bool *nulls;
Oid *types;
- /* build argument values to build the object */
- int nargs = extract_variadic_args(fcinfo, 0, true,
- &args, &types, &nulls);
+ /* build argument values to build the array */
+ nargs = extract_variadic_args(fcinfo, 0, true, &args, &types, &nulls);
if (nargs < 0)
PG_RETURN_NULL();
- PG_RETURN_DATUM(jsonb_build_array_worker(nargs, args, nulls, types, false));
-}
+ memset(&result, 0, sizeof(JsonbInState));
+
+ result.res = pushJsonbValue(&result.parseState, WJB_BEGIN_ARRAY, NULL);
+ for (i = 0; i < nargs; i++)
+ add_jsonb(args[i], nulls[i], &result, types[i], false);
+
+ result.res = pushJsonbValue(&result.parseState, WJB_END_ARRAY, NULL);
+
+ PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
+}
/*
* degenerate case of jsonb_build_array where it gets 0 arguments.
{
ocursor->contVal = icursor->contVal;
ocursor->size = icursor->size;
- ocursor->unique_keys = icursor->unique_keys;
- ocursor->skip_nulls = icursor->skip_nulls;
icursor = icursor->next;
if (icursor == NULL)
break;
return result;
}
-static Datum
-jsonb_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null)
+
+/*
+ * jsonb_agg aggregate function
+ */
+Datum
+jsonb_agg_transfn(PG_FUNCTION_ARGS)
{
MemoryContext oldcontext,
aggcontext;
result = state->res;
}
- if (absent_on_null && PG_ARGISNULL(1))
- PG_RETURN_POINTER(state);
-
/* turn the argument into jsonb in the normal function context */
val = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1);
PG_RETURN_POINTER(state);
}
-/*
- * jsonb_agg aggregate function
- */
-Datum
-jsonb_agg_transfn(PG_FUNCTION_ARGS)
-{
- return jsonb_agg_transfn_worker(fcinfo, false);
-}
-
-/*
- * jsonb_agg_strict aggregate function
- */
-Datum
-jsonb_agg_strict_transfn(PG_FUNCTION_ARGS)
-{
- return jsonb_agg_transfn_worker(fcinfo, true);
-}
-
Datum
jsonb_agg_finalfn(PG_FUNCTION_ARGS)
{
PG_RETURN_POINTER(out);
}
-static Datum
-jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo,
- bool absent_on_null, bool unique_keys)
+/*
+ * jsonb_object_agg aggregate function
+ */
+Datum
+jsonb_object_agg_transfn(PG_FUNCTION_ARGS)
{
MemoryContext oldcontext,
aggcontext;
*jbval;
JsonbValue v;
JsonbIteratorToken type;
- bool skip;
if (!AggCheckCallContext(fcinfo, &aggcontext))
{
state->res = result;
result->res = pushJsonbValue(&result->parseState,
WJB_BEGIN_OBJECT, NULL);
- result->parseState->unique_keys = unique_keys;
- result->parseState->skip_nulls = absent_on_null;
-
MemoryContextSwitchTo(oldcontext);
arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("field name must not be null")));
- /*
- * Skip null values if absent_on_null unless key uniqueness check is
- * needed (because we must save keys in this case).
- */
- skip = absent_on_null && PG_ARGISNULL(2);
-
- if (skip && !unique_keys)
- PG_RETURN_POINTER(state);
-
val = PG_GETARG_DATUM(1);
memset(&elem, 0, sizeof(JsonbInState));
}
result->res = pushJsonbValue(&result->parseState,
WJB_KEY, &v);
-
- if (skip)
- {
- v.type = jbvNull;
- result->res = pushJsonbValue(&result->parseState,
- WJB_VALUE, &v);
- MemoryContextSwitchTo(oldcontext);
- PG_RETURN_POINTER(state);
- }
-
break;
case WJB_END_ARRAY:
break;
PG_RETURN_POINTER(state);
}
-/*
- * jsonb_object_agg aggregate function
- */
-Datum
-jsonb_object_agg_transfn(PG_FUNCTION_ARGS)
-{
- return jsonb_object_agg_transfn_worker(fcinfo, false, false);
-}
-
-
-/*
- * jsonb_object_agg_strict aggregate function
- */
-Datum
-jsonb_object_agg_strict_transfn(PG_FUNCTION_ARGS)
-{
- return jsonb_object_agg_transfn_worker(fcinfo, true, false);
-}
-
-/*
- * jsonb_object_agg_unique aggregate function
- */
-Datum
-jsonb_object_agg_unique_transfn(PG_FUNCTION_ARGS)
-{
- return jsonb_object_agg_transfn_worker(fcinfo, false, true);
-}
-
-/*
- * jsonb_object_agg_unique_strict aggregate function
- */
-Datum
-jsonb_object_agg_unique_strict_transfn(PG_FUNCTION_ARGS)
-{
- return jsonb_object_agg_transfn_worker(fcinfo, true, true);
-}
-
Datum
jsonb_object_agg_finalfn(PG_FUNCTION_ARGS)
{
PG_RETURN_DATUM(retValue);
}
-
-/*
- * Construct an empty array jsonb.
- */
-Jsonb *
-JsonbMakeEmptyArray(void)
-{
- JsonbValue jbv;
-
- jbv.type = jbvArray;
- jbv.val.array.elems = NULL;
- jbv.val.array.nElems = 0;
- jbv.val.array.rawScalar = false;
-
- return JsonbValueToJsonb(&jbv);
-}
-
-/*
- * Construct an empty object jsonb.
- */
-Jsonb *
-JsonbMakeEmptyObject(void)
-{
- JsonbValue jbv;
-
- jbv.type = jbvObject;
- jbv.val.object.pairs = NULL;
- jbv.val.object.nPairs = 0;
-
- return JsonbValueToJsonb(&jbv);
-}
-
-/*
- * Convert jsonb to a C-string stripping quotes from scalar strings.
- */
-char *
-JsonbUnquote(Jsonb *jb)
-{
- if (JB_ROOT_IS_SCALAR(jb))
- {
- JsonbValue v;
-
- (void) JsonbExtractScalar(&jb->root, &v);
-
- if (v.type == jbvString)
- return pnstrdup(v.val.string.val, v.val.string.len);
- else if (v.type == jbvBool)
- return pstrdup(v.val.boolean ? "true" : "false");
- else if (v.type == jbvNumeric)
- return DatumGetCString(DirectFunctionCall1(numeric_out,
- PointerGetDatum(v.val.numeric)));
- else if (v.type == jbvNull)
- return pstrdup("null");
- else
- {
- elog(ERROR, "unrecognized jsonb value type %d", v.type);
- return NULL;
- }
- }
- else
- return JsonbToCString(NULL, &jb->root, VARSIZE(jb));
-}
static int lengthCompareJsonbString(const char *val1, int len1,
const char *val2, int len2);
static int lengthCompareJsonbPair(const void *a, const void *b, void *arg);
-static void uniqueifyJsonbObject(JsonbValue *object, bool unique_keys,
- bool skip_nulls);
+static void uniqueifyJsonbObject(JsonbValue *object);
static JsonbValue *pushJsonbValueScalar(JsonbParseState **pstate,
JsonbIteratorToken seq,
JsonbValue *scalarVal);
appendElement(*pstate, scalarVal);
break;
case WJB_END_OBJECT:
- uniqueifyJsonbObject(&(*pstate)->contVal,
- (*pstate)->unique_keys,
- (*pstate)->skip_nulls);
+ uniqueifyJsonbObject(&(*pstate)->contVal);
/* fall through! */
case WJB_END_ARRAY:
/* Steps here common to WJB_END_OBJECT case */
JsonbParseState *ns = palloc(sizeof(JsonbParseState));
ns->next = *pstate;
- ns->unique_keys = false;
- ns->skip_nulls = false;
-
return ns;
}
* Sort and unique-ify pairs in JsonbValue object
*/
static void
-uniqueifyJsonbObject(JsonbValue *object, bool unique_keys, bool skip_nulls)
+uniqueifyJsonbObject(JsonbValue *object)
{
bool hasNonUniq = false;
qsort_arg(object->val.object.pairs, object->val.object.nPairs, sizeof(JsonbPair),
lengthCompareJsonbPair, &hasNonUniq);
- if (hasNonUniq && unique_keys)
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_JSON_OBJECT_KEY_VALUE),
- errmsg("duplicate JSON object key value")));
-
- if (hasNonUniq || skip_nulls)
+ if (hasNonUniq)
{
- JsonbPair *ptr,
- *res;
-
- while (skip_nulls && object->val.object.nPairs > 0 &&
- object->val.object.pairs->value.type == jbvNull)
- {
- /* If skip_nulls is true, remove leading items with null */
- object->val.object.pairs++;
- object->val.object.nPairs--;
- }
-
- ptr = object->val.object.pairs + 1;
- res = object->val.object.pairs;
+ JsonbPair *ptr = object->val.object.pairs + 1,
+ *res = object->val.object.pairs;
while (ptr - object->val.object.pairs < object->val.object.nPairs)
{
- /* Avoid copying over duplicate or null */
- if (lengthCompareJsonbStringValue(ptr, res) != 0 &&
- (!skip_nulls || ptr->value.type != jbvNull))
+ /* Avoid copying over duplicate */
+ if (lengthCompareJsonbStringValue(ptr, res) != 0)
{
res++;
if (ptr != res)
check_stack_depth();
- if (jbv->type != jbvBinary ||
- !JsonContainerIsArray(jbc) ||
- JsonContainerIsScalar(jbc))
+ if (jbv->type != jbvBinary || !JsonContainerIsArray(jbc))
populate_array_report_expected_array(ctx, ndim - 1);
+ Assert(!JsonContainerIsScalar(jbc));
+
it = JsonbIteratorInit(jbc);
tok = JsonbIteratorNext(&it, &val, true);
}
}
-/* recursively populate specified type from a json/jsonb value */
-Datum
-json_populate_type(Datum json_val, Oid json_type, Oid typid, int32 typmod,
- void **cache, MemoryContext mcxt, bool *isnull)
-{
- JsValue jsv = {0};
- JsonbValue jbv;
-
- jsv.is_json = json_type == JSONOID;
-
- if (*isnull)
- {
- if (jsv.is_json)
- jsv.val.json.str = NULL;
- else
- jsv.val.jsonb = NULL;
- }
- else if (jsv.is_json)
- {
- text *json = DatumGetTextPP(json_val);
-
- jsv.val.json.str = VARDATA_ANY(json);
- jsv.val.json.len = VARSIZE_ANY_EXHDR(json);
- jsv.val.json.type = JSON_TOKEN_INVALID; /* not used in
- * populate_composite() */
- }
- else
- {
- Jsonb *jsonb = DatumGetJsonbP(json_val);
-
- jsv.val.jsonb = &jbv;
-
- /* fill binary jsonb value pointing to jb */
- jbv.type = jbvBinary;
- jbv.val.binary.data = &jsonb->root;
- jbv.val.binary.len = VARSIZE(jsonb) - VARHDRSZ;
- }
-
- if (!*cache)
- *cache = MemoryContextAllocZero(mcxt, sizeof(ColumnIOData));
-
- return populate_record_field(*cache, typid, typmod, NULL, mcxt,
- PointerGetDatum(NULL), &jsv, isnull);
-}
-
static RecordIOData *
allocate_record_info(MemoryContext mcxt, int ncolumns)
{
else
appendStringInfoString(_state->strval, token);
}
-
-JsonTokenType
-json_get_first_token(text *json, bool throw_error)
-{
- JsonLexContext *lex;
- JsonParseErrorType result;
-
- lex = makeJsonLexContext(json, false);
-
- /* Lex exactly one token from the input and check its type. */
- result = json_lex(lex);
-
- if (result == JSON_SUCCESS)
- return lex->token_type;
-
- if (throw_error)
- json_ereport_error(result, lex);
-
- return JSON_TOKEN_INVALID; /* invalid json */
-}
#include "lib/stringinfo.h"
#include "libpq/pqformat.h"
#include "miscadmin.h"
-#include "nodes/nodeFuncs.h"
#include "utils/builtins.h"
-#include "utils/formatting.h"
#include "utils/json.h"
#include "utils/jsonpath.h"
return true;
}
-
-/* SQL/JSON datatype status: */
-typedef enum JsonPathDatatypeStatus
-{
- jpdsNonDateTime, /* null, bool, numeric, string, array, object */
- jpdsUnknownDateTime, /* unknown datetime type */
- jpdsDateTimeZoned, /* timetz, timestamptz */
- jpdsDateTimeNonZoned /* time, timestamp, date */
-} JsonPathDatatypeStatus;
-
-/* Context for jspIsMutableWalker() */
-typedef struct JsonPathMutableContext
-{
- List *varnames; /* list of variable names */
- List *varexprs; /* list of variable expressions */
- JsonPathDatatypeStatus current; /* status of @ item */
- bool lax; /* jsonpath is lax or strict */
- bool mutable; /* resulting mutability status */
-} JsonPathMutableContext;
-
-/*
- * Recursive walker for jspIsMutable()
- */
-static JsonPathDatatypeStatus
-jspIsMutableWalker(JsonPathItem *jpi, JsonPathMutableContext *cxt)
-{
- JsonPathItem next;
- JsonPathDatatypeStatus status = jpdsNonDateTime;
-
- while (!cxt->mutable)
- {
- JsonPathItem arg;
- JsonPathDatatypeStatus leftStatus;
- JsonPathDatatypeStatus rightStatus;
-
- switch (jpi->type)
- {
- case jpiRoot:
- Assert(status == jpdsNonDateTime);
- break;
-
- case jpiCurrent:
- Assert(status == jpdsNonDateTime);
- status = cxt->current;
- break;
-
- case jpiFilter:
- {
- JsonPathDatatypeStatus prevStatus = cxt->current;
-
- cxt->current = status;
- jspGetArg(jpi, &arg);
- jspIsMutableWalker(&arg, cxt);
-
- cxt->current = prevStatus;
- break;
- }
-
- case jpiVariable:
- {
- int32 len;
- const char *name = jspGetString(jpi, &len);
- ListCell *lc1;
- ListCell *lc2;
-
- Assert(status == jpdsNonDateTime);
-
- forboth(lc1, cxt->varnames, lc2, cxt->varexprs)
- {
- String *varname = lfirst_node(String, lc1);
- Node *varexpr = lfirst(lc2);
-
- if (strncmp(varname->sval, name, len))
- continue;
-
- switch (exprType(varexpr))
- {
- case DATEOID:
- case TIMEOID:
- case TIMESTAMPOID:
- status = jpdsDateTimeNonZoned;
- break;
-
- case TIMETZOID:
- case TIMESTAMPTZOID:
- status = jpdsDateTimeZoned;
- break;
-
- default:
- status = jpdsNonDateTime;
- break;
- }
-
- break;
- }
- break;
- }
-
- case jpiEqual:
- case jpiNotEqual:
- case jpiLess:
- case jpiGreater:
- case jpiLessOrEqual:
- case jpiGreaterOrEqual:
- Assert(status == jpdsNonDateTime);
- jspGetLeftArg(jpi, &arg);
- leftStatus = jspIsMutableWalker(&arg, cxt);
-
- jspGetRightArg(jpi, &arg);
- rightStatus = jspIsMutableWalker(&arg, cxt);
-
- /*
- * Comparison of datetime type with different timezone status
- * is mutable.
- */
- if (leftStatus != jpdsNonDateTime &&
- rightStatus != jpdsNonDateTime &&
- (leftStatus == jpdsUnknownDateTime ||
- rightStatus == jpdsUnknownDateTime ||
- leftStatus != rightStatus))
- cxt->mutable = true;
- break;
-
- case jpiNot:
- case jpiIsUnknown:
- case jpiExists:
- case jpiPlus:
- case jpiMinus:
- Assert(status == jpdsNonDateTime);
- jspGetArg(jpi, &arg);
- jspIsMutableWalker(&arg, cxt);
- break;
-
- case jpiAnd:
- case jpiOr:
- case jpiAdd:
- case jpiSub:
- case jpiMul:
- case jpiDiv:
- case jpiMod:
- case jpiStartsWith:
- Assert(status == jpdsNonDateTime);
- jspGetLeftArg(jpi, &arg);
- jspIsMutableWalker(&arg, cxt);
- jspGetRightArg(jpi, &arg);
- jspIsMutableWalker(&arg, cxt);
- break;
-
- case jpiIndexArray:
- for (int i = 0; i < jpi->content.array.nelems; i++)
- {
- JsonPathItem from;
- JsonPathItem to;
-
- if (jspGetArraySubscript(jpi, &from, &to, i))
- jspIsMutableWalker(&to, cxt);
-
- jspIsMutableWalker(&from, cxt);
- }
- /* FALLTHROUGH */
-
- case jpiAnyArray:
- if (!cxt->lax)
- status = jpdsNonDateTime;
- break;
-
- case jpiAny:
- if (jpi->content.anybounds.first > 0)
- status = jpdsNonDateTime;
- break;
-
- case jpiDatetime:
- if (jpi->content.arg)
- {
- char *template;
- int flags;
-
- jspGetArg(jpi, &arg);
- if (arg.type != jpiString)
- {
- status = jpdsNonDateTime;
- break; /* there will be runtime error */
- }
-
- template = jspGetString(&arg, NULL);
- flags = datetime_format_flags(template, NULL);
- if (flags & DCH_ZONED)
- status = jpdsDateTimeZoned;
- else
- status = jpdsDateTimeNonZoned;
- }
- else
- {
- status = jpdsUnknownDateTime;
- }
- break;
-
- case jpiLikeRegex:
- Assert(status == jpdsNonDateTime);
- jspInitByBuffer(&arg, jpi->base, jpi->content.like_regex.expr);
- jspIsMutableWalker(&arg, cxt);
- break;
-
- /* literals */
- case jpiNull:
- case jpiString:
- case jpiNumeric:
- case jpiBool:
- /* accessors */
- case jpiKey:
- case jpiAnyKey:
- /* special items */
- case jpiSubscript:
- case jpiLast:
- /* item methods */
- case jpiType:
- case jpiSize:
- case jpiAbs:
- case jpiFloor:
- case jpiCeiling:
- case jpiDouble:
- case jpiKeyValue:
- status = jpdsNonDateTime;
- break;
- }
-
- if (!jspGetNext(jpi, &next))
- break;
-
- jpi = &next;
- }
-
- return status;
-}
-
-/*
- * Check whether jsonpath expression is immutable or not.
- */
-bool
-jspIsMutable(JsonPath *path, List *varnames, List *varexprs)
-{
- JsonPathMutableContext cxt;
- JsonPathItem jpi;
-
- cxt.varnames = varnames;
- cxt.varexprs = varexprs;
- cxt.current = jpdsNonDateTime;
- cxt.lax = (path->header & JSONPATH_LAX) != 0;
- cxt.mutable = false;
-
- jspInit(&jpi, path);
- jspIsMutableWalker(&jpi, &cxt);
-
- return cxt.mutable;
-}
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
-#include "executor/execExpr.h"
#include "funcapi.h"
#include "lib/stringinfo.h"
#include "miscadmin.h"
-#include "nodes/nodeFuncs.h"
#include "regex/regex.h"
#include "utils/builtins.h"
#include "utils/date.h"
#include "utils/guc.h"
#include "utils/json.h"
#include "utils/jsonpath.h"
-#include "utils/lsyscache.h"
-#include "utils/memutils.h"
#include "utils/timestamp.h"
#include "utils/varlena.h"
int id;
} JsonBaseObjectInfo;
-typedef int (*JsonPathVarCallback) (void *vars, char *varName, int varNameLen,
- JsonbValue *val, JsonbValue *baseObject);
-
/*
* Context of jsonpath execution.
*/
typedef struct JsonPathExecContext
{
- void *vars; /* variables to substitute into jsonpath */
- JsonPathVarCallback getVar;
+ Jsonb *vars; /* variables to substitute into jsonpath */
JsonbValue *root; /* for $ evaluation */
JsonbValue *current; /* for @ evaluation */
JsonBaseObjectInfo baseObject; /* "base object" for .keyvalue()
ListCell *next;
} JsonValueListIterator;
-/* Structures for JSON_TABLE execution */
-typedef struct JsonTableScanState JsonTableScanState;
-typedef struct JsonTableJoinState JsonTableJoinState;
-
-struct JsonTableScanState
-{
- JsonTableScanState *parent;
- JsonTableJoinState *nested;
- MemoryContext mcxt;
- JsonPath *path;
- List *args;
- JsonValueList found;
- JsonValueListIterator iter;
- Datum current;
- int ordinal;
- bool currentIsNull;
- bool outerJoin;
- bool errorOnError;
- bool advanceNested;
- bool reset;
-};
-
-struct JsonTableJoinState
-{
- union
- {
- struct
- {
- JsonTableJoinState *left;
- JsonTableJoinState *right;
- bool cross;
- bool advanceRight;
- } join;
- JsonTableScanState scan;
- } u;
- bool is_join;
-};
-
-/* random number to identify JsonTableContext */
-#define JSON_TABLE_CONTEXT_MAGIC 418352867
-
-typedef struct JsonTableContext
-{
- int magic;
- struct
- {
- ExprState *expr;
- JsonTableScanState *scan;
- } *colexprs;
- JsonTableScanState root;
- bool empty;
-} JsonTableContext;
-
/* strict/lax flags is decomposed into four [un]wrap/error flags */
#define jspStrictAbsenseOfErrors(cxt) (!(cxt)->laxMode)
#define jspAutoUnwrap(cxt) ((cxt)->laxMode)
void *param);
typedef Numeric (*BinaryArithmFunc) (Numeric num1, Numeric num2, bool *error);
-static JsonPathExecResult executeJsonPath(JsonPath *path, void *vars,
- JsonPathVarCallback getVar,
+static JsonPathExecResult executeJsonPath(JsonPath *path, Jsonb *vars,
Jsonb *json, bool throwErrors,
JsonValueList *result, bool useTz);
static JsonPathExecResult executeItem(JsonPathExecContext *cxt,
static void getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item,
JsonbValue *value);
static void getJsonPathVariable(JsonPathExecContext *cxt,
- JsonPathItem *variable, JsonbValue *value);
-static int getJsonPathVariableFromJsonb(void *varsJsonb, char *varName,
- int varNameLen, JsonbValue *val,
- JsonbValue *baseObject);
+ JsonPathItem *variable, Jsonb *vars, JsonbValue *value);
static int JsonbArraySize(JsonbValue *jb);
static JsonPathBool executeComparison(JsonPathItem *cmp, JsonbValue *lv,
JsonbValue *rv, void *p);
JsonPathItem *jsp, JsonbValue *jb, int32 *index);
static JsonBaseObjectInfo setBaseObject(JsonPathExecContext *cxt,
JsonbValue *jbv, int32 id);
-static void JsonValueListClear(JsonValueList *jvl);
static void JsonValueListAppend(JsonValueList *jvl, JsonbValue *jbv);
static int JsonValueListLength(const JsonValueList *jvl);
static bool JsonValueListIsEmpty(JsonValueList *jvl);
static int compareDatetime(Datum val1, Oid typid1, Datum val2, Oid typid2,
bool useTz, bool *have_error);
-
-static JsonTableJoinState *JsonTableInitPlanState(JsonTableContext *cxt,
- Node *plan, JsonTableScanState *parent);
-static bool JsonTableNextRow(JsonTableScanState *scan);
-
-
/****************** User interface to JsonPath executor ********************/
/*
silent = PG_GETARG_BOOL(3);
}
- res = executeJsonPath(jp, vars, getJsonPathVariableFromJsonb,
- jb, !silent, NULL, tz);
+ res = executeJsonPath(jp, vars, jb, !silent, NULL, tz);
PG_FREE_IF_COPY(jb, 0);
PG_FREE_IF_COPY(jp, 1);
silent = PG_GETARG_BOOL(3);
}
- (void) executeJsonPath(jp, vars, getJsonPathVariableFromJsonb,
- jb, !silent, &found, tz);
+ (void) executeJsonPath(jp, vars, jb, !silent, &found, tz);
PG_FREE_IF_COPY(jb, 0);
PG_FREE_IF_COPY(jp, 1);
vars = PG_GETARG_JSONB_P_COPY(2);
silent = PG_GETARG_BOOL(3);
- (void) executeJsonPath(jp, vars, getJsonPathVariableFromJsonb,
- jb, !silent, &found, tz);
+ (void) executeJsonPath(jp, vars, jb, !silent, &found, tz);
funcctx->user_fctx = JsonValueListGetList(&found);
Jsonb *vars = PG_GETARG_JSONB_P(2);
bool silent = PG_GETARG_BOOL(3);
- (void) executeJsonPath(jp, vars, getJsonPathVariableFromJsonb,
- jb, !silent, &found, tz);
+ (void) executeJsonPath(jp, vars, jb, !silent, &found, tz);
PG_RETURN_JSONB_P(JsonbValueToJsonb(wrapItemsInArray(&found)));
}
Jsonb *vars = PG_GETARG_JSONB_P(2);
bool silent = PG_GETARG_BOOL(3);
- (void) executeJsonPath(jp, vars, getJsonPathVariableFromJsonb,
- jb, !silent, &found, tz);
+ (void) executeJsonPath(jp, vars, jb, !silent, &found, tz);
if (JsonValueListLength(&found) >= 1)
PG_RETURN_JSONB_P(JsonbValueToJsonb(JsonValueListHead(&found)));
* In other case it tries to find all the satisfied result items.
*/
static JsonPathExecResult
-executeJsonPath(JsonPath *path, void *vars, JsonPathVarCallback getVar,
- Jsonb *json, bool throwErrors, JsonValueList *result,
- bool useTz)
+executeJsonPath(JsonPath *path, Jsonb *vars, Jsonb *json, bool throwErrors,
+ JsonValueList *result, bool useTz)
{
JsonPathExecContext cxt;
JsonPathExecResult res;
if (!JsonbExtractScalar(&json->root, &jbv))
JsonbInitBinary(&jbv, json);
+ if (vars && !JsonContainerIsObject(&vars->root))
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("\"vars\" argument is not an object"),
+ errdetail("Jsonpath parameters should be encoded as key-value pairs of \"vars\" object.")));
+ }
+
cxt.vars = vars;
- cxt.getVar = getVar;
cxt.laxMode = (path->header & JSONPATH_LAX) != 0;
cxt.ignoreStructuralErrors = cxt.laxMode;
cxt.root = &jbv;
cxt.current = &jbv;
cxt.baseObject.jbc = NULL;
cxt.baseObject.id = 0;
- /* 1 + number of base objects in vars */
- cxt.lastGeneratedObjectId = 1 + getVar(vars, NULL, 0, NULL, NULL);
+ cxt.lastGeneratedObjectId = vars ? 2 : 1;
cxt.innermostArraySize = -1;
cxt.throwErrors = throwErrors;
cxt.useTz = useTz;
&value->val.string.len);
break;
case jpiVariable:
- getJsonPathVariable(cxt, item, value);
+ getJsonPathVariable(cxt, item, cxt->vars, value);
return;
default:
elog(ERROR, "unexpected jsonpath item type");
*/
static void
getJsonPathVariable(JsonPathExecContext *cxt, JsonPathItem *variable,
- JsonbValue *value)
+ Jsonb *vars, JsonbValue *value)
{
char *varName;
int varNameLength;
- JsonbValue baseObject;
- int baseObjectId;
-
- Assert(variable->type == jpiVariable);
- varName = jspGetString(variable, &varNameLength);
-
- if (!cxt->vars ||
- (baseObjectId = cxt->getVar(cxt->vars, varName, varNameLength, value,
- &baseObject)) < 0)
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("could not find jsonpath variable \"%s\"",
- pnstrdup(varName, varNameLength))));
-
- if (baseObjectId > 0)
- setBaseObject(cxt, &baseObject, baseObjectId);
-}
-
-static int
-getJsonPathVariableFromJsonb(void *varsJsonb, char *varName, int varNameLength,
- JsonbValue *value, JsonbValue *baseObject)
-{
- Jsonb *vars = varsJsonb;
JsonbValue tmp;
JsonbValue *v;
- if (!varName)
+ if (!vars)
{
- if (vars && !JsonContainerIsObject(&vars->root))
- {
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("\"vars\" argument is not an object"),
- errdetail("Jsonpath parameters should be encoded as key-value pairs of \"vars\" object.")));
- }
-
- return vars ? 1 : 0; /* count of base objects */
+ value->type = jbvNull;
+ return;
}
+ Assert(variable->type == jpiVariable);
+ varName = jspGetString(variable, &varNameLength);
tmp.type = jbvString;
tmp.val.string.val = varName;
tmp.val.string.len = varNameLength;
v = findJsonbValueFromContainer(&vars->root, JB_FOBJECT, &tmp);
- if (!v)
- return -1;
-
- *value = *v;
- pfree(v);
+ if (v)
+ {
+ *value = *v;
+ pfree(v);
+ }
+ else
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("could not find jsonpath variable \"%s\"",
+ pnstrdup(varName, varNameLength))));
+ }
- JsonbInitBinary(baseObject, vars);
- return 1;
+ JsonbInitBinary(&tmp, vars);
+ setBaseObject(cxt, &tmp, 1);
}
/**************** Support functions for JsonPath execution *****************/
return baseObject;
}
-static void
-JsonValueListClear(JsonValueList *jvl)
-{
- jvl->singleton = NULL;
- jvl->list = NULL;
-}
-
static void
JsonValueListAppend(JsonValueList *jvl, JsonbValue *jbv)
{
return DatumGetInt32(DirectFunctionCall2(cmpfunc, val1, val2));
}
-
-/********************Interface to pgsql's executor***************************/
-
-bool
-JsonPathExists(Datum jb, JsonPath *jp, List *vars, bool *error)
-{
- JsonPathExecResult res = executeJsonPath(jp, vars, EvalJsonPathVar,
- DatumGetJsonbP(jb), !error, NULL,
- true);
-
- Assert(error || !jperIsError(res));
-
- if (error && jperIsError(res))
- *error = true;
-
- return res == jperOk;
-}
-
-Datum
-JsonPathQuery(Datum jb, JsonPath *jp, JsonWrapper wrapper, bool *empty,
- bool *error, List *vars)
-{
- JsonbValue *first;
- bool wrap;
- JsonValueList found = {0};
- JsonPathExecResult res PG_USED_FOR_ASSERTS_ONLY;
- int count;
-
- res = executeJsonPath(jp, vars, EvalJsonPathVar, DatumGetJsonbP(jb), !error,
- &found, true);
-
- Assert(error || !jperIsError(res));
-
- if (error && jperIsError(res))
- {
- *error = true;
- *empty = false;
- return (Datum) 0;
- }
-
- count = JsonValueListLength(&found);
-
- first = count ? JsonValueListHead(&found) : NULL;
-
- if (!first)
- wrap = false;
- else if (wrapper == JSW_NONE)
- wrap = false;
- else if (wrapper == JSW_UNCONDITIONAL)
- wrap = true;
- else if (wrapper == JSW_CONDITIONAL)
- wrap = count > 1 ||
- IsAJsonbScalar(first) ||
- (first->type == jbvBinary &&
- JsonContainerIsScalar(first->val.binary.data));
- else
- {
- elog(ERROR, "unrecognized json wrapper %d", wrapper);
- wrap = false;
- }
-
- if (wrap)
- return JsonbPGetDatum(JsonbValueToJsonb(wrapItemsInArray(&found)));
-
- if (count > 1)
- {
- if (error)
- {
- *error = true;
- return (Datum) 0;
- }
-
- ereport(ERROR,
- (errcode(ERRCODE_MORE_THAN_ONE_SQL_JSON_ITEM),
- errmsg("JSON path expression in JSON_QUERY should return "
- "singleton item without wrapper"),
- errhint("Use WITH WRAPPER clause to wrap SQL/JSON item "
- "sequence into array.")));
- }
-
- if (first)
- return JsonbPGetDatum(JsonbValueToJsonb(first));
-
- *empty = true;
- return PointerGetDatum(NULL);
-}
-
-JsonbValue *
-JsonPathValue(Datum jb, JsonPath *jp, bool *empty, bool *error, List *vars)
-{
- JsonbValue *res;
- JsonValueList found = {0};
- JsonPathExecResult jper PG_USED_FOR_ASSERTS_ONLY;
- int count;
-
- jper = executeJsonPath(jp, vars, EvalJsonPathVar, DatumGetJsonbP(jb), !error,
- &found, true);
-
- Assert(error || !jperIsError(jper));
-
- if (error && jperIsError(jper))
- {
- *error = true;
- *empty = false;
- return NULL;
- }
-
- count = JsonValueListLength(&found);
-
- *empty = !count;
-
- if (*empty)
- return NULL;
-
- if (count > 1)
- {
- if (error)
- {
- *error = true;
- return NULL;
- }
-
- ereport(ERROR,
- (errcode(ERRCODE_MORE_THAN_ONE_SQL_JSON_ITEM),
- errmsg("JSON path expression in JSON_VALUE should return "
- "singleton scalar item")));
- }
-
- res = JsonValueListHead(&found);
-
- if (res->type == jbvBinary &&
- JsonContainerIsScalar(res->val.binary.data))
- JsonbExtractScalar(res->val.binary.data, res);
-
- if (!IsAJsonbScalar(res))
- {
- if (error)
- {
- *error = true;
- return NULL;
- }
-
- ereport(ERROR,
- (errcode(ERRCODE_SQL_JSON_SCALAR_REQUIRED),
- errmsg("JSON path expression in JSON_VALUE should return "
- "singleton scalar item")));
- }
-
- if (res->type == jbvNull)
- return NULL;
-
- return res;
-}
-
-static void
-JsonbValueInitNumericDatum(JsonbValue *jbv, Datum num)
-{
- jbv->type = jbvNumeric;
- jbv->val.numeric = DatumGetNumeric(num);
-}
-
-void
-JsonItemFromDatum(Datum val, Oid typid, int32 typmod, JsonbValue *res)
-{
- switch (typid)
- {
- case BOOLOID:
- res->type = jbvBool;
- res->val.boolean = DatumGetBool(val);
- break;
- case NUMERICOID:
- JsonbValueInitNumericDatum(res, val);
- break;
- case INT2OID:
- JsonbValueInitNumericDatum(res, DirectFunctionCall1(int2_numeric, val));
- break;
- case INT4OID:
- JsonbValueInitNumericDatum(res, DirectFunctionCall1(int4_numeric, val));
- break;
- case INT8OID:
- JsonbValueInitNumericDatum(res, DirectFunctionCall1(int8_numeric, val));
- break;
- case FLOAT4OID:
- JsonbValueInitNumericDatum(res, DirectFunctionCall1(float4_numeric, val));
- break;
- case FLOAT8OID:
- JsonbValueInitNumericDatum(res, DirectFunctionCall1(float8_numeric, val));
- break;
- case TEXTOID:
- case VARCHAROID:
- res->type = jbvString;
- res->val.string.val = VARDATA_ANY(val);
- res->val.string.len = VARSIZE_ANY_EXHDR(val);
- break;
- case DATEOID:
- case TIMEOID:
- case TIMETZOID:
- case TIMESTAMPOID:
- case TIMESTAMPTZOID:
- res->type = jbvDatetime;
- res->val.datetime.value = val;
- res->val.datetime.typid = typid;
- res->val.datetime.typmod = typmod;
- res->val.datetime.tz = 0;
- break;
- case JSONBOID:
- {
- JsonbValue *jbv = res;
- Jsonb *jb = DatumGetJsonbP(val);
-
- if (JsonContainerIsScalar(&jb->root))
- {
- bool result PG_USED_FOR_ASSERTS_ONLY;
-
- result = JsonbExtractScalar(&jb->root, jbv);
- Assert(result);
- }
- else
- JsonbInitBinary(jbv, jb);
- break;
- }
- case JSONOID:
- {
- text *txt = DatumGetTextP(val);
- char *str = text_to_cstring(txt);
- Jsonb *jb =
- DatumGetJsonbP(DirectFunctionCall1(jsonb_in,
- CStringGetDatum(str)));
-
- pfree(str);
-
- JsonItemFromDatum(JsonbPGetDatum(jb), JSONBOID, -1, res);
- break;
- }
- default:
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("only bool, numeric, and text types could be "
- "casted to supported jsonpath types.")));
- }
-}
-
-/************************ JSON_TABLE functions ***************************/
-
-/*
- * Returns private data from executor state. Ensure validity by check with
- * MAGIC number.
- */
-static inline JsonTableContext *
-GetJsonTableContext(TableFuncScanState *state, const char *fname)
-{
- JsonTableContext *result;
-
- if (!IsA(state, TableFuncScanState))
- elog(ERROR, "%s called with invalid TableFuncScanState", fname);
- result = (JsonTableContext *) state->opaque;
- if (result->magic != JSON_TABLE_CONTEXT_MAGIC)
- elog(ERROR, "%s called with invalid TableFuncScanState", fname);
-
- return result;
-}
-
-/* Recursively initialize JSON_TABLE scan state */
-static void
-JsonTableInitScanState(JsonTableContext *cxt, JsonTableScanState *scan,
- JsonTableParent *node, JsonTableScanState *parent,
- List *args, MemoryContext mcxt)
-{
- int i;
-
- scan->parent = parent;
- scan->outerJoin = node->outerJoin;
- scan->errorOnError = node->errorOnError;
- scan->path = DatumGetJsonPathP(node->path->constvalue);
- scan->args = args;
- scan->mcxt = AllocSetContextCreate(mcxt, "JsonTableContext",
- ALLOCSET_DEFAULT_SIZES);
- scan->nested = node->child ?
- JsonTableInitPlanState(cxt, node->child, scan) : NULL;
- scan->current = PointerGetDatum(NULL);
- scan->currentIsNull = true;
-
- for (i = node->colMin; i <= node->colMax; i++)
- cxt->colexprs[i].scan = scan;
-}
-
-/* Recursively initialize JSON_TABLE scan state */
-static JsonTableJoinState *
-JsonTableInitPlanState(JsonTableContext *cxt, Node *plan,
- JsonTableScanState *parent)
-{
- JsonTableJoinState *state = palloc0(sizeof(*state));
-
- if (IsA(plan, JsonTableSibling))
- {
- JsonTableSibling *join = castNode(JsonTableSibling, plan);
-
- state->is_join = true;
- state->u.join.cross = join->cross;
- state->u.join.left = JsonTableInitPlanState(cxt, join->larg, parent);
- state->u.join.right = JsonTableInitPlanState(cxt, join->rarg, parent);
- }
- else
- {
- JsonTableParent *node = castNode(JsonTableParent, plan);
-
- state->is_join = false;
-
- JsonTableInitScanState(cxt, &state->u.scan, node, parent,
- parent->args, parent->mcxt);
- }
-
- return state;
-}
-
-/*
- * JsonTableInitOpaque
- * Fill in TableFuncScanState->opaque for JsonTable processor
- */
-static void
-JsonTableInitOpaque(TableFuncScanState *state, int natts)
-{
- JsonTableContext *cxt;
- PlanState *ps = &state->ss.ps;
- TableFuncScan *tfs = castNode(TableFuncScan, ps->plan);
- TableFunc *tf = tfs->tablefunc;
- JsonExpr *ci = castNode(JsonExpr, tf->docexpr);
- JsonTableParent *root = castNode(JsonTableParent, tf->plan);
- List *args = NIL;
- ListCell *lc;
- int i;
-
- cxt = palloc0(sizeof(JsonTableContext));
- cxt->magic = JSON_TABLE_CONTEXT_MAGIC;
-
- if (ci->passing_values)
- {
- ListCell *exprlc;
- ListCell *namelc;
-
- forboth(exprlc, ci->passing_values,
- namelc, ci->passing_names)
- {
- Expr *expr = (Expr *) lfirst(exprlc);
- String *name = lfirst_node(String, namelc);
- JsonPathVariableEvalContext *var = palloc(sizeof(*var));
-
- var->name = pstrdup(name->sval);
- var->typid = exprType((Node *) expr);
- var->typmod = exprTypmod((Node *) expr);
- var->estate = ExecInitExpr(expr, ps);
- var->econtext = ps->ps_ExprContext;
- var->mcxt = CurrentMemoryContext;
- var->evaluated = false;
- var->value = (Datum) 0;
- var->isnull = true;
-
- args = lappend(args, var);
- }
- }
-
- cxt->colexprs = palloc(sizeof(*cxt->colexprs) *
- list_length(tf->colvalexprs));
-
- JsonTableInitScanState(cxt, &cxt->root, root, NULL, args,
- CurrentMemoryContext);
-
- i = 0;
-
- foreach(lc, tf->colvalexprs)
- {
- Expr *expr = lfirst(lc);
-
- cxt->colexprs[i].expr =
- ExecInitExprWithCaseValue(expr, ps,
- &cxt->colexprs[i].scan->current,
- &cxt->colexprs[i].scan->currentIsNull);
-
- i++;
- }
-
- state->opaque = cxt;
-}
-
-/* Reset scan iterator to the beginning of the item list */
-static void
-JsonTableRescan(JsonTableScanState *scan)
-{
- JsonValueListInitIterator(&scan->found, &scan->iter);
- scan->current = PointerGetDatum(NULL);
- scan->currentIsNull = true;
- scan->advanceNested = false;
- scan->ordinal = 0;
-}
-
-/* Reset context item of a scan, execute JSON path and reset a scan */
-static void
-JsonTableResetContextItem(JsonTableScanState *scan, Datum item)
-{
- MemoryContext oldcxt;
- JsonPathExecResult res;
- Jsonb *js = (Jsonb *) DatumGetJsonbP(item);
-
- JsonValueListClear(&scan->found);
-
- MemoryContextResetOnly(scan->mcxt);
-
- oldcxt = MemoryContextSwitchTo(scan->mcxt);
-
- res = executeJsonPath(scan->path, scan->args, EvalJsonPathVar, js,
- scan->errorOnError, &scan->found, false /* FIXME */ );
-
- MemoryContextSwitchTo(oldcxt);
-
- if (jperIsError(res))
- {
- Assert(!scan->errorOnError);
- JsonValueListClear(&scan->found); /* EMPTY ON ERROR case */
- }
-
- JsonTableRescan(scan);
-}
-
-/*
- * JsonTableSetDocument
- * Install the input document
- */
-static void
-JsonTableSetDocument(TableFuncScanState *state, Datum value)
-{
- JsonTableContext *cxt = GetJsonTableContext(state, "JsonTableSetDocument");
-
- JsonTableResetContextItem(&cxt->root, value);
-}
-
-/* Recursively reset scan and its child nodes */
-static void
-JsonTableRescanRecursive(JsonTableJoinState *state)
-{
- if (state->is_join)
- {
- JsonTableRescanRecursive(state->u.join.left);
- JsonTableRescanRecursive(state->u.join.right);
- state->u.join.advanceRight = false;
- }
- else
- {
- JsonTableRescan(&state->u.scan);
- if (state->u.scan.nested)
- JsonTableRescanRecursive(state->u.scan.nested);
- }
-}
-
-/*
- * Fetch next row from a cross/union joined scan.
- *
- * Returns false at the end of a scan, true otherwise.
- */
-static bool
-JsonTableNextJoinRow(JsonTableJoinState *state)
-{
- if (!state->is_join)
- return JsonTableNextRow(&state->u.scan);
-
- if (state->u.join.advanceRight)
- {
- /* fetch next inner row */
- if (JsonTableNextJoinRow(state->u.join.right))
- return true;
-
- /* inner rows are exhausted */
- if (state->u.join.cross)
- state->u.join.advanceRight = false; /* next outer row */
- else
- return false; /* end of scan */
- }
-
- while (!state->u.join.advanceRight)
- {
- /* fetch next outer row */
- bool left = JsonTableNextJoinRow(state->u.join.left);
-
- if (state->u.join.cross)
- {
- if (!left)
- return false; /* end of scan */
-
- JsonTableRescanRecursive(state->u.join.right);
-
- if (!JsonTableNextJoinRow(state->u.join.right))
- continue; /* next outer row */
-
- state->u.join.advanceRight = true; /* next inner row */
- }
- else if (!left)
- {
- if (!JsonTableNextJoinRow(state->u.join.right))
- return false; /* end of scan */
-
- state->u.join.advanceRight = true; /* next inner row */
- }
-
- break;
- }
-
- return true;
-}
-
-/* Recursively set 'reset' flag of scan and its child nodes */
-static void
-JsonTableJoinReset(JsonTableJoinState *state)
-{
- if (state->is_join)
- {
- JsonTableJoinReset(state->u.join.left);
- JsonTableJoinReset(state->u.join.right);
- state->u.join.advanceRight = false;
- }
- else
- {
- state->u.scan.reset = true;
- state->u.scan.advanceNested = false;
-
- if (state->u.scan.nested)
- JsonTableJoinReset(state->u.scan.nested);
- }
-}
-
-/*
- * Fetch next row from a simple scan with outer/inner joined nested subscans.
- *
- * Returns false at the end of a scan, true otherwise.
- */
-static bool
-JsonTableNextRow(JsonTableScanState *scan)
-{
- /* reset context item if requested */
- if (scan->reset)
- {
- Assert(!scan->parent->currentIsNull);
- JsonTableResetContextItem(scan, scan->parent->current);
- scan->reset = false;
- }
-
- if (scan->advanceNested)
- {
- /* fetch next nested row */
- scan->advanceNested = JsonTableNextJoinRow(scan->nested);
-
- if (scan->advanceNested)
- return true;
- }
-
- for (;;)
- {
- /* fetch next row */
- JsonbValue *jbv = JsonValueListNext(&scan->found, &scan->iter);
- MemoryContext oldcxt;
-
- if (!jbv)
- {
- scan->current = PointerGetDatum(NULL);
- scan->currentIsNull = true;
- return false; /* end of scan */
- }
-
- /* set current row item */
- oldcxt = MemoryContextSwitchTo(scan->mcxt);
- scan->current = JsonbPGetDatum(JsonbValueToJsonb(jbv));
- scan->currentIsNull = false;
- MemoryContextSwitchTo(oldcxt);
-
- scan->ordinal++;
-
- if (!scan->nested)
- break;
-
- JsonTableJoinReset(scan->nested);
-
- scan->advanceNested = JsonTableNextJoinRow(scan->nested);
-
- if (scan->advanceNested || scan->outerJoin)
- break;
- }
-
- return true;
-}
-
-/*
- * JsonTableFetchRow
- * Prepare the next "current" tuple for upcoming GetValue calls.
- * Returns FALSE if the row-filter expression returned no more rows.
- */
-static bool
-JsonTableFetchRow(TableFuncScanState *state)
-{
- JsonTableContext *cxt = GetJsonTableContext(state, "JsonTableFetchRow");
-
- if (cxt->empty)
- return false;
-
- return JsonTableNextRow(&cxt->root);
-}
-
-/*
- * JsonTableGetValue
- * Return the value for column number 'colnum' for the current row.
- *
- * This leaks memory, so be sure to reset often the context in which it's
- * called.
- */
-static Datum
-JsonTableGetValue(TableFuncScanState *state, int colnum,
- Oid typid, int32 typmod, bool *isnull)
-{
- JsonTableContext *cxt = GetJsonTableContext(state, "JsonTableGetValue");
- ExprContext *econtext = state->ss.ps.ps_ExprContext;
- ExprState *estate = cxt->colexprs[colnum].expr;
- JsonTableScanState *scan = cxt->colexprs[colnum].scan;
- Datum result;
-
- if (scan->currentIsNull) /* NULL from outer/union join */
- {
- result = (Datum) 0;
- *isnull = true;
- }
- else if (estate) /* regular column */
- {
- result = ExecEvalExpr(estate, econtext, isnull);
- }
- else
- {
- result = Int32GetDatum(scan->ordinal); /* ordinality column */
- *isnull = false;
- }
-
- return result;
-}
-
-/*
- * JsonTableDestroyOpaque
- */
-static void
-JsonTableDestroyOpaque(TableFuncScanState *state)
-{
- JsonTableContext *cxt = GetJsonTableContext(state, "JsonTableDestroyOpaque");
-
- /* not valid anymore */
- cxt->magic = 0;
-
- state->opaque = NULL;
-}
-
-const TableFuncRoutine JsonbTableRoutine =
-{
- JsonTableInitOpaque,
- JsonTableSetDocument,
- NULL,
- NULL,
- NULL,
- JsonTableFetchRow,
- JsonTableGetValue,
- JsonTableDestroyOpaque
-};
Node *parentNode);
static void get_const_expr(Const *constval, deparse_context *context,
int showtype);
-static void get_json_constructor(JsonConstructorExpr *ctor,
- deparse_context *context, bool showimplicit);
-static void get_json_agg_constructor(JsonConstructorExpr *ctor,
- deparse_context *context,
- const char *funcname,
- bool is_json_objectagg);
static void get_const_collation(Const *constval, deparse_context *context);
static void simple_quote_literal(StringInfo buf, const char *val);
static void get_sublink_expr(SubLink *sublink, deparse_context *context);
static text *string_to_text(char *str);
static char *flatten_reloptions(Oid relid);
static void get_reloptions(StringInfo buf, Datum reloptions);
-static void get_json_path_spec(Node *path_spec, deparse_context *context,
- bool showimplicit);
-static void get_json_table_columns(TableFunc *tf, JsonTableParent *node,
- deparse_context *context, bool showimplicit);
#define only_marker(rte) ((rte)->inh ? "" : "ONLY ")
bool need_paren = (PRETTY_PAREN(context)
|| IsA(expr, FuncExpr)
|| IsA(expr, Aggref)
- || IsA(expr, WindowFunc)
- || IsA(expr, JsonConstructorExpr));
+ || IsA(expr, WindowFunc));
if (need_paren)
appendStringInfoChar(context->buf, '(');
case T_GroupingFunc:
case T_WindowFunc:
case T_FuncExpr:
- case T_JsonConstructorExpr:
- case T_JsonExpr:
/* function-like: name(..) or name[..] */
return true;
case T_NullTest:
case T_BooleanTest:
case T_DistinctExpr:
- case T_JsonIsPredicate:
switch (nodeTag(parentNode))
{
case T_FuncExpr:
case T_GroupingFunc: /* own parentheses */
case T_WindowFunc: /* own parentheses */
case T_CaseExpr: /* other separators */
- case T_JsonExpr: /* own parentheses */
return true;
default:
return false;
return false;
}
- case T_JsonValueExpr:
- /* maybe simple, check args */
- return isSimpleNode((Node *) ((JsonValueExpr *) node)->raw_expr,
- node, prettyFlags);
-
default:
break;
}
}
-/*
- * get_json_path_spec - Parse back a JSON path specification
- */
-static void
-get_json_path_spec(Node *path_spec, deparse_context *context, bool showimplicit)
-{
- if (IsA(path_spec, Const))
- get_const_expr((Const *) path_spec, context, -1);
- else
- get_rule_expr(path_spec, context, showimplicit);
-}
-
-/*
- * get_json_format - Parse back a JsonFormat node
- */
-static void
-get_json_format(JsonFormat *format, StringInfo buf)
-{
- if (format->format_type == JS_FORMAT_DEFAULT)
- return;
-
- appendStringInfoString(buf,
- format->format_type == JS_FORMAT_JSONB ?
- " FORMAT JSONB" : " FORMAT JSON");
-
- if (format->encoding != JS_ENC_DEFAULT)
- {
- const char *encoding =
- format->encoding == JS_ENC_UTF16 ? "UTF16" :
- format->encoding == JS_ENC_UTF32 ? "UTF32" : "UTF8";
-
- appendStringInfo(buf, " ENCODING %s", encoding);
- }
-}
-
-/*
- * get_json_returning - Parse back a JsonReturning structure
- */
-static void
-get_json_returning(JsonReturning *returning, StringInfo buf,
- bool json_format_by_default)
-{
- if (!OidIsValid(returning->typid))
- return;
-
- appendStringInfo(buf, " RETURNING %s",
- format_type_with_typemod(returning->typid,
- returning->typmod));
-
- if (!json_format_by_default ||
- returning->format->format_type !=
- (returning->typid == JSONBOID ? JS_FORMAT_JSONB : JS_FORMAT_JSON))
- get_json_format(returning->format, buf);
-}
-
-static void
-get_json_behavior(JsonBehavior *behavior, deparse_context *context,
- const char *on)
-{
- /*
- * The order of array elements must correspond to the order of
- * JsonBehaviorType members.
- */
- const char *behavior_names[] =
- {
- " NULL",
- " ERROR",
- " EMPTY",
- " TRUE",
- " FALSE",
- " UNKNOWN",
- " EMPTY ARRAY",
- " EMPTY OBJECT",
- " DEFAULT "
- };
-
- if ((int) behavior->btype < 0 || behavior->btype >= lengthof(behavior_names))
- elog(ERROR, "invalid json behavior type: %d", behavior->btype);
-
- appendStringInfoString(context->buf, behavior_names[behavior->btype]);
-
- if (behavior->btype == JSON_BEHAVIOR_DEFAULT)
- get_rule_expr(behavior->default_expr, context, false);
-
- appendStringInfo(context->buf, " ON %s", on);
-}
-
-/*
- * get_json_expr_options
- *
- * Parse back common options for JSON_QUERY, JSON_VALUE, JSON_EXISTS and
- * JSON_TABLE columns.
- */
-static void
-get_json_expr_options(JsonExpr *jsexpr, deparse_context *context,
- JsonBehaviorType default_behavior)
-{
- if (jsexpr->op == JSON_QUERY_OP)
- {
- if (jsexpr->wrapper == JSW_CONDITIONAL)
- appendStringInfo(context->buf, " WITH CONDITIONAL WRAPPER");
- else if (jsexpr->wrapper == JSW_UNCONDITIONAL)
- appendStringInfo(context->buf, " WITH UNCONDITIONAL WRAPPER");
-
- if (jsexpr->omit_quotes)
- appendStringInfo(context->buf, " OMIT QUOTES");
- }
-
- if (jsexpr->op != JSON_EXISTS_OP &&
- jsexpr->on_empty->btype != default_behavior)
- get_json_behavior(jsexpr->on_empty, context, "EMPTY");
-
- if (jsexpr->on_error->btype != default_behavior)
- get_json_behavior(jsexpr->on_error, context, "ERROR");
-}
-
/* ----------
* get_rule_expr - Parse back an expression
*
}
break;
-
- case T_JsonValueExpr:
- {
- JsonValueExpr *jve = (JsonValueExpr *) node;
-
- get_rule_expr((Node *) jve->raw_expr, context, false);
- get_json_format(jve->format, context->buf);
- }
- break;
-
- case T_JsonConstructorExpr:
- get_json_constructor((JsonConstructorExpr *) node, context, false);
- break;
-
- case T_JsonIsPredicate:
- {
- JsonIsPredicate *pred = (JsonIsPredicate *) node;
-
- if (!PRETTY_PAREN(context))
- appendStringInfoChar(context->buf, '(');
-
- get_rule_expr_paren(pred->expr, context, true, node);
-
- appendStringInfoString(context->buf, " IS JSON");
-
- /* TODO: handle FORMAT clause */
-
- switch (pred->item_type)
- {
- case JS_TYPE_SCALAR:
- appendStringInfoString(context->buf, " SCALAR");
- break;
- case JS_TYPE_ARRAY:
- appendStringInfoString(context->buf, " ARRAY");
- break;
- case JS_TYPE_OBJECT:
- appendStringInfoString(context->buf, " OBJECT");
- break;
- default:
- break;
- }
-
- if (pred->unique_keys)
- appendStringInfoString(context->buf, " WITH UNIQUE KEYS");
-
- if (!PRETTY_PAREN(context))
- appendStringInfoChar(context->buf, ')');
- }
- break;
-
- case T_JsonExpr:
- {
- JsonExpr *jexpr = (JsonExpr *) node;
-
- switch (jexpr->op)
- {
- case JSON_QUERY_OP:
- appendStringInfoString(buf, "JSON_QUERY(");
- break;
- case JSON_VALUE_OP:
- appendStringInfoString(buf, "JSON_VALUE(");
- break;
- case JSON_EXISTS_OP:
- appendStringInfoString(buf, "JSON_EXISTS(");
- break;
- default:
- elog(ERROR, "unexpected JsonExpr type: %d", jexpr->op);
- break;
- }
-
- get_rule_expr(jexpr->formatted_expr, context, showimplicit);
-
- appendStringInfoString(buf, ", ");
-
- get_json_path_spec(jexpr->path_spec, context, showimplicit);
-
- if (jexpr->passing_values)
- {
- ListCell *lc1,
- *lc2;
- bool needcomma = false;
-
- appendStringInfoString(buf, " PASSING ");
-
- forboth(lc1, jexpr->passing_names,
- lc2, jexpr->passing_values)
- {
- if (needcomma)
- appendStringInfoString(buf, ", ");
- needcomma = true;
-
- get_rule_expr((Node *) lfirst(lc2), context, showimplicit);
- appendStringInfo(buf, " AS %s",
- ((String *) lfirst_node(String, lc1))->sval);
- }
- }
-
- if (jexpr->op != JSON_EXISTS_OP ||
- jexpr->returning->typid != BOOLOID)
- get_json_returning(jexpr->returning, context->buf,
- jexpr->op == JSON_QUERY_OP);
-
- get_json_expr_options(jexpr, context,
- jexpr->op == JSON_EXISTS_OP ?
- JSON_BEHAVIOR_FALSE : JSON_BEHAVIOR_NULL);
-
- appendStringInfoString(buf, ")");
- }
- break;
-
case T_List:
{
char *sep;
case T_MinMaxExpr:
case T_SQLValueFunction:
case T_XmlExpr:
- case T_JsonExpr:
/* these are all accepted by func_expr_common_subexpr */
return true;
default:
appendStringInfoChar(buf, ')');
}
-static void
-get_json_constructor_options(JsonConstructorExpr *ctor, StringInfo buf)
-{
- if (ctor->absent_on_null)
- {
- if (ctor->type == JSCTOR_JSON_OBJECT ||
- ctor->type == JSCTOR_JSON_OBJECTAGG)
- appendStringInfoString(buf, " ABSENT ON NULL");
- }
- else
- {
- if (ctor->type == JSCTOR_JSON_ARRAY ||
- ctor->type == JSCTOR_JSON_ARRAYAGG)
- appendStringInfoString(buf, " NULL ON NULL");
- }
-
- if (ctor->unique)
- appendStringInfoString(buf, " WITH UNIQUE KEYS");
-
- if (!((ctor->type == JSCTOR_JSON_PARSE ||
- ctor->type == JSCTOR_JSON_SCALAR) &&
- ctor->returning->typid == JSONOID))
- get_json_returning(ctor->returning, buf, true);
-}
-
-static void
-get_json_constructor(JsonConstructorExpr *ctor, deparse_context *context,
- bool showimplicit)
-{
- StringInfo buf = context->buf;
- const char *funcname;
- int nargs;
- ListCell *lc;
-
- switch (ctor->type)
- {
- case JSCTOR_JSON_PARSE:
- funcname = "JSON";
- break;
- case JSCTOR_JSON_SCALAR:
- funcname = "JSON_SCALAR";
- break;
- case JSCTOR_JSON_SERIALIZE:
- funcname = "JSON_SERIALIZE";
- break;
- case JSCTOR_JSON_OBJECT:
- funcname = "JSON_OBJECT";
- break;
- case JSCTOR_JSON_ARRAY:
- funcname = "JSON_ARRAY";
- break;
- case JSCTOR_JSON_OBJECTAGG:
- get_json_agg_constructor(ctor, context, "JSON_OBJECTAGG", true);
- return;
- case JSCTOR_JSON_ARRAYAGG:
- get_json_agg_constructor(ctor, context, "JSON_ARRAYAGG", false);
- return;
- default:
- elog(ERROR, "invalid JsonConstructorExprType %d", ctor->type);
- }
-
- appendStringInfo(buf, "%s(", funcname);
-
- nargs = 0;
- foreach(lc, ctor->args)
- {
- if (nargs > 0)
- {
- const char *sep = ctor->type == JSCTOR_JSON_OBJECT &&
- (nargs % 2) != 0 ? " : " : ", ";
-
- appendStringInfoString(buf, sep);
- }
-
- get_rule_expr((Node *) lfirst(lc), context, true);
-
- nargs++;
- }
-
- get_json_constructor_options(ctor, buf);
-
- appendStringInfo(buf, ")");
-}
-
-
/*
- * get_agg_expr_helper - Parse back an Aggref node
+ * get_agg_expr - Parse back an Aggref node
*/
static void
-get_agg_expr_helper(Aggref *aggref, deparse_context *context,
- Aggref *original_aggref, const char *funcname,
- const char *options, bool is_json_objectagg)
+get_agg_expr(Aggref *aggref, deparse_context *context,
+ Aggref *original_aggref)
{
StringInfo buf = context->buf;
Oid argtypes[FUNC_MAX_ARGS];
int nargs;
- bool use_variadic = false;
+ bool use_variadic;
/*
* For a combining aggregate, we look up and deparse the corresponding
/* Extract the argument types as seen by the parser */
nargs = get_aggregate_argtypes(aggref, argtypes);
- if (!funcname)
- funcname = generate_function_name(aggref->aggfnoid, nargs, NIL,
- argtypes, aggref->aggvariadic,
- &use_variadic,
- context->special_exprkind);
-
/* Print the aggregate name, schema-qualified if needed */
- appendStringInfo(buf, "%s(%s", funcname,
+ appendStringInfo(buf, "%s(%s",
+ generate_function_name(aggref->aggfnoid, nargs,
+ NIL, argtypes,
+ aggref->aggvariadic,
+ &use_variadic,
+ context->special_exprkind),
(aggref->aggdistinct != NIL) ? "DISTINCT " : "");
if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
if (tle->resjunk)
continue;
if (i++ > 0)
- {
- if (is_json_objectagg)
- {
- if (i > 2)
- break; /* skip ABSENT ON NULL and WITH UNIQUE
- * args */
-
- appendStringInfoString(buf, " : ");
- }
- else
- appendStringInfoString(buf, ", ");
- }
+ appendStringInfoString(buf, ", ");
if (use_variadic && i == nargs)
appendStringInfoString(buf, "VARIADIC ");
get_rule_expr(arg, context, true);
}
}
- if (options)
- appendStringInfoString(buf, options);
-
if (aggref->aggfilter != NULL)
{
appendStringInfoString(buf, ") FILTER (WHERE ");
appendStringInfoChar(buf, ')');
}
-/*
- * get_agg_expr - Parse back an Aggref node
- */
-static void
-get_agg_expr(Aggref *aggref, deparse_context *context, Aggref *original_aggref)
-{
- get_agg_expr_helper(aggref, context, original_aggref, NULL, NULL,
- false);
-}
-
/*
* This is a helper function for get_agg_expr(). It's used when we deparse
* a combining Aggref; resolve_special_varno locates the corresponding partial
}
/*
- * get_windowfunc_expr_helper - Parse back a WindowFunc node
+ * get_windowfunc_expr - Parse back a WindowFunc node
*/
static void
-get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context,
- const char *funcname, const char *options,
- bool is_json_objectagg)
+get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
{
StringInfo buf = context->buf;
Oid argtypes[FUNC_MAX_ARGS];
nargs++;
}
- if (!funcname)
- funcname = generate_function_name(wfunc->winfnoid, nargs, argnames,
- argtypes, false, NULL,
- context->special_exprkind);
-
- appendStringInfo(buf, "%s(", funcname);
-
+ appendStringInfo(buf, "%s(",
+ generate_function_name(wfunc->winfnoid, nargs,
+ argnames, argtypes,
+ false, NULL,
+ context->special_exprkind));
/* winstar can be set only in zero-argument aggregates */
if (wfunc->winstar)
appendStringInfoChar(buf, '*');
else
- {
- if (is_json_objectagg)
- {
- get_rule_expr((Node *) linitial(wfunc->args), context, false);
- appendStringInfoString(buf, " : ");
- get_rule_expr((Node *) lsecond(wfunc->args), context, false);
- }
- else
- get_rule_expr((Node *) wfunc->args, context, true);
- }
-
- if (options)
- appendStringInfoString(buf, options);
+ get_rule_expr((Node *) wfunc->args, context, true);
if (wfunc->aggfilter != NULL)
{
}
}
-/*
- * get_windowfunc_expr - Parse back a WindowFunc node
- */
-static void
-get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
-{
- get_windowfunc_expr_helper(wfunc, context, NULL, NULL, false);
-}
-
/*
* get_func_sql_syntax - Parse back a SQL-syntax function call
*
return false;
}
-/*
- * get_json_agg_constructor - Parse back an aggregate JsonConstructorExpr node
- */
-static void
-get_json_agg_constructor(JsonConstructorExpr *ctor, deparse_context *context,
- const char *funcname, bool is_json_objectagg)
-{
- StringInfoData options;
-
- initStringInfo(&options);
- get_json_constructor_options(ctor, &options);
-
- if (IsA(ctor->func, Aggref))
- get_agg_expr_helper((Aggref *) ctor->func, context,
- (Aggref *) ctor->func,
- funcname, options.data, is_json_objectagg);
- else if (IsA(ctor->func, WindowFunc))
- get_windowfunc_expr_helper((WindowFunc *) ctor->func, context,
- funcname, options.data,
- is_json_objectagg);
- else
- elog(ERROR, "invalid JsonConstructorExpr underlying node type: %d",
- nodeTag(ctor->func));
-}
-
/* ----------
* get_coercion_expr
*
/* ----------
- * get_xmltable - Parse back a XMLTABLE function
+ * get_tablefunc - Parse back a table function
* ----------
*/
static void
-get_xmltable(TableFunc *tf, deparse_context *context, bool showimplicit)
+get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
{
StringInfo buf = context->buf;
+ /* XMLTABLE is the only existing implementation. */
+
appendStringInfoString(buf, "XMLTABLE(");
if (tf->ns_uris != NIL)
appendStringInfoChar(buf, ')');
}
-/*
- * get_json_nested_columns - Parse back nested JSON_TABLE columns
- */
-static void
-get_json_table_nested_columns(TableFunc *tf, Node *node,
- deparse_context *context, bool showimplicit,
- bool needcomma)
-{
- if (IsA(node, JsonTableSibling))
- {
- JsonTableSibling *n = (JsonTableSibling *) node;
-
- get_json_table_nested_columns(tf, n->larg, context, showimplicit,
- needcomma);
- get_json_table_nested_columns(tf, n->rarg, context, showimplicit, true);
- }
- else
- {
- JsonTableParent *n = castNode(JsonTableParent, node);
-
- if (needcomma)
- appendStringInfoChar(context->buf, ',');
-
- appendStringInfoChar(context->buf, ' ');
- appendContextKeyword(context, "NESTED PATH ", 0, 0, 0);
- get_const_expr(n->path, context, -1);
- appendStringInfo(context->buf, " AS %s", quote_identifier(n->name));
- get_json_table_columns(tf, n, context, showimplicit);
- }
-}
-
-/*
- * get_json_table_plan - Parse back a JSON_TABLE plan
- */
-static void
-get_json_table_plan(TableFunc *tf, Node *node, deparse_context *context,
- bool parenthesize)
-{
- if (parenthesize)
- appendStringInfoChar(context->buf, '(');
-
- if (IsA(node, JsonTableSibling))
- {
- JsonTableSibling *n = (JsonTableSibling *) node;
-
- get_json_table_plan(tf, n->larg, context,
- IsA(n->larg, JsonTableSibling) ||
- castNode(JsonTableParent, n->larg)->child);
-
- appendStringInfoString(context->buf, n->cross ? " CROSS " : " UNION ");
-
- get_json_table_plan(tf, n->rarg, context,
- IsA(n->rarg, JsonTableSibling) ||
- castNode(JsonTableParent, n->rarg)->child);
- }
- else
- {
- JsonTableParent *n = castNode(JsonTableParent, node);
-
- appendStringInfoString(context->buf, quote_identifier(n->name));
-
- if (n->child)
- {
- appendStringInfoString(context->buf,
- n->outerJoin ? " OUTER " : " INNER ");
- get_json_table_plan(tf, n->child, context,
- IsA(n->child, JsonTableSibling));
- }
- }
-
- if (parenthesize)
- appendStringInfoChar(context->buf, ')');
-}
-
-/*
- * get_json_table_columns - Parse back JSON_TABLE columns
- */
-static void
-get_json_table_columns(TableFunc *tf, JsonTableParent *node,
- deparse_context *context, bool showimplicit)
-{
- StringInfo buf = context->buf;
- JsonExpr *jexpr = castNode(JsonExpr, tf->docexpr);
- ListCell *lc_colname;
- ListCell *lc_coltype;
- ListCell *lc_coltypmod;
- ListCell *lc_colvarexpr;
- int colnum = 0;
-
- appendStringInfoChar(buf, ' ');
- appendContextKeyword(context, "COLUMNS (", 0, 0, 0);
-
- if (PRETTY_INDENT(context))
- context->indentLevel += PRETTYINDENT_VAR;
-
- forfour(lc_colname, tf->colnames,
- lc_coltype, tf->coltypes,
- lc_coltypmod, tf->coltypmods,
- lc_colvarexpr, tf->colvalexprs)
- {
- char *colname = strVal(lfirst(lc_colname));
- JsonExpr *colexpr;
- Oid typid;
- int32 typmod;
- bool ordinality;
- JsonBehaviorType default_behavior;
-
- typid = lfirst_oid(lc_coltype);
- typmod = lfirst_int(lc_coltypmod);
- colexpr = castNode(JsonExpr, lfirst(lc_colvarexpr));
-
- if (colnum < node->colMin)
- {
- colnum++;
- continue;
- }
-
- if (colnum > node->colMax)
- break;
-
- if (colnum > node->colMin)
- appendStringInfoString(buf, ", ");
-
- colnum++;
-
- ordinality = !colexpr;
-
- appendContextKeyword(context, "", 0, 0, 0);
-
- appendStringInfo(buf, "%s %s", quote_identifier(colname),
- ordinality ? "FOR ORDINALITY" :
- format_type_with_typemod(typid, typmod));
- if (ordinality)
- continue;
-
- if (colexpr->op == JSON_EXISTS_OP)
- {
- appendStringInfoString(buf, " EXISTS");
- default_behavior = JSON_BEHAVIOR_FALSE;
- }
- else
- {
- if (colexpr->op == JSON_QUERY_OP)
- {
- char typcategory;
- bool typispreferred;
-
- get_type_category_preferred(typid, &typcategory, &typispreferred);
-
- if (typcategory == TYPCATEGORY_STRING)
- appendStringInfoString(buf,
- colexpr->format->format_type == JS_FORMAT_JSONB ?
- " FORMAT JSONB" : " FORMAT JSON");
- }
-
- default_behavior = JSON_BEHAVIOR_NULL;
- }
-
- if (jexpr->on_error->btype == JSON_BEHAVIOR_ERROR)
- default_behavior = JSON_BEHAVIOR_ERROR;
-
- appendStringInfoString(buf, " PATH ");
-
- get_json_path_spec(colexpr->path_spec, context, showimplicit);
-
- get_json_expr_options(colexpr, context, default_behavior);
- }
-
- if (node->child)
- get_json_table_nested_columns(tf, node->child, context, showimplicit,
- node->colMax >= node->colMin);
-
- if (PRETTY_INDENT(context))
- context->indentLevel -= PRETTYINDENT_VAR;
-
- appendContextKeyword(context, ")", 0, 0, 0);
-}
-
-/* ----------
- * get_json_table - Parse back a JSON_TABLE function
- * ----------
- */
-static void
-get_json_table(TableFunc *tf, deparse_context *context, bool showimplicit)
-{
- StringInfo buf = context->buf;
- JsonExpr *jexpr = castNode(JsonExpr, tf->docexpr);
- JsonTableParent *root = castNode(JsonTableParent, tf->plan);
-
- appendStringInfoString(buf, "JSON_TABLE(");
-
- if (PRETTY_INDENT(context))
- context->indentLevel += PRETTYINDENT_VAR;
-
- appendContextKeyword(context, "", 0, 0, 0);
-
- get_rule_expr(jexpr->formatted_expr, context, showimplicit);
-
- appendStringInfoString(buf, ", ");
-
- get_const_expr(root->path, context, -1);
-
- appendStringInfo(buf, " AS %s", quote_identifier(root->name));
-
- if (jexpr->passing_values)
- {
- ListCell *lc1,
- *lc2;
- bool needcomma = false;
-
- appendStringInfoChar(buf, ' ');
- appendContextKeyword(context, "PASSING ", 0, 0, 0);
-
- if (PRETTY_INDENT(context))
- context->indentLevel += PRETTYINDENT_VAR;
-
- forboth(lc1, jexpr->passing_names,
- lc2, jexpr->passing_values)
- {
- if (needcomma)
- appendStringInfoString(buf, ", ");
- needcomma = true;
-
- appendContextKeyword(context, "", 0, 0, 0);
-
- get_rule_expr((Node *) lfirst(lc2), context, false);
- appendStringInfo(buf, " AS %s",
- quote_identifier((lfirst_node(String, lc1))->sval)
- );
- }
-
- if (PRETTY_INDENT(context))
- context->indentLevel -= PRETTYINDENT_VAR;
- }
-
- get_json_table_columns(tf, root, context, showimplicit);
-
- appendStringInfoChar(buf, ' ');
- appendContextKeyword(context, "PLAN ", 0, 0, 0);
- get_json_table_plan(tf, (Node *) root, context, true);
-
- if (jexpr->on_error->btype != JSON_BEHAVIOR_EMPTY)
- get_json_behavior(jexpr->on_error, context, "ERROR");
-
- if (PRETTY_INDENT(context))
- context->indentLevel -= PRETTYINDENT_VAR;
-
- appendContextKeyword(context, ")", 0, 0, 0);
-}
-
-/* ----------
- * get_tablefunc - Parse back a table function
- * ----------
- */
-static void
-get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
-{
- /* XMLTABLE and JSON_TABLE are the only existing implementations. */
-
- if (tf->functype == TFT_XMLTABLE)
- get_xmltable(tf, context, showimplicit);
- else if (tf->functype == TFT_JSON_TABLE)
- get_json_table(tf, context, showimplicit);
-}
-
/* ----------
* get_from_clause - Parse back a FROM clause
*
JumbleExpr(jstate, (Node *) conf->exclRelTlist);
}
break;
- case T_JsonFormat:
- {
- JsonFormat *format = (JsonFormat *) node;
-
- APP_JUMB(format->format_type);
- APP_JUMB(format->encoding);
- }
- break;
- case T_JsonReturning:
- {
- JsonReturning *returning = (JsonReturning *) node;
-
- JumbleExpr(jstate, (Node *) returning->format);
- APP_JUMB(returning->typid);
- APP_JUMB(returning->typmod);
- }
- break;
- case T_JsonValueExpr:
- {
- JsonValueExpr *expr = (JsonValueExpr *) node;
-
- JumbleExpr(jstate, (Node *) expr->raw_expr);
- JumbleExpr(jstate, (Node *) expr->formatted_expr);
- JumbleExpr(jstate, (Node *) expr->format);
- }
- break;
- case T_JsonConstructorExpr:
- {
- JsonConstructorExpr *ctor = (JsonConstructorExpr *) node;
-
- APP_JUMB(ctor->type);
- JumbleExpr(jstate, (Node *) ctor->args);
- JumbleExpr(jstate, (Node *) ctor->func);
- JumbleExpr(jstate, (Node *) ctor->coercion);
- JumbleExpr(jstate, (Node *) ctor->returning);
- APP_JUMB(ctor->absent_on_null);
- APP_JUMB(ctor->unique);
- }
- break;
- case T_JsonIsPredicate:
- {
- JsonIsPredicate *pred = (JsonIsPredicate *) node;
-
- JumbleExpr(jstate, (Node *) pred->expr);
- JumbleExpr(jstate, (Node *) pred->format);
- APP_JUMB(pred->item_type);
- APP_JUMB(pred->unique_keys);
- }
- break;
- case T_JsonExpr:
- {
- JsonExpr *jexpr = (JsonExpr *) node;
-
- APP_JUMB(jexpr->op);
- JumbleExpr(jstate, jexpr->formatted_expr);
- JumbleExpr(jstate, jexpr->path_spec);
- foreach(temp, jexpr->passing_names)
- {
- APP_JUMB_STRING(lfirst_node(String, temp)->sval);
- }
- JumbleExpr(jstate, (Node *) jexpr->passing_values);
- if (jexpr->on_empty)
- {
- APP_JUMB(jexpr->on_empty->btype);
- JumbleExpr(jstate, jexpr->on_empty->default_expr);
- }
- APP_JUMB(jexpr->on_error->btype);
- JumbleExpr(jstate, jexpr->on_error->default_expr);
- }
- break;
case T_List:
foreach(temp, (List *) node)
{
{
TableFunc *tablefunc = (TableFunc *) node;
- APP_JUMB(tablefunc->functype);
JumbleExpr(jstate, tablefunc->docexpr);
JumbleExpr(jstate, tablefunc->rowexpr);
JumbleExpr(jstate, (Node *) tablefunc->colexprs);
- JumbleExpr(jstate, (Node *) tablefunc->colvalexprs);
}
break;
case T_TableSampleClause:
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 202208251
+#define CATALOG_VERSION_NO 202209011
#endif
# json
{ aggfnoid => 'json_agg', aggtransfn => 'json_agg_transfn',
aggfinalfn => 'json_agg_finalfn', aggtranstype => 'internal' },
-{ aggfnoid => 'json_agg_strict', aggtransfn => 'json_agg_strict_transfn',
- aggfinalfn => 'json_agg_finalfn', aggtranstype => 'internal' },
{ aggfnoid => 'json_object_agg', aggtransfn => 'json_object_agg_transfn',
aggfinalfn => 'json_object_agg_finalfn', aggtranstype => 'internal' },
-{ aggfnoid => 'json_object_agg_unique',
- aggtransfn => 'json_object_agg_unique_transfn',
- aggfinalfn => 'json_object_agg_finalfn', aggtranstype => 'internal' },
-{ aggfnoid => 'json_object_agg_strict',
- aggtransfn => 'json_object_agg_strict_transfn',
- aggfinalfn => 'json_object_agg_finalfn', aggtranstype => 'internal' },
-{ aggfnoid => 'json_object_agg_unique_strict',
- aggtransfn => 'json_object_agg_unique_strict_transfn',
- aggfinalfn => 'json_object_agg_finalfn', aggtranstype => 'internal' },
# jsonb
{ aggfnoid => 'jsonb_agg', aggtransfn => 'jsonb_agg_transfn',
aggfinalfn => 'jsonb_agg_finalfn', aggtranstype => 'internal' },
-{ aggfnoid => 'jsonb_agg_strict', aggtransfn => 'jsonb_agg_strict_transfn',
- aggfinalfn => 'jsonb_agg_finalfn', aggtranstype => 'internal' },
{ aggfnoid => 'jsonb_object_agg', aggtransfn => 'jsonb_object_agg_transfn',
aggfinalfn => 'jsonb_object_agg_finalfn', aggtranstype => 'internal' },
-{ aggfnoid => 'jsonb_object_agg_unique',
- aggtransfn => 'jsonb_object_agg_unique_transfn',
- aggfinalfn => 'jsonb_object_agg_finalfn', aggtranstype => 'internal' },
-{ aggfnoid => 'jsonb_object_agg_strict',
- aggtransfn => 'jsonb_object_agg_strict_transfn',
- aggfinalfn => 'jsonb_object_agg_finalfn', aggtranstype => 'internal' },
-{ aggfnoid => 'jsonb_object_agg_unique_strict',
- aggtransfn => 'jsonb_object_agg_unique_strict_transfn',
- aggfinalfn => 'jsonb_object_agg_finalfn', aggtranstype => 'internal' },
# ordered-set and hypothetical-set aggregates
{ aggfnoid => 'percentile_disc(float8,anyelement)', aggkind => 'o',
proname => 'json_agg_transfn', proisstrict => 'f', provolatile => 's',
prorettype => 'internal', proargtypes => 'internal anyelement',
prosrc => 'json_agg_transfn' },
-{ oid => '6208', descr => 'json aggregate transition function',
- proname => 'json_agg_strict_transfn', proisstrict => 'f', provolatile => 's',
- prorettype => 'internal', proargtypes => 'internal anyelement',
- prosrc => 'json_agg_strict_transfn' },
{ oid => '3174', descr => 'json aggregate final function',
proname => 'json_agg_finalfn', proisstrict => 'f', prorettype => 'json',
proargtypes => 'internal', prosrc => 'json_agg_finalfn' },
proname => 'json_agg', prokind => 'a', proisstrict => 'f', provolatile => 's',
prorettype => 'json', proargtypes => 'anyelement',
prosrc => 'aggregate_dummy' },
-{ oid => '6209', descr => 'aggregate input into json',
- proname => 'json_agg_strict', prokind => 'a', proisstrict => 'f',
- provolatile => 's', prorettype => 'json', proargtypes => 'anyelement',
- prosrc => 'aggregate_dummy' },
{ oid => '3180', descr => 'json object aggregate transition function',
proname => 'json_object_agg_transfn', proisstrict => 'f', provolatile => 's',
prorettype => 'internal', proargtypes => 'internal any any',
prosrc => 'json_object_agg_transfn' },
-{ oid => '6210', descr => 'json object aggregate transition function',
- proname => 'json_object_agg_strict_transfn', proisstrict => 'f',
- provolatile => 's', prorettype => 'internal',
- proargtypes => 'internal any any',
- prosrc => 'json_object_agg_strict_transfn' },
-{ oid => '6211', descr => 'json object aggregate transition function',
- proname => 'json_object_agg_unique_transfn', proisstrict => 'f',
- provolatile => 's', prorettype => 'internal',
- proargtypes => 'internal any any',
- prosrc => 'json_object_agg_unique_transfn' },
-{ oid => '6212', descr => 'json object aggregate transition function',
- proname => 'json_object_agg_unique_strict_transfn', proisstrict => 'f',
- provolatile => 's', prorettype => 'internal',
- proargtypes => 'internal any any',
- prosrc => 'json_object_agg_unique_strict_transfn' },
{ oid => '3196', descr => 'json object aggregate final function',
proname => 'json_object_agg_finalfn', proisstrict => 'f',
prorettype => 'json', proargtypes => 'internal',
proname => 'json_object_agg', prokind => 'a', proisstrict => 'f',
provolatile => 's', prorettype => 'json', proargtypes => 'any any',
prosrc => 'aggregate_dummy' },
-{ oid => '6213', descr => 'aggregate non-NULL input into a json object',
- proname => 'json_object_agg_strict', prokind => 'a', proisstrict => 'f',
- provolatile => 's', prorettype => 'json', proargtypes => 'any any',
- prosrc => 'aggregate_dummy' },
-{ oid => '6214',
- descr => 'aggregate input into a json object with unique keys',
- proname => 'json_object_agg_unique', prokind => 'a', proisstrict => 'f',
- provolatile => 's', prorettype => 'json', proargtypes => 'any any',
- prosrc => 'aggregate_dummy' },
-{ oid => '6215',
- descr => 'aggregate non-NULL input into a json object with unique keys',
- proname => 'json_object_agg_unique_strict', prokind => 'a',
- proisstrict => 'f', provolatile => 's', prorettype => 'json',
- proargtypes => 'any any', prosrc => 'aggregate_dummy' },
{ oid => '3198', descr => 'build a json array from any inputs',
proname => 'json_build_array', provariadic => 'any', proisstrict => 'f',
provolatile => 's', prorettype => 'json', proargtypes => 'any',
proname => 'jsonb_agg_transfn', proisstrict => 'f', provolatile => 's',
prorettype => 'internal', proargtypes => 'internal anyelement',
prosrc => 'jsonb_agg_transfn' },
-{ oid => '6216', descr => 'jsonb aggregate transition function',
- proname => 'jsonb_agg_strict_transfn', proisstrict => 'f', provolatile => 's',
- prorettype => 'internal', proargtypes => 'internal anyelement',
- prosrc => 'jsonb_agg_strict_transfn' },
{ oid => '3266', descr => 'jsonb aggregate final function',
proname => 'jsonb_agg_finalfn', proisstrict => 'f', provolatile => 's',
prorettype => 'jsonb', proargtypes => 'internal',
proname => 'jsonb_agg', prokind => 'a', proisstrict => 'f',
provolatile => 's', prorettype => 'jsonb', proargtypes => 'anyelement',
prosrc => 'aggregate_dummy' },
-{ oid => '6217', descr => 'aggregate input into jsonb skipping nulls',
- proname => 'jsonb_agg_strict', prokind => 'a', proisstrict => 'f',
- provolatile => 's', prorettype => 'jsonb', proargtypes => 'anyelement',
- prosrc => 'aggregate_dummy' },
{ oid => '3268', descr => 'jsonb object aggregate transition function',
proname => 'jsonb_object_agg_transfn', proisstrict => 'f', provolatile => 's',
prorettype => 'internal', proargtypes => 'internal any any',
prosrc => 'jsonb_object_agg_transfn' },
-{ oid => '6218', descr => 'jsonb object aggregate transition function',
- proname => 'jsonb_object_agg_strict_transfn', proisstrict => 'f',
- provolatile => 's', prorettype => 'internal',
- proargtypes => 'internal any any',
- prosrc => 'jsonb_object_agg_strict_transfn' },
-{ oid => '6219', descr => 'jsonb object aggregate transition function',
- proname => 'jsonb_object_agg_unique_transfn', proisstrict => 'f',
- provolatile => 's', prorettype => 'internal',
- proargtypes => 'internal any any',
- prosrc => 'jsonb_object_agg_unique_transfn' },
-{ oid => '6220', descr => 'jsonb object aggregate transition function',
- proname => 'jsonb_object_agg_unique_strict_transfn', proisstrict => 'f',
- provolatile => 's', prorettype => 'internal',
- proargtypes => 'internal any any',
- prosrc => 'jsonb_object_agg_unique_strict_transfn' },
{ oid => '3269', descr => 'jsonb object aggregate final function',
proname => 'jsonb_object_agg_finalfn', proisstrict => 'f', provolatile => 's',
prorettype => 'jsonb', proargtypes => 'internal',
proname => 'jsonb_object_agg', prokind => 'a', proisstrict => 'f',
prorettype => 'jsonb', proargtypes => 'any any',
prosrc => 'aggregate_dummy' },
-{ oid => '6221', descr => 'aggregate non-NULL inputs into jsonb object',
- proname => 'jsonb_object_agg_strict', prokind => 'a', proisstrict => 'f',
- prorettype => 'jsonb', proargtypes => 'any any',
- prosrc => 'aggregate_dummy' },
-{ oid => '6222',
- descr => 'aggregate inputs into jsonb object checking key uniqueness',
- proname => 'jsonb_object_agg_unique', prokind => 'a', proisstrict => 'f',
- prorettype => 'jsonb', proargtypes => 'any any',
- prosrc => 'aggregate_dummy' },
-{ oid => '6223',
- descr => 'aggregate non-NULL inputs into jsonb object checking key uniqueness',
- proname => 'jsonb_object_agg_unique_strict', prokind => 'a',
- proisstrict => 'f', prorettype => 'jsonb', proargtypes => 'any any',
- prosrc => 'aggregate_dummy' },
{ oid => '3271', descr => 'build a jsonb array from any inputs',
proname => 'jsonb_build_array', provariadic => 'any', proisstrict => 'f',
provolatile => 's', prorettype => 'jsonb', proargtypes => 'any',
struct ExprEvalStep;
struct SubscriptingRefState;
struct ScalarArrayOpExprHashTable;
-struct JsonbValue;
-struct JsonExprState;
-struct JsonConstructorExprState;
/* Bits in ExprState->flags (see also execnodes.h for public flag bits): */
/* expression's interpreter has been initialized */
EEOP_GROUPING_FUNC,
EEOP_WINDOW_FUNC,
EEOP_SUBPLAN,
- EEOP_JSON_CONSTRUCTOR,
- EEOP_IS_JSON,
- EEOP_JSONEXPR,
/* aggregation related nodes */
EEOP_AGG_STRICT_DESERIALIZE,
int transno;
int setoff;
} agg_trans;
-
- /* for EEOP_JSON_CONSTRUCTOR */
- struct
- {
- struct JsonConstructorExprState *jcstate;
- } json_constructor;
-
- /* for EEOP_IS_JSON */
- struct
- {
- JsonIsPredicate *pred; /* original expression node */
- } is_json;
-
- /* for EEOP_JSONEXPR */
- struct
- {
- struct JsonExprState *jsestate;
- } jsonexpr;
-
} d;
} ExprEvalStep;
ExecEvalSubroutine sbs_fetch_old; /* fetch old value for assignment */
} SubscriptExecSteps;
-/* EEOP_JSON_CONSTRUCTOR state, too big to inline */
-typedef struct JsonConstructorExprState
-{
- JsonConstructorExpr *constructor;
- Datum *arg_values;
- bool *arg_nulls;
- Oid *arg_types;
- struct
- {
- int category;
- Oid outfuncid;
- } *arg_type_cache; /* cache for datum_to_json[b]() */
- int nargs;
-} JsonConstructorExprState;
-
-/* EEOP_JSONEXPR state, too big to inline */
-typedef struct JsonExprState
-{
- JsonExpr *jsexpr; /* original expression node */
-
- struct
- {
- FmgrInfo func; /* typinput function for output type */
- Oid typioparam;
- } input; /* I/O info for output type */
-
- NullableDatum
- *formatted_expr, /* formatted context item value */
- *res_expr, /* result item */
- *coercion_expr, /* input for JSON item coercion */
- *pathspec; /* path specification value */
-
- ExprState *result_expr; /* coerced to output type */
- ExprState *default_on_empty; /* ON EMPTY DEFAULT expression */
- ExprState *default_on_error; /* ON ERROR DEFAULT expression */
- List *args; /* passing arguments */
-
- void *cache; /* cache for json_populate_type() */
-
- struct JsonCoercionsState
- {
- struct JsonCoercionState
- {
- JsonCoercion *coercion; /* coercion expression */
- ExprState *estate; /* coercion expression state */
- } null,
- string,
- numeric ,
- boolean,
- date,
- time,
- timetz,
- timestamp,
- timestamptz,
- composite;
- } coercions; /* states for coercion from SQL/JSON item
- * types directly to the output type */
-} JsonExprState;
/* functions in execExpr.c */
extern void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s);
extern void ExecEvalConstraintNotNull(ExprState *state, ExprEvalStep *op);
extern void ExecEvalConstraintCheck(ExprState *state, ExprEvalStep *op);
extern void ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op);
-extern void ExecEvalJsonIsPredicate(ExprState *state, ExprEvalStep *op);
extern void ExecEvalGroupingFunc(ExprState *state, ExprEvalStep *op);
extern void ExecEvalSubPlan(ExprState *state, ExprEvalStep *op,
ExprContext *econtext);
ExprContext *econtext);
extern void ExecEvalSysVar(ExprState *state, ExprEvalStep *op,
ExprContext *econtext, TupleTableSlot *slot);
-extern void ExecEvalJsonConstructor(ExprState *state, ExprEvalStep *op,
- ExprContext *econtext);
-extern void ExecEvalJson(ExprState *state, ExprEvalStep *op,
- ExprContext *econtext);
-extern Datum ExecPrepareJsonItemCoercion(struct JsonbValue *item,
- JsonReturning *returning,
- struct JsonCoercionsState *coercions,
- struct JsonCoercionState **pjcstate);
-extern bool ExecEvalJsonNeedsSubTransaction(JsonExpr *jsexpr,
- struct JsonCoercionsState *);
-extern Datum ExecEvalExprPassingCaseValue(ExprState *estate,
- ExprContext *econtext, bool *isnull,
- Datum caseval_datum,
- bool caseval_isnull);
extern void ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroup,
ExprContext *aggcontext);
*/
extern ExprState *ExecInitExpr(Expr *node, PlanState *parent);
extern ExprState *ExecInitExprWithParams(Expr *node, ParamListInfo ext_params);
-extern ExprState *ExecInitExprWithCaseValue(Expr *node, PlanState *parent,
- Datum *caseval, bool *casenull);
extern ExprState *ExecInitQual(List *qual, PlanState *parent);
extern ExprState *ExecInitCheck(List *qual, PlanState *parent);
extern List *ExecInitExprList(List *nodes, PlanState *parent);
extern VacuumRelation *makeVacuumRelation(RangeVar *relation, Oid oid, List *va_cols);
-extern JsonFormat *makeJsonFormat(JsonFormatType type, JsonEncoding encoding,
- int location);
-extern JsonValueExpr *makeJsonValueExpr(Expr *expr, JsonFormat *format);
-extern JsonBehavior *makeJsonBehavior(JsonBehaviorType type, Node *expr);
-extern Node *makeJsonTableJoinedPlan(JsonTablePlanJoinType type,
- Node *plan1, Node *plan2, int location);
-extern Node *makeJsonKeyValue(Node *key, Node *value);
-extern Node *makeJsonIsPredicate(Node *expr, JsonFormat *format,
- JsonValueType item_type, bool unique_keys,
- int location);
-extern JsonEncoding makeJsonEncoding(char *name);
-
#endif /* MAKEFUNC_H */
bool isTable;
} TriggerTransition;
-/* Nodes for SQL/JSON support */
-
-/*
- * JsonQuotes -
- * representation of [KEEP|OMIT] QUOTES clause for JSON_QUERY()
- */
-typedef enum JsonQuotes
-{
- JS_QUOTES_UNSPEC, /* unspecified */
- JS_QUOTES_KEEP, /* KEEP QUOTES */
- JS_QUOTES_OMIT /* OMIT QUOTES */
-} JsonQuotes;
-
-/*
- * JsonTableColumnType -
- * enumeration of JSON_TABLE column types
- */
-typedef enum JsonTableColumnType
-{
- JTC_FOR_ORDINALITY,
- JTC_REGULAR,
- JTC_EXISTS,
- JTC_FORMATTED,
- JTC_NESTED,
-} JsonTableColumnType;
-
-/*
- * JsonOutput -
- * representation of JSON output clause (RETURNING type [FORMAT format])
- */
-typedef struct JsonOutput
-{
- NodeTag type;
- TypeName *typeName; /* RETURNING type name, if specified */
- JsonReturning *returning; /* RETURNING FORMAT clause and type Oids */
-} JsonOutput;
-
-/*
- * JsonArgument -
- * representation of argument from JSON PASSING clause
- */
-typedef struct JsonArgument
-{
- NodeTag type;
- JsonValueExpr *val; /* argument value expression */
- char *name; /* argument name */
-} JsonArgument;
-
-/*
- * JsonCommon -
- * representation of common syntax of functions using JSON path
- */
-typedef struct JsonCommon
-{
- NodeTag type;
- JsonValueExpr *expr; /* context item expression */
- Node *pathspec; /* JSON path specification expression */
- char *pathname; /* path name, if any */
- List *passing; /* list of PASSING clause arguments, if any */
- int location; /* token location, or -1 if unknown */
-} JsonCommon;
-
-/*
- * JsonFuncExpr -
- * untransformed representation of JSON function expressions
- */
-typedef struct JsonFuncExpr
-{
- NodeTag type;
- JsonExprOp op; /* expression type */
- JsonCommon *common; /* common syntax */
- JsonOutput *output; /* output clause, if specified */
- JsonBehavior *on_empty; /* ON EMPTY behavior, if specified */
- JsonBehavior *on_error; /* ON ERROR behavior, if specified */
- JsonWrapper wrapper; /* array wrapper behavior (JSON_QUERY only) */
- bool omit_quotes; /* omit or keep quotes? (JSON_QUERY only) */
- int location; /* token location, or -1 if unknown */
-} JsonFuncExpr;
-
-/*
- * JsonTableColumn -
- * untransformed representation of JSON_TABLE column
- */
-typedef struct JsonTableColumn
-{
- NodeTag type;
- JsonTableColumnType coltype; /* column type */
- char *name; /* column name */
- TypeName *typeName; /* column type name */
- char *pathspec; /* path specification, if any */
- char *pathname; /* path name, if any */
- JsonFormat *format; /* JSON format clause, if specified */
- JsonWrapper wrapper; /* WRAPPER behavior for formatted columns */
- bool omit_quotes; /* omit or keep quotes on scalar strings? */
- List *columns; /* nested columns */
- JsonBehavior *on_empty; /* ON EMPTY behavior */
- JsonBehavior *on_error; /* ON ERROR behavior */
- int location; /* token location, or -1 if unknown */
-} JsonTableColumn;
-
-/*
- * JsonTablePlanType -
- * flags for JSON_TABLE plan node types representation
- */
-typedef enum JsonTablePlanType
-{
- JSTP_DEFAULT,
- JSTP_SIMPLE,
- JSTP_JOINED,
-} JsonTablePlanType;
-
-/*
- * JsonTablePlanJoinType -
- * flags for JSON_TABLE join types representation
- */
-typedef enum JsonTablePlanJoinType
-{
- JSTPJ_INNER = 0x01,
- JSTPJ_OUTER = 0x02,
- JSTPJ_CROSS = 0x04,
- JSTPJ_UNION = 0x08,
-} JsonTablePlanJoinType;
-
-typedef struct JsonTablePlan JsonTablePlan;
-
-/*
- * JsonTablePlan -
- * untransformed representation of JSON_TABLE plan node
- */
-struct JsonTablePlan
-{
- NodeTag type;
- JsonTablePlanType plan_type; /* plan type */
- JsonTablePlanJoinType join_type; /* join type (for joined plan only) */
- JsonTablePlan *plan1; /* first joined plan */
- JsonTablePlan *plan2; /* second joined plan */
- char *pathname; /* path name (for simple plan only) */
- int location; /* token location, or -1 if unknown */
-};
-
-/*
- * JsonTable -
- * untransformed representation of JSON_TABLE
- */
-typedef struct JsonTable
-{
- NodeTag type;
- JsonCommon *common; /* common JSON path syntax fields */
- List *columns; /* list of JsonTableColumn */
- JsonTablePlan *plan; /* join plan, if specified */
- JsonBehavior *on_error; /* ON ERROR behavior, if specified */
- Alias *alias; /* table alias in FROM clause */
- bool lateral; /* does it have LATERAL prefix? */
- int location; /* token location, or -1 if unknown */
-} JsonTable;
-
-/*
- * JsonKeyValue -
- * untransformed representation of JSON object key-value pair for
- * JSON_OBJECT() and JSON_OBJECTAGG()
- */
-typedef struct JsonKeyValue
-{
- NodeTag type;
- Expr *key; /* key expression */
- JsonValueExpr *value; /* JSON value expression */
-} JsonKeyValue;
-
-/*
- * JsonParseExpr -
- * untransformed representation of JSON()
- */
-typedef struct JsonParseExpr
-{
- NodeTag type;
- JsonValueExpr *expr; /* string expression */
- JsonOutput *output; /* RETURNING clause, if specified */
- bool unique_keys; /* WITH UNIQUE KEYS? */
- int location; /* token location, or -1 if unknown */
-} JsonParseExpr;
-
-/*
- * JsonScalarExpr -
- * untransformed representation of JSON_SCALAR()
- */
-typedef struct JsonScalarExpr
-{
- NodeTag type;
- Expr *expr; /* scalar expression */
- JsonOutput *output; /* RETURNING clause, if specified */
- int location; /* token location, or -1 if unknown */
-} JsonScalarExpr;
-
-/*
- * JsonSerializeExpr -
- * untransformed representation of JSON_SERIALIZE() function
- */
-typedef struct JsonSerializeExpr
-{
- NodeTag type;
- JsonValueExpr *expr; /* json value expression */
- JsonOutput *output; /* RETURNING clause, if specified */
- int location; /* token location, or -1 if unknown */
-} JsonSerializeExpr;
-
-/*
- * JsonObjectConstructor -
- * untransformed representation of JSON_OBJECT() constructor
- */
-typedef struct JsonObjectConstructor
-{
- NodeTag type;
- List *exprs; /* list of JsonKeyValue pairs */
- JsonOutput *output; /* RETURNING clause, if specified */
- bool absent_on_null; /* skip NULL values? */
- bool unique; /* check key uniqueness? */
- int location; /* token location, or -1 if unknown */
-} JsonObjectConstructor;
-
-/*
- * JsonArrayConstructor -
- * untransformed representation of JSON_ARRAY(element,...) constructor
- */
-typedef struct JsonArrayConstructor
-{
- NodeTag type;
- List *exprs; /* list of JsonValueExpr elements */
- JsonOutput *output; /* RETURNING clause, if specified */
- bool absent_on_null; /* skip NULL elements? */
- int location; /* token location, or -1 if unknown */
-} JsonArrayConstructor;
-
-/*
- * JsonArrayQueryConstructor -
- * untransformed representation of JSON_ARRAY(subquery) constructor
- */
-typedef struct JsonArrayQueryConstructor
-{
- NodeTag type;
- Node *query; /* subquery */
- JsonOutput *output; /* RETURNING clause, if specified */
- JsonFormat *format; /* FORMAT clause for subquery, if specified */
- bool absent_on_null; /* skip NULL elements? */
- int location; /* token location, or -1 if unknown */
-} JsonArrayQueryConstructor;
-
-/*
- * JsonAggConstructor -
- * common fields of untransformed representation of
- * JSON_ARRAYAGG() and JSON_OBJECTAGG()
- */
-typedef struct JsonAggConstructor
-{
- NodeTag type;
- JsonOutput *output; /* RETURNING clause, if any */
- Node *agg_filter; /* FILTER clause, if any */
- List *agg_order; /* ORDER BY clause, if any */
- struct WindowDef *over; /* OVER clause, if any */
- int location; /* token location, or -1 if unknown */
-} JsonAggConstructor;
-
-/*
- * JsonObjectAgg -
- * untransformed representation of JSON_OBJECTAGG()
- */
-typedef struct JsonObjectAgg
-{
- NodeTag type;
- JsonAggConstructor *constructor; /* common fields */
- JsonKeyValue *arg; /* object key-value pair */
- bool absent_on_null; /* skip NULL values? */
- bool unique; /* check key uniqueness? */
-} JsonObjectAgg;
-
-/*
- * JsonArrayAgg -
- * untransformed representation of JSON_ARRRAYAGG()
- */
-typedef struct JsonArrayAgg
-{
- NodeTag type;
- JsonAggConstructor *constructor; /* common fields */
- JsonValueExpr *arg; /* array element expression */
- bool absent_on_null; /* skip NULL elements? */
-} JsonArrayAgg;
-
-
/*****************************************************************************
* Raw Grammar Output Statements
*****************************************************************************/
int location;
} RangeVar;
-typedef enum TableFuncType
-{
- TFT_XMLTABLE,
- TFT_JSON_TABLE
-} TableFuncType;
-
/*
- * TableFunc - node for a table function, such as XMLTABLE or JSON_TABLE.
+ * TableFunc - node for a table function, such as XMLTABLE.
*
* Entries in the ns_names list are either String nodes containing
* literal namespace names, or NULL pointers to represent DEFAULT.
typedef struct TableFunc
{
NodeTag type;
- TableFuncType functype; /* XMLTABLE or JSON_TABLE */
List *ns_uris; /* list of namespace URI expressions */
List *ns_names; /* list of namespace names or NULL */
Node *docexpr; /* input document expression */
List *colcollations; /* OID list of column collation OIDs */
List *colexprs; /* list of column filter expressions */
List *coldefexprs; /* list of column default expressions */
- List *colvalexprs; /* list of column value expressions */
Bitmapset *notnulls; /* nullability flag for each output column */
- Node *plan; /* JSON_TABLE plan */
int ordinalitycol; /* counts from 0; -1 if none specified */
int location; /* token location, or -1 if unknown */
} TableFunc;
int location; /* token location, or -1 if unknown */
} XmlExpr;
-/*
- * JsonExprOp -
- * enumeration of JSON functions using JSON path
- */
-typedef enum JsonExprOp
-{
- JSON_VALUE_OP, /* JSON_VALUE() */
- JSON_QUERY_OP, /* JSON_QUERY() */
- JSON_EXISTS_OP, /* JSON_EXISTS() */
- JSON_TABLE_OP /* JSON_TABLE() */
-} JsonExprOp;
-
-/*
- * JsonEncoding -
- * representation of JSON ENCODING clause
- */
-typedef enum JsonEncoding
-{
- JS_ENC_DEFAULT, /* unspecified */
- JS_ENC_UTF8,
- JS_ENC_UTF16,
- JS_ENC_UTF32,
-} JsonEncoding;
-
-/*
- * JsonFormatType -
- * enumeration of JSON formats used in JSON FORMAT clause
- */
-typedef enum JsonFormatType
-{
- JS_FORMAT_DEFAULT, /* unspecified */
- JS_FORMAT_JSON, /* FORMAT JSON [ENCODING ...] */
- JS_FORMAT_JSONB /* implicit internal format for RETURNING
- * jsonb */
-} JsonFormatType;
-
-/*
- * JsonBehaviorType -
- * enumeration of behavior types used in JSON ON ... BEHAVIOR clause
- *
- * If enum members are reordered, get_json_behavior() from ruleutils.c
- * must be updated accordingly.
- */
-typedef enum JsonBehaviorType
-{
- JSON_BEHAVIOR_NULL = 0,
- JSON_BEHAVIOR_ERROR,
- JSON_BEHAVIOR_EMPTY,
- JSON_BEHAVIOR_TRUE,
- JSON_BEHAVIOR_FALSE,
- JSON_BEHAVIOR_UNKNOWN,
- JSON_BEHAVIOR_EMPTY_ARRAY,
- JSON_BEHAVIOR_EMPTY_OBJECT,
- JSON_BEHAVIOR_DEFAULT
-} JsonBehaviorType;
-
-/*
- * JsonWrapper -
- * representation of WRAPPER clause for JSON_QUERY()
- */
-typedef enum JsonWrapper
-{
- JSW_NONE,
- JSW_CONDITIONAL,
- JSW_UNCONDITIONAL,
-} JsonWrapper;
-
-/*
- * JsonFormat -
- * representation of JSON FORMAT clause
- */
-typedef struct JsonFormat
-{
- NodeTag type;
- JsonFormatType format_type; /* format type */
- JsonEncoding encoding; /* JSON encoding */
- int location; /* token location, or -1 if unknown */
-} JsonFormat;
-
-/*
- * JsonReturning -
- * transformed representation of JSON RETURNING clause
- */
-typedef struct JsonReturning
-{
- NodeTag type;
- JsonFormat *format; /* output JSON format */
- Oid typid; /* target type Oid */
- int32 typmod; /* target type modifier */
-} JsonReturning;
-
-/*
- * JsonValueExpr -
- * representation of JSON value expression (expr [FORMAT json_format])
- */
-typedef struct JsonValueExpr
-{
- NodeTag type;
- Expr *raw_expr; /* raw expression */
- Expr *formatted_expr; /* formatted expression or NULL */
- JsonFormat *format; /* FORMAT clause, if specified */
-} JsonValueExpr;
-
-typedef enum JsonConstructorType
-{
- JSCTOR_JSON_OBJECT = 1,
- JSCTOR_JSON_ARRAY = 2,
- JSCTOR_JSON_OBJECTAGG = 3,
- JSCTOR_JSON_ARRAYAGG = 4,
- JSCTOR_JSON_SCALAR = 5,
- JSCTOR_JSON_SERIALIZE = 6,
- JSCTOR_JSON_PARSE = 7
-} JsonConstructorType;
-
-/*
- * JsonConstructorExpr -
- * wrapper over FuncExpr/Aggref/WindowFunc for SQL/JSON constructors
- */
-typedef struct JsonConstructorExpr
-{
- Expr xpr;
- JsonConstructorType type; /* constructor type */
- List *args;
- Expr *func; /* underlying json[b]_xxx() function call */
- Expr *coercion; /* coercion to RETURNING type */
- JsonReturning *returning; /* RETURNING clause */
- bool absent_on_null; /* ABSENT ON NULL? */
- bool unique; /* WITH UNIQUE KEYS? (JSON_OBJECT[AGG] only) */
- int location;
-} JsonConstructorExpr;
-
-/*
- * JsonValueType -
- * representation of JSON item type in IS JSON predicate
- */
-typedef enum JsonValueType
-{
- JS_TYPE_ANY, /* IS JSON [VALUE] */
- JS_TYPE_OBJECT, /* IS JSON OBJECT */
- JS_TYPE_ARRAY, /* IS JSON ARRAY */
- JS_TYPE_SCALAR /* IS JSON SCALAR */
-} JsonValueType;
-
-/*
- * JsonIsPredicate -
- * representation of IS JSON predicate
- */
-typedef struct JsonIsPredicate
-{
- NodeTag type;
- Node *expr; /* subject expression */
- JsonFormat *format; /* FORMAT clause, if specified */
- JsonValueType item_type; /* JSON item type */
- bool unique_keys; /* check key uniqueness? */
- int location; /* token location, or -1 if unknown */
-} JsonIsPredicate;
-
-/*
- * JsonBehavior -
- * representation of JSON ON ... BEHAVIOR clause
- */
-typedef struct JsonBehavior
-{
- NodeTag type;
- JsonBehaviorType btype; /* behavior type */
- Node *default_expr; /* default expression, if any */
-} JsonBehavior;
-
-/*
- * JsonCoercion -
- * coercion from SQL/JSON item types to SQL types
- */
-typedef struct JsonCoercion
-{
- NodeTag type;
- Node *expr; /* resulting expression coerced to target type */
- bool via_populate; /* coerce result using json_populate_type()? */
- bool via_io; /* coerce result using type input function? */
- Oid collation; /* collation for coercion via I/O or populate */
-} JsonCoercion;
-
-/*
- * JsonItemCoercions -
- * expressions for coercion from SQL/JSON item types directly to the
- * output SQL type
- */
-typedef struct JsonItemCoercions
-{
- NodeTag type;
- JsonCoercion *null;
- JsonCoercion *string;
- JsonCoercion *numeric;
- JsonCoercion *boolean;
- JsonCoercion *date;
- JsonCoercion *time;
- JsonCoercion *timetz;
- JsonCoercion *timestamp;
- JsonCoercion *timestamptz;
- JsonCoercion *composite; /* arrays and objects */
-} JsonItemCoercions;
-
-/*
- * JsonExpr -
- * transformed representation of JSON_VALUE(), JSON_QUERY(), JSON_EXISTS()
- */
-typedef struct JsonExpr
-{
- Expr xpr;
- JsonExprOp op; /* json function ID */
- Node *formatted_expr; /* formatted context item expression */
- JsonCoercion *result_coercion; /* resulting coercion to RETURNING type */
- JsonFormat *format; /* context item format (JSON/JSONB) */
- Node *path_spec; /* JSON path specification expression */
- List *passing_names; /* PASSING argument names */
- List *passing_values; /* PASSING argument values */
- JsonReturning *returning; /* RETURNING clause type/format info */
- JsonBehavior *on_empty; /* ON EMPTY behavior */
- JsonBehavior *on_error; /* ON ERROR behavior */
- JsonItemCoercions *coercions; /* coercions for JSON_VALUE */
- JsonWrapper wrapper; /* WRAPPER for JSON_QUERY */
- bool omit_quotes; /* KEEP/OMIT QUOTES for JSON_QUERY */
- int location; /* token location, or -1 if unknown */
-} JsonExpr;
-
-/*
- * JsonTableParent -
- * transformed representation of parent JSON_TABLE plan node
- */
-typedef struct JsonTableParent
-{
- NodeTag type;
- Const *path; /* jsonpath constant */
- char *name; /* path name */
- Node *child; /* nested columns, if any */
- bool outerJoin; /* outer or inner join for nested columns? */
- int colMin; /* min column index in the resulting column
- * list */
- int colMax; /* max column index in the resulting column
- * list */
- bool errorOnError; /* ERROR/EMPTY ON ERROR behavior */
-} JsonTableParent;
-
-/*
- * JsonTableSibling -
- * transformed representation of joined sibling JSON_TABLE plan node
- */
-typedef struct JsonTableSibling
-{
- NodeTag type;
- Node *larg; /* left join node */
- Node *rarg; /* right join node */
- bool cross; /* cross or union join? */
-} JsonTableSibling;
-
/* ----------------
* NullTest
*
/* name, value, category, is-bare-label */
PG_KEYWORD("abort", ABORT_P, UNRESERVED_KEYWORD, BARE_LABEL)
-PG_KEYWORD("absent", ABSENT, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("absolute", ABSOLUTE_P, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("access", ACCESS, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("action", ACTION, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("committed", COMMITTED, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("compression", COMPRESSION, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("concurrently", CONCURRENTLY, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
-PG_KEYWORD("conditional", CONDITIONAL, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("configuration", CONFIGURATION, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("conflict", CONFLICT, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("connection", CONNECTION, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("drop", DROP, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("each", EACH, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("else", ELSE, RESERVED_KEYWORD, BARE_LABEL)
-PG_KEYWORD("empty", EMPTY_P, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("enable", ENABLE_P, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("encoding", ENCODING, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("encrypted", ENCRYPTED, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("end", END_P, RESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("enum", ENUM_P, UNRESERVED_KEYWORD, BARE_LABEL)
-PG_KEYWORD("error", ERROR_P, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("escape", ESCAPE, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("event", EVENT, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("except", EXCEPT, RESERVED_KEYWORD, AS_LABEL)
PG_KEYWORD("for", FOR, RESERVED_KEYWORD, AS_LABEL)
PG_KEYWORD("force", FORCE, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("foreign", FOREIGN, RESERVED_KEYWORD, BARE_LABEL)
-PG_KEYWORD("format", FORMAT, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("forward", FORWARD, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("freeze", FREEZE, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
PG_KEYWORD("from", FROM, RESERVED_KEYWORD, AS_LABEL)
PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD, AS_LABEL)
PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
-PG_KEYWORD("json", JSON, COL_NAME_KEYWORD, BARE_LABEL)
-PG_KEYWORD("json_array", JSON_ARRAY, COL_NAME_KEYWORD, BARE_LABEL)
-PG_KEYWORD("json_arrayagg", JSON_ARRAYAGG, COL_NAME_KEYWORD, BARE_LABEL)
-PG_KEYWORD("json_exists", JSON_EXISTS, COL_NAME_KEYWORD, BARE_LABEL)
-PG_KEYWORD("json_object", JSON_OBJECT, COL_NAME_KEYWORD, BARE_LABEL)
-PG_KEYWORD("json_objectagg", JSON_OBJECTAGG, COL_NAME_KEYWORD, BARE_LABEL)
-PG_KEYWORD("json_query", JSON_QUERY, COL_NAME_KEYWORD, BARE_LABEL)
-PG_KEYWORD("json_scalar", JSON_SCALAR, COL_NAME_KEYWORD, BARE_LABEL)
-PG_KEYWORD("json_serialize", JSON_SERIALIZE, COL_NAME_KEYWORD, BARE_LABEL)
-PG_KEYWORD("json_table", JSON_TABLE, COL_NAME_KEYWORD, BARE_LABEL)
-PG_KEYWORD("json_value", JSON_VALUE, COL_NAME_KEYWORD, BARE_LABEL)
-PG_KEYWORD("keep", KEEP, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD, BARE_LABEL)
-PG_KEYWORD("keys", KEYS, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("national", NATIONAL, COL_NAME_KEYWORD, BARE_LABEL)
PG_KEYWORD("natural", NATURAL, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
PG_KEYWORD("nchar", NCHAR, COL_NAME_KEYWORD, BARE_LABEL)
-PG_KEYWORD("nested", NESTED, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("new", NEW, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("next", NEXT, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("nfc", NFC, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("offset", OFFSET, RESERVED_KEYWORD, AS_LABEL)
PG_KEYWORD("oids", OIDS, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("old", OLD, UNRESERVED_KEYWORD, BARE_LABEL)
-PG_KEYWORD("omit", OMIT, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("on", ON, RESERVED_KEYWORD, AS_LABEL)
PG_KEYWORD("only", ONLY, RESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("operator", OPERATOR, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD, BARE_LABEL)
-PG_KEYWORD("path", PATH, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD, BARE_LABEL)
-PG_KEYWORD("plan", PLAN, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("position", POSITION, COL_NAME_KEYWORD, BARE_LABEL)
PG_KEYWORD("program", PROGRAM, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("publication", PUBLICATION, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("quote", QUOTE, UNRESERVED_KEYWORD, BARE_LABEL)
-PG_KEYWORD("quotes", QUOTES, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("range", RANGE, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("read", READ, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("real", REAL, COL_NAME_KEYWORD, BARE_LABEL)
PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("savepoint", SAVEPOINT, UNRESERVED_KEYWORD, BARE_LABEL)
-PG_KEYWORD("scalar", SCALAR, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("schema", SCHEMA, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("schemas", SCHEMAS, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("storage", STORAGE, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("stored", STORED, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD, BARE_LABEL)
-PG_KEYWORD("string", STRING, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD, BARE_LABEL)
PG_KEYWORD("uescape", UESCAPE, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("unbounded", UNBOUNDED, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("uncommitted", UNCOMMITTED, UNRESERVED_KEYWORD, BARE_LABEL)
-PG_KEYWORD("unconditional", UNCONDITIONAL, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("unencrypted", UNENCRYPTED, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("union", UNION, RESERVED_KEYWORD, AS_LABEL)
PG_KEYWORD("unique", UNIQUE, RESERVED_KEYWORD, BARE_LABEL)
extern Index assignSortGroupRef(TargetEntry *tle, List *tlist);
extern bool targetIsInSortList(TargetEntry *tle, Oid sortop, List *sortList);
-/* functions in parse_jsontable.c */
-extern ParseNamespaceItem *transformJsonTable(ParseState *pstate, JsonTable *jt);
-
#endif /* PARSE_CLAUSE_H */
#ifndef _FORMATTING_H_
#define _FORMATTING_H_
-#define DCH_DATED 0x01
-#define DCH_TIMED 0x02
-#define DCH_ZONED 0x04
extern char *str_tolower(const char *buff, size_t nbytes, Oid collid);
extern char *str_toupper(const char *buff, size_t nbytes, Oid collid);
extern Datum parse_datetime(text *date_txt, text *fmt, Oid collid, bool strict,
Oid *typid, int32 *typmod, int *tz,
bool *have_error);
-extern int datetime_format_flags(const char *fmt_str, bool *have_error);
#endif
#include "lib/stringinfo.h"
-typedef enum /* type categories for datum_to_json */
-{
- JSONTYPE_NULL, /* null, so we didn't bother to identify */
- JSONTYPE_BOOL, /* boolean (built-in types only) */
- JSONTYPE_NUMERIC, /* numeric (ditto) */
- JSONTYPE_DATE, /* we use special formatting for datetimes */
- JSONTYPE_TIMESTAMP,
- JSONTYPE_TIMESTAMPTZ,
- JSONTYPE_JSON, /* JSON itself (and JSONB) */
- JSONTYPE_ARRAY, /* array */
- JSONTYPE_COMPOSITE, /* composite */
- JSONTYPE_CAST, /* something with an explicit cast to JSON */
- JSONTYPE_OTHER /* all else */
-} JsonTypeCategory;
-
/* functions in json.c */
extern void escape_json(StringInfo buf, const char *str);
extern char *JsonEncodeDateTime(char *buf, Datum value, Oid typid,
const int *tzp);
-extern bool to_json_is_immutable(Oid typoid);
-extern void json_categorize_type(Oid typoid, JsonTypeCategory *tcategory,
- Oid *outfuncoid);
-extern Datum to_json_worker(Datum val, JsonTypeCategory tcategory,
- Oid outfuncoid);
-extern Datum json_build_object_worker(int nargs, Datum *args, bool *nulls,
- Oid *types, bool absent_on_null,
- bool unique_keys);
-extern Datum json_build_array_worker(int nargs, Datum *args, bool *nulls,
- Oid *types, bool absent_on_null);
-extern bool json_validate(text *json, bool check_unique_keys, bool throw_error);
#endif /* JSON_H */
JsonbValue contVal;
Size size;
struct JsonbParseState *next;
- bool unique_keys; /* Check object key uniqueness */
- bool skip_nulls; /* Skip null object fields */
} JsonbParseState;
/*
struct JsonbIterator *parent;
} JsonbIterator;
-/* unlike with json categories, we need to treat json and jsonb differently */
-typedef enum /* type categories for datum_to_jsonb */
-{
- JSONBTYPE_NULL, /* null, so we didn't bother to identify */
- JSONBTYPE_BOOL, /* boolean (built-in types only) */
- JSONBTYPE_NUMERIC, /* numeric (ditto) */
- JSONBTYPE_DATE, /* we use special formatting for datetimes */
- JSONBTYPE_TIMESTAMP, /* we use special formatting for timestamp */
- JSONBTYPE_TIMESTAMPTZ, /* ... and timestamptz */
- JSONBTYPE_JSON, /* JSON */
- JSONBTYPE_JSONB, /* JSONB */
- JSONBTYPE_ARRAY, /* array */
- JSONBTYPE_COMPOSITE, /* composite */
- JSONBTYPE_JSONCAST, /* something with an explicit cast to JSON */
- JSONBTYPE_OTHER /* all else */
-} JsonbTypeCategory;
/* Support functions */
extern uint32 getJsonbOffset(const JsonbContainer *jc, int index);
uint64 *hash, uint64 seed);
/* jsonb.c support functions */
-extern Datum jsonb_from_text(text *js, bool unique_keys);
extern char *JsonbToCString(StringInfo out, JsonbContainer *in,
int estimated_len);
extern char *JsonbToCStringIndent(StringInfo out, JsonbContainer *in,
int estimated_len);
-extern Jsonb *JsonbMakeEmptyArray(void);
-extern Jsonb *JsonbMakeEmptyObject(void);
-extern char *JsonbUnquote(Jsonb *jb);
extern bool JsonbExtractScalar(JsonbContainer *jbc, JsonbValue *res);
extern const char *JsonbTypeName(JsonbValue *jb);
JsonbValue *newval);
extern Datum jsonb_get_element(Jsonb *jb, Datum *path, int npath,
bool *isnull, bool as_text);
-extern bool to_jsonb_is_immutable(Oid typoid);
-extern void jsonb_categorize_type(Oid typoid, JsonbTypeCategory *tcategory,
- Oid *outfuncoid);
-extern Datum to_jsonb_worker(Datum val, JsonbTypeCategory tcategory,
- Oid outfuncoid);
-extern Datum jsonb_build_object_worker(int nargs, Datum *args, bool *nulls,
- Oid *types, bool absent_on_null,
- bool unique_keys);
-extern Datum jsonb_build_array_worker(int nargs, Datum *args, bool *nulls,
- Oid *types, bool absent_on_null);
-
#endif /* __JSONB_H__ */
/* report an error during json lexing or parsing */
extern void json_ereport_error(JsonParseErrorType error, JsonLexContext *lex);
-/* get first JSON token */
-extern JsonTokenType json_get_first_token(text *json, bool throw_error);
-
extern uint32 parse_jsonb_index_flags(Jsonb *jb);
extern void iterate_jsonb_values(Jsonb *jb, uint32 flags, void *state,
JsonIterateStringValuesAction action);
extern text *transform_json_string_values(text *json, void *action_state,
JsonTransformStringValuesAction transform_action);
-extern Datum json_populate_type(Datum json_val, Oid json_type,
- Oid typid, int32 typmod,
- void **cache, MemoryContext mcxt, bool *isnull);
-
#endif
#define JSONPATH_H
#include "fmgr.h"
-#include "executor/tablefunc.h"
#include "nodes/pg_list.h"
-#include "nodes/primnodes.h"
#include "utils/jsonb.h"
-#include "utils/jsonfuncs.h"
typedef struct
{
extern char *jspGetString(JsonPathItem *v, int32 *len);
extern bool jspGetArraySubscript(JsonPathItem *v, JsonPathItem *from,
JsonPathItem *to, int i);
-extern bool jspIsMutable(JsonPath *path, List *varnames, List *varexprs);
extern const char *jspOperationName(JsonPathItemType type);
extern int jspConvertRegexFlags(uint32 xflags);
-/*
- * Evaluation of jsonpath
- */
-
-/* External variable passed into jsonpath. */
-typedef struct JsonPathVariableEvalContext
-{
- char *name;
- Oid typid;
- int32 typmod;
- struct ExprContext *econtext;
- struct ExprState *estate;
- MemoryContext mcxt; /* memory context for cached value */
- Datum value;
- bool isnull;
- bool evaluated;
-} JsonPathVariableEvalContext;
-
-/* SQL/JSON item */
-extern void JsonItemFromDatum(Datum val, Oid typid, int32 typmod,
- JsonbValue *res);
-
-extern bool JsonPathExists(Datum jb, JsonPath *path, List *vars, bool *error);
-extern Datum JsonPathQuery(Datum jb, JsonPath *jp, JsonWrapper wrapper,
- bool *empty, bool *error, List *vars);
-extern JsonbValue *JsonPathValue(Datum jb, JsonPath *jp, bool *empty,
- bool *error, List *vars);
-
-extern int EvalJsonPathVar(void *vars, char *varName, int varNameLen,
- JsonbValue *val, JsonbValue *baseObject);
-
-extern PGDLLIMPORT const TableFuncRoutine JsonbTableRoutine;
-
#endif
$$.type_index = mm_strdup("-1");
$$.type_sizeof = NULL;
}
- | STRING
- {
- if (INFORMIX_MODE)
- {
- /* In Informix mode, "string" is automatically a typedef */
- $$.type_enum = ECPGt_string;
- $$.type_str = mm_strdup("char");
- $$.type_dimension = mm_strdup("-1");
- $$.type_index = mm_strdup("-1");
- $$.type_sizeof = NULL;
- }
- else
- {
- /* Otherwise, legal only if user typedef'ed it */
- struct typedefs *this = get_typedef("string", false);
-
- $$.type_str = (this->type->type_enum == ECPGt_varchar || this->type->type_enum == ECPGt_bytea) ? EMPTY : mm_strdup(this->name);
- $$.type_enum = this->type->type_enum;
- $$.type_dimension = this->type->type_dimension;
- $$.type_index = this->type->type_index;
- if (this->type->type_sizeof && strlen(this->type->type_sizeof) != 0)
- $$.type_sizeof = this->type->type_sizeof;
- else
- $$.type_sizeof = cat_str(3, mm_strdup("sizeof("), mm_strdup(this->name), mm_strdup(")"));
-
- struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list);
- }
- }
| IDENT ecpg_interval
{
/*
'NOT_LA' => 'not',
'NULLS_LA' => 'nulls',
'WITH_LA' => 'with',
- 'WITH_LA_UNIQUE' => 'with',
- 'WITHOUT_LA' => 'without',
'TYPECAST' => '::',
'DOT_DOT' => '..',
'COLON_EQUALS' => ':=',
case WITH:
case UIDENT:
case USCONST:
- case WITHOUT:
break;
default:
return cur_token;
case ORDINALITY:
cur_token = WITH_LA;
break;
- case UNIQUE:
- cur_token = WITH_LA_UNIQUE;
- break;
- }
- break;
-
- case WITHOUT:
- /* Replace WITHOUT by WITHOUT_LA if it's followed by TIME */
- switch (next_token)
- {
- case TIME:
- cur_token = WITHOUT_LA;
- break;
}
break;
case UIDENT:
+++ /dev/null
--- JSON_EXISTS
-SELECT JSON_EXISTS(NULL FORMAT JSON, '$');
-ERROR: JSON_EXISTS() is not yet implemented for the json type
-LINE 1: SELECT JSON_EXISTS(NULL FORMAT JSON, '$');
- ^
-HINT: Try casting the argument to jsonb
--- JSON_VALUE
-SELECT JSON_VALUE(NULL FORMAT JSON, '$');
-ERROR: JSON_VALUE() is not yet implemented for the json type
-LINE 1: SELECT JSON_VALUE(NULL FORMAT JSON, '$');
- ^
-HINT: Try casting the argument to jsonb
--- JSON_QUERY
-SELECT JSON_QUERY(NULL FORMAT JSON, '$');
-ERROR: JSON_QUERY() is not yet implemented for the json type
-LINE 1: SELECT JSON_QUERY(NULL FORMAT JSON, '$');
- ^
-HINT: Try casting the argument to jsonb
--- JSON_TABLE
-SELECT * FROM JSON_TABLE(NULL FORMAT JSON, '$' COLUMNS (foo text));
-ERROR: JSON_TABLE() is not yet implemented for the json type
-LINE 1: SELECT * FROM JSON_TABLE(NULL FORMAT JSON, '$' COLUMNS (foo ...
- ^
-HINT: Try casting the argument to jsonb
+++ /dev/null
--- JSON_EXISTS
-SELECT JSON_EXISTS(NULL::jsonb, '$');
- json_exists
--------------
-
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '[]', '$');
- json_exists
--------------
- t
-(1 row)
-
-SELECT JSON_EXISTS(JSON_OBJECT(RETURNING jsonb), '$');
- json_exists
--------------
- t
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '1', '$');
- json_exists
--------------
- t
-(1 row)
-
-SELECT JSON_EXISTS(jsonb 'null', '$');
- json_exists
--------------
- t
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '[]', '$');
- json_exists
--------------
- t
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '1', '$.a');
- json_exists
--------------
- f
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '1', 'strict $.a');
- json_exists
--------------
- f
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '1', 'strict $.a' ERROR ON ERROR);
-ERROR: jsonpath member accessor can only be applied to an object
-SELECT JSON_EXISTS(jsonb 'null', '$.a');
- json_exists
--------------
- f
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '[]', '$.a');
- json_exists
--------------
- f
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '[1, "aaa", {"a": 1}]', 'strict $.a');
- json_exists
--------------
- f
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '[1, "aaa", {"a": 1}]', 'lax $.a');
- json_exists
--------------
- t
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '{}', '$.a');
- json_exists
--------------
- f
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '{"b": 1, "a": 2}', '$.a');
- json_exists
--------------
- t
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '1', '$.a.b');
- json_exists
--------------
- f
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '{"a": {"b": 1}}', '$.a.b');
- json_exists
--------------
- t
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '{"a": 1, "b": 2}', '$.a.b');
- json_exists
--------------
- f
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '{"a": 1, "b": 2}', '$.* ? (@ > $x)' PASSING 1 AS x);
- json_exists
--------------
- t
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '{"a": 1, "b": 2}', '$.* ? (@ > $x)' PASSING '1' AS x);
- json_exists
--------------
- f
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '{"a": 1, "b": 2}', '$.* ? (@ > $x && @ < $y)' PASSING 0 AS x, 2 AS y);
- json_exists
--------------
- t
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '{"a": 1, "b": 2}', '$.* ? (@ > $x && @ < $y)' PASSING 0 AS x, 1 AS y);
- json_exists
--------------
- f
-(1 row)
-
--- extension: boolean expressions
-SELECT JSON_EXISTS(jsonb '1', '$ > 2');
- json_exists
--------------
- t
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '1', '$.a > 2' ERROR ON ERROR);
- json_exists
--------------
- t
-(1 row)
-
--- extension: RETURNING clause
-SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING bool);
- json_exists
--------------
- t
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '1', '$[1]' RETURNING bool);
- json_exists
--------------
- f
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING int);
- json_exists
--------------
- 1
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '1', '$[1]' RETURNING int);
- json_exists
--------------
- 0
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING text);
- json_exists
--------------
- true
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '1', '$[1]' RETURNING text);
- json_exists
--------------
- false
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '1', 'strict $[1]' RETURNING text FALSE ON ERROR);
- json_exists
--------------
- false
-(1 row)
-
-SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING jsonb);
-ERROR: cannot cast type boolean to jsonb
-LINE 1: SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING jsonb);
- ^
-SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING float4);
-ERROR: cannot cast type boolean to real
-LINE 1: SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING float4);
- ^
--- JSON_VALUE
-SELECT JSON_VALUE(NULL::jsonb, '$');
- json_value
-------------
-
-(1 row)
-
-SELECT JSON_VALUE(jsonb 'null', '$');
- json_value
-------------
-
-(1 row)
-
-SELECT JSON_VALUE(jsonb 'null', '$' RETURNING int);
- json_value
-------------
-
-(1 row)
-
-SELECT JSON_VALUE(jsonb 'true', '$');
- json_value
-------------
- true
-(1 row)
-
-SELECT JSON_VALUE(jsonb 'true', '$' RETURNING bool);
- json_value
-------------
- t
-(1 row)
-
-SELECT JSON_VALUE(jsonb '123', '$');
- json_value
-------------
- 123
-(1 row)
-
-SELECT JSON_VALUE(jsonb '123', '$' RETURNING int) + 234;
- ?column?
-----------
- 357
-(1 row)
-
-SELECT JSON_VALUE(jsonb '123', '$' RETURNING text);
- json_value
-------------
- 123
-(1 row)
-
-/* jsonb bytea ??? */
-SELECT JSON_VALUE(jsonb '123', '$' RETURNING bytea ERROR ON ERROR);
-ERROR: SQL/JSON item cannot be cast to target type
-SELECT JSON_VALUE(jsonb '1.23', '$');
- json_value
-------------
- 1.23
-(1 row)
-
-SELECT JSON_VALUE(jsonb '1.23', '$' RETURNING int);
- json_value
-------------
- 1
-(1 row)
-
-SELECT JSON_VALUE(jsonb '"1.23"', '$' RETURNING numeric);
- json_value
-------------
- 1.23
-(1 row)
-
-SELECT JSON_VALUE(jsonb '"1.23"', '$' RETURNING int ERROR ON ERROR);
-ERROR: invalid input syntax for type integer: "1.23"
-SELECT JSON_VALUE(jsonb '"aaa"', '$');
- json_value
-------------
- aaa
-(1 row)
-
-SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING text);
- json_value
-------------
- aaa
-(1 row)
-
-SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING char(5));
- json_value
-------------
- aaa
-(1 row)
-
-SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING char(2));
- json_value
-------------
- aa
-(1 row)
-
-SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING json);
- json_value
-------------
- "aaa"
-(1 row)
-
-SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING jsonb);
- json_value
-------------
- "aaa"
-(1 row)
-
-SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING json ERROR ON ERROR);
- json_value
-------------
- "aaa"
-(1 row)
-
-SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING jsonb ERROR ON ERROR);
- json_value
-------------
- "aaa"
-(1 row)
-
-SELECT JSON_VALUE(jsonb '"\"aaa\""', '$' RETURNING json);
- json_value
-------------
- "\"aaa\""
-(1 row)
-
-SELECT JSON_VALUE(jsonb '"\"aaa\""', '$' RETURNING jsonb);
- json_value
-------------
- "\"aaa\""
-(1 row)
-
-SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING int);
- json_value
-------------
-
-(1 row)
-
-SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING int ERROR ON ERROR);
-ERROR: invalid input syntax for type integer: "aaa"
-SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING int DEFAULT 111 ON ERROR);
- json_value
-------------
- 111
-(1 row)
-
-SELECT JSON_VALUE(jsonb '"123"', '$' RETURNING int) + 234;
- ?column?
-----------
- 357
-(1 row)
-
-SELECT JSON_VALUE(jsonb '"2017-02-20"', '$' RETURNING date) + 9;
- ?column?
-------------
- 03-01-2017
-(1 row)
-
--- Test NULL checks execution in domain types
-CREATE DOMAIN sqljsonb_int_not_null AS int NOT NULL;
-SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null);
-ERROR: domain sqljsonb_int_not_null does not allow null values
-SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null NULL ON ERROR);
-ERROR: domain sqljsonb_int_not_null does not allow null values
-SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null DEFAULT NULL ON ERROR);
-ERROR: domain sqljsonb_int_not_null does not allow null values
-SELECT JSON_VALUE(jsonb '[]', '$');
- json_value
-------------
-
-(1 row)
-
-SELECT JSON_VALUE(jsonb '[]', '$' ERROR ON ERROR);
-ERROR: JSON path expression in JSON_VALUE should return singleton scalar item
-SELECT JSON_VALUE(jsonb '{}', '$');
- json_value
-------------
-
-(1 row)
-
-SELECT JSON_VALUE(jsonb '{}', '$' ERROR ON ERROR);
-ERROR: JSON path expression in JSON_VALUE should return singleton scalar item
-SELECT JSON_VALUE(jsonb '1', '$.a');
- json_value
-------------
-
-(1 row)
-
-SELECT JSON_VALUE(jsonb '1', 'strict $.a' ERROR ON ERROR);
-ERROR: jsonpath member accessor can only be applied to an object
-SELECT JSON_VALUE(jsonb '1', 'strict $.a' DEFAULT 'error' ON ERROR);
- json_value
-------------
- error
-(1 row)
-
-SELECT JSON_VALUE(jsonb '1', 'lax $.a' ERROR ON ERROR);
- json_value
-------------
-
-(1 row)
-
-SELECT JSON_VALUE(jsonb '1', 'lax $.a' ERROR ON EMPTY ERROR ON ERROR);
-ERROR: no SQL/JSON item
-SELECT JSON_VALUE(jsonb '1', 'strict $.a' DEFAULT 2 ON ERROR);
- json_value
-------------
- 2
-(1 row)
-
-SELECT JSON_VALUE(jsonb '1', 'lax $.a' DEFAULT 2 ON ERROR);
- json_value
-------------
-
-(1 row)
-
-SELECT JSON_VALUE(jsonb '1', 'lax $.a' DEFAULT '2' ON ERROR);
- json_value
-------------
-
-(1 row)
-
-SELECT JSON_VALUE(jsonb '1', 'lax $.a' NULL ON EMPTY DEFAULT '2' ON ERROR);
- json_value
-------------
-
-(1 row)
-
-SELECT JSON_VALUE(jsonb '1', 'lax $.a' DEFAULT '2' ON EMPTY DEFAULT '3' ON ERROR);
- json_value
-------------
- 2
-(1 row)
-
-SELECT JSON_VALUE(jsonb '1', 'lax $.a' ERROR ON EMPTY DEFAULT '3' ON ERROR);
- json_value
-------------
- 3
-(1 row)
-
-SELECT JSON_VALUE(jsonb '[1,2]', '$[*]' ERROR ON ERROR);
-ERROR: JSON path expression in JSON_VALUE should return singleton scalar item
-SELECT JSON_VALUE(jsonb '[1,2]', '$[*]' DEFAULT '0' ON ERROR);
- json_value
-------------
- 0
-(1 row)
-
-SELECT JSON_VALUE(jsonb '[" "]', '$[*]' RETURNING int ERROR ON ERROR);
-ERROR: invalid input syntax for type integer: " "
-SELECT JSON_VALUE(jsonb '[" "]', '$[*]' RETURNING int DEFAULT 2 + 3 ON ERROR);
- json_value
-------------
- 5
-(1 row)
-
-SELECT JSON_VALUE(jsonb '["1"]', '$[*]' RETURNING int DEFAULT 2 + 3 ON ERROR);
- json_value
-------------
- 1
-(1 row)
-
-SELECT
- x,
- JSON_VALUE(
- jsonb '{"a": 1, "b": 2}',
- '$.* ? (@ > $x)' PASSING x AS x
- RETURNING int
- DEFAULT -1 ON EMPTY
- DEFAULT -2 ON ERROR
- ) y
-FROM
- generate_series(0, 2) x;
- x | y
----+----
- 0 | -2
- 1 | 2
- 2 | -1
-(3 rows)
-
-SELECT JSON_VALUE(jsonb 'null', '$a' PASSING point ' (1, 2 )' AS a);
- json_value
-------------
- (1,2)
-(1 row)
-
-SELECT JSON_VALUE(jsonb 'null', '$a' PASSING point ' (1, 2 )' AS a RETURNING point);
- json_value
-------------
- (1,2)
-(1 row)
-
--- Test timestamptz passing and output
-SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts);
- json_value
-------------------------------
- Tue Feb 20 18:34:56 2018 PST
-(1 row)
-
-SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING timestamptz);
- json_value
-------------------------------
- Tue Feb 20 18:34:56 2018 PST
-(1 row)
-
-SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING timestamp);
- json_value
---------------------------
- Tue Feb 20 18:34:56 2018
-(1 row)
-
-SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING json);
- json_value
------------------------------
- "2018-02-21T02:34:56+00:00"
-(1 row)
-
-SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING jsonb);
- json_value
------------------------------
- "2018-02-21T02:34:56+00:00"
-(1 row)
-
--- JSON_QUERY
-SELECT
- JSON_QUERY(js, '$'),
- JSON_QUERY(js, '$' WITHOUT WRAPPER),
- JSON_QUERY(js, '$' WITH CONDITIONAL WRAPPER),
- JSON_QUERY(js, '$' WITH UNCONDITIONAL ARRAY WRAPPER),
- JSON_QUERY(js, '$' WITH ARRAY WRAPPER)
-FROM
- (VALUES
- (jsonb 'null'),
- ('12.3'),
- ('true'),
- ('"aaa"'),
- ('[1, null, "2"]'),
- ('{"a": 1, "b": [2]}')
- ) foo(js);
- json_query | json_query | json_query | json_query | json_query
---------------------+--------------------+--------------------+----------------------+----------------------
- null | null | [null] | [null] | [null]
- 12.3 | 12.3 | [12.3] | [12.3] | [12.3]
- true | true | [true] | [true] | [true]
- "aaa" | "aaa" | ["aaa"] | ["aaa"] | ["aaa"]
- [1, null, "2"] | [1, null, "2"] | [1, null, "2"] | [[1, null, "2"]] | [[1, null, "2"]]
- {"a": 1, "b": [2]} | {"a": 1, "b": [2]} | {"a": 1, "b": [2]} | [{"a": 1, "b": [2]}] | [{"a": 1, "b": [2]}]
-(6 rows)
-
-SELECT
- JSON_QUERY(js, 'strict $[*]') AS "unspec",
- JSON_QUERY(js, 'strict $[*]' WITHOUT WRAPPER) AS "without",
- JSON_QUERY(js, 'strict $[*]' WITH CONDITIONAL WRAPPER) AS "with cond",
- JSON_QUERY(js, 'strict $[*]' WITH UNCONDITIONAL ARRAY WRAPPER) AS "with uncond",
- JSON_QUERY(js, 'strict $[*]' WITH ARRAY WRAPPER) AS "with"
-FROM
- (VALUES
- (jsonb '1'),
- ('[]'),
- ('[null]'),
- ('[12.3]'),
- ('[true]'),
- ('["aaa"]'),
- ('[[1, 2, 3]]'),
- ('[{"a": 1, "b": [2]}]'),
- ('[1, "2", null, [3]]')
- ) foo(js);
- unspec | without | with cond | with uncond | with
---------------------+--------------------+---------------------+----------------------+----------------------
- | | | |
- | | | |
- null | null | [null] | [null] | [null]
- 12.3 | 12.3 | [12.3] | [12.3] | [12.3]
- true | true | [true] | [true] | [true]
- "aaa" | "aaa" | ["aaa"] | ["aaa"] | ["aaa"]
- [1, 2, 3] | [1, 2, 3] | [1, 2, 3] | [[1, 2, 3]] | [[1, 2, 3]]
- {"a": 1, "b": [2]} | {"a": 1, "b": [2]} | {"a": 1, "b": [2]} | [{"a": 1, "b": [2]}] | [{"a": 1, "b": [2]}]
- | | [1, "2", null, [3]] | [1, "2", null, [3]] | [1, "2", null, [3]]
-(9 rows)
-
-SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text);
- json_query
-------------
- "aaa"
-(1 row)
-
-SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text KEEP QUOTES);
- json_query
-------------
- "aaa"
-(1 row)
-
-SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text KEEP QUOTES ON SCALAR STRING);
- json_query
-------------
- "aaa"
-(1 row)
-
-SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text OMIT QUOTES);
- json_query
-------------
- aaa
-(1 row)
-
-SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text OMIT QUOTES ON SCALAR STRING);
- json_query
-------------
- aaa
-(1 row)
-
-SELECT JSON_QUERY(jsonb '"aaa"', '$' OMIT QUOTES ERROR ON ERROR);
-ERROR: invalid input syntax for type json
-DETAIL: Token "aaa" is invalid.
-CONTEXT: JSON data, line 1: aaa
-SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING json OMIT QUOTES ERROR ON ERROR);
-ERROR: invalid input syntax for type json
-DETAIL: Token "aaa" is invalid.
-CONTEXT: JSON data, line 1: aaa
-SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING bytea FORMAT JSON OMIT QUOTES ERROR ON ERROR);
- json_query
-------------
- \x616161
-(1 row)
-
--- QUOTES behavior should not be specified when WITH WRAPPER used:
--- Should fail
-SELECT JSON_QUERY(jsonb '[1]', '$' WITH WRAPPER OMIT QUOTES);
-ERROR: SQL/JSON QUOTES behavior must not be specified when WITH WRAPPER is used
-LINE 1: SELECT JSON_QUERY(jsonb '[1]', '$' WITH WRAPPER OMIT QUOTES)...
- ^
-SELECT JSON_QUERY(jsonb '[1]', '$' WITH WRAPPER KEEP QUOTES);
-ERROR: SQL/JSON QUOTES behavior must not be specified when WITH WRAPPER is used
-LINE 1: SELECT JSON_QUERY(jsonb '[1]', '$' WITH WRAPPER KEEP QUOTES)...
- ^
-SELECT JSON_QUERY(jsonb '[1]', '$' WITH CONDITIONAL WRAPPER KEEP QUOTES);
-ERROR: SQL/JSON QUOTES behavior must not be specified when WITH WRAPPER is used
-LINE 1: ...N_QUERY(jsonb '[1]', '$' WITH CONDITIONAL WRAPPER KEEP QUOTE...
- ^
-SELECT JSON_QUERY(jsonb '[1]', '$' WITH CONDITIONAL WRAPPER OMIT QUOTES);
-ERROR: SQL/JSON QUOTES behavior must not be specified when WITH WRAPPER is used
-LINE 1: ...N_QUERY(jsonb '[1]', '$' WITH CONDITIONAL WRAPPER OMIT QUOTE...
- ^
--- Should succeed
-SELECT JSON_QUERY(jsonb '[1]', '$' WITHOUT WRAPPER OMIT QUOTES);
- json_query
-------------
- [1]
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[1]', '$' WITHOUT WRAPPER KEEP QUOTES);
- json_query
-------------
- [1]
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[]', '$[*]');
- json_query
-------------
-
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[]', '$[*]' NULL ON EMPTY);
- json_query
-------------
-
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[]', '$[*]' EMPTY ON EMPTY);
- json_query
-------------
- []
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[]', '$[*]' EMPTY ARRAY ON EMPTY);
- json_query
-------------
- []
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[]', '$[*]' EMPTY OBJECT ON EMPTY);
- json_query
-------------
- {}
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY);
- json_query
-------------
-
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[]', '$[*]' DEFAULT '"empty"' ON EMPTY);
- json_query
-------------
- "empty"
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY NULL ON ERROR);
- json_query
-------------
-
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY EMPTY ARRAY ON ERROR);
- json_query
-------------
- []
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY EMPTY OBJECT ON ERROR);
- json_query
-------------
- {}
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY ERROR ON ERROR);
-ERROR: no SQL/JSON item
-SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON ERROR);
- json_query
-------------
-
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' ERROR ON ERROR);
-ERROR: JSON path expression in JSON_QUERY should return singleton item without wrapper
-HINT: Use WITH WRAPPER clause to wrap SQL/JSON item sequence into array.
-SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' DEFAULT '"empty"' ON ERROR);
- json_query
-------------
- "empty"
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING json);
- json_query
-------------
- [1, 2]
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING json FORMAT JSON);
- json_query
-------------
- [1, 2]
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING jsonb);
- json_query
-------------
- [1, 2]
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING jsonb FORMAT JSON);
- json_query
-------------
- [1, 2]
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING text);
- json_query
-------------
- [1, 2]
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING char(10));
- json_query
-------------
- [1, 2]
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING char(3));
- json_query
-------------
- [1,
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING text FORMAT JSON);
- json_query
-------------
- [1, 2]
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING bytea);
- json_query
-----------------
- \x5b312c20325d
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING bytea FORMAT JSON);
- json_query
-----------------
- \x5b312c20325d
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' RETURNING bytea EMPTY OBJECT ON ERROR);
- json_query
-------------
- \x7b7d
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' RETURNING bytea FORMAT JSON EMPTY OBJECT ON ERROR);
- json_query
-------------
- \x7b7d
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' RETURNING json EMPTY OBJECT ON ERROR);
- json_query
-------------
- {}
-(1 row)
-
-SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' RETURNING jsonb EMPTY OBJECT ON ERROR);
- json_query
-------------
- {}
-(1 row)
-
-SELECT
- x, y,
- JSON_QUERY(
- jsonb '[1,2,3,4,5,null]',
- '$[*] ? (@ >= $x && @ <= $y)'
- PASSING x AS x, y AS y
- WITH CONDITIONAL WRAPPER
- EMPTY ARRAY ON EMPTY
- ) list
-FROM
- generate_series(0, 4) x,
- generate_series(0, 4) y;
- x | y | list
----+---+--------------
- 0 | 0 | []
- 0 | 1 | [1]
- 0 | 2 | [1, 2]
- 0 | 3 | [1, 2, 3]
- 0 | 4 | [1, 2, 3, 4]
- 1 | 0 | []
- 1 | 1 | [1]
- 1 | 2 | [1, 2]
- 1 | 3 | [1, 2, 3]
- 1 | 4 | [1, 2, 3, 4]
- 2 | 0 | []
- 2 | 1 | []
- 2 | 2 | [2]
- 2 | 3 | [2, 3]
- 2 | 4 | [2, 3, 4]
- 3 | 0 | []
- 3 | 1 | []
- 3 | 2 | []
- 3 | 3 | [3]
- 3 | 4 | [3, 4]
- 4 | 0 | []
- 4 | 1 | []
- 4 | 2 | []
- 4 | 3 | []
- 4 | 4 | [4]
-(25 rows)
-
--- Extension: record types returning
-CREATE TYPE sqljsonb_rec AS (a int, t text, js json, jb jsonb, jsa json[]);
-CREATE TYPE sqljsonb_reca AS (reca sqljsonb_rec[]);
-SELECT JSON_QUERY(jsonb '[{"a": 1, "b": "foo", "t": "aaa", "js": [1, "2", {}], "jb": {"x": [1, "2", {}]}}, {"a": 2}]', '$[0]' RETURNING sqljsonb_rec);
- json_query
------------------------------------------------------
- (1,aaa,"[1, ""2"", {}]","{""x"": [1, ""2"", {}]}",)
-(1 row)
-
-SELECT * FROM unnest((JSON_QUERY(jsonb '{"jsa": [{"a": 1, "b": ["foo"]}, {"a": 2, "c": {}}, 123]}', '$' RETURNING sqljsonb_rec)).jsa);
- unnest
-------------------------
- {"a": 1, "b": ["foo"]}
- {"a": 2, "c": {}}
- 123
-(3 rows)
-
-SELECT * FROM unnest((JSON_QUERY(jsonb '{"reca": [{"a": 1, "t": ["foo", []]}, {"a": 2, "jb": [{}, true]}]}', '$' RETURNING sqljsonb_reca)).reca);
- a | t | js | jb | jsa
----+-------------+----+------------+-----
- 1 | ["foo", []] | | |
- 2 | | | [{}, true] |
-(2 rows)
-
--- Extension: array types returning
-SELECT JSON_QUERY(jsonb '[1,2,null,"3"]', '$[*]' RETURNING int[] WITH WRAPPER);
- json_query
---------------
- {1,2,NULL,3}
-(1 row)
-
-SELECT * FROM unnest(JSON_QUERY(jsonb '[{"a": 1, "t": ["foo", []]}, {"a": 2, "jb": [{}, true]}]', '$' RETURNING sqljsonb_rec[]));
- a | t | js | jb | jsa
----+-------------+----+------------+-----
- 1 | ["foo", []] | | |
- 2 | | | [{}, true] |
-(2 rows)
-
--- Extension: domain types returning
-SELECT JSON_QUERY(jsonb '{"a": 1}', '$.a' RETURNING sqljsonb_int_not_null);
- json_query
-------------
- 1
-(1 row)
-
-SELECT JSON_QUERY(jsonb '{"a": 1}', '$.b' RETURNING sqljsonb_int_not_null);
-ERROR: domain sqljsonb_int_not_null does not allow null values
--- Test timestamptz passing and output
-SELECT JSON_QUERY(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts);
- json_query
------------------------------
- "2018-02-21T02:34:56+00:00"
-(1 row)
-
-SELECT JSON_QUERY(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING json);
- json_query
------------------------------
- "2018-02-21T02:34:56+00:00"
-(1 row)
-
-SELECT JSON_QUERY(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING jsonb);
- json_query
------------------------------
- "2018-02-21T02:34:56+00:00"
-(1 row)
-
--- Test constraints
-CREATE TABLE test_jsonb_constraints (
- js text,
- i int,
- x jsonb DEFAULT JSON_QUERY(jsonb '[1,2]', '$[*]' WITH WRAPPER)
- CONSTRAINT test_jsonb_constraint1
- CHECK (js IS JSON)
- CONSTRAINT test_jsonb_constraint2
- CHECK (JSON_EXISTS(js::jsonb, '$.a' PASSING i + 5 AS int, i::text AS txt, array[1,2,3] as arr))
- CONSTRAINT test_jsonb_constraint3
- CHECK (JSON_VALUE(js::jsonb, '$.a' RETURNING int DEFAULT ('12' || i)::int ON EMPTY ERROR ON ERROR) > i)
- CONSTRAINT test_jsonb_constraint4
- CHECK (JSON_QUERY(js::jsonb, '$.a' WITH CONDITIONAL WRAPPER EMPTY OBJECT ON ERROR) < jsonb '[10]')
- CONSTRAINT test_jsonb_constraint5
- CHECK (JSON_QUERY(js::jsonb, '$.a' RETURNING char(5) OMIT QUOTES EMPTY ARRAY ON EMPTY) > 'a' COLLATE "C")
- CONSTRAINT test_jsonb_constraint6
- CHECK (JSON_EXISTS(js::jsonb, 'strict $.a' RETURNING int TRUE ON ERROR) < 2)
-);
-\d test_jsonb_constraints
- Table "public.test_jsonb_constraints"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+--------------------------------------------------------------------------------
- js | text | | |
- i | integer | | |
- x | jsonb | | | JSON_QUERY('[1, 2]'::jsonb, '$[*]' RETURNING jsonb WITH UNCONDITIONAL WRAPPER)
-Check constraints:
- "test_jsonb_constraint1" CHECK (js IS JSON)
- "test_jsonb_constraint2" CHECK (JSON_EXISTS(js::jsonb, '$."a"' PASSING i + 5 AS int, i::text AS txt, ARRAY[1, 2, 3] AS arr))
- "test_jsonb_constraint3" CHECK (JSON_VALUE(js::jsonb, '$."a"' RETURNING integer DEFAULT ('12'::text || i)::integer ON EMPTY ERROR ON ERROR) > i)
- "test_jsonb_constraint4" CHECK (JSON_QUERY(js::jsonb, '$."a"' RETURNING jsonb WITH CONDITIONAL WRAPPER EMPTY OBJECT ON ERROR) < '[10]'::jsonb)
- "test_jsonb_constraint5" CHECK (JSON_QUERY(js::jsonb, '$."a"' RETURNING character(5) OMIT QUOTES EMPTY ARRAY ON EMPTY) > ('a'::bpchar COLLATE "C"))
- "test_jsonb_constraint6" CHECK (JSON_EXISTS(js::jsonb, 'strict $."a"' RETURNING integer TRUE ON ERROR) < 2)
-
-SELECT check_clause
-FROM information_schema.check_constraints
-WHERE constraint_name LIKE 'test_jsonb_constraint%'
-ORDER BY 1;
- check_clause
---------------------------------------------------------------------------------------------------------------------------
- ((JSON_EXISTS((js)::jsonb, 'strict $."a"' RETURNING integer TRUE ON ERROR) < 2))
- ((JSON_QUERY((js)::jsonb, '$."a"' RETURNING character(5) OMIT QUOTES EMPTY ARRAY ON EMPTY) > ('a'::bpchar COLLATE "C")))
- ((JSON_QUERY((js)::jsonb, '$."a"' RETURNING jsonb WITH CONDITIONAL WRAPPER EMPTY OBJECT ON ERROR) < '[10]'::jsonb))
- ((JSON_VALUE((js)::jsonb, '$."a"' RETURNING integer DEFAULT (('12'::text || i))::integer ON EMPTY ERROR ON ERROR) > i))
- ((js IS JSON))
- (JSON_EXISTS((js)::jsonb, '$."a"' PASSING (i + 5) AS int, (i)::text AS txt, ARRAY[1, 2, 3] AS arr))
-(6 rows)
-
-SELECT pg_get_expr(adbin, adrelid)
-FROM pg_attrdef
-WHERE adrelid = 'test_jsonb_constraints'::regclass
-ORDER BY 1;
- pg_get_expr
---------------------------------------------------------------------------------
- JSON_QUERY('[1, 2]'::jsonb, '$[*]' RETURNING jsonb WITH UNCONDITIONAL WRAPPER)
-(1 row)
-
-INSERT INTO test_jsonb_constraints VALUES ('', 1);
-ERROR: new row for relation "test_jsonb_constraints" violates check constraint "test_jsonb_constraint1"
-DETAIL: Failing row contains (, 1, [1, 2]).
-INSERT INTO test_jsonb_constraints VALUES ('1', 1);
-ERROR: new row for relation "test_jsonb_constraints" violates check constraint "test_jsonb_constraint2"
-DETAIL: Failing row contains (1, 1, [1, 2]).
-INSERT INTO test_jsonb_constraints VALUES ('[]');
-ERROR: new row for relation "test_jsonb_constraints" violates check constraint "test_jsonb_constraint2"
-DETAIL: Failing row contains ([], null, [1, 2]).
-INSERT INTO test_jsonb_constraints VALUES ('{"b": 1}', 1);
-ERROR: new row for relation "test_jsonb_constraints" violates check constraint "test_jsonb_constraint2"
-DETAIL: Failing row contains ({"b": 1}, 1, [1, 2]).
-INSERT INTO test_jsonb_constraints VALUES ('{"a": 1}', 1);
-ERROR: new row for relation "test_jsonb_constraints" violates check constraint "test_jsonb_constraint3"
-DETAIL: Failing row contains ({"a": 1}, 1, [1, 2]).
-INSERT INTO test_jsonb_constraints VALUES ('{"a": 7}', 1);
-ERROR: new row for relation "test_jsonb_constraints" violates check constraint "test_jsonb_constraint5"
-DETAIL: Failing row contains ({"a": 7}, 1, [1, 2]).
-INSERT INTO test_jsonb_constraints VALUES ('{"a": 10}', 1);
-ERROR: new row for relation "test_jsonb_constraints" violates check constraint "test_jsonb_constraint4"
-DETAIL: Failing row contains ({"a": 10}, 1, [1, 2]).
-DROP TABLE test_jsonb_constraints;
--- Test mutabilily od query functions
-CREATE TABLE test_jsonb_mutability(js jsonb);
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$'));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a[0]'));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime()'));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@ < $.datetime())'));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime() < $.datetime())'));
-ERROR: functions in index expression must be marked IMMUTABLE
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime() < $.datetime("HH:MI TZH"))'));
-ERROR: functions in index expression must be marked IMMUTABLE
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime("HH:MI TZH") < $.datetime("HH:MI TZH"))'));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime("HH:MI") < $.datetime("YY-MM-DD HH:MI"))'));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime("HH:MI TZH") < $.datetime("YY-MM-DD HH:MI"))'));
-ERROR: functions in index expression must be marked IMMUTABLE
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime("HH:MI TZH") < $x' PASSING '12:34'::timetz AS x));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime("HH:MI TZH") < $y' PASSING '12:34'::timetz AS x));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime() < $x' PASSING '12:34'::timetz AS x));
-ERROR: functions in index expression must be marked IMMUTABLE
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime() < $x' PASSING '1234'::int AS x));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime() ? (@ == $x)' PASSING '12:34'::time AS x));
-ERROR: functions in index expression must be marked IMMUTABLE
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime("YY-MM-DD") ? (@ == $x)' PASSING '2020-07-14'::date AS x));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$[1, $.a ? (@.datetime() == $x)]' PASSING '12:34'::time AS x));
-ERROR: functions in index expression must be marked IMMUTABLE
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$[1, 0 to $.a ? (@.datetime() == $x)]' PASSING '12:34'::time AS x));
-ERROR: functions in index expression must be marked IMMUTABLE
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$[1, $.a ? (@.datetime("HH:MI") == $x)]' PASSING '12:34'::time AS x));
-DROP TABLE test_jsonb_mutability;
--- JSON_TABLE
--- Should fail (JSON_TABLE can be used only in FROM clause)
-SELECT JSON_TABLE('[]', '$');
-ERROR: syntax error at or near "("
-LINE 1: SELECT JSON_TABLE('[]', '$');
- ^
--- Should fail (no columns)
-SELECT * FROM JSON_TABLE(NULL, '$' COLUMNS ());
-ERROR: syntax error at or near ")"
-LINE 1: SELECT * FROM JSON_TABLE(NULL, '$' COLUMNS ());
- ^
-SELECT * FROM JSON_TABLE (NULL::jsonb, '$' COLUMNS (v1 timestamp)) AS f (v1, v2);
-ERROR: JSON_TABLE function has 1 columns available but 2 columns specified
--- NULL => empty table
-SELECT * FROM JSON_TABLE(NULL::jsonb, '$' COLUMNS (foo int)) bar;
- foo
------
-(0 rows)
-
---
-SELECT * FROM JSON_TABLE(jsonb '123', '$'
- COLUMNS (item int PATH '$', foo int)) bar;
- item | foo
-------+-----
- 123 |
-(1 row)
-
--- JSON_TABLE: basic functionality
-CREATE DOMAIN jsonb_test_domain AS text CHECK (value <> 'foo');
-SELECT *
-FROM
- (VALUES
- ('1'),
- ('[]'),
- ('{}'),
- ('[1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""]')
- ) vals(js)
- LEFT OUTER JOIN
--- JSON_TABLE is implicitly lateral
- JSON_TABLE(
- vals.js::jsonb, 'lax $[*]'
- COLUMNS (
- id FOR ORDINALITY,
- id2 FOR ORDINALITY, -- allowed additional ordinality columns
- "int" int PATH '$',
- "text" text PATH '$',
- "char(4)" char(4) PATH '$',
- "bool" bool PATH '$',
- "numeric" numeric PATH '$',
- "domain" jsonb_test_domain PATH '$',
- js json PATH '$',
- jb jsonb PATH '$',
- jst text FORMAT JSON PATH '$',
- jsc char(4) FORMAT JSON PATH '$',
- jsv varchar(4) FORMAT JSON PATH '$',
- jsb jsonb FORMAT JSON PATH '$',
- jsbq jsonb FORMAT JSON PATH '$' OMIT QUOTES,
- aaa int, -- implicit path '$."aaa"',
- aaa1 int PATH '$.aaa',
- exists1 bool EXISTS PATH '$.aaa',
- exists2 int EXISTS PATH '$.aaa',
- exists3 int EXISTS PATH 'strict $.aaa' UNKNOWN ON ERROR,
- exists4 text EXISTS PATH 'strict $.aaa' FALSE ON ERROR,
- js2 json PATH '$',
- jsb2w jsonb PATH '$' WITH WRAPPER,
- jsb2q jsonb PATH '$' OMIT QUOTES,
- ia int[] PATH '$',
- ta text[] PATH '$',
- jba jsonb[] PATH '$'
- )
- ) jt
- ON true;
- js | id | id2 | int | text | char(4) | bool | numeric | domain | js | jb | jst | jsc | jsv | jsb | jsbq | aaa | aaa1 | exists1 | exists2 | exists3 | exists4 | js2 | jsb2w | jsb2q | ia | ta | jba
----------------------------------------------------------------------------------------+----+-----+-----+---------+---------+------+---------+---------+--------------+--------------+--------------+------+------+--------------+--------------+-----+------+---------+---------+---------+---------+--------------+----------------+--------------+----+----+-----
- 1 | 1 | 1 | 1 | 1 | 1 | | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | | | f | 0 | | false | 1 | [1] | 1 | | |
- [] | | | | | | | | | | | | | | | | | | | | | | | | | | |
- {} | 1 | 1 | | | | | | | {} | {} | {} | {} | {} | {} | {} | | | f | 0 | | false | {} | [{}] | {} | | |
- [1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""] | 1 | 1 | 1 | 1 | 1 | | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | | | f | 0 | | false | 1 | [1] | 1 | | |
- [1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""] | 2 | 2 | 1 | 1.23 | 1.23 | | 1.23 | 1.23 | 1.23 | 1.23 | 1.23 | 1.23 | 1.23 | 1.23 | 1.23 | | | f | 0 | | false | 1.23 | [1.23] | 1.23 | | |
- [1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""] | 3 | 3 | 2 | 2 | 2 | | 2 | 2 | "2" | "2" | "2" | "2" | "2" | "2" | 2 | | | f | 0 | | false | "2" | ["2"] | 2 | | |
- [1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""] | 4 | 4 | | aaaaaaa | aaaa | | | aaaaaaa | "aaaaaaa" | "aaaaaaa" | "aaaaaaa" | "aaa | "aaa | "aaaaaaa" | | | | f | 0 | | false | "aaaaaaa" | ["aaaaaaa"] | | | |
- [1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""] | 5 | 5 | | foo | foo | | | | "foo" | "foo" | "foo" | "foo | "foo | "foo" | | | | f | 0 | | false | "foo" | ["foo"] | | | |
- [1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""] | 6 | 6 | | | | | | | null | null | null | null | null | null | null | | | f | 0 | | false | null | [null] | null | | |
- [1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""] | 7 | 7 | 0 | false | fals | f | | false | false | false | false | fals | fals | false | false | | | f | 0 | | false | false | [false] | false | | |
- [1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""] | 8 | 8 | 1 | true | true | t | | true | true | true | true | true | true | true | true | | | f | 0 | | false | true | [true] | true | | |
- [1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""] | 9 | 9 | | | | | | | {"aaa": 123} | {"aaa": 123} | {"aaa": 123} | {"aa | {"aa | {"aaa": 123} | {"aaa": 123} | 123 | 123 | t | 1 | 1 | true | {"aaa": 123} | [{"aaa": 123}] | {"aaa": 123} | | |
- [1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""] | 10 | 10 | | [1,2] | [1,2 | | | [1,2] | "[1,2]" | "[1,2]" | "[1,2]" | "[1, | "[1, | "[1,2]" | [1, 2] | | | f | 0 | | false | "[1,2]" | ["[1,2]"] | [1, 2] | | |
- [1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""] | 11 | 11 | | "str" | "str | | | "str" | "\"str\"" | "\"str\"" | "\"str\"" | "\"s | "\"s | "\"str\"" | "str" | | | f | 0 | | false | "\"str\"" | ["\"str\""] | "str" | | |
-(14 rows)
-
--- JSON_TABLE: Test backward parsing
-CREATE VIEW jsonb_table_view AS
-SELECT * FROM
- JSON_TABLE(
- jsonb 'null', 'lax $[*]' PASSING 1 + 2 AS a, json '"foo"' AS "b c"
- COLUMNS (
- id FOR ORDINALITY,
- id2 FOR ORDINALITY, -- allowed additional ordinality columns
- "int" int PATH '$',
- "text" text PATH '$',
- "char(4)" char(4) PATH '$',
- "bool" bool PATH '$',
- "numeric" numeric PATH '$',
- "domain" jsonb_test_domain PATH '$',
- js json PATH '$',
- jb jsonb PATH '$',
- jst text FORMAT JSON PATH '$',
- jsc char(4) FORMAT JSON PATH '$',
- jsv varchar(4) FORMAT JSON PATH '$',
- jsb jsonb FORMAT JSON PATH '$',
- jsbq jsonb FORMAT JSON PATH '$' OMIT QUOTES,
- aaa int, -- implicit path '$."aaa"',
- aaa1 int PATH '$.aaa',
- exists1 bool EXISTS PATH '$.aaa',
- exists2 int EXISTS PATH '$.aaa' TRUE ON ERROR,
- exists3 text EXISTS PATH 'strict $.aaa' UNKNOWN ON ERROR,
- js2 json PATH '$',
- jsb2w jsonb PATH '$' WITH WRAPPER,
- jsb2q jsonb PATH '$' OMIT QUOTES,
- ia int[] PATH '$',
- ta text[] PATH '$',
- jba jsonb[] PATH '$',
- NESTED PATH '$[1]' AS p1 COLUMNS (
- a1 int,
- NESTED PATH '$[*]' AS "p1 1" COLUMNS (
- a11 text
- ),
- b1 text
- ),
- NESTED PATH '$[2]' AS p2 COLUMNS (
- NESTED PATH '$[*]' AS "p2:1" COLUMNS (
- a21 text
- ),
- NESTED PATH '$[*]' AS p22 COLUMNS (
- a22 text
- )
- )
- )
- );
-\sv jsonb_table_view
-CREATE OR REPLACE VIEW public.jsonb_table_view AS
- SELECT "json_table".id,
- "json_table".id2,
- "json_table"."int",
- "json_table".text,
- "json_table"."char(4)",
- "json_table".bool,
- "json_table"."numeric",
- "json_table".domain,
- "json_table".js,
- "json_table".jb,
- "json_table".jst,
- "json_table".jsc,
- "json_table".jsv,
- "json_table".jsb,
- "json_table".jsbq,
- "json_table".aaa,
- "json_table".aaa1,
- "json_table".exists1,
- "json_table".exists2,
- "json_table".exists3,
- "json_table".js2,
- "json_table".jsb2w,
- "json_table".jsb2q,
- "json_table".ia,
- "json_table".ta,
- "json_table".jba,
- "json_table".a1,
- "json_table".b1,
- "json_table".a11,
- "json_table".a21,
- "json_table".a22
- FROM JSON_TABLE(
- 'null'::jsonb, '$[*]' AS json_table_path_1
- PASSING
- 1 + 2 AS a,
- '"foo"'::json AS "b c"
- COLUMNS (
- id FOR ORDINALITY,
- id2 FOR ORDINALITY,
- "int" integer PATH '$',
- text text PATH '$',
- "char(4)" character(4) PATH '$',
- bool boolean PATH '$',
- "numeric" numeric PATH '$',
- domain jsonb_test_domain PATH '$',
- js json PATH '$',
- jb jsonb PATH '$',
- jst text FORMAT JSON PATH '$',
- jsc character(4) FORMAT JSON PATH '$',
- jsv character varying(4) FORMAT JSON PATH '$',
- jsb jsonb PATH '$',
- jsbq jsonb PATH '$' OMIT QUOTES,
- aaa integer PATH '$."aaa"',
- aaa1 integer PATH '$."aaa"',
- exists1 boolean EXISTS PATH '$."aaa"',
- exists2 integer EXISTS PATH '$."aaa"' TRUE ON ERROR,
- exists3 text EXISTS PATH 'strict $."aaa"' UNKNOWN ON ERROR,
- js2 json PATH '$',
- jsb2w jsonb PATH '$' WITH UNCONDITIONAL WRAPPER,
- jsb2q jsonb PATH '$' OMIT QUOTES,
- ia integer[] PATH '$',
- ta text[] PATH '$',
- jba jsonb[] PATH '$',
- NESTED PATH '$[1]' AS p1
- COLUMNS (
- a1 integer PATH '$."a1"',
- b1 text PATH '$."b1"',
- NESTED PATH '$[*]' AS "p1 1"
- COLUMNS (
- a11 text PATH '$."a11"'
- )
- ),
- NESTED PATH '$[2]' AS p2
- COLUMNS (
- NESTED PATH '$[*]' AS "p2:1"
- COLUMNS (
- a21 text PATH '$."a21"'
- ),
- NESTED PATH '$[*]' AS p22
- COLUMNS (
- a22 text PATH '$."a22"'
- )
- )
- )
- PLAN (json_table_path_1 OUTER ((p1 OUTER "p1 1") UNION (p2 OUTER ("p2:1" UNION p22))))
- )
-EXPLAIN (COSTS OFF, VERBOSE) SELECT * FROM jsonb_table_view;
- QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- Table Function Scan on "json_table"
- Output: "json_table".id, "json_table".id2, "json_table"."int", "json_table".text, "json_table"."char(4)", "json_table".bool, "json_table"."numeric", "json_table".domain, "json_table".js, "json_table".jb, "json_table".jst, "json_table".jsc, "json_table".jsv, "json_table".jsb, "json_table".jsbq, "json_table".aaa, "json_table".aaa1, "json_table".exists1, "json_table".exists2, "json_table".exists3, "json_table".js2, "json_table".jsb2w, "json_table".jsb2q, "json_table".ia, "json_table".ta, "json_table".jba, "json_table".a1, "json_table".b1, "json_table".a11, "json_table".a21, "json_table".a22
- Table Function Call: JSON_TABLE('null'::jsonb, '$[*]' AS json_table_path_1 PASSING 3 AS a, '"foo"'::jsonb AS "b c" COLUMNS (id FOR ORDINALITY, id2 FOR ORDINALITY, "int" integer PATH '$', text text PATH '$', "char(4)" character(4) PATH '$', bool boolean PATH '$', "numeric" numeric PATH '$', domain jsonb_test_domain PATH '$', js json PATH '$', jb jsonb PATH '$', jst text FORMAT JSON PATH '$', jsc character(4) FORMAT JSON PATH '$', jsv character varying(4) FORMAT JSON PATH '$', jsb jsonb PATH '$', jsbq jsonb PATH '$' OMIT QUOTES, aaa integer PATH '$."aaa"', aaa1 integer PATH '$."aaa"', exists1 boolean EXISTS PATH '$."aaa"', exists2 integer EXISTS PATH '$."aaa"' TRUE ON ERROR, exists3 text EXISTS PATH 'strict $."aaa"' UNKNOWN ON ERROR, js2 json PATH '$', jsb2w jsonb PATH '$' WITH UNCONDITIONAL WRAPPER, jsb2q jsonb PATH '$' OMIT QUOTES, ia integer[] PATH '$', ta text[] PATH '$', jba jsonb[] PATH '$', NESTED PATH '$[1]' AS p1 COLUMNS (a1 integer PATH '$."a1"', b1 text PATH '$."b1"', NESTED PATH '$[*]' AS "p1 1" COLUMNS (a11 text PATH '$."a11"')), NESTED PATH '$[2]' AS p2 COLUMNS ( NESTED PATH '$[*]' AS "p2:1" COLUMNS (a21 text PATH '$."a21"'), NESTED PATH '$[*]' AS p22 COLUMNS (a22 text PATH '$."a22"'))) PLAN (json_table_path_1 OUTER ((p1 OUTER "p1 1") UNION (p2 OUTER ("p2:1" UNION p22)))))
-(3 rows)
-
-DROP VIEW jsonb_table_view;
-DROP DOMAIN jsonb_test_domain;
--- JSON_TABLE: ON EMPTY/ON ERROR behavior
-SELECT *
-FROM
- (VALUES ('1'), ('"err"')) vals(js),
- JSON_TABLE(vals.js::jsonb, '$' COLUMNS (a int PATH '$')) jt;
- js | a
--------+---
- 1 | 1
- "err" |
-(2 rows)
-
-SELECT *
-FROM
- (VALUES ('1'), ('"err"')) vals(js)
- LEFT OUTER JOIN
- JSON_TABLE(vals.js::jsonb, '$' COLUMNS (a int PATH '$') ERROR ON ERROR) jt
- ON true;
-ERROR: invalid input syntax for type integer: "err"
-SELECT *
-FROM
- (VALUES ('1'), ('"err"')) vals(js)
- LEFT OUTER JOIN
- JSON_TABLE(vals.js::jsonb, '$' COLUMNS (a int PATH '$' ERROR ON ERROR)) jt
- ON true;
-ERROR: invalid input syntax for type integer: "err"
-SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (a int PATH '$.a' ERROR ON EMPTY)) jt;
- a
----
-
-(1 row)
-
-SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (a int PATH 'strict $.a' ERROR ON EMPTY) ERROR ON ERROR) jt;
-ERROR: jsonpath member accessor can only be applied to an object
-SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (a int PATH 'lax $.a' ERROR ON EMPTY) ERROR ON ERROR) jt;
-ERROR: no SQL/JSON item
-SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int PATH '$' DEFAULT 1 ON EMPTY DEFAULT 2 ON ERROR)) jt;
- a
----
- 2
-(1 row)
-
-SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int PATH 'strict $.a' DEFAULT 1 ON EMPTY DEFAULT 2 ON ERROR)) jt;
- a
----
- 2
-(1 row)
-
-SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int PATH 'lax $.a' DEFAULT 1 ON EMPTY DEFAULT 2 ON ERROR)) jt;
- a
----
- 1
-(1 row)
-
--- JSON_TABLE: EXISTS PATH types
-SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int4 EXISTS PATH '$.a'));
- a
----
- 0
-(1 row)
-
-SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int2 EXISTS PATH '$.a'));
-ERROR: cannot cast type boolean to smallint
-LINE 1: ...ELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int2 EXI...
- ^
-SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int8 EXISTS PATH '$.a'));
-ERROR: cannot cast type boolean to bigint
-LINE 1: ...ELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int8 EXI...
- ^
-SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a float4 EXISTS PATH '$.a'));
-ERROR: cannot cast type boolean to real
-LINE 1: ...ELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a float4 E...
- ^
-SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a char(3) EXISTS PATH '$.a'));
- a
------
- fal
-(1 row)
-
-SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a json EXISTS PATH '$.a'));
-ERROR: cannot cast type boolean to json
-LINE 1: ...ELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a json EXI...
- ^
-SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a jsonb EXISTS PATH '$.a'));
-ERROR: cannot cast type boolean to jsonb
-LINE 1: ...ELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a jsonb EX...
- ^
--- JSON_TABLE: nested paths and plans
--- Should fail (JSON_TABLE columns must contain explicit AS path
--- specifications if explicit PLAN clause is used)
-SELECT * FROM JSON_TABLE(
- jsonb '[]', '$' -- AS <path name> required here
- COLUMNS (
- foo int PATH '$'
- )
- PLAN DEFAULT (UNION)
-) jt;
-ERROR: invalid JSON_TABLE expression
-LINE 2: jsonb '[]', '$' -- AS <path name> required here
- ^
-DETAIL: JSON_TABLE columns must contain explicit AS pathname specification if explicit PLAN clause is used
-SELECT * FROM JSON_TABLE(
- jsonb '[]', '$' AS path1
- COLUMNS (
- NESTED PATH '$' COLUMNS ( -- AS <path name> required here
- foo int PATH '$'
- )
- )
- PLAN DEFAULT (UNION)
-) jt;
-ERROR: invalid JSON_TABLE expression
-LINE 4: NESTED PATH '$' COLUMNS ( -- AS <path name> required here
- ^
-DETAIL: JSON_TABLE columns must contain explicit AS pathname specification if explicit PLAN clause is used
--- Should fail (column names must be distinct)
-SELECT * FROM JSON_TABLE(
- jsonb '[]', '$' AS a
- COLUMNS (
- a int
- )
-) jt;
-ERROR: duplicate JSON_TABLE column name: a
-HINT: JSON_TABLE column names must be distinct from one another.
-SELECT * FROM JSON_TABLE(
- jsonb '[]', '$' AS a
- COLUMNS (
- b int,
- NESTED PATH '$' AS a
- COLUMNS (
- c int
- )
- )
-) jt;
-ERROR: duplicate JSON_TABLE column name: a
-HINT: JSON_TABLE column names must be distinct from one another.
-SELECT * FROM JSON_TABLE(
- jsonb '[]', '$'
- COLUMNS (
- b int,
- NESTED PATH '$' AS b
- COLUMNS (
- c int
- )
- )
-) jt;
-ERROR: duplicate JSON_TABLE column name: b
-HINT: JSON_TABLE column names must be distinct from one another.
-SELECT * FROM JSON_TABLE(
- jsonb '[]', '$'
- COLUMNS (
- NESTED PATH '$' AS a
- COLUMNS (
- b int
- ),
- NESTED PATH '$'
- COLUMNS (
- NESTED PATH '$' AS a
- COLUMNS (
- c int
- )
- )
- )
-) jt;
-ERROR: duplicate JSON_TABLE column name: a
-HINT: JSON_TABLE column names must be distinct from one another.
--- JSON_TABLE: plan validation
-SELECT * FROM JSON_TABLE(
- jsonb 'null', '$[*]' AS p0
- COLUMNS (
- NESTED PATH '$' AS p1 COLUMNS (
- NESTED PATH '$' AS p11 COLUMNS ( foo int ),
- NESTED PATH '$' AS p12 COLUMNS ( bar int )
- ),
- NESTED PATH '$' AS p2 COLUMNS (
- NESTED PATH '$' AS p21 COLUMNS ( baz int )
- )
- )
- PLAN (p1)
-) jt;
-ERROR: invalid JSON_TABLE plan
-LINE 12: PLAN (p1)
- ^
-DETAIL: Path name mismatch: expected p0 but p1 is given.
-SELECT * FROM JSON_TABLE(
- jsonb 'null', '$[*]' AS p0
- COLUMNS (
- NESTED PATH '$' AS p1 COLUMNS (
- NESTED PATH '$' AS p11 COLUMNS ( foo int ),
- NESTED PATH '$' AS p12 COLUMNS ( bar int )
- ),
- NESTED PATH '$' AS p2 COLUMNS (
- NESTED PATH '$' AS p21 COLUMNS ( baz int )
- )
- )
- PLAN (p0)
-) jt;
-ERROR: invalid JSON_TABLE plan
-LINE 4: NESTED PATH '$' AS p1 COLUMNS (
- ^
-DETAIL: Plan node for nested path p1 was not found in plan.
-SELECT * FROM JSON_TABLE(
- jsonb 'null', '$[*]' AS p0
- COLUMNS (
- NESTED PATH '$' AS p1 COLUMNS (
- NESTED PATH '$' AS p11 COLUMNS ( foo int ),
- NESTED PATH '$' AS p12 COLUMNS ( bar int )
- ),
- NESTED PATH '$' AS p2 COLUMNS (
- NESTED PATH '$' AS p21 COLUMNS ( baz int )
- )
- )
- PLAN (p0 OUTER p3)
-) jt;
-ERROR: invalid JSON_TABLE plan
-LINE 4: NESTED PATH '$' AS p1 COLUMNS (
- ^
-DETAIL: Plan node for nested path p1 was not found in plan.
-SELECT * FROM JSON_TABLE(
- jsonb 'null', '$[*]' AS p0
- COLUMNS (
- NESTED PATH '$' AS p1 COLUMNS (
- NESTED PATH '$' AS p11 COLUMNS ( foo int ),
- NESTED PATH '$' AS p12 COLUMNS ( bar int )
- ),
- NESTED PATH '$' AS p2 COLUMNS (
- NESTED PATH '$' AS p21 COLUMNS ( baz int )
- )
- )
- PLAN (p0 UNION p1 UNION p11)
-) jt;
-ERROR: invalid JSON_TABLE plan
-LINE 12: PLAN (p0 UNION p1 UNION p11)
- ^
-DETAIL: Expected INNER or OUTER JSON_TABLE plan node.
-SELECT * FROM JSON_TABLE(
- jsonb 'null', '$[*]' AS p0
- COLUMNS (
- NESTED PATH '$' AS p1 COLUMNS (
- NESTED PATH '$' AS p11 COLUMNS ( foo int ),
- NESTED PATH '$' AS p12 COLUMNS ( bar int )
- ),
- NESTED PATH '$' AS p2 COLUMNS (
- NESTED PATH '$' AS p21 COLUMNS ( baz int )
- )
- )
- PLAN (p0 OUTER (p1 CROSS p13))
-) jt;
-ERROR: invalid JSON_TABLE plan
-LINE 8: NESTED PATH '$' AS p2 COLUMNS (
- ^
-DETAIL: Plan node for nested path p2 was not found in plan.
-SELECT * FROM JSON_TABLE(
- jsonb 'null', '$[*]' AS p0
- COLUMNS (
- NESTED PATH '$' AS p1 COLUMNS (
- NESTED PATH '$' AS p11 COLUMNS ( foo int ),
- NESTED PATH '$' AS p12 COLUMNS ( bar int )
- ),
- NESTED PATH '$' AS p2 COLUMNS (
- NESTED PATH '$' AS p21 COLUMNS ( baz int )
- )
- )
- PLAN (p0 OUTER (p1 CROSS p2))
-) jt;
-ERROR: invalid JSON_TABLE plan
-LINE 5: NESTED PATH '$' AS p11 COLUMNS ( foo int ),
- ^
-DETAIL: Plan node for nested path p11 was not found in plan.
-SELECT * FROM JSON_TABLE(
- jsonb 'null', '$[*]' AS p0
- COLUMNS (
- NESTED PATH '$' AS p1 COLUMNS (
- NESTED PATH '$' AS p11 COLUMNS ( foo int ),
- NESTED PATH '$' AS p12 COLUMNS ( bar int )
- ),
- NESTED PATH '$' AS p2 COLUMNS (
- NESTED PATH '$' AS p21 COLUMNS ( baz int )
- )
- )
- PLAN (p0 OUTER ((p1 UNION p11) CROSS p2))
-) jt;
-ERROR: invalid JSON_TABLE plan
-LINE 12: PLAN (p0 OUTER ((p1 UNION p11) CROSS p2))
- ^
-DETAIL: Plan node contains some extra or duplicate sibling nodes.
-SELECT * FROM JSON_TABLE(
- jsonb 'null', '$[*]' AS p0
- COLUMNS (
- NESTED PATH '$' AS p1 COLUMNS (
- NESTED PATH '$' AS p11 COLUMNS ( foo int ),
- NESTED PATH '$' AS p12 COLUMNS ( bar int )
- ),
- NESTED PATH '$' AS p2 COLUMNS (
- NESTED PATH '$' AS p21 COLUMNS ( baz int )
- )
- )
- PLAN (p0 OUTER ((p1 INNER p11) CROSS p2))
-) jt;
-ERROR: invalid JSON_TABLE plan
-LINE 6: NESTED PATH '$' AS p12 COLUMNS ( bar int )
- ^
-DETAIL: Plan node for nested path p12 was not found in plan.
-SELECT * FROM JSON_TABLE(
- jsonb 'null', '$[*]' AS p0
- COLUMNS (
- NESTED PATH '$' AS p1 COLUMNS (
- NESTED PATH '$' AS p11 COLUMNS ( foo int ),
- NESTED PATH '$' AS p12 COLUMNS ( bar int )
- ),
- NESTED PATH '$' AS p2 COLUMNS (
- NESTED PATH '$' AS p21 COLUMNS ( baz int )
- )
- )
- PLAN (p0 OUTER ((p1 INNER (p12 CROSS p11)) CROSS p2))
-) jt;
-ERROR: invalid JSON_TABLE plan
-LINE 9: NESTED PATH '$' AS p21 COLUMNS ( baz int )
- ^
-DETAIL: Plan node for nested path p21 was not found in plan.
-SELECT * FROM JSON_TABLE(
- jsonb 'null', 'strict $[*]' AS p0
- COLUMNS (
- NESTED PATH '$' AS p1 COLUMNS (
- NESTED PATH '$' AS p11 COLUMNS ( foo int ),
- NESTED PATH '$' AS p12 COLUMNS ( bar int )
- ),
- NESTED PATH '$' AS p2 COLUMNS (
- NESTED PATH '$' AS p21 COLUMNS ( baz int )
- )
- )
- PLAN (p0 OUTER ((p1 INNER (p12 CROSS p11)) CROSS (p2 INNER p21)))
-) jt;
- bar | foo | baz
------+-----+-----
-(0 rows)
-
-SELECT * FROM JSON_TABLE(
- jsonb 'null', 'strict $[*]' -- without root path name
- COLUMNS (
- NESTED PATH '$' AS p1 COLUMNS (
- NESTED PATH '$' AS p11 COLUMNS ( foo int ),
- NESTED PATH '$' AS p12 COLUMNS ( bar int )
- ),
- NESTED PATH '$' AS p2 COLUMNS (
- NESTED PATH '$' AS p21 COLUMNS ( baz int )
- )
- )
- PLAN ((p1 INNER (p12 CROSS p11)) CROSS (p2 INNER p21))
-) jt;
-ERROR: invalid JSON_TABLE expression
-LINE 2: jsonb 'null', 'strict $[*]' -- without root path name
- ^
-DETAIL: JSON_TABLE columns must contain explicit AS pathname specification if explicit PLAN clause is used
--- JSON_TABLE: plan execution
-CREATE TEMP TABLE jsonb_table_test (js jsonb);
-INSERT INTO jsonb_table_test
-VALUES (
- '[
- {"a": 1, "b": [], "c": []},
- {"a": 2, "b": [1, 2, 3], "c": [10, null, 20]},
- {"a": 3, "b": [1, 2], "c": []},
- {"x": "4", "b": [1, 2], "c": 123}
- ]'
-);
--- unspecified plan (outer, union)
-select
- jt.*
-from
- jsonb_table_test jtt,
- json_table (
- jtt.js,'strict $[*]' as p
- columns (
- n for ordinality,
- a int path 'lax $.a' default -1 on empty,
- nested path 'strict $.b[*]' as pb columns ( b int path '$' ),
- nested path 'strict $.c[*]' as pc columns ( c int path '$' )
- )
- ) jt;
- n | a | b | c
----+----+---+----
- 1 | 1 | |
- 2 | 2 | 1 |
- 2 | 2 | 2 |
- 2 | 2 | 3 |
- 2 | 2 | | 10
- 2 | 2 | |
- 2 | 2 | | 20
- 3 | 3 | 1 |
- 3 | 3 | 2 |
- 4 | -1 | 1 |
- 4 | -1 | 2 |
-(11 rows)
-
--- default plan (outer, union)
-select
- jt.*
-from
- jsonb_table_test jtt,
- json_table (
- jtt.js,'strict $[*]' as p
- columns (
- n for ordinality,
- a int path 'lax $.a' default -1 on empty,
- nested path 'strict $.b[*]' as pb columns ( b int path '$' ),
- nested path 'strict $.c[*]' as pc columns ( c int path '$' )
- )
- plan default (outer, union)
- ) jt;
- n | a | b | c
----+----+---+----
- 1 | 1 | |
- 2 | 2 | 1 |
- 2 | 2 | 2 |
- 2 | 2 | 3 |
- 2 | 2 | | 10
- 2 | 2 | |
- 2 | 2 | | 20
- 3 | 3 | 1 |
- 3 | 3 | 2 |
- 4 | -1 | 1 |
- 4 | -1 | 2 |
-(11 rows)
-
--- specific plan (p outer (pb union pc))
-select
- jt.*
-from
- jsonb_table_test jtt,
- json_table (
- jtt.js,'strict $[*]' as p
- columns (
- n for ordinality,
- a int path 'lax $.a' default -1 on empty,
- nested path 'strict $.b[*]' as pb columns ( b int path '$' ),
- nested path 'strict $.c[*]' as pc columns ( c int path '$' )
- )
- plan (p outer (pb union pc))
- ) jt;
- n | a | b | c
----+----+---+----
- 1 | 1 | |
- 2 | 2 | 1 |
- 2 | 2 | 2 |
- 2 | 2 | 3 |
- 2 | 2 | | 10
- 2 | 2 | |
- 2 | 2 | | 20
- 3 | 3 | 1 |
- 3 | 3 | 2 |
- 4 | -1 | 1 |
- 4 | -1 | 2 |
-(11 rows)
-
--- specific plan (p outer (pc union pb))
-select
- jt.*
-from
- jsonb_table_test jtt,
- json_table (
- jtt.js,'strict $[*]' as p
- columns (
- n for ordinality,
- a int path 'lax $.a' default -1 on empty,
- nested path 'strict $.b[*]' as pb columns ( b int path '$' ),
- nested path 'strict $.c[*]' as pc columns ( c int path '$' )
- )
- plan (p outer (pc union pb))
- ) jt;
- n | a | c | b
----+----+----+---
- 1 | 1 | |
- 2 | 2 | 10 |
- 2 | 2 | |
- 2 | 2 | 20 |
- 2 | 2 | | 1
- 2 | 2 | | 2
- 2 | 2 | | 3
- 3 | 3 | | 1
- 3 | 3 | | 2
- 4 | -1 | | 1
- 4 | -1 | | 2
-(11 rows)
-
--- default plan (inner, union)
-select
- jt.*
-from
- jsonb_table_test jtt,
- json_table (
- jtt.js,'strict $[*]' as p
- columns (
- n for ordinality,
- a int path 'lax $.a' default -1 on empty,
- nested path 'strict $.b[*]' as pb columns ( b int path '$' ),
- nested path 'strict $.c[*]' as pc columns ( c int path '$' )
- )
- plan default (inner)
- ) jt;
- n | a | b | c
----+----+---+----
- 2 | 2 | 1 |
- 2 | 2 | 2 |
- 2 | 2 | 3 |
- 2 | 2 | | 10
- 2 | 2 | |
- 2 | 2 | | 20
- 3 | 3 | 1 |
- 3 | 3 | 2 |
- 4 | -1 | 1 |
- 4 | -1 | 2 |
-(10 rows)
-
--- specific plan (p inner (pb union pc))
-select
- jt.*
-from
- jsonb_table_test jtt,
- json_table (
- jtt.js,'strict $[*]' as p
- columns (
- n for ordinality,
- a int path 'lax $.a' default -1 on empty,
- nested path 'strict $.b[*]' as pb columns ( b int path '$' ),
- nested path 'strict $.c[*]' as pc columns ( c int path '$' )
- )
- plan (p inner (pb union pc))
- ) jt;
- n | a | b | c
----+----+---+----
- 2 | 2 | 1 |
- 2 | 2 | 2 |
- 2 | 2 | 3 |
- 2 | 2 | | 10
- 2 | 2 | |
- 2 | 2 | | 20
- 3 | 3 | 1 |
- 3 | 3 | 2 |
- 4 | -1 | 1 |
- 4 | -1 | 2 |
-(10 rows)
-
--- default plan (inner, cross)
-select
- jt.*
-from
- jsonb_table_test jtt,
- json_table (
- jtt.js,'strict $[*]' as p
- columns (
- n for ordinality,
- a int path 'lax $.a' default -1 on empty,
- nested path 'strict $.b[*]' as pb columns ( b int path '$' ),
- nested path 'strict $.c[*]' as pc columns ( c int path '$' )
- )
- plan default (cross, inner)
- ) jt;
- n | a | b | c
----+---+---+----
- 2 | 2 | 1 | 10
- 2 | 2 | 1 |
- 2 | 2 | 1 | 20
- 2 | 2 | 2 | 10
- 2 | 2 | 2 |
- 2 | 2 | 2 | 20
- 2 | 2 | 3 | 10
- 2 | 2 | 3 |
- 2 | 2 | 3 | 20
-(9 rows)
-
--- specific plan (p inner (pb cross pc))
-select
- jt.*
-from
- jsonb_table_test jtt,
- json_table (
- jtt.js,'strict $[*]' as p
- columns (
- n for ordinality,
- a int path 'lax $.a' default -1 on empty,
- nested path 'strict $.b[*]' as pb columns ( b int path '$' ),
- nested path 'strict $.c[*]' as pc columns ( c int path '$' )
- )
- plan (p inner (pb cross pc))
- ) jt;
- n | a | b | c
----+---+---+----
- 2 | 2 | 1 | 10
- 2 | 2 | 1 |
- 2 | 2 | 1 | 20
- 2 | 2 | 2 | 10
- 2 | 2 | 2 |
- 2 | 2 | 2 | 20
- 2 | 2 | 3 | 10
- 2 | 2 | 3 |
- 2 | 2 | 3 | 20
-(9 rows)
-
--- default plan (outer, cross)
-select
- jt.*
-from
- jsonb_table_test jtt,
- json_table (
- jtt.js,'strict $[*]' as p
- columns (
- n for ordinality,
- a int path 'lax $.a' default -1 on empty,
- nested path 'strict $.b[*]' as pb columns ( b int path '$' ),
- nested path 'strict $.c[*]' as pc columns ( c int path '$' )
- )
- plan default (outer, cross)
- ) jt;
- n | a | b | c
----+----+---+----
- 1 | 1 | |
- 2 | 2 | 1 | 10
- 2 | 2 | 1 |
- 2 | 2 | 1 | 20
- 2 | 2 | 2 | 10
- 2 | 2 | 2 |
- 2 | 2 | 2 | 20
- 2 | 2 | 3 | 10
- 2 | 2 | 3 |
- 2 | 2 | 3 | 20
- 3 | 3 | |
- 4 | -1 | |
-(12 rows)
-
--- specific plan (p outer (pb cross pc))
-select
- jt.*
-from
- jsonb_table_test jtt,
- json_table (
- jtt.js,'strict $[*]' as p
- columns (
- n for ordinality,
- a int path 'lax $.a' default -1 on empty,
- nested path 'strict $.b[*]' as pb columns ( b int path '$' ),
- nested path 'strict $.c[*]' as pc columns ( c int path '$' )
- )
- plan (p outer (pb cross pc))
- ) jt;
- n | a | b | c
----+----+---+----
- 1 | 1 | |
- 2 | 2 | 1 | 10
- 2 | 2 | 1 |
- 2 | 2 | 1 | 20
- 2 | 2 | 2 | 10
- 2 | 2 | 2 |
- 2 | 2 | 2 | 20
- 2 | 2 | 3 | 10
- 2 | 2 | 3 |
- 2 | 2 | 3 | 20
- 3 | 3 | |
- 4 | -1 | |
-(12 rows)
-
-select
- jt.*, b1 + 100 as b
-from
- json_table (jsonb
- '[
- {"a": 1, "b": [[1, 10], [2], [3, 30, 300]], "c": [1, null, 2]},
- {"a": 2, "b": [10, 20], "c": [1, null, 2]},
- {"x": "3", "b": [11, 22, 33, 44]}
- ]',
- '$[*]' as p
- columns (
- n for ordinality,
- a int path 'lax $.a' default -1 on error,
- nested path 'strict $.b[*]' as pb columns (
- b text format json path '$',
- nested path 'strict $[*]' as pb1 columns (
- b1 int path '$'
- )
- ),
- nested path 'strict $.c[*]' as pc columns (
- c text format json path '$',
- nested path 'strict $[*]' as pc1 columns (
- c1 int path '$'
- )
- )
- )
- --plan default(outer, cross)
- plan(p outer ((pb inner pb1) cross (pc outer pc1)))
- ) jt;
- n | a | b | b1 | c | c1 | b
----+---+--------------+-----+------+----+-----
- 1 | 1 | [1, 10] | 1 | 1 | | 101
- 1 | 1 | [1, 10] | 1 | null | | 101
- 1 | 1 | [1, 10] | 1 | 2 | | 101
- 1 | 1 | [1, 10] | 10 | 1 | | 110
- 1 | 1 | [1, 10] | 10 | null | | 110
- 1 | 1 | [1, 10] | 10 | 2 | | 110
- 1 | 1 | [2] | 2 | 1 | | 102
- 1 | 1 | [2] | 2 | null | | 102
- 1 | 1 | [2] | 2 | 2 | | 102
- 1 | 1 | [3, 30, 300] | 3 | 1 | | 103
- 1 | 1 | [3, 30, 300] | 3 | null | | 103
- 1 | 1 | [3, 30, 300] | 3 | 2 | | 103
- 1 | 1 | [3, 30, 300] | 30 | 1 | | 130
- 1 | 1 | [3, 30, 300] | 30 | null | | 130
- 1 | 1 | [3, 30, 300] | 30 | 2 | | 130
- 1 | 1 | [3, 30, 300] | 300 | 1 | | 400
- 1 | 1 | [3, 30, 300] | 300 | null | | 400
- 1 | 1 | [3, 30, 300] | 300 | 2 | | 400
- 2 | 2 | | | | |
- 3 | | | | | |
-(20 rows)
-
--- Should succeed (JSON arguments are passed to root and nested paths)
-SELECT *
-FROM
- generate_series(1, 4) x,
- generate_series(1, 3) y,
- JSON_TABLE(jsonb
- '[[1,2,3],[2,3,4,5],[3,4,5,6]]',
- 'strict $[*] ? (@[*] < $x)'
- PASSING x AS x, y AS y
- COLUMNS (
- y text FORMAT JSON PATH '$',
- NESTED PATH 'strict $[*] ? (@ >= $y)'
- COLUMNS (
- z int PATH '$'
- )
- )
- ) jt;
- x | y | y | z
----+---+--------------+---
- 2 | 1 | [1, 2, 3] | 1
- 2 | 1 | [1, 2, 3] | 2
- 2 | 1 | [1, 2, 3] | 3
- 3 | 1 | [1, 2, 3] | 1
- 3 | 1 | [1, 2, 3] | 2
- 3 | 1 | [1, 2, 3] | 3
- 3 | 1 | [2, 3, 4, 5] | 2
- 3 | 1 | [2, 3, 4, 5] | 3
- 3 | 1 | [2, 3, 4, 5] | 4
- 3 | 1 | [2, 3, 4, 5] | 5
- 4 | 1 | [1, 2, 3] | 1
- 4 | 1 | [1, 2, 3] | 2
- 4 | 1 | [1, 2, 3] | 3
- 4 | 1 | [2, 3, 4, 5] | 2
- 4 | 1 | [2, 3, 4, 5] | 3
- 4 | 1 | [2, 3, 4, 5] | 4
- 4 | 1 | [2, 3, 4, 5] | 5
- 4 | 1 | [3, 4, 5, 6] | 3
- 4 | 1 | [3, 4, 5, 6] | 4
- 4 | 1 | [3, 4, 5, 6] | 5
- 4 | 1 | [3, 4, 5, 6] | 6
- 2 | 2 | [1, 2, 3] | 2
- 2 | 2 | [1, 2, 3] | 3
- 3 | 2 | [1, 2, 3] | 2
- 3 | 2 | [1, 2, 3] | 3
- 3 | 2 | [2, 3, 4, 5] | 2
- 3 | 2 | [2, 3, 4, 5] | 3
- 3 | 2 | [2, 3, 4, 5] | 4
- 3 | 2 | [2, 3, 4, 5] | 5
- 4 | 2 | [1, 2, 3] | 2
- 4 | 2 | [1, 2, 3] | 3
- 4 | 2 | [2, 3, 4, 5] | 2
- 4 | 2 | [2, 3, 4, 5] | 3
- 4 | 2 | [2, 3, 4, 5] | 4
- 4 | 2 | [2, 3, 4, 5] | 5
- 4 | 2 | [3, 4, 5, 6] | 3
- 4 | 2 | [3, 4, 5, 6] | 4
- 4 | 2 | [3, 4, 5, 6] | 5
- 4 | 2 | [3, 4, 5, 6] | 6
- 2 | 3 | [1, 2, 3] | 3
- 3 | 3 | [1, 2, 3] | 3
- 3 | 3 | [2, 3, 4, 5] | 3
- 3 | 3 | [2, 3, 4, 5] | 4
- 3 | 3 | [2, 3, 4, 5] | 5
- 4 | 3 | [1, 2, 3] | 3
- 4 | 3 | [2, 3, 4, 5] | 3
- 4 | 3 | [2, 3, 4, 5] | 4
- 4 | 3 | [2, 3, 4, 5] | 5
- 4 | 3 | [3, 4, 5, 6] | 3
- 4 | 3 | [3, 4, 5, 6] | 4
- 4 | 3 | [3, 4, 5, 6] | 5
- 4 | 3 | [3, 4, 5, 6] | 6
-(52 rows)
-
--- Should fail (JSON arguments are not passed to column paths)
-SELECT *
-FROM JSON_TABLE(
- jsonb '[1,2,3]',
- '$[*] ? (@ < $x)'
- PASSING 10 AS x
- COLUMNS (y text FORMAT JSON PATH '$ ? (@ < $x)')
- ) jt;
-ERROR: could not find jsonpath variable "x"
--- Extension: non-constant JSON path
-SELECT JSON_EXISTS(jsonb '{"a": 123}', '$' || '.' || 'a');
- json_exists
--------------
- t
-(1 row)
-
-SELECT JSON_VALUE(jsonb '{"a": 123}', '$' || '.' || 'a');
- json_value
-------------
- 123
-(1 row)
-
-SELECT JSON_VALUE(jsonb '{"a": 123}', '$' || '.' || 'b' DEFAULT 'foo' ON EMPTY);
- json_value
-------------
- foo
-(1 row)
-
-SELECT JSON_QUERY(jsonb '{"a": 123}', '$' || '.' || 'a');
- json_query
-------------
- 123
-(1 row)
-
-SELECT JSON_QUERY(jsonb '{"a": 123}', '$' || '.' || 'a' WITH WRAPPER);
- json_query
-------------
- [123]
-(1 row)
-
--- Should fail (invalid path)
-SELECT JSON_QUERY(jsonb '{"a": 123}', 'error' || ' ' || 'error');
-ERROR: syntax error at or near " " of jsonpath input
--- Should fail (not supported)
-SELECT * FROM JSON_TABLE(jsonb '{"a": 123}', '$' || '.' || 'a' COLUMNS (foo int));
-ERROR: only string constants supported in JSON_TABLE path specification
-LINE 1: SELECT * FROM JSON_TABLE(jsonb '{"a": 123}', '$' || '.' || '...
- ^
--- Test parallel JSON_VALUE()
-CREATE UNLOGGED TABLE test_parallel_jsonb_value AS
-SELECT i::text::jsonb AS js
-FROM generate_series(1, 50000) i;
--- encourage use of parallel plans
-set parallel_setup_cost=0;
-set parallel_tuple_cost=0;
-set min_parallel_table_scan_size=0;
-set max_parallel_workers_per_gather=4;
-set parallel_leader_participation = off;
--- Should be non-parallel due to subtransactions
-EXPLAIN (COSTS OFF)
-SELECT sum(JSON_VALUE(js, '$' RETURNING numeric)) FROM test_parallel_jsonb_value;
- QUERY PLAN
----------------------------------------------
- Aggregate
- -> Seq Scan on test_parallel_jsonb_value
-(2 rows)
-
-SELECT sum(JSON_VALUE(js, '$' RETURNING numeric)) FROM test_parallel_jsonb_value;
- sum
-------------
- 1250025000
-(1 row)
-
--- Should be parallel
-EXPLAIN (COSTS OFF)
-SELECT sum(JSON_VALUE(js, '$' RETURNING numeric ERROR ON ERROR)) FROM test_parallel_jsonb_value;
- QUERY PLAN
-------------------------------------------------------------------
- Finalize Aggregate
- -> Gather
- Workers Planned: 4
- -> Partial Aggregate
- -> Parallel Seq Scan on test_parallel_jsonb_value
-(5 rows)
-
-SELECT sum(JSON_VALUE(js, '$' RETURNING numeric ERROR ON ERROR)) FROM test_parallel_jsonb_value;
- sum
-------------
- 1250025000
-(1 row)
-
-DROP TABLE test_parallel_jsonb_value;
NOT binary_coercible(p.proargtypes[1], ptr.proargtypes[2]))
OR (p.pronargs > 2 AND
NOT binary_coercible(p.proargtypes[2], ptr.proargtypes[3]))
- OR (p.pronargs > 3 AND
- NOT binary_coercible(p.proargtypes[3], ptr.proargtypes[4]))
- -- we could carry the check further, but 4 args is enough for now
- OR (p.pronargs > 4)
+ -- we could carry the check further, but 3 args is enough for now
+ OR (p.pronargs > 3)
);
aggfnoid | proname | oid | proname
----------+---------+-----+---------
+++ /dev/null
--- JSON()
-SELECT JSON();
-ERROR: syntax error at or near ")"
-LINE 1: SELECT JSON();
- ^
-SELECT JSON(NULL);
- json
-------
-
-(1 row)
-
-SELECT JSON('{ "a" : 1 } ');
- json
---------------
- { "a" : 1 }
-(1 row)
-
-SELECT JSON('{ "a" : 1 } ' FORMAT JSON);
- json
---------------
- { "a" : 1 }
-(1 row)
-
-SELECT JSON('{ "a" : 1 } ' FORMAT JSON ENCODING UTF8);
-ERROR: JSON ENCODING clause is only allowed for bytea input type
-LINE 1: SELECT JSON('{ "a" : 1 } ' FORMAT JSON ENCODING UTF8);
- ^
-SELECT JSON('{ "a" : 1 } '::bytea FORMAT JSON ENCODING UTF8);
- json
---------------
- { "a" : 1 }
-(1 row)
-
-SELECT pg_typeof(JSON('{ "a" : 1 } '));
- pg_typeof
------------
- json
-(1 row)
-
-SELECT JSON(' 1 '::json);
- json
----------
- 1
-(1 row)
-
-SELECT JSON(' 1 '::jsonb);
- json
-------
- 1
-(1 row)
-
-SELECT JSON(' 1 '::json WITH UNIQUE KEYS);
-ERROR: cannot use non-string types with WITH UNIQUE KEYS clause
-LINE 1: SELECT JSON(' 1 '::json WITH UNIQUE KEYS);
- ^
-SELECT JSON(123);
-ERROR: cannot cast type integer to json
-LINE 1: SELECT JSON(123);
- ^
-SELECT JSON('{"a": 1, "a": 2}');
- json
-------------------
- {"a": 1, "a": 2}
-(1 row)
-
-SELECT JSON('{"a": 1, "a": 2}' WITH UNIQUE KEYS);
-ERROR: duplicate JSON object key value
-SELECT JSON('{"a": 1, "a": 2}' WITHOUT UNIQUE KEYS);
- json
-------------------
- {"a": 1, "a": 2}
-(1 row)
-
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123');
- QUERY PLAN
------------------------------
- Result
- Output: JSON('123'::json)
-(2 rows)
-
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' FORMAT JSON);
- QUERY PLAN
------------------------------
- Result
- Output: JSON('123'::json)
-(2 rows)
-
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123'::bytea FORMAT JSON);
- QUERY PLAN
------------------------------------------------
- Result
- Output: JSON('\x313233'::bytea FORMAT JSON)
-(2 rows)
-
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123'::bytea FORMAT JSON ENCODING UTF8);
- QUERY PLAN
--------------------------------------------------------------
- Result
- Output: JSON('\x313233'::bytea FORMAT JSON ENCODING UTF8)
-(2 rows)
-
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' WITH UNIQUE KEYS);
- QUERY PLAN
-----------------------------------------------
- Result
- Output: JSON('123'::text WITH UNIQUE KEYS)
-(2 rows)
-
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' WITHOUT UNIQUE KEYS);
- QUERY PLAN
------------------------------
- Result
- Output: JSON('123'::json)
-(2 rows)
-
-SELECT JSON('123' RETURNING text);
-ERROR: cannot use RETURNING type text in JSON()
-LINE 1: SELECT JSON('123' RETURNING text);
- ^
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123');
- QUERY PLAN
------------------------------
- Result
- Output: JSON('123'::json)
-(2 rows)
-
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' RETURNING json);
- QUERY PLAN
------------------------------
- Result
- Output: JSON('123'::json)
-(2 rows)
-
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' RETURNING jsonb);
- QUERY PLAN
-----------------------------------------------
- Result
- Output: JSON('123'::jsonb RETURNING jsonb)
-(2 rows)
-
-SELECT pg_typeof(JSON('123'));
- pg_typeof
------------
- json
-(1 row)
-
-SELECT pg_typeof(JSON('123' RETURNING json));
- pg_typeof
------------
- json
-(1 row)
-
-SELECT pg_typeof(JSON('123' RETURNING jsonb));
- pg_typeof
------------
- jsonb
-(1 row)
-
--- JSON_SCALAR()
-SELECT JSON_SCALAR();
-ERROR: syntax error at or near ")"
-LINE 1: SELECT JSON_SCALAR();
- ^
-SELECT JSON_SCALAR(NULL);
- json_scalar
--------------
-
-(1 row)
-
-SELECT JSON_SCALAR(NULL::int);
- json_scalar
--------------
-
-(1 row)
-
-SELECT JSON_SCALAR(123);
- json_scalar
--------------
- 123
-(1 row)
-
-SELECT JSON_SCALAR(123.45);
- json_scalar
--------------
- 123.45
-(1 row)
-
-SELECT JSON_SCALAR(123.45::numeric);
- json_scalar
--------------
- 123.45
-(1 row)
-
-SELECT JSON_SCALAR(true);
- json_scalar
--------------
- true
-(1 row)
-
-SELECT JSON_SCALAR(false);
- json_scalar
--------------
- false
-(1 row)
-
-SELECT JSON_SCALAR(' 123.45');
- json_scalar
--------------
- " 123.45"
-(1 row)
-
-SELECT JSON_SCALAR('2020-06-07'::date);
- json_scalar
---------------
- "2020-06-07"
-(1 row)
-
-SELECT JSON_SCALAR('2020-06-07 01:02:03'::timestamp);
- json_scalar
------------------------
- "2020-06-07T01:02:03"
-(1 row)
-
-SELECT JSON_SCALAR('{}'::json);
- json_scalar
--------------
- {}
-(1 row)
-
-SELECT JSON_SCALAR('{}'::jsonb);
- json_scalar
--------------
- {}
-(1 row)
-
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR(123);
- QUERY PLAN
-----------------------------
- Result
- Output: JSON_SCALAR(123)
-(2 rows)
-
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR('123');
- QUERY PLAN
-------------------------------------
- Result
- Output: JSON_SCALAR('123'::text)
-(2 rows)
-
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR(123 RETURNING json);
- QUERY PLAN
-----------------------------
- Result
- Output: JSON_SCALAR(123)
-(2 rows)
-
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR(123 RETURNING jsonb);
- QUERY PLAN
---------------------------------------------
- Result
- Output: JSON_SCALAR(123 RETURNING jsonb)
-(2 rows)
-
--- JSON_SERIALIZE()
-SELECT JSON_SERIALIZE();
-ERROR: syntax error at or near ")"
-LINE 1: SELECT JSON_SERIALIZE();
- ^
-SELECT JSON_SERIALIZE(NULL);
- json_serialize
-----------------
-
-(1 row)
-
-SELECT JSON_SERIALIZE(JSON('{ "a" : 1 } '));
- json_serialize
-----------------
- { "a" : 1 }
-(1 row)
-
-SELECT JSON_SERIALIZE('{ "a" : 1 } ');
- json_serialize
-----------------
- { "a" : 1 }
-(1 row)
-
-SELECT JSON_SERIALIZE('1');
- json_serialize
-----------------
- 1
-(1 row)
-
-SELECT JSON_SERIALIZE('1' FORMAT JSON);
- json_serialize
-----------------
- 1
-(1 row)
-
-SELECT JSON_SERIALIZE('{ "a" : 1 } ' RETURNING bytea);
- json_serialize
-----------------------------
- \x7b20226122203a2031207d20
-(1 row)
-
-SELECT JSON_SERIALIZE('{ "a" : 1 } ' RETURNING varchar);
- json_serialize
-----------------
- { "a" : 1 }
-(1 row)
-
-SELECT pg_typeof(JSON_SERIALIZE(NULL));
- pg_typeof
------------
- text
-(1 row)
-
--- only string types or bytea allowed
-SELECT JSON_SERIALIZE('{ "a" : 1 } ' RETURNING jsonb);
-ERROR: cannot use RETURNING type jsonb in JSON_SERIALIZE()
-HINT: Try returning a string type or bytea.
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SERIALIZE('{}');
- QUERY PLAN
------------------------------------------------------
- Result
- Output: JSON_SERIALIZE('{}'::json RETURNING text)
-(2 rows)
-
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SERIALIZE('{}' RETURNING bytea);
- QUERY PLAN
-------------------------------------------------------
- Result
- Output: JSON_SERIALIZE('{}'::json RETURNING bytea)
-(2 rows)
-
--- JSON_OBJECT()
-SELECT JSON_OBJECT();
- json_object
--------------
- {}
-(1 row)
-
-SELECT JSON_OBJECT(RETURNING json);
- json_object
--------------
- {}
-(1 row)
-
-SELECT JSON_OBJECT(RETURNING json FORMAT JSON);
- json_object
--------------
- {}
-(1 row)
-
-SELECT JSON_OBJECT(RETURNING jsonb);
- json_object
--------------
- {}
-(1 row)
-
-SELECT JSON_OBJECT(RETURNING jsonb FORMAT JSON);
- json_object
--------------
- {}
-(1 row)
-
-SELECT JSON_OBJECT(RETURNING text);
- json_object
--------------
- {}
-(1 row)
-
-SELECT JSON_OBJECT(RETURNING text FORMAT JSON);
- json_object
--------------
- {}
-(1 row)
-
-SELECT JSON_OBJECT(RETURNING text FORMAT JSON ENCODING UTF8);
-ERROR: cannot set JSON encoding for non-bytea output types
-LINE 1: SELECT JSON_OBJECT(RETURNING text FORMAT JSON ENCODING UTF8)...
- ^
-SELECT JSON_OBJECT(RETURNING text FORMAT JSON ENCODING INVALID_ENCODING);
-ERROR: unrecognized JSON encoding: invalid_encoding
-SELECT JSON_OBJECT(RETURNING bytea);
- json_object
--------------
- \x7b7d
-(1 row)
-
-SELECT JSON_OBJECT(RETURNING bytea FORMAT JSON);
- json_object
--------------
- \x7b7d
-(1 row)
-
-SELECT JSON_OBJECT(RETURNING bytea FORMAT JSON ENCODING UTF8);
- json_object
--------------
- \x7b7d
-(1 row)
-
-SELECT JSON_OBJECT(RETURNING bytea FORMAT JSON ENCODING UTF16);
-ERROR: unsupported JSON encoding
-LINE 1: SELECT JSON_OBJECT(RETURNING bytea FORMAT JSON ENCODING UTF1...
- ^
-HINT: Only UTF8 JSON encoding is supported.
-SELECT JSON_OBJECT(RETURNING bytea FORMAT JSON ENCODING UTF32);
-ERROR: unsupported JSON encoding
-LINE 1: SELECT JSON_OBJECT(RETURNING bytea FORMAT JSON ENCODING UTF3...
- ^
-HINT: Only UTF8 JSON encoding is supported.
-SELECT JSON_OBJECT('foo': NULL::int FORMAT JSON);
-ERROR: cannot use non-string types with explicit FORMAT JSON clause
-LINE 1: SELECT JSON_OBJECT('foo': NULL::int FORMAT JSON);
- ^
-SELECT JSON_OBJECT('foo': NULL::int FORMAT JSON ENCODING UTF8);
-ERROR: JSON ENCODING clause is only allowed for bytea input type
-LINE 1: SELECT JSON_OBJECT('foo': NULL::int FORMAT JSON ENCODING UTF...
- ^
-SELECT JSON_OBJECT('foo': NULL::json FORMAT JSON);
-WARNING: FORMAT JSON has no effect for json and jsonb types
-LINE 1: SELECT JSON_OBJECT('foo': NULL::json FORMAT JSON);
- ^
- json_object
-----------------
- {"foo" : null}
-(1 row)
-
-SELECT JSON_OBJECT('foo': NULL::json FORMAT JSON ENCODING UTF8);
-ERROR: JSON ENCODING clause is only allowed for bytea input type
-LINE 1: SELECT JSON_OBJECT('foo': NULL::json FORMAT JSON ENCODING UT...
- ^
-SELECT JSON_OBJECT('foo': NULL::jsonb FORMAT JSON);
-WARNING: FORMAT JSON has no effect for json and jsonb types
-LINE 1: SELECT JSON_OBJECT('foo': NULL::jsonb FORMAT JSON);
- ^
- json_object
----------------
- {"foo": null}
-(1 row)
-
-SELECT JSON_OBJECT('foo': NULL::jsonb FORMAT JSON ENCODING UTF8);
-ERROR: JSON ENCODING clause is only allowed for bytea input type
-LINE 1: SELECT JSON_OBJECT('foo': NULL::jsonb FORMAT JSON ENCODING U...
- ^
-SELECT JSON_OBJECT(NULL: 1);
-ERROR: argument 1 cannot be null
-HINT: Object keys should be text.
-SELECT JSON_OBJECT('a': 2 + 3);
- json_object
--------------
- {"a" : 5}
-(1 row)
-
-SELECT JSON_OBJECT('a' VALUE 2 + 3);
- json_object
--------------
- {"a" : 5}
-(1 row)
-
---SELECT JSON_OBJECT(KEY 'a' VALUE 2 + 3);
-SELECT JSON_OBJECT('a' || 2: 1);
- json_object
--------------
- {"a2" : 1}
-(1 row)
-
-SELECT JSON_OBJECT(('a' || 2) VALUE 1);
- json_object
--------------
- {"a2" : 1}
-(1 row)
-
---SELECT JSON_OBJECT('a' || 2 VALUE 1);
---SELECT JSON_OBJECT(KEY 'a' || 2 VALUE 1);
-SELECT JSON_OBJECT('a': 2::text);
- json_object
--------------
- {"a" : "2"}
-(1 row)
-
-SELECT JSON_OBJECT('a' VALUE 2::text);
- json_object
--------------
- {"a" : "2"}
-(1 row)
-
---SELECT JSON_OBJECT(KEY 'a' VALUE 2::text);
-SELECT JSON_OBJECT(1::text: 2);
- json_object
--------------
- {"1" : 2}
-(1 row)
-
-SELECT JSON_OBJECT((1::text) VALUE 2);
- json_object
--------------
- {"1" : 2}
-(1 row)
-
---SELECT JSON_OBJECT(1::text VALUE 2);
---SELECT JSON_OBJECT(KEY 1::text VALUE 2);
-SELECT JSON_OBJECT(json '[1]': 123);
-ERROR: key value must be scalar, not array, composite, or json
-SELECT JSON_OBJECT(ARRAY[1,2,3]: 'aaa');
-ERROR: key value must be scalar, not array, composite, or json
-SELECT JSON_OBJECT(
- 'a': '123',
- 1.23: 123,
- 'c': json '[ 1,true,{ } ]',
- 'd': jsonb '{ "x" : 123.45 }'
-);
- json_object
--------------------------------------------------------------------
- {"a": "123", "c": [1, true, {}], "d": {"x": 123.45}, "1.23": 123}
-(1 row)
-
-SELECT JSON_OBJECT(
- 'a': '123',
- 1.23: 123,
- 'c': json '[ 1,true,{ } ]',
- 'd': jsonb '{ "x" : 123.45 }'
- RETURNING jsonb
-);
- json_object
--------------------------------------------------------------------
- {"a": "123", "c": [1, true, {}], "d": {"x": 123.45}, "1.23": 123}
-(1 row)
-
-/*
-SELECT JSON_OBJECT(
- 'a': '123',
- KEY 1.23 VALUE 123,
- 'c' VALUE json '[1, true, {}]'
-);
-*/
-SELECT JSON_OBJECT('a': '123', 'b': JSON_OBJECT('a': 111, 'b': 'aaa'));
- json_object
------------------------------------------------
- {"a" : "123", "b" : {"a" : 111, "b" : "aaa"}}
-(1 row)
-
-SELECT JSON_OBJECT('a': '123', 'b': JSON_OBJECT('a': 111, 'b': 'aaa' RETURNING jsonb));
- json_object
--------------------------------------------
- {"a": "123", "b": {"a": 111, "b": "aaa"}}
-(1 row)
-
-SELECT JSON_OBJECT('a': JSON_OBJECT('b': 1 RETURNING text));
- json_object
------------------------
- {"a" : "{\"b\" : 1}"}
-(1 row)
-
-SELECT JSON_OBJECT('a': JSON_OBJECT('b': 1 RETURNING text) FORMAT JSON);
- json_object
--------------------
- {"a" : {"b" : 1}}
-(1 row)
-
-SELECT JSON_OBJECT('a': JSON_OBJECT('b': 1 RETURNING bytea));
- json_object
----------------------------------
- {"a" : "\\x7b226222203a20317d"}
-(1 row)
-
-SELECT JSON_OBJECT('a': JSON_OBJECT('b': 1 RETURNING bytea) FORMAT JSON);
- json_object
--------------------
- {"a" : {"b" : 1}}
-(1 row)
-
-SELECT JSON_OBJECT('a': '1', 'b': NULL, 'c': 2);
- json_object
-----------------------------------
- {"a" : "1", "b" : null, "c" : 2}
-(1 row)
-
-SELECT JSON_OBJECT('a': '1', 'b': NULL, 'c': 2 NULL ON NULL);
- json_object
-----------------------------------
- {"a" : "1", "b" : null, "c" : 2}
-(1 row)
-
-SELECT JSON_OBJECT('a': '1', 'b': NULL, 'c': 2 ABSENT ON NULL);
- json_object
-----------------------
- {"a" : "1", "c" : 2}
-(1 row)
-
-SELECT JSON_OBJECT(1: 1, '1': NULL WITH UNIQUE);
-ERROR: duplicate JSON key "1"
-SELECT JSON_OBJECT(1: 1, '1': NULL ABSENT ON NULL WITH UNIQUE);
-ERROR: duplicate JSON key "1"
-SELECT JSON_OBJECT(1: 1, '1': NULL NULL ON NULL WITH UNIQUE RETURNING jsonb);
-ERROR: duplicate JSON object key value
-SELECT JSON_OBJECT(1: 1, '1': NULL ABSENT ON NULL WITH UNIQUE RETURNING jsonb);
-ERROR: duplicate JSON object key value
-SELECT JSON_OBJECT(1: 1, '2': NULL, '1': 1 NULL ON NULL WITH UNIQUE);
-ERROR: duplicate JSON key "1"
-SELECT JSON_OBJECT(1: 1, '2': NULL, '1': 1 ABSENT ON NULL WITH UNIQUE);
-ERROR: duplicate JSON key "1"
-SELECT JSON_OBJECT(1: 1, '2': NULL, '1': 1 ABSENT ON NULL WITHOUT UNIQUE);
- json_object
---------------------
- {"1" : 1, "1" : 1}
-(1 row)
-
-SELECT JSON_OBJECT(1: 1, '2': NULL, '1': 1 ABSENT ON NULL WITH UNIQUE RETURNING jsonb);
-ERROR: duplicate JSON object key value
-SELECT JSON_OBJECT(1: 1, '2': NULL, '1': 1 ABSENT ON NULL WITHOUT UNIQUE RETURNING jsonb);
- json_object
--------------
- {"1": 1}
-(1 row)
-
-SELECT JSON_OBJECT(1: 1, '2': NULL, '3': 1, 4: NULL, '5': 'a' ABSENT ON NULL WITH UNIQUE RETURNING jsonb);
- json_object
-----------------------------
- {"1": 1, "3": 1, "5": "a"}
-(1 row)
-
--- JSON_ARRAY()
-SELECT JSON_ARRAY();
- json_array
-------------
- []
-(1 row)
-
-SELECT JSON_ARRAY(RETURNING json);
- json_array
-------------
- []
-(1 row)
-
-SELECT JSON_ARRAY(RETURNING json FORMAT JSON);
- json_array
-------------
- []
-(1 row)
-
-SELECT JSON_ARRAY(RETURNING jsonb);
- json_array
-------------
- []
-(1 row)
-
-SELECT JSON_ARRAY(RETURNING jsonb FORMAT JSON);
- json_array
-------------
- []
-(1 row)
-
-SELECT JSON_ARRAY(RETURNING text);
- json_array
-------------
- []
-(1 row)
-
-SELECT JSON_ARRAY(RETURNING text FORMAT JSON);
- json_array
-------------
- []
-(1 row)
-
-SELECT JSON_ARRAY(RETURNING text FORMAT JSON ENCODING UTF8);
-ERROR: cannot set JSON encoding for non-bytea output types
-LINE 1: SELECT JSON_ARRAY(RETURNING text FORMAT JSON ENCODING UTF8);
- ^
-SELECT JSON_ARRAY(RETURNING text FORMAT JSON ENCODING INVALID_ENCODING);
-ERROR: unrecognized JSON encoding: invalid_encoding
-SELECT JSON_ARRAY(RETURNING bytea);
- json_array
-------------
- \x5b5d
-(1 row)
-
-SELECT JSON_ARRAY(RETURNING bytea FORMAT JSON);
- json_array
-------------
- \x5b5d
-(1 row)
-
-SELECT JSON_ARRAY(RETURNING bytea FORMAT JSON ENCODING UTF8);
- json_array
-------------
- \x5b5d
-(1 row)
-
-SELECT JSON_ARRAY(RETURNING bytea FORMAT JSON ENCODING UTF16);
-ERROR: unsupported JSON encoding
-LINE 1: SELECT JSON_ARRAY(RETURNING bytea FORMAT JSON ENCODING UTF16...
- ^
-HINT: Only UTF8 JSON encoding is supported.
-SELECT JSON_ARRAY(RETURNING bytea FORMAT JSON ENCODING UTF32);
-ERROR: unsupported JSON encoding
-LINE 1: SELECT JSON_ARRAY(RETURNING bytea FORMAT JSON ENCODING UTF32...
- ^
-HINT: Only UTF8 JSON encoding is supported.
-SELECT JSON_ARRAY('aaa', 111, true, array[1,2,3], NULL, json '{"a": [1]}', jsonb '["a",3]');
- json_array
------------------------------------------------------
- ["aaa", 111, true, [1, 2, 3], {"a": [1]}, ["a", 3]]
-(1 row)
-
-SELECT JSON_ARRAY('a', NULL, 'b' NULL ON NULL);
- json_array
-------------------
- ["a", null, "b"]
-(1 row)
-
-SELECT JSON_ARRAY('a', NULL, 'b' ABSENT ON NULL);
- json_array
-------------
- ["a", "b"]
-(1 row)
-
-SELECT JSON_ARRAY(NULL, NULL, 'b' ABSENT ON NULL);
- json_array
-------------
- ["b"]
-(1 row)
-
-SELECT JSON_ARRAY('a', NULL, 'b' NULL ON NULL RETURNING jsonb);
- json_array
-------------------
- ["a", null, "b"]
-(1 row)
-
-SELECT JSON_ARRAY('a', NULL, 'b' ABSENT ON NULL RETURNING jsonb);
- json_array
-------------
- ["a", "b"]
-(1 row)
-
-SELECT JSON_ARRAY(NULL, NULL, 'b' ABSENT ON NULL RETURNING jsonb);
- json_array
-------------
- ["b"]
-(1 row)
-
-SELECT JSON_ARRAY(JSON_ARRAY('{ "a" : 123 }' RETURNING text));
- json_array
--------------------------------
- ["[\"{ \\\"a\\\" : 123 }\"]"]
-(1 row)
-
-SELECT JSON_ARRAY(JSON_ARRAY('{ "a" : 123 }' FORMAT JSON RETURNING text));
- json_array
------------------------
- ["[{ \"a\" : 123 }]"]
-(1 row)
-
-SELECT JSON_ARRAY(JSON_ARRAY('{ "a" : 123 }' FORMAT JSON RETURNING text) FORMAT JSON);
- json_array
--------------------
- [[{ "a" : 123 }]]
-(1 row)
-
-SELECT JSON_ARRAY(SELECT i FROM (VALUES (1), (2), (NULL), (4)) foo(i));
- json_array
-------------
- [1, 2, 4]
-(1 row)
-
-SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i));
- json_array
-------------
- [[1,2], +
- [3,4]]
-(1 row)
-
-SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) RETURNING jsonb);
- json_array
-------------------
- [[1, 2], [3, 4]]
-(1 row)
-
---SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) NULL ON NULL);
---SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) NULL ON NULL RETURNING jsonb);
-SELECT JSON_ARRAY(SELECT i FROM (VALUES (3), (1), (NULL), (2)) foo(i) ORDER BY i);
- json_array
-------------
- [1, 2, 3]
-(1 row)
-
--- Should fail
-SELECT JSON_ARRAY(SELECT FROM (VALUES (1)) foo(i));
-ERROR: subquery must return only one column
-LINE 1: SELECT JSON_ARRAY(SELECT FROM (VALUES (1)) foo(i));
- ^
-SELECT JSON_ARRAY(SELECT i, i FROM (VALUES (1)) foo(i));
-ERROR: subquery must return only one column
-LINE 1: SELECT JSON_ARRAY(SELECT i, i FROM (VALUES (1)) foo(i));
- ^
-SELECT JSON_ARRAY(SELECT * FROM (VALUES (1, 2)) foo(i, j));
-ERROR: subquery must return only one column
-LINE 1: SELECT JSON_ARRAY(SELECT * FROM (VALUES (1, 2)) foo(i, j));
- ^
--- JSON_ARRAYAGG()
-SELECT JSON_ARRAYAGG(i) IS NULL,
- JSON_ARRAYAGG(i RETURNING jsonb) IS NULL
-FROM generate_series(1, 0) i;
- ?column? | ?column?
-----------+----------
- t | t
-(1 row)
-
-SELECT JSON_ARRAYAGG(i),
- JSON_ARRAYAGG(i RETURNING jsonb)
-FROM generate_series(1, 5) i;
- json_arrayagg | json_arrayagg
------------------+-----------------
- [1, 2, 3, 4, 5] | [1, 2, 3, 4, 5]
-(1 row)
-
-SELECT JSON_ARRAYAGG(i ORDER BY i DESC)
-FROM generate_series(1, 5) i;
- json_arrayagg
------------------
- [5, 4, 3, 2, 1]
-(1 row)
-
-SELECT JSON_ARRAYAGG(i::text::json)
-FROM generate_series(1, 5) i;
- json_arrayagg
------------------
- [1, 2, 3, 4, 5]
-(1 row)
-
-SELECT JSON_ARRAYAGG(JSON_ARRAY(i, i + 1 RETURNING text) FORMAT JSON)
-FROM generate_series(1, 5) i;
- json_arrayagg
-------------------------------------------
- [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6]]
-(1 row)
-
-SELECT JSON_ARRAYAGG(NULL),
- JSON_ARRAYAGG(NULL RETURNING jsonb)
-FROM generate_series(1, 5);
- json_arrayagg | json_arrayagg
----------------+---------------
- [] | []
-(1 row)
-
-SELECT JSON_ARRAYAGG(NULL NULL ON NULL),
- JSON_ARRAYAGG(NULL NULL ON NULL RETURNING jsonb)
-FROM generate_series(1, 5);
- json_arrayagg | json_arrayagg
---------------------------------+--------------------------------
- [null, null, null, null, null] | [null, null, null, null, null]
-(1 row)
-
-SELECT
- JSON_ARRAYAGG(bar),
- JSON_ARRAYAGG(bar RETURNING jsonb),
- JSON_ARRAYAGG(bar ABSENT ON NULL),
- JSON_ARRAYAGG(bar ABSENT ON NULL RETURNING jsonb),
- JSON_ARRAYAGG(bar NULL ON NULL),
- JSON_ARRAYAGG(bar NULL ON NULL RETURNING jsonb),
- JSON_ARRAYAGG(foo),
- JSON_ARRAYAGG(foo RETURNING jsonb),
- JSON_ARRAYAGG(foo ORDER BY bar) FILTER (WHERE bar > 2),
- JSON_ARRAYAGG(foo ORDER BY bar RETURNING jsonb) FILTER (WHERE bar > 2)
-FROM
- (VALUES (NULL), (3), (1), (NULL), (NULL), (5), (2), (4), (NULL)) foo(bar);
- json_arrayagg | json_arrayagg | json_arrayagg | json_arrayagg | json_arrayagg | json_arrayagg | json_arrayagg | json_arrayagg | json_arrayagg | json_arrayagg
------------------+-----------------+-----------------+-----------------+-----------------------------------------+-----------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------------------+---------------+--------------------------------------
- [1, 2, 3, 4, 5] | [1, 2, 3, 4, 5] | [1, 2, 3, 4, 5] | [1, 2, 3, 4, 5] | [1, 2, 3, 4, 5, null, null, null, null] | [1, 2, 3, 4, 5, null, null, null, null] | [{"bar":1}, +| [{"bar": 1}, {"bar": 2}, {"bar": 3}, {"bar": 4}, {"bar": 5}, {"bar": null}, {"bar": null}, {"bar": null}, {"bar": null}] | [{"bar":3}, +| [{"bar": 3}, {"bar": 4}, {"bar": 5}]
- | | | | | | {"bar":2}, +| | {"bar":4}, +|
- | | | | | | {"bar":3}, +| | {"bar":5}] |
- | | | | | | {"bar":4}, +| | |
- | | | | | | {"bar":5}, +| | |
- | | | | | | {"bar":null}, +| | |
- | | | | | | {"bar":null}, +| | |
- | | | | | | {"bar":null}, +| | |
- | | | | | | {"bar":null}] | | |
-(1 row)
-
-SELECT
- bar, JSON_ARRAYAGG(bar) FILTER (WHERE bar > 2) OVER (PARTITION BY foo.bar % 2)
-FROM
- (VALUES (NULL), (3), (1), (NULL), (NULL), (5), (2), (4), (NULL), (5), (4)) foo(bar);
- bar | json_arrayagg
------+---------------
- 4 | [4, 4]
- 4 | [4, 4]
- 2 | [4, 4]
- 5 | [5, 3, 5]
- 3 | [5, 3, 5]
- 1 | [5, 3, 5]
- 5 | [5, 3, 5]
- |
- |
- |
- |
-(11 rows)
-
--- JSON_OBJECTAGG()
-SELECT JSON_OBJECTAGG('key': 1) IS NULL,
- JSON_OBJECTAGG('key': 1 RETURNING jsonb) IS NULL
-WHERE FALSE;
- ?column? | ?column?
-----------+----------
- t | t
-(1 row)
-
-SELECT JSON_OBJECTAGG(NULL: 1);
-ERROR: field name must not be null
-SELECT JSON_OBJECTAGG(NULL: 1 RETURNING jsonb);
-ERROR: field name must not be null
-SELECT
- JSON_OBJECTAGG(i: i),
--- JSON_OBJECTAGG(i VALUE i),
--- JSON_OBJECTAGG(KEY i VALUE i),
- JSON_OBJECTAGG(i: i RETURNING jsonb)
-FROM
- generate_series(1, 5) i;
- json_objectagg | json_objectagg
--------------------------------------------------+------------------------------------------
- { "1" : 1, "2" : 2, "3" : 3, "4" : 4, "5" : 5 } | {"1": 1, "2": 2, "3": 3, "4": 4, "5": 5}
-(1 row)
-
-SELECT
- JSON_OBJECTAGG(k: v),
- JSON_OBJECTAGG(k: v NULL ON NULL),
- JSON_OBJECTAGG(k: v ABSENT ON NULL),
- JSON_OBJECTAGG(k: v RETURNING jsonb),
- JSON_OBJECTAGG(k: v NULL ON NULL RETURNING jsonb),
- JSON_OBJECTAGG(k: v ABSENT ON NULL RETURNING jsonb)
-FROM
- (VALUES (1, 1), (1, NULL), (2, NULL), (3, 3)) foo(k, v);
- json_objectagg | json_objectagg | json_objectagg | json_objectagg | json_objectagg | json_objectagg
-----------------------------------------------+----------------------------------------------+----------------------+--------------------------------+--------------------------------+------------------
- { "1" : 1, "1" : null, "2" : null, "3" : 3 } | { "1" : 1, "1" : null, "2" : null, "3" : 3 } | { "1" : 1, "3" : 3 } | {"1": null, "2": null, "3": 3} | {"1": null, "2": null, "3": 3} | {"1": 1, "3": 3}
-(1 row)
-
-SELECT JSON_OBJECTAGG(k: v WITH UNIQUE KEYS)
-FROM (VALUES (1, 1), (1, NULL), (2, 2)) foo(k, v);
-ERROR: duplicate JSON key "1"
-SELECT JSON_OBJECTAGG(k: v ABSENT ON NULL WITH UNIQUE KEYS)
-FROM (VALUES (1, 1), (1, NULL), (2, 2)) foo(k, v);
-ERROR: duplicate JSON key "1"
-SELECT JSON_OBJECTAGG(k: v ABSENT ON NULL WITH UNIQUE KEYS)
-FROM (VALUES (1, 1), (0, NULL), (3, NULL), (2, 2), (4, NULL)) foo(k, v);
- json_objectagg
-----------------------
- { "1" : 1, "2" : 2 }
-(1 row)
-
-SELECT JSON_OBJECTAGG(k: v WITH UNIQUE KEYS RETURNING jsonb)
-FROM (VALUES (1, 1), (1, NULL), (2, 2)) foo(k, v);
-ERROR: duplicate JSON object key value
-SELECT JSON_OBJECTAGG(k: v ABSENT ON NULL WITH UNIQUE KEYS RETURNING jsonb)
-FROM (VALUES (1, 1), (1, NULL), (2, 2)) foo(k, v);
-ERROR: duplicate JSON object key value
-SELECT JSON_OBJECTAGG(k: v ABSENT ON NULL WITH UNIQUE KEYS RETURNING jsonb)
-FROM (VALUES (1, 1), (0, NULL),(4, null), (5, null),(6, null),(2, 2)) foo(k, v);
- json_objectagg
-------------------
- {"1": 1, "2": 2}
-(1 row)
-
--- Test JSON_OBJECT deparsing
-EXPLAIN (VERBOSE, COSTS OFF)
-SELECT JSON_OBJECT('foo' : '1' FORMAT JSON, 'bar' : 'baz' RETURNING json);
- QUERY PLAN
-------------------------------------------------------------------------------
- Result
- Output: JSON_OBJECT('foo' : '1'::json, 'bar' : 'baz'::text RETURNING json)
-(2 rows)
-
-CREATE VIEW json_object_view AS
-SELECT JSON_OBJECT('foo' : '1' FORMAT JSON, 'bar' : 'baz' RETURNING json);
-\sv json_object_view
-CREATE OR REPLACE VIEW public.json_object_view AS
- SELECT JSON_OBJECT('foo' : '1'::text FORMAT JSON, 'bar' : 'baz'::text RETURNING json) AS "json_object"
-DROP VIEW json_object_view;
-SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v WITH UNIQUE KEYS) OVER (ORDER BY k)
-FROM (VALUES (1,1), (2,2)) a(k,v);
- a | json_objectagg
----------------+----------------------
- {"k":1,"v":1} | { "1" : 1 }
- {"k":2,"v":2} | { "1" : 1, "2" : 2 }
-(2 rows)
-
-SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v WITH UNIQUE KEYS) OVER (ORDER BY k)
-FROM (VALUES (1,1), (1,2), (2,2)) a(k,v);
-ERROR: duplicate JSON key "1"
-SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v ABSENT ON NULL WITH UNIQUE KEYS)
- OVER (ORDER BY k)
-FROM (VALUES (1,1), (1,null), (2,2)) a(k,v);
-ERROR: duplicate JSON key "1"
-SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v ABSENT ON NULL)
-OVER (ORDER BY k)
-FROM (VALUES (1,1), (1,null), (2,2)) a(k,v);
- a | json_objectagg
-------------------+----------------------
- {"k":1,"v":1} | { "1" : 1 }
- {"k":1,"v":null} | { "1" : 1 }
- {"k":2,"v":2} | { "1" : 1, "2" : 2 }
-(3 rows)
-
-SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v ABSENT ON NULL)
-OVER (ORDER BY k RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
-FROM (VALUES (1,1), (1,null), (2,2)) a(k,v);
- a | json_objectagg
-------------------+----------------------
- {"k":1,"v":1} | { "1" : 1, "2" : 2 }
- {"k":1,"v":null} | { "1" : 1, "2" : 2 }
- {"k":2,"v":2} | { "1" : 1, "2" : 2 }
-(3 rows)
-
--- Test JSON_ARRAY deparsing
-EXPLAIN (VERBOSE, COSTS OFF)
-SELECT JSON_ARRAY('1' FORMAT JSON, 2 RETURNING json);
- QUERY PLAN
----------------------------------------------------
- Result
- Output: JSON_ARRAY('1'::json, 2 RETURNING json)
-(2 rows)
-
-CREATE VIEW json_array_view AS
-SELECT JSON_ARRAY('1' FORMAT JSON, 2 RETURNING json);
-\sv json_array_view
-CREATE OR REPLACE VIEW public.json_array_view AS
- SELECT JSON_ARRAY('1'::text FORMAT JSON, 2 RETURNING json) AS "json_array"
-DROP VIEW json_array_view;
--- Test JSON_OBJECTAGG deparsing
-EXPLAIN (VERBOSE, COSTS OFF)
-SELECT JSON_OBJECTAGG(i: ('111' || i)::bytea FORMAT JSON WITH UNIQUE RETURNING text) FILTER (WHERE i > 3)
-FROM generate_series(1,5) i;
- QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------
- Aggregate
- Output: JSON_OBJECTAGG(i : (('111'::text || (i)::text))::bytea FORMAT JSON WITH UNIQUE KEYS RETURNING text) FILTER (WHERE (i > 3))
- -> Function Scan on pg_catalog.generate_series i
- Output: i
- Function Call: generate_series(1, 5)
-(5 rows)
-
-EXPLAIN (VERBOSE, COSTS OFF)
-SELECT JSON_OBJECTAGG(i: ('111' || i)::bytea FORMAT JSON WITH UNIQUE RETURNING text) OVER (PARTITION BY i % 2)
-FROM generate_series(1,5) i;
- QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------
- WindowAgg
- Output: JSON_OBJECTAGG(i : (('111'::text || (i)::text))::bytea FORMAT JSON WITH UNIQUE KEYS RETURNING text) OVER (?), ((i % 2))
- -> Sort
- Output: ((i % 2)), i
- Sort Key: ((i.i % 2))
- -> Function Scan on pg_catalog.generate_series i
- Output: (i % 2), i
- Function Call: generate_series(1, 5)
-(8 rows)
-
-CREATE VIEW json_objectagg_view AS
-SELECT JSON_OBJECTAGG(i: ('111' || i)::bytea FORMAT JSON WITH UNIQUE RETURNING text) FILTER (WHERE i > 3)
-FROM generate_series(1,5) i;
-\sv json_objectagg_view
-CREATE OR REPLACE VIEW public.json_objectagg_view AS
- SELECT JSON_OBJECTAGG(i.i : ('111'::text || i.i)::bytea FORMAT JSON WITH UNIQUE KEYS RETURNING text) FILTER (WHERE i.i > 3) AS "json_objectagg"
- FROM generate_series(1, 5) i(i)
-DROP VIEW json_objectagg_view;
--- Test JSON_ARRAYAGG deparsing
-EXPLAIN (VERBOSE, COSTS OFF)
-SELECT JSON_ARRAYAGG(('111' || i)::bytea FORMAT JSON NULL ON NULL RETURNING text) FILTER (WHERE i > 3)
-FROM generate_series(1,5) i;
- QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------
- Aggregate
- Output: JSON_ARRAYAGG((('111'::text || (i)::text))::bytea FORMAT JSON NULL ON NULL RETURNING text) FILTER (WHERE (i > 3))
- -> Function Scan on pg_catalog.generate_series i
- Output: i
- Function Call: generate_series(1, 5)
-(5 rows)
-
-EXPLAIN (VERBOSE, COSTS OFF)
-SELECT JSON_ARRAYAGG(('111' || i)::bytea FORMAT JSON NULL ON NULL RETURNING text) OVER (PARTITION BY i % 2)
-FROM generate_series(1,5) i;
- QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------
- WindowAgg
- Output: JSON_ARRAYAGG((('111'::text || (i)::text))::bytea FORMAT JSON NULL ON NULL RETURNING text) OVER (?), ((i % 2))
- -> Sort
- Output: ((i % 2)), i
- Sort Key: ((i.i % 2))
- -> Function Scan on pg_catalog.generate_series i
- Output: (i % 2), i
- Function Call: generate_series(1, 5)
-(8 rows)
-
-CREATE VIEW json_arrayagg_view AS
-SELECT JSON_ARRAYAGG(('111' || i)::bytea FORMAT JSON NULL ON NULL RETURNING text) FILTER (WHERE i > 3)
-FROM generate_series(1,5) i;
-\sv json_arrayagg_view
-CREATE OR REPLACE VIEW public.json_arrayagg_view AS
- SELECT JSON_ARRAYAGG(('111'::text || i.i)::bytea FORMAT JSON NULL ON NULL RETURNING text) FILTER (WHERE i.i > 3) AS "json_arrayagg"
- FROM generate_series(1, 5) i(i)
-DROP VIEW json_arrayagg_view;
--- Test JSON_ARRAY(subquery) deparsing
-EXPLAIN (VERBOSE, COSTS OFF)
-SELECT JSON_ARRAY(SELECT i FROM (VALUES (1), (2), (NULL), (4)) foo(i) RETURNING jsonb);
- QUERY PLAN
----------------------------------------------------------------------
- Result
- Output: $0
- InitPlan 1 (returns $0)
- -> Aggregate
- Output: JSON_ARRAYAGG("*VALUES*".column1 RETURNING jsonb)
- -> Values Scan on "*VALUES*"
- Output: "*VALUES*".column1
-(7 rows)
-
-CREATE VIEW json_array_subquery_view AS
-SELECT JSON_ARRAY(SELECT i FROM (VALUES (1), (2), (NULL), (4)) foo(i) RETURNING jsonb);
-\sv json_array_subquery_view
-CREATE OR REPLACE VIEW public.json_array_subquery_view AS
- SELECT ( SELECT JSON_ARRAYAGG(q.a RETURNING jsonb) AS "json_arrayagg"
- FROM ( SELECT foo.i
- FROM ( VALUES (1), (2), (NULL::integer), (4)) foo(i)) q(a)) AS "json_array"
-DROP VIEW json_array_subquery_view;
--- IS JSON predicate
-SELECT NULL IS JSON;
- ?column?
-----------
-
-(1 row)
-
-SELECT NULL IS NOT JSON;
- ?column?
-----------
-
-(1 row)
-
-SELECT NULL::json IS JSON;
- ?column?
-----------
-
-(1 row)
-
-SELECT NULL::jsonb IS JSON;
- ?column?
-----------
-
-(1 row)
-
-SELECT NULL::text IS JSON;
- ?column?
-----------
-
-(1 row)
-
-SELECT NULL::bytea IS JSON;
- ?column?
-----------
-
-(1 row)
-
-SELECT NULL::int IS JSON;
-ERROR: cannot use type integer in IS JSON predicate
-SELECT '' IS JSON;
- ?column?
-----------
- f
-(1 row)
-
-SELECT bytea '\x00' IS JSON;
-ERROR: invalid byte sequence for encoding "UTF8": 0x00
-CREATE TABLE test_is_json (js text);
-INSERT INTO test_is_json VALUES
- (NULL),
- (''),
- ('123'),
- ('"aaa "'),
- ('true'),
- ('null'),
- ('[]'),
- ('[1, "2", {}]'),
- ('{}'),
- ('{ "a": 1, "b": null }'),
- ('{ "a": 1, "a": null }'),
- ('{ "a": 1, "b": [{ "a": 1 }, { "a": 2 }] }'),
- ('{ "a": 1, "b": [{ "a": 1, "b": 0, "a": 2 }] }'),
- ('aaa'),
- ('{a:1}'),
- ('["a",]');
-SELECT
- js,
- js IS JSON "IS JSON",
- js IS NOT JSON "IS NOT JSON",
- js IS JSON VALUE "IS VALUE",
- js IS JSON OBJECT "IS OBJECT",
- js IS JSON ARRAY "IS ARRAY",
- js IS JSON SCALAR "IS SCALAR",
- js IS JSON WITHOUT UNIQUE KEYS "WITHOUT UNIQUE",
- js IS JSON WITH UNIQUE KEYS "WITH UNIQUE"
-FROM
- test_is_json;
- js | IS JSON | IS NOT JSON | IS VALUE | IS OBJECT | IS ARRAY | IS SCALAR | WITHOUT UNIQUE | WITH UNIQUE
------------------------------------------------+---------+-------------+----------+-----------+----------+-----------+----------------+-------------
- | | | | | | | |
- | f | t | f | f | f | f | f | f
- 123 | t | f | t | f | f | t | t | t
- "aaa " | t | f | t | f | f | t | t | t
- true | t | f | t | f | f | t | t | t
- null | t | f | t | f | f | t | t | t
- [] | t | f | t | f | t | f | t | t
- [1, "2", {}] | t | f | t | f | t | f | t | t
- {} | t | f | t | t | f | f | t | t
- { "a": 1, "b": null } | t | f | t | t | f | f | t | t
- { "a": 1, "a": null } | t | f | t | t | f | f | t | f
- { "a": 1, "b": [{ "a": 1 }, { "a": 2 }] } | t | f | t | t | f | f | t | t
- { "a": 1, "b": [{ "a": 1, "b": 0, "a": 2 }] } | t | f | t | t | f | f | t | f
- aaa | f | t | f | f | f | f | f | f
- {a:1} | f | t | f | f | f | f | f | f
- ["a",] | f | t | f | f | f | f | f | f
-(16 rows)
-
-SELECT
- js,
- js IS JSON "IS JSON",
- js IS NOT JSON "IS NOT JSON",
- js IS JSON VALUE "IS VALUE",
- js IS JSON OBJECT "IS OBJECT",
- js IS JSON ARRAY "IS ARRAY",
- js IS JSON SCALAR "IS SCALAR",
- js IS JSON WITHOUT UNIQUE KEYS "WITHOUT UNIQUE",
- js IS JSON WITH UNIQUE KEYS "WITH UNIQUE"
-FROM
- (SELECT js::json FROM test_is_json WHERE js IS JSON) foo(js);
- js | IS JSON | IS NOT JSON | IS VALUE | IS OBJECT | IS ARRAY | IS SCALAR | WITHOUT UNIQUE | WITH UNIQUE
------------------------------------------------+---------+-------------+----------+-----------+----------+-----------+----------------+-------------
- 123 | t | f | t | f | f | t | t | t
- "aaa " | t | f | t | f | f | t | t | t
- true | t | f | t | f | f | t | t | t
- null | t | f | t | f | f | t | t | t
- [] | t | f | t | f | t | f | t | t
- [1, "2", {}] | t | f | t | f | t | f | t | t
- {} | t | f | t | t | f | f | t | t
- { "a": 1, "b": null } | t | f | t | t | f | f | t | t
- { "a": 1, "a": null } | t | f | t | t | f | f | t | f
- { "a": 1, "b": [{ "a": 1 }, { "a": 2 }] } | t | f | t | t | f | f | t | t
- { "a": 1, "b": [{ "a": 1, "b": 0, "a": 2 }] } | t | f | t | t | f | f | t | f
-(11 rows)
-
-SELECT
- js0,
- js IS JSON "IS JSON",
- js IS NOT JSON "IS NOT JSON",
- js IS JSON VALUE "IS VALUE",
- js IS JSON OBJECT "IS OBJECT",
- js IS JSON ARRAY "IS ARRAY",
- js IS JSON SCALAR "IS SCALAR",
- js IS JSON WITHOUT UNIQUE KEYS "WITHOUT UNIQUE",
- js IS JSON WITH UNIQUE KEYS "WITH UNIQUE"
-FROM
- (SELECT js, js::bytea FROM test_is_json WHERE js IS JSON) foo(js0, js);
- js0 | IS JSON | IS NOT JSON | IS VALUE | IS OBJECT | IS ARRAY | IS SCALAR | WITHOUT UNIQUE | WITH UNIQUE
------------------------------------------------+---------+-------------+----------+-----------+----------+-----------+----------------+-------------
- 123 | t | f | t | f | f | t | t | t
- "aaa " | t | f | t | f | f | t | t | t
- true | t | f | t | f | f | t | t | t
- null | t | f | t | f | f | t | t | t
- [] | t | f | t | f | t | f | t | t
- [1, "2", {}] | t | f | t | f | t | f | t | t
- {} | t | f | t | t | f | f | t | t
- { "a": 1, "b": null } | t | f | t | t | f | f | t | t
- { "a": 1, "a": null } | t | f | t | t | f | f | t | f
- { "a": 1, "b": [{ "a": 1 }, { "a": 2 }] } | t | f | t | t | f | f | t | t
- { "a": 1, "b": [{ "a": 1, "b": 0, "a": 2 }] } | t | f | t | t | f | f | t | f
-(11 rows)
-
-SELECT
- js,
- js IS JSON "IS JSON",
- js IS NOT JSON "IS NOT JSON",
- js IS JSON VALUE "IS VALUE",
- js IS JSON OBJECT "IS OBJECT",
- js IS JSON ARRAY "IS ARRAY",
- js IS JSON SCALAR "IS SCALAR",
- js IS JSON WITHOUT UNIQUE KEYS "WITHOUT UNIQUE",
- js IS JSON WITH UNIQUE KEYS "WITH UNIQUE"
-FROM
- (SELECT js::jsonb FROM test_is_json WHERE js IS JSON) foo(js);
- js | IS JSON | IS NOT JSON | IS VALUE | IS OBJECT | IS ARRAY | IS SCALAR | WITHOUT UNIQUE | WITH UNIQUE
--------------------------------------+---------+-------------+----------+-----------+----------+-----------+----------------+-------------
- 123 | t | f | t | f | f | t | t | t
- "aaa " | t | f | t | f | f | t | t | t
- true | t | f | t | f | f | t | t | t
- null | t | f | t | f | f | t | t | t
- [] | t | f | t | f | t | f | t | t
- [1, "2", {}] | t | f | t | f | t | f | t | t
- {} | t | f | t | t | f | f | t | t
- {"a": 1, "b": null} | t | f | t | t | f | f | t | t
- {"a": null} | t | f | t | t | f | f | t | t
- {"a": 1, "b": [{"a": 1}, {"a": 2}]} | t | f | t | t | f | f | t | t
- {"a": 1, "b": [{"a": 2, "b": 0}]} | t | f | t | t | f | f | t | t
-(11 rows)
-
--- Test IS JSON deparsing
-EXPLAIN (VERBOSE, COSTS OFF)
-SELECT '1' IS JSON AS "any", ('1' || i) IS JSON SCALAR AS "scalar", '[]' IS NOT JSON ARRAY AS "array", '{}' IS JSON OBJECT WITH UNIQUE AS "object" FROM generate_series(1, 3) i;
- QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------
- Function Scan on pg_catalog.generate_series i
- Output: ('1'::text IS JSON), (('1'::text || (i)::text) IS JSON SCALAR), (NOT ('[]'::text IS JSON ARRAY)), ('{}'::text IS JSON OBJECT WITH UNIQUE KEYS)
- Function Call: generate_series(1, 3)
-(3 rows)
-
-CREATE VIEW is_json_view AS
-SELECT '1' IS JSON AS "any", ('1' || i) IS JSON SCALAR AS "scalar", '[]' IS NOT JSON ARRAY AS "array", '{}' IS JSON OBJECT WITH UNIQUE AS "object" FROM generate_series(1, 3) i;
-\sv is_json_view
-CREATE OR REPLACE VIEW public.is_json_view AS
- SELECT '1'::text IS JSON AS "any",
- ('1'::text || i.i) IS JSON SCALAR AS scalar,
- NOT '[]'::text IS JSON ARRAY AS "array",
- '{}'::text IS JSON OBJECT WITH UNIQUE KEYS AS object
- FROM generate_series(1, 3) i(i)
-DROP VIEW is_json_view;
# ----------
# Another group of parallel tests (JSON related)
# ----------
-test: json jsonb json_encoding jsonpath jsonpath_encoding jsonb_jsonpath sqljson json_sqljson jsonb_sqljson
+test: json jsonb json_encoding jsonpath jsonpath_encoding jsonb_jsonpath
# ----------
# Another group of parallel tests
+++ /dev/null
--- JSON_EXISTS
-
-SELECT JSON_EXISTS(NULL FORMAT JSON, '$');
-
--- JSON_VALUE
-
-SELECT JSON_VALUE(NULL FORMAT JSON, '$');
-
--- JSON_QUERY
-
-SELECT JSON_QUERY(NULL FORMAT JSON, '$');
-
--- JSON_TABLE
-
-SELECT * FROM JSON_TABLE(NULL FORMAT JSON, '$' COLUMNS (foo text));
+++ /dev/null
--- JSON_EXISTS
-
-SELECT JSON_EXISTS(NULL::jsonb, '$');
-
-SELECT JSON_EXISTS(jsonb '[]', '$');
-SELECT JSON_EXISTS(JSON_OBJECT(RETURNING jsonb), '$');
-
-SELECT JSON_EXISTS(jsonb '1', '$');
-SELECT JSON_EXISTS(jsonb 'null', '$');
-SELECT JSON_EXISTS(jsonb '[]', '$');
-
-SELECT JSON_EXISTS(jsonb '1', '$.a');
-SELECT JSON_EXISTS(jsonb '1', 'strict $.a');
-SELECT JSON_EXISTS(jsonb '1', 'strict $.a' ERROR ON ERROR);
-SELECT JSON_EXISTS(jsonb 'null', '$.a');
-SELECT JSON_EXISTS(jsonb '[]', '$.a');
-SELECT JSON_EXISTS(jsonb '[1, "aaa", {"a": 1}]', 'strict $.a');
-SELECT JSON_EXISTS(jsonb '[1, "aaa", {"a": 1}]', 'lax $.a');
-SELECT JSON_EXISTS(jsonb '{}', '$.a');
-SELECT JSON_EXISTS(jsonb '{"b": 1, "a": 2}', '$.a');
-
-SELECT JSON_EXISTS(jsonb '1', '$.a.b');
-SELECT JSON_EXISTS(jsonb '{"a": {"b": 1}}', '$.a.b');
-SELECT JSON_EXISTS(jsonb '{"a": 1, "b": 2}', '$.a.b');
-
-SELECT JSON_EXISTS(jsonb '{"a": 1, "b": 2}', '$.* ? (@ > $x)' PASSING 1 AS x);
-SELECT JSON_EXISTS(jsonb '{"a": 1, "b": 2}', '$.* ? (@ > $x)' PASSING '1' AS x);
-SELECT JSON_EXISTS(jsonb '{"a": 1, "b": 2}', '$.* ? (@ > $x && @ < $y)' PASSING 0 AS x, 2 AS y);
-SELECT JSON_EXISTS(jsonb '{"a": 1, "b": 2}', '$.* ? (@ > $x && @ < $y)' PASSING 0 AS x, 1 AS y);
-
--- extension: boolean expressions
-SELECT JSON_EXISTS(jsonb '1', '$ > 2');
-SELECT JSON_EXISTS(jsonb '1', '$.a > 2' ERROR ON ERROR);
-
--- extension: RETURNING clause
-SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING bool);
-SELECT JSON_EXISTS(jsonb '1', '$[1]' RETURNING bool);
-SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING int);
-SELECT JSON_EXISTS(jsonb '1', '$[1]' RETURNING int);
-SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING text);
-SELECT JSON_EXISTS(jsonb '1', '$[1]' RETURNING text);
-SELECT JSON_EXISTS(jsonb '1', 'strict $[1]' RETURNING text FALSE ON ERROR);
-SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING jsonb);
-SELECT JSON_EXISTS(jsonb '1', '$[0]' RETURNING float4);
-
-
--- JSON_VALUE
-
-SELECT JSON_VALUE(NULL::jsonb, '$');
-
-SELECT JSON_VALUE(jsonb 'null', '$');
-SELECT JSON_VALUE(jsonb 'null', '$' RETURNING int);
-
-SELECT JSON_VALUE(jsonb 'true', '$');
-SELECT JSON_VALUE(jsonb 'true', '$' RETURNING bool);
-
-SELECT JSON_VALUE(jsonb '123', '$');
-SELECT JSON_VALUE(jsonb '123', '$' RETURNING int) + 234;
-SELECT JSON_VALUE(jsonb '123', '$' RETURNING text);
-/* jsonb bytea ??? */
-SELECT JSON_VALUE(jsonb '123', '$' RETURNING bytea ERROR ON ERROR);
-
-SELECT JSON_VALUE(jsonb '1.23', '$');
-SELECT JSON_VALUE(jsonb '1.23', '$' RETURNING int);
-SELECT JSON_VALUE(jsonb '"1.23"', '$' RETURNING numeric);
-SELECT JSON_VALUE(jsonb '"1.23"', '$' RETURNING int ERROR ON ERROR);
-
-SELECT JSON_VALUE(jsonb '"aaa"', '$');
-SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING text);
-SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING char(5));
-SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING char(2));
-SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING json);
-SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING jsonb);
-SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING json ERROR ON ERROR);
-SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING jsonb ERROR ON ERROR);
-SELECT JSON_VALUE(jsonb '"\"aaa\""', '$' RETURNING json);
-SELECT JSON_VALUE(jsonb '"\"aaa\""', '$' RETURNING jsonb);
-SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING int);
-SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING int ERROR ON ERROR);
-SELECT JSON_VALUE(jsonb '"aaa"', '$' RETURNING int DEFAULT 111 ON ERROR);
-SELECT JSON_VALUE(jsonb '"123"', '$' RETURNING int) + 234;
-
-SELECT JSON_VALUE(jsonb '"2017-02-20"', '$' RETURNING date) + 9;
-
--- Test NULL checks execution in domain types
-CREATE DOMAIN sqljsonb_int_not_null AS int NOT NULL;
-SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null);
-SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null NULL ON ERROR);
-SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null DEFAULT NULL ON ERROR);
-
-SELECT JSON_VALUE(jsonb '[]', '$');
-SELECT JSON_VALUE(jsonb '[]', '$' ERROR ON ERROR);
-SELECT JSON_VALUE(jsonb '{}', '$');
-SELECT JSON_VALUE(jsonb '{}', '$' ERROR ON ERROR);
-
-SELECT JSON_VALUE(jsonb '1', '$.a');
-SELECT JSON_VALUE(jsonb '1', 'strict $.a' ERROR ON ERROR);
-SELECT JSON_VALUE(jsonb '1', 'strict $.a' DEFAULT 'error' ON ERROR);
-SELECT JSON_VALUE(jsonb '1', 'lax $.a' ERROR ON ERROR);
-SELECT JSON_VALUE(jsonb '1', 'lax $.a' ERROR ON EMPTY ERROR ON ERROR);
-SELECT JSON_VALUE(jsonb '1', 'strict $.a' DEFAULT 2 ON ERROR);
-SELECT JSON_VALUE(jsonb '1', 'lax $.a' DEFAULT 2 ON ERROR);
-SELECT JSON_VALUE(jsonb '1', 'lax $.a' DEFAULT '2' ON ERROR);
-SELECT JSON_VALUE(jsonb '1', 'lax $.a' NULL ON EMPTY DEFAULT '2' ON ERROR);
-SELECT JSON_VALUE(jsonb '1', 'lax $.a' DEFAULT '2' ON EMPTY DEFAULT '3' ON ERROR);
-SELECT JSON_VALUE(jsonb '1', 'lax $.a' ERROR ON EMPTY DEFAULT '3' ON ERROR);
-
-SELECT JSON_VALUE(jsonb '[1,2]', '$[*]' ERROR ON ERROR);
-SELECT JSON_VALUE(jsonb '[1,2]', '$[*]' DEFAULT '0' ON ERROR);
-SELECT JSON_VALUE(jsonb '[" "]', '$[*]' RETURNING int ERROR ON ERROR);
-SELECT JSON_VALUE(jsonb '[" "]', '$[*]' RETURNING int DEFAULT 2 + 3 ON ERROR);
-SELECT JSON_VALUE(jsonb '["1"]', '$[*]' RETURNING int DEFAULT 2 + 3 ON ERROR);
-
-SELECT
- x,
- JSON_VALUE(
- jsonb '{"a": 1, "b": 2}',
- '$.* ? (@ > $x)' PASSING x AS x
- RETURNING int
- DEFAULT -1 ON EMPTY
- DEFAULT -2 ON ERROR
- ) y
-FROM
- generate_series(0, 2) x;
-
-SELECT JSON_VALUE(jsonb 'null', '$a' PASSING point ' (1, 2 )' AS a);
-SELECT JSON_VALUE(jsonb 'null', '$a' PASSING point ' (1, 2 )' AS a RETURNING point);
-
--- Test timestamptz passing and output
-SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts);
-SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING timestamptz);
-SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING timestamp);
-SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING json);
-SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING jsonb);
-
--- JSON_QUERY
-
-SELECT
- JSON_QUERY(js, '$'),
- JSON_QUERY(js, '$' WITHOUT WRAPPER),
- JSON_QUERY(js, '$' WITH CONDITIONAL WRAPPER),
- JSON_QUERY(js, '$' WITH UNCONDITIONAL ARRAY WRAPPER),
- JSON_QUERY(js, '$' WITH ARRAY WRAPPER)
-FROM
- (VALUES
- (jsonb 'null'),
- ('12.3'),
- ('true'),
- ('"aaa"'),
- ('[1, null, "2"]'),
- ('{"a": 1, "b": [2]}')
- ) foo(js);
-
-SELECT
- JSON_QUERY(js, 'strict $[*]') AS "unspec",
- JSON_QUERY(js, 'strict $[*]' WITHOUT WRAPPER) AS "without",
- JSON_QUERY(js, 'strict $[*]' WITH CONDITIONAL WRAPPER) AS "with cond",
- JSON_QUERY(js, 'strict $[*]' WITH UNCONDITIONAL ARRAY WRAPPER) AS "with uncond",
- JSON_QUERY(js, 'strict $[*]' WITH ARRAY WRAPPER) AS "with"
-FROM
- (VALUES
- (jsonb '1'),
- ('[]'),
- ('[null]'),
- ('[12.3]'),
- ('[true]'),
- ('["aaa"]'),
- ('[[1, 2, 3]]'),
- ('[{"a": 1, "b": [2]}]'),
- ('[1, "2", null, [3]]')
- ) foo(js);
-
-SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text);
-SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text KEEP QUOTES);
-SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text KEEP QUOTES ON SCALAR STRING);
-SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text OMIT QUOTES);
-SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text OMIT QUOTES ON SCALAR STRING);
-SELECT JSON_QUERY(jsonb '"aaa"', '$' OMIT QUOTES ERROR ON ERROR);
-SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING json OMIT QUOTES ERROR ON ERROR);
-SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING bytea FORMAT JSON OMIT QUOTES ERROR ON ERROR);
-
--- QUOTES behavior should not be specified when WITH WRAPPER used:
--- Should fail
-SELECT JSON_QUERY(jsonb '[1]', '$' WITH WRAPPER OMIT QUOTES);
-SELECT JSON_QUERY(jsonb '[1]', '$' WITH WRAPPER KEEP QUOTES);
-SELECT JSON_QUERY(jsonb '[1]', '$' WITH CONDITIONAL WRAPPER KEEP QUOTES);
-SELECT JSON_QUERY(jsonb '[1]', '$' WITH CONDITIONAL WRAPPER OMIT QUOTES);
--- Should succeed
-SELECT JSON_QUERY(jsonb '[1]', '$' WITHOUT WRAPPER OMIT QUOTES);
-SELECT JSON_QUERY(jsonb '[1]', '$' WITHOUT WRAPPER KEEP QUOTES);
-
-SELECT JSON_QUERY(jsonb '[]', '$[*]');
-SELECT JSON_QUERY(jsonb '[]', '$[*]' NULL ON EMPTY);
-SELECT JSON_QUERY(jsonb '[]', '$[*]' EMPTY ON EMPTY);
-SELECT JSON_QUERY(jsonb '[]', '$[*]' EMPTY ARRAY ON EMPTY);
-SELECT JSON_QUERY(jsonb '[]', '$[*]' EMPTY OBJECT ON EMPTY);
-SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY);
-SELECT JSON_QUERY(jsonb '[]', '$[*]' DEFAULT '"empty"' ON EMPTY);
-
-SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY NULL ON ERROR);
-SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY EMPTY ARRAY ON ERROR);
-SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY EMPTY OBJECT ON ERROR);
-SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY ERROR ON ERROR);
-SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON ERROR);
-
-SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' ERROR ON ERROR);
-SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' DEFAULT '"empty"' ON ERROR);
-
-SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING json);
-SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING json FORMAT JSON);
-SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING jsonb);
-SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING jsonb FORMAT JSON);
-SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING text);
-SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING char(10));
-SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING char(3));
-SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING text FORMAT JSON);
-SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING bytea);
-SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING bytea FORMAT JSON);
-
-SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' RETURNING bytea EMPTY OBJECT ON ERROR);
-SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' RETURNING bytea FORMAT JSON EMPTY OBJECT ON ERROR);
-SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' RETURNING json EMPTY OBJECT ON ERROR);
-SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' RETURNING jsonb EMPTY OBJECT ON ERROR);
-
-SELECT
- x, y,
- JSON_QUERY(
- jsonb '[1,2,3,4,5,null]',
- '$[*] ? (@ >= $x && @ <= $y)'
- PASSING x AS x, y AS y
- WITH CONDITIONAL WRAPPER
- EMPTY ARRAY ON EMPTY
- ) list
-FROM
- generate_series(0, 4) x,
- generate_series(0, 4) y;
-
--- Extension: record types returning
-CREATE TYPE sqljsonb_rec AS (a int, t text, js json, jb jsonb, jsa json[]);
-CREATE TYPE sqljsonb_reca AS (reca sqljsonb_rec[]);
-
-SELECT JSON_QUERY(jsonb '[{"a": 1, "b": "foo", "t": "aaa", "js": [1, "2", {}], "jb": {"x": [1, "2", {}]}}, {"a": 2}]', '$[0]' RETURNING sqljsonb_rec);
-SELECT * FROM unnest((JSON_QUERY(jsonb '{"jsa": [{"a": 1, "b": ["foo"]}, {"a": 2, "c": {}}, 123]}', '$' RETURNING sqljsonb_rec)).jsa);
-SELECT * FROM unnest((JSON_QUERY(jsonb '{"reca": [{"a": 1, "t": ["foo", []]}, {"a": 2, "jb": [{}, true]}]}', '$' RETURNING sqljsonb_reca)).reca);
-
--- Extension: array types returning
-SELECT JSON_QUERY(jsonb '[1,2,null,"3"]', '$[*]' RETURNING int[] WITH WRAPPER);
-SELECT * FROM unnest(JSON_QUERY(jsonb '[{"a": 1, "t": ["foo", []]}, {"a": 2, "jb": [{}, true]}]', '$' RETURNING sqljsonb_rec[]));
-
--- Extension: domain types returning
-SELECT JSON_QUERY(jsonb '{"a": 1}', '$.a' RETURNING sqljsonb_int_not_null);
-SELECT JSON_QUERY(jsonb '{"a": 1}', '$.b' RETURNING sqljsonb_int_not_null);
-
--- Test timestamptz passing and output
-SELECT JSON_QUERY(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts);
-SELECT JSON_QUERY(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING json);
-SELECT JSON_QUERY(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING jsonb);
-
--- Test constraints
-
-CREATE TABLE test_jsonb_constraints (
- js text,
- i int,
- x jsonb DEFAULT JSON_QUERY(jsonb '[1,2]', '$[*]' WITH WRAPPER)
- CONSTRAINT test_jsonb_constraint1
- CHECK (js IS JSON)
- CONSTRAINT test_jsonb_constraint2
- CHECK (JSON_EXISTS(js::jsonb, '$.a' PASSING i + 5 AS int, i::text AS txt, array[1,2,3] as arr))
- CONSTRAINT test_jsonb_constraint3
- CHECK (JSON_VALUE(js::jsonb, '$.a' RETURNING int DEFAULT ('12' || i)::int ON EMPTY ERROR ON ERROR) > i)
- CONSTRAINT test_jsonb_constraint4
- CHECK (JSON_QUERY(js::jsonb, '$.a' WITH CONDITIONAL WRAPPER EMPTY OBJECT ON ERROR) < jsonb '[10]')
- CONSTRAINT test_jsonb_constraint5
- CHECK (JSON_QUERY(js::jsonb, '$.a' RETURNING char(5) OMIT QUOTES EMPTY ARRAY ON EMPTY) > 'a' COLLATE "C")
- CONSTRAINT test_jsonb_constraint6
- CHECK (JSON_EXISTS(js::jsonb, 'strict $.a' RETURNING int TRUE ON ERROR) < 2)
-);
-
-\d test_jsonb_constraints
-
-SELECT check_clause
-FROM information_schema.check_constraints
-WHERE constraint_name LIKE 'test_jsonb_constraint%'
-ORDER BY 1;
-
-SELECT pg_get_expr(adbin, adrelid)
-FROM pg_attrdef
-WHERE adrelid = 'test_jsonb_constraints'::regclass
-ORDER BY 1;
-
-INSERT INTO test_jsonb_constraints VALUES ('', 1);
-INSERT INTO test_jsonb_constraints VALUES ('1', 1);
-INSERT INTO test_jsonb_constraints VALUES ('[]');
-INSERT INTO test_jsonb_constraints VALUES ('{"b": 1}', 1);
-INSERT INTO test_jsonb_constraints VALUES ('{"a": 1}', 1);
-INSERT INTO test_jsonb_constraints VALUES ('{"a": 7}', 1);
-INSERT INTO test_jsonb_constraints VALUES ('{"a": 10}', 1);
-
-DROP TABLE test_jsonb_constraints;
-
--- Test mutabilily od query functions
-CREATE TABLE test_jsonb_mutability(js jsonb);
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$'));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a[0]'));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime()'));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@ < $.datetime())'));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime() < $.datetime())'));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime() < $.datetime("HH:MI TZH"))'));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime("HH:MI TZH") < $.datetime("HH:MI TZH"))'));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime("HH:MI") < $.datetime("YY-MM-DD HH:MI"))'));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime("HH:MI TZH") < $.datetime("YY-MM-DD HH:MI"))'));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime("HH:MI TZH") < $x' PASSING '12:34'::timetz AS x));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime("HH:MI TZH") < $y' PASSING '12:34'::timetz AS x));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime() < $x' PASSING '12:34'::timetz AS x));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime() < $x' PASSING '1234'::int AS x));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime() ? (@ == $x)' PASSING '12:34'::time AS x));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime("YY-MM-DD") ? (@ == $x)' PASSING '2020-07-14'::date AS x));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$[1, $.a ? (@.datetime() == $x)]' PASSING '12:34'::time AS x));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$[1, 0 to $.a ? (@.datetime() == $x)]' PASSING '12:34'::time AS x));
-CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$[1, $.a ? (@.datetime("HH:MI") == $x)]' PASSING '12:34'::time AS x));
-DROP TABLE test_jsonb_mutability;
-
--- JSON_TABLE
-
--- Should fail (JSON_TABLE can be used only in FROM clause)
-SELECT JSON_TABLE('[]', '$');
-
--- Should fail (no columns)
-SELECT * FROM JSON_TABLE(NULL, '$' COLUMNS ());
-
-SELECT * FROM JSON_TABLE (NULL::jsonb, '$' COLUMNS (v1 timestamp)) AS f (v1, v2);
-
--- NULL => empty table
-SELECT * FROM JSON_TABLE(NULL::jsonb, '$' COLUMNS (foo int)) bar;
-
---
-SELECT * FROM JSON_TABLE(jsonb '123', '$'
- COLUMNS (item int PATH '$', foo int)) bar;
-
--- JSON_TABLE: basic functionality
-CREATE DOMAIN jsonb_test_domain AS text CHECK (value <> 'foo');
-
-SELECT *
-FROM
- (VALUES
- ('1'),
- ('[]'),
- ('{}'),
- ('[1, 1.23, "2", "aaaaaaa", "foo", null, false, true, {"aaa": 123}, "[1,2]", "\"str\""]')
- ) vals(js)
- LEFT OUTER JOIN
--- JSON_TABLE is implicitly lateral
- JSON_TABLE(
- vals.js::jsonb, 'lax $[*]'
- COLUMNS (
- id FOR ORDINALITY,
- id2 FOR ORDINALITY, -- allowed additional ordinality columns
- "int" int PATH '$',
- "text" text PATH '$',
- "char(4)" char(4) PATH '$',
- "bool" bool PATH '$',
- "numeric" numeric PATH '$',
- "domain" jsonb_test_domain PATH '$',
- js json PATH '$',
- jb jsonb PATH '$',
- jst text FORMAT JSON PATH '$',
- jsc char(4) FORMAT JSON PATH '$',
- jsv varchar(4) FORMAT JSON PATH '$',
- jsb jsonb FORMAT JSON PATH '$',
- jsbq jsonb FORMAT JSON PATH '$' OMIT QUOTES,
- aaa int, -- implicit path '$."aaa"',
- aaa1 int PATH '$.aaa',
- exists1 bool EXISTS PATH '$.aaa',
- exists2 int EXISTS PATH '$.aaa',
- exists3 int EXISTS PATH 'strict $.aaa' UNKNOWN ON ERROR,
- exists4 text EXISTS PATH 'strict $.aaa' FALSE ON ERROR,
-
- js2 json PATH '$',
- jsb2w jsonb PATH '$' WITH WRAPPER,
- jsb2q jsonb PATH '$' OMIT QUOTES,
- ia int[] PATH '$',
- ta text[] PATH '$',
- jba jsonb[] PATH '$'
- )
- ) jt
- ON true;
-
--- JSON_TABLE: Test backward parsing
-
-CREATE VIEW jsonb_table_view AS
-SELECT * FROM
- JSON_TABLE(
- jsonb 'null', 'lax $[*]' PASSING 1 + 2 AS a, json '"foo"' AS "b c"
- COLUMNS (
- id FOR ORDINALITY,
- id2 FOR ORDINALITY, -- allowed additional ordinality columns
- "int" int PATH '$',
- "text" text PATH '$',
- "char(4)" char(4) PATH '$',
- "bool" bool PATH '$',
- "numeric" numeric PATH '$',
- "domain" jsonb_test_domain PATH '$',
- js json PATH '$',
- jb jsonb PATH '$',
- jst text FORMAT JSON PATH '$',
- jsc char(4) FORMAT JSON PATH '$',
- jsv varchar(4) FORMAT JSON PATH '$',
- jsb jsonb FORMAT JSON PATH '$',
- jsbq jsonb FORMAT JSON PATH '$' OMIT QUOTES,
- aaa int, -- implicit path '$."aaa"',
- aaa1 int PATH '$.aaa',
- exists1 bool EXISTS PATH '$.aaa',
- exists2 int EXISTS PATH '$.aaa' TRUE ON ERROR,
- exists3 text EXISTS PATH 'strict $.aaa' UNKNOWN ON ERROR,
-
- js2 json PATH '$',
- jsb2w jsonb PATH '$' WITH WRAPPER,
- jsb2q jsonb PATH '$' OMIT QUOTES,
- ia int[] PATH '$',
- ta text[] PATH '$',
- jba jsonb[] PATH '$',
-
- NESTED PATH '$[1]' AS p1 COLUMNS (
- a1 int,
- NESTED PATH '$[*]' AS "p1 1" COLUMNS (
- a11 text
- ),
- b1 text
- ),
- NESTED PATH '$[2]' AS p2 COLUMNS (
- NESTED PATH '$[*]' AS "p2:1" COLUMNS (
- a21 text
- ),
- NESTED PATH '$[*]' AS p22 COLUMNS (
- a22 text
- )
- )
- )
- );
-
-\sv jsonb_table_view
-
-EXPLAIN (COSTS OFF, VERBOSE) SELECT * FROM jsonb_table_view;
-
-DROP VIEW jsonb_table_view;
-DROP DOMAIN jsonb_test_domain;
-
--- JSON_TABLE: ON EMPTY/ON ERROR behavior
-SELECT *
-FROM
- (VALUES ('1'), ('"err"')) vals(js),
- JSON_TABLE(vals.js::jsonb, '$' COLUMNS (a int PATH '$')) jt;
-
-SELECT *
-FROM
- (VALUES ('1'), ('"err"')) vals(js)
- LEFT OUTER JOIN
- JSON_TABLE(vals.js::jsonb, '$' COLUMNS (a int PATH '$') ERROR ON ERROR) jt
- ON true;
-
-SELECT *
-FROM
- (VALUES ('1'), ('"err"')) vals(js)
- LEFT OUTER JOIN
- JSON_TABLE(vals.js::jsonb, '$' COLUMNS (a int PATH '$' ERROR ON ERROR)) jt
- ON true;
-
-SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (a int PATH '$.a' ERROR ON EMPTY)) jt;
-SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (a int PATH 'strict $.a' ERROR ON EMPTY) ERROR ON ERROR) jt;
-SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (a int PATH 'lax $.a' ERROR ON EMPTY) ERROR ON ERROR) jt;
-
-SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int PATH '$' DEFAULT 1 ON EMPTY DEFAULT 2 ON ERROR)) jt;
-SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int PATH 'strict $.a' DEFAULT 1 ON EMPTY DEFAULT 2 ON ERROR)) jt;
-SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int PATH 'lax $.a' DEFAULT 1 ON EMPTY DEFAULT 2 ON ERROR)) jt;
-
--- JSON_TABLE: EXISTS PATH types
-SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int4 EXISTS PATH '$.a'));
-SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int2 EXISTS PATH '$.a'));
-SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int8 EXISTS PATH '$.a'));
-SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a float4 EXISTS PATH '$.a'));
-SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a char(3) EXISTS PATH '$.a'));
-SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a json EXISTS PATH '$.a'));
-SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a jsonb EXISTS PATH '$.a'));
-
--- JSON_TABLE: nested paths and plans
-
--- Should fail (JSON_TABLE columns must contain explicit AS path
--- specifications if explicit PLAN clause is used)
-SELECT * FROM JSON_TABLE(
- jsonb '[]', '$' -- AS <path name> required here
- COLUMNS (
- foo int PATH '$'
- )
- PLAN DEFAULT (UNION)
-) jt;
-
-SELECT * FROM JSON_TABLE(
- jsonb '[]', '$' AS path1
- COLUMNS (
- NESTED PATH '$' COLUMNS ( -- AS <path name> required here
- foo int PATH '$'
- )
- )
- PLAN DEFAULT (UNION)
-) jt;
-
--- Should fail (column names must be distinct)
-SELECT * FROM JSON_TABLE(
- jsonb '[]', '$' AS a
- COLUMNS (
- a int
- )
-) jt;
-
-SELECT * FROM JSON_TABLE(
- jsonb '[]', '$' AS a
- COLUMNS (
- b int,
- NESTED PATH '$' AS a
- COLUMNS (
- c int
- )
- )
-) jt;
-
-SELECT * FROM JSON_TABLE(
- jsonb '[]', '$'
- COLUMNS (
- b int,
- NESTED PATH '$' AS b
- COLUMNS (
- c int
- )
- )
-) jt;
-
-SELECT * FROM JSON_TABLE(
- jsonb '[]', '$'
- COLUMNS (
- NESTED PATH '$' AS a
- COLUMNS (
- b int
- ),
- NESTED PATH '$'
- COLUMNS (
- NESTED PATH '$' AS a
- COLUMNS (
- c int
- )
- )
- )
-) jt;
-
--- JSON_TABLE: plan validation
-
-SELECT * FROM JSON_TABLE(
- jsonb 'null', '$[*]' AS p0
- COLUMNS (
- NESTED PATH '$' AS p1 COLUMNS (
- NESTED PATH '$' AS p11 COLUMNS ( foo int ),
- NESTED PATH '$' AS p12 COLUMNS ( bar int )
- ),
- NESTED PATH '$' AS p2 COLUMNS (
- NESTED PATH '$' AS p21 COLUMNS ( baz int )
- )
- )
- PLAN (p1)
-) jt;
-
-SELECT * FROM JSON_TABLE(
- jsonb 'null', '$[*]' AS p0
- COLUMNS (
- NESTED PATH '$' AS p1 COLUMNS (
- NESTED PATH '$' AS p11 COLUMNS ( foo int ),
- NESTED PATH '$' AS p12 COLUMNS ( bar int )
- ),
- NESTED PATH '$' AS p2 COLUMNS (
- NESTED PATH '$' AS p21 COLUMNS ( baz int )
- )
- )
- PLAN (p0)
-) jt;
-
-SELECT * FROM JSON_TABLE(
- jsonb 'null', '$[*]' AS p0
- COLUMNS (
- NESTED PATH '$' AS p1 COLUMNS (
- NESTED PATH '$' AS p11 COLUMNS ( foo int ),
- NESTED PATH '$' AS p12 COLUMNS ( bar int )
- ),
- NESTED PATH '$' AS p2 COLUMNS (
- NESTED PATH '$' AS p21 COLUMNS ( baz int )
- )
- )
- PLAN (p0 OUTER p3)
-) jt;
-
-SELECT * FROM JSON_TABLE(
- jsonb 'null', '$[*]' AS p0
- COLUMNS (
- NESTED PATH '$' AS p1 COLUMNS (
- NESTED PATH '$' AS p11 COLUMNS ( foo int ),
- NESTED PATH '$' AS p12 COLUMNS ( bar int )
- ),
- NESTED PATH '$' AS p2 COLUMNS (
- NESTED PATH '$' AS p21 COLUMNS ( baz int )
- )
- )
- PLAN (p0 UNION p1 UNION p11)
-) jt;
-
-SELECT * FROM JSON_TABLE(
- jsonb 'null', '$[*]' AS p0
- COLUMNS (
- NESTED PATH '$' AS p1 COLUMNS (
- NESTED PATH '$' AS p11 COLUMNS ( foo int ),
- NESTED PATH '$' AS p12 COLUMNS ( bar int )
- ),
- NESTED PATH '$' AS p2 COLUMNS (
- NESTED PATH '$' AS p21 COLUMNS ( baz int )
- )
- )
- PLAN (p0 OUTER (p1 CROSS p13))
-) jt;
-
-SELECT * FROM JSON_TABLE(
- jsonb 'null', '$[*]' AS p0
- COLUMNS (
- NESTED PATH '$' AS p1 COLUMNS (
- NESTED PATH '$' AS p11 COLUMNS ( foo int ),
- NESTED PATH '$' AS p12 COLUMNS ( bar int )
- ),
- NESTED PATH '$' AS p2 COLUMNS (
- NESTED PATH '$' AS p21 COLUMNS ( baz int )
- )
- )
- PLAN (p0 OUTER (p1 CROSS p2))
-) jt;
-
-SELECT * FROM JSON_TABLE(
- jsonb 'null', '$[*]' AS p0
- COLUMNS (
- NESTED PATH '$' AS p1 COLUMNS (
- NESTED PATH '$' AS p11 COLUMNS ( foo int ),
- NESTED PATH '$' AS p12 COLUMNS ( bar int )
- ),
- NESTED PATH '$' AS p2 COLUMNS (
- NESTED PATH '$' AS p21 COLUMNS ( baz int )
- )
- )
- PLAN (p0 OUTER ((p1 UNION p11) CROSS p2))
-) jt;
-
-SELECT * FROM JSON_TABLE(
- jsonb 'null', '$[*]' AS p0
- COLUMNS (
- NESTED PATH '$' AS p1 COLUMNS (
- NESTED PATH '$' AS p11 COLUMNS ( foo int ),
- NESTED PATH '$' AS p12 COLUMNS ( bar int )
- ),
- NESTED PATH '$' AS p2 COLUMNS (
- NESTED PATH '$' AS p21 COLUMNS ( baz int )
- )
- )
- PLAN (p0 OUTER ((p1 INNER p11) CROSS p2))
-) jt;
-
-SELECT * FROM JSON_TABLE(
- jsonb 'null', '$[*]' AS p0
- COLUMNS (
- NESTED PATH '$' AS p1 COLUMNS (
- NESTED PATH '$' AS p11 COLUMNS ( foo int ),
- NESTED PATH '$' AS p12 COLUMNS ( bar int )
- ),
- NESTED PATH '$' AS p2 COLUMNS (
- NESTED PATH '$' AS p21 COLUMNS ( baz int )
- )
- )
- PLAN (p0 OUTER ((p1 INNER (p12 CROSS p11)) CROSS p2))
-) jt;
-
-SELECT * FROM JSON_TABLE(
- jsonb 'null', 'strict $[*]' AS p0
- COLUMNS (
- NESTED PATH '$' AS p1 COLUMNS (
- NESTED PATH '$' AS p11 COLUMNS ( foo int ),
- NESTED PATH '$' AS p12 COLUMNS ( bar int )
- ),
- NESTED PATH '$' AS p2 COLUMNS (
- NESTED PATH '$' AS p21 COLUMNS ( baz int )
- )
- )
- PLAN (p0 OUTER ((p1 INNER (p12 CROSS p11)) CROSS (p2 INNER p21)))
-) jt;
-
-SELECT * FROM JSON_TABLE(
- jsonb 'null', 'strict $[*]' -- without root path name
- COLUMNS (
- NESTED PATH '$' AS p1 COLUMNS (
- NESTED PATH '$' AS p11 COLUMNS ( foo int ),
- NESTED PATH '$' AS p12 COLUMNS ( bar int )
- ),
- NESTED PATH '$' AS p2 COLUMNS (
- NESTED PATH '$' AS p21 COLUMNS ( baz int )
- )
- )
- PLAN ((p1 INNER (p12 CROSS p11)) CROSS (p2 INNER p21))
-) jt;
-
--- JSON_TABLE: plan execution
-
-CREATE TEMP TABLE jsonb_table_test (js jsonb);
-
-INSERT INTO jsonb_table_test
-VALUES (
- '[
- {"a": 1, "b": [], "c": []},
- {"a": 2, "b": [1, 2, 3], "c": [10, null, 20]},
- {"a": 3, "b": [1, 2], "c": []},
- {"x": "4", "b": [1, 2], "c": 123}
- ]'
-);
-
--- unspecified plan (outer, union)
-select
- jt.*
-from
- jsonb_table_test jtt,
- json_table (
- jtt.js,'strict $[*]' as p
- columns (
- n for ordinality,
- a int path 'lax $.a' default -1 on empty,
- nested path 'strict $.b[*]' as pb columns ( b int path '$' ),
- nested path 'strict $.c[*]' as pc columns ( c int path '$' )
- )
- ) jt;
-
--- default plan (outer, union)
-select
- jt.*
-from
- jsonb_table_test jtt,
- json_table (
- jtt.js,'strict $[*]' as p
- columns (
- n for ordinality,
- a int path 'lax $.a' default -1 on empty,
- nested path 'strict $.b[*]' as pb columns ( b int path '$' ),
- nested path 'strict $.c[*]' as pc columns ( c int path '$' )
- )
- plan default (outer, union)
- ) jt;
-
--- specific plan (p outer (pb union pc))
-select
- jt.*
-from
- jsonb_table_test jtt,
- json_table (
- jtt.js,'strict $[*]' as p
- columns (
- n for ordinality,
- a int path 'lax $.a' default -1 on empty,
- nested path 'strict $.b[*]' as pb columns ( b int path '$' ),
- nested path 'strict $.c[*]' as pc columns ( c int path '$' )
- )
- plan (p outer (pb union pc))
- ) jt;
-
--- specific plan (p outer (pc union pb))
-select
- jt.*
-from
- jsonb_table_test jtt,
- json_table (
- jtt.js,'strict $[*]' as p
- columns (
- n for ordinality,
- a int path 'lax $.a' default -1 on empty,
- nested path 'strict $.b[*]' as pb columns ( b int path '$' ),
- nested path 'strict $.c[*]' as pc columns ( c int path '$' )
- )
- plan (p outer (pc union pb))
- ) jt;
-
--- default plan (inner, union)
-select
- jt.*
-from
- jsonb_table_test jtt,
- json_table (
- jtt.js,'strict $[*]' as p
- columns (
- n for ordinality,
- a int path 'lax $.a' default -1 on empty,
- nested path 'strict $.b[*]' as pb columns ( b int path '$' ),
- nested path 'strict $.c[*]' as pc columns ( c int path '$' )
- )
- plan default (inner)
- ) jt;
-
--- specific plan (p inner (pb union pc))
-select
- jt.*
-from
- jsonb_table_test jtt,
- json_table (
- jtt.js,'strict $[*]' as p
- columns (
- n for ordinality,
- a int path 'lax $.a' default -1 on empty,
- nested path 'strict $.b[*]' as pb columns ( b int path '$' ),
- nested path 'strict $.c[*]' as pc columns ( c int path '$' )
- )
- plan (p inner (pb union pc))
- ) jt;
-
--- default plan (inner, cross)
-select
- jt.*
-from
- jsonb_table_test jtt,
- json_table (
- jtt.js,'strict $[*]' as p
- columns (
- n for ordinality,
- a int path 'lax $.a' default -1 on empty,
- nested path 'strict $.b[*]' as pb columns ( b int path '$' ),
- nested path 'strict $.c[*]' as pc columns ( c int path '$' )
- )
- plan default (cross, inner)
- ) jt;
-
--- specific plan (p inner (pb cross pc))
-select
- jt.*
-from
- jsonb_table_test jtt,
- json_table (
- jtt.js,'strict $[*]' as p
- columns (
- n for ordinality,
- a int path 'lax $.a' default -1 on empty,
- nested path 'strict $.b[*]' as pb columns ( b int path '$' ),
- nested path 'strict $.c[*]' as pc columns ( c int path '$' )
- )
- plan (p inner (pb cross pc))
- ) jt;
-
--- default plan (outer, cross)
-select
- jt.*
-from
- jsonb_table_test jtt,
- json_table (
- jtt.js,'strict $[*]' as p
- columns (
- n for ordinality,
- a int path 'lax $.a' default -1 on empty,
- nested path 'strict $.b[*]' as pb columns ( b int path '$' ),
- nested path 'strict $.c[*]' as pc columns ( c int path '$' )
- )
- plan default (outer, cross)
- ) jt;
-
--- specific plan (p outer (pb cross pc))
-select
- jt.*
-from
- jsonb_table_test jtt,
- json_table (
- jtt.js,'strict $[*]' as p
- columns (
- n for ordinality,
- a int path 'lax $.a' default -1 on empty,
- nested path 'strict $.b[*]' as pb columns ( b int path '$' ),
- nested path 'strict $.c[*]' as pc columns ( c int path '$' )
- )
- plan (p outer (pb cross pc))
- ) jt;
-
-
-select
- jt.*, b1 + 100 as b
-from
- json_table (jsonb
- '[
- {"a": 1, "b": [[1, 10], [2], [3, 30, 300]], "c": [1, null, 2]},
- {"a": 2, "b": [10, 20], "c": [1, null, 2]},
- {"x": "3", "b": [11, 22, 33, 44]}
- ]',
- '$[*]' as p
- columns (
- n for ordinality,
- a int path 'lax $.a' default -1 on error,
- nested path 'strict $.b[*]' as pb columns (
- b text format json path '$',
- nested path 'strict $[*]' as pb1 columns (
- b1 int path '$'
- )
- ),
- nested path 'strict $.c[*]' as pc columns (
- c text format json path '$',
- nested path 'strict $[*]' as pc1 columns (
- c1 int path '$'
- )
- )
- )
- --plan default(outer, cross)
- plan(p outer ((pb inner pb1) cross (pc outer pc1)))
- ) jt;
-
--- Should succeed (JSON arguments are passed to root and nested paths)
-SELECT *
-FROM
- generate_series(1, 4) x,
- generate_series(1, 3) y,
- JSON_TABLE(jsonb
- '[[1,2,3],[2,3,4,5],[3,4,5,6]]',
- 'strict $[*] ? (@[*] < $x)'
- PASSING x AS x, y AS y
- COLUMNS (
- y text FORMAT JSON PATH '$',
- NESTED PATH 'strict $[*] ? (@ >= $y)'
- COLUMNS (
- z int PATH '$'
- )
- )
- ) jt;
-
--- Should fail (JSON arguments are not passed to column paths)
-SELECT *
-FROM JSON_TABLE(
- jsonb '[1,2,3]',
- '$[*] ? (@ < $x)'
- PASSING 10 AS x
- COLUMNS (y text FORMAT JSON PATH '$ ? (@ < $x)')
- ) jt;
-
--- Extension: non-constant JSON path
-SELECT JSON_EXISTS(jsonb '{"a": 123}', '$' || '.' || 'a');
-SELECT JSON_VALUE(jsonb '{"a": 123}', '$' || '.' || 'a');
-SELECT JSON_VALUE(jsonb '{"a": 123}', '$' || '.' || 'b' DEFAULT 'foo' ON EMPTY);
-SELECT JSON_QUERY(jsonb '{"a": 123}', '$' || '.' || 'a');
-SELECT JSON_QUERY(jsonb '{"a": 123}', '$' || '.' || 'a' WITH WRAPPER);
--- Should fail (invalid path)
-SELECT JSON_QUERY(jsonb '{"a": 123}', 'error' || ' ' || 'error');
--- Should fail (not supported)
-SELECT * FROM JSON_TABLE(jsonb '{"a": 123}', '$' || '.' || 'a' COLUMNS (foo int));
-
--- Test parallel JSON_VALUE()
-
-
-CREATE UNLOGGED TABLE test_parallel_jsonb_value AS
-SELECT i::text::jsonb AS js
-FROM generate_series(1, 50000) i;
-
-
--- encourage use of parallel plans
-set parallel_setup_cost=0;
-set parallel_tuple_cost=0;
-set min_parallel_table_scan_size=0;
-set max_parallel_workers_per_gather=4;
-set parallel_leader_participation = off;
-
--- Should be non-parallel due to subtransactions
-EXPLAIN (COSTS OFF)
-SELECT sum(JSON_VALUE(js, '$' RETURNING numeric)) FROM test_parallel_jsonb_value;
-SELECT sum(JSON_VALUE(js, '$' RETURNING numeric)) FROM test_parallel_jsonb_value;
-
--- Should be parallel
-EXPLAIN (COSTS OFF)
-SELECT sum(JSON_VALUE(js, '$' RETURNING numeric ERROR ON ERROR)) FROM test_parallel_jsonb_value;
-SELECT sum(JSON_VALUE(js, '$' RETURNING numeric ERROR ON ERROR)) FROM test_parallel_jsonb_value;
-
-DROP TABLE test_parallel_jsonb_value;
NOT binary_coercible(p.proargtypes[1], ptr.proargtypes[2]))
OR (p.pronargs > 2 AND
NOT binary_coercible(p.proargtypes[2], ptr.proargtypes[3]))
- OR (p.pronargs > 3 AND
- NOT binary_coercible(p.proargtypes[3], ptr.proargtypes[4]))
- -- we could carry the check further, but 4 args is enough for now
- OR (p.pronargs > 4)
+ -- we could carry the check further, but 3 args is enough for now
+ OR (p.pronargs > 3)
);
-- Cross-check finalfn (if present) against its entry in pg_proc.
+++ /dev/null
--- JSON()
-SELECT JSON();
-SELECT JSON(NULL);
-SELECT JSON('{ "a" : 1 } ');
-SELECT JSON('{ "a" : 1 } ' FORMAT JSON);
-SELECT JSON('{ "a" : 1 } ' FORMAT JSON ENCODING UTF8);
-SELECT JSON('{ "a" : 1 } '::bytea FORMAT JSON ENCODING UTF8);
-SELECT pg_typeof(JSON('{ "a" : 1 } '));
-
-SELECT JSON(' 1 '::json);
-SELECT JSON(' 1 '::jsonb);
-SELECT JSON(' 1 '::json WITH UNIQUE KEYS);
-SELECT JSON(123);
-
-SELECT JSON('{"a": 1, "a": 2}');
-SELECT JSON('{"a": 1, "a": 2}' WITH UNIQUE KEYS);
-SELECT JSON('{"a": 1, "a": 2}' WITHOUT UNIQUE KEYS);
-
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123');
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' FORMAT JSON);
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123'::bytea FORMAT JSON);
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123'::bytea FORMAT JSON ENCODING UTF8);
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' WITH UNIQUE KEYS);
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' WITHOUT UNIQUE KEYS);
-
-SELECT JSON('123' RETURNING text);
-
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123');
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' RETURNING json);
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' RETURNING jsonb);
-SELECT pg_typeof(JSON('123'));
-SELECT pg_typeof(JSON('123' RETURNING json));
-SELECT pg_typeof(JSON('123' RETURNING jsonb));
-
--- JSON_SCALAR()
-SELECT JSON_SCALAR();
-SELECT JSON_SCALAR(NULL);
-SELECT JSON_SCALAR(NULL::int);
-SELECT JSON_SCALAR(123);
-SELECT JSON_SCALAR(123.45);
-SELECT JSON_SCALAR(123.45::numeric);
-SELECT JSON_SCALAR(true);
-SELECT JSON_SCALAR(false);
-SELECT JSON_SCALAR(' 123.45');
-SELECT JSON_SCALAR('2020-06-07'::date);
-SELECT JSON_SCALAR('2020-06-07 01:02:03'::timestamp);
-SELECT JSON_SCALAR('{}'::json);
-SELECT JSON_SCALAR('{}'::jsonb);
-
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR(123);
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR('123');
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR(123 RETURNING json);
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR(123 RETURNING jsonb);
-
--- JSON_SERIALIZE()
-SELECT JSON_SERIALIZE();
-SELECT JSON_SERIALIZE(NULL);
-SELECT JSON_SERIALIZE(JSON('{ "a" : 1 } '));
-SELECT JSON_SERIALIZE('{ "a" : 1 } ');
-SELECT JSON_SERIALIZE('1');
-SELECT JSON_SERIALIZE('1' FORMAT JSON);
-SELECT JSON_SERIALIZE('{ "a" : 1 } ' RETURNING bytea);
-SELECT JSON_SERIALIZE('{ "a" : 1 } ' RETURNING varchar);
-SELECT pg_typeof(JSON_SERIALIZE(NULL));
-
--- only string types or bytea allowed
-SELECT JSON_SERIALIZE('{ "a" : 1 } ' RETURNING jsonb);
-
-
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SERIALIZE('{}');
-EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SERIALIZE('{}' RETURNING bytea);
-
--- JSON_OBJECT()
-SELECT JSON_OBJECT();
-SELECT JSON_OBJECT(RETURNING json);
-SELECT JSON_OBJECT(RETURNING json FORMAT JSON);
-SELECT JSON_OBJECT(RETURNING jsonb);
-SELECT JSON_OBJECT(RETURNING jsonb FORMAT JSON);
-SELECT JSON_OBJECT(RETURNING text);
-SELECT JSON_OBJECT(RETURNING text FORMAT JSON);
-SELECT JSON_OBJECT(RETURNING text FORMAT JSON ENCODING UTF8);
-SELECT JSON_OBJECT(RETURNING text FORMAT JSON ENCODING INVALID_ENCODING);
-SELECT JSON_OBJECT(RETURNING bytea);
-SELECT JSON_OBJECT(RETURNING bytea FORMAT JSON);
-SELECT JSON_OBJECT(RETURNING bytea FORMAT JSON ENCODING UTF8);
-SELECT JSON_OBJECT(RETURNING bytea FORMAT JSON ENCODING UTF16);
-SELECT JSON_OBJECT(RETURNING bytea FORMAT JSON ENCODING UTF32);
-
-SELECT JSON_OBJECT('foo': NULL::int FORMAT JSON);
-SELECT JSON_OBJECT('foo': NULL::int FORMAT JSON ENCODING UTF8);
-SELECT JSON_OBJECT('foo': NULL::json FORMAT JSON);
-SELECT JSON_OBJECT('foo': NULL::json FORMAT JSON ENCODING UTF8);
-SELECT JSON_OBJECT('foo': NULL::jsonb FORMAT JSON);
-SELECT JSON_OBJECT('foo': NULL::jsonb FORMAT JSON ENCODING UTF8);
-
-SELECT JSON_OBJECT(NULL: 1);
-SELECT JSON_OBJECT('a': 2 + 3);
-SELECT JSON_OBJECT('a' VALUE 2 + 3);
---SELECT JSON_OBJECT(KEY 'a' VALUE 2 + 3);
-SELECT JSON_OBJECT('a' || 2: 1);
-SELECT JSON_OBJECT(('a' || 2) VALUE 1);
---SELECT JSON_OBJECT('a' || 2 VALUE 1);
---SELECT JSON_OBJECT(KEY 'a' || 2 VALUE 1);
-SELECT JSON_OBJECT('a': 2::text);
-SELECT JSON_OBJECT('a' VALUE 2::text);
---SELECT JSON_OBJECT(KEY 'a' VALUE 2::text);
-SELECT JSON_OBJECT(1::text: 2);
-SELECT JSON_OBJECT((1::text) VALUE 2);
---SELECT JSON_OBJECT(1::text VALUE 2);
---SELECT JSON_OBJECT(KEY 1::text VALUE 2);
-SELECT JSON_OBJECT(json '[1]': 123);
-SELECT JSON_OBJECT(ARRAY[1,2,3]: 'aaa');
-
-SELECT JSON_OBJECT(
- 'a': '123',
- 1.23: 123,
- 'c': json '[ 1,true,{ } ]',
- 'd': jsonb '{ "x" : 123.45 }'
-);
-
-SELECT JSON_OBJECT(
- 'a': '123',
- 1.23: 123,
- 'c': json '[ 1,true,{ } ]',
- 'd': jsonb '{ "x" : 123.45 }'
- RETURNING jsonb
-);
-
-/*
-SELECT JSON_OBJECT(
- 'a': '123',
- KEY 1.23 VALUE 123,
- 'c' VALUE json '[1, true, {}]'
-);
-*/
-
-SELECT JSON_OBJECT('a': '123', 'b': JSON_OBJECT('a': 111, 'b': 'aaa'));
-SELECT JSON_OBJECT('a': '123', 'b': JSON_OBJECT('a': 111, 'b': 'aaa' RETURNING jsonb));
-
-SELECT JSON_OBJECT('a': JSON_OBJECT('b': 1 RETURNING text));
-SELECT JSON_OBJECT('a': JSON_OBJECT('b': 1 RETURNING text) FORMAT JSON);
-SELECT JSON_OBJECT('a': JSON_OBJECT('b': 1 RETURNING bytea));
-SELECT JSON_OBJECT('a': JSON_OBJECT('b': 1 RETURNING bytea) FORMAT JSON);
-
-SELECT JSON_OBJECT('a': '1', 'b': NULL, 'c': 2);
-SELECT JSON_OBJECT('a': '1', 'b': NULL, 'c': 2 NULL ON NULL);
-SELECT JSON_OBJECT('a': '1', 'b': NULL, 'c': 2 ABSENT ON NULL);
-
-SELECT JSON_OBJECT(1: 1, '1': NULL WITH UNIQUE);
-SELECT JSON_OBJECT(1: 1, '1': NULL ABSENT ON NULL WITH UNIQUE);
-SELECT JSON_OBJECT(1: 1, '1': NULL NULL ON NULL WITH UNIQUE RETURNING jsonb);
-SELECT JSON_OBJECT(1: 1, '1': NULL ABSENT ON NULL WITH UNIQUE RETURNING jsonb);
-
-SELECT JSON_OBJECT(1: 1, '2': NULL, '1': 1 NULL ON NULL WITH UNIQUE);
-SELECT JSON_OBJECT(1: 1, '2': NULL, '1': 1 ABSENT ON NULL WITH UNIQUE);
-SELECT JSON_OBJECT(1: 1, '2': NULL, '1': 1 ABSENT ON NULL WITHOUT UNIQUE);
-SELECT JSON_OBJECT(1: 1, '2': NULL, '1': 1 ABSENT ON NULL WITH UNIQUE RETURNING jsonb);
-SELECT JSON_OBJECT(1: 1, '2': NULL, '1': 1 ABSENT ON NULL WITHOUT UNIQUE RETURNING jsonb);
-SELECT JSON_OBJECT(1: 1, '2': NULL, '3': 1, 4: NULL, '5': 'a' ABSENT ON NULL WITH UNIQUE RETURNING jsonb);
-
-
--- JSON_ARRAY()
-SELECT JSON_ARRAY();
-SELECT JSON_ARRAY(RETURNING json);
-SELECT JSON_ARRAY(RETURNING json FORMAT JSON);
-SELECT JSON_ARRAY(RETURNING jsonb);
-SELECT JSON_ARRAY(RETURNING jsonb FORMAT JSON);
-SELECT JSON_ARRAY(RETURNING text);
-SELECT JSON_ARRAY(RETURNING text FORMAT JSON);
-SELECT JSON_ARRAY(RETURNING text FORMAT JSON ENCODING UTF8);
-SELECT JSON_ARRAY(RETURNING text FORMAT JSON ENCODING INVALID_ENCODING);
-SELECT JSON_ARRAY(RETURNING bytea);
-SELECT JSON_ARRAY(RETURNING bytea FORMAT JSON);
-SELECT JSON_ARRAY(RETURNING bytea FORMAT JSON ENCODING UTF8);
-SELECT JSON_ARRAY(RETURNING bytea FORMAT JSON ENCODING UTF16);
-SELECT JSON_ARRAY(RETURNING bytea FORMAT JSON ENCODING UTF32);
-
-SELECT JSON_ARRAY('aaa', 111, true, array[1,2,3], NULL, json '{"a": [1]}', jsonb '["a",3]');
-
-SELECT JSON_ARRAY('a', NULL, 'b' NULL ON NULL);
-SELECT JSON_ARRAY('a', NULL, 'b' ABSENT ON NULL);
-SELECT JSON_ARRAY(NULL, NULL, 'b' ABSENT ON NULL);
-SELECT JSON_ARRAY('a', NULL, 'b' NULL ON NULL RETURNING jsonb);
-SELECT JSON_ARRAY('a', NULL, 'b' ABSENT ON NULL RETURNING jsonb);
-SELECT JSON_ARRAY(NULL, NULL, 'b' ABSENT ON NULL RETURNING jsonb);
-
-SELECT JSON_ARRAY(JSON_ARRAY('{ "a" : 123 }' RETURNING text));
-SELECT JSON_ARRAY(JSON_ARRAY('{ "a" : 123 }' FORMAT JSON RETURNING text));
-SELECT JSON_ARRAY(JSON_ARRAY('{ "a" : 123 }' FORMAT JSON RETURNING text) FORMAT JSON);
-
-SELECT JSON_ARRAY(SELECT i FROM (VALUES (1), (2), (NULL), (4)) foo(i));
-SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i));
-SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) RETURNING jsonb);
---SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) NULL ON NULL);
---SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) NULL ON NULL RETURNING jsonb);
-SELECT JSON_ARRAY(SELECT i FROM (VALUES (3), (1), (NULL), (2)) foo(i) ORDER BY i);
--- Should fail
-SELECT JSON_ARRAY(SELECT FROM (VALUES (1)) foo(i));
-SELECT JSON_ARRAY(SELECT i, i FROM (VALUES (1)) foo(i));
-SELECT JSON_ARRAY(SELECT * FROM (VALUES (1, 2)) foo(i, j));
-
--- JSON_ARRAYAGG()
-SELECT JSON_ARRAYAGG(i) IS NULL,
- JSON_ARRAYAGG(i RETURNING jsonb) IS NULL
-FROM generate_series(1, 0) i;
-
-SELECT JSON_ARRAYAGG(i),
- JSON_ARRAYAGG(i RETURNING jsonb)
-FROM generate_series(1, 5) i;
-
-SELECT JSON_ARRAYAGG(i ORDER BY i DESC)
-FROM generate_series(1, 5) i;
-
-SELECT JSON_ARRAYAGG(i::text::json)
-FROM generate_series(1, 5) i;
-
-SELECT JSON_ARRAYAGG(JSON_ARRAY(i, i + 1 RETURNING text) FORMAT JSON)
-FROM generate_series(1, 5) i;
-
-SELECT JSON_ARRAYAGG(NULL),
- JSON_ARRAYAGG(NULL RETURNING jsonb)
-FROM generate_series(1, 5);
-
-SELECT JSON_ARRAYAGG(NULL NULL ON NULL),
- JSON_ARRAYAGG(NULL NULL ON NULL RETURNING jsonb)
-FROM generate_series(1, 5);
-
-SELECT
- JSON_ARRAYAGG(bar),
- JSON_ARRAYAGG(bar RETURNING jsonb),
- JSON_ARRAYAGG(bar ABSENT ON NULL),
- JSON_ARRAYAGG(bar ABSENT ON NULL RETURNING jsonb),
- JSON_ARRAYAGG(bar NULL ON NULL),
- JSON_ARRAYAGG(bar NULL ON NULL RETURNING jsonb),
- JSON_ARRAYAGG(foo),
- JSON_ARRAYAGG(foo RETURNING jsonb),
- JSON_ARRAYAGG(foo ORDER BY bar) FILTER (WHERE bar > 2),
- JSON_ARRAYAGG(foo ORDER BY bar RETURNING jsonb) FILTER (WHERE bar > 2)
-FROM
- (VALUES (NULL), (3), (1), (NULL), (NULL), (5), (2), (4), (NULL)) foo(bar);
-
-SELECT
- bar, JSON_ARRAYAGG(bar) FILTER (WHERE bar > 2) OVER (PARTITION BY foo.bar % 2)
-FROM
- (VALUES (NULL), (3), (1), (NULL), (NULL), (5), (2), (4), (NULL), (5), (4)) foo(bar);
-
--- JSON_OBJECTAGG()
-SELECT JSON_OBJECTAGG('key': 1) IS NULL,
- JSON_OBJECTAGG('key': 1 RETURNING jsonb) IS NULL
-WHERE FALSE;
-
-SELECT JSON_OBJECTAGG(NULL: 1);
-
-SELECT JSON_OBJECTAGG(NULL: 1 RETURNING jsonb);
-
-SELECT
- JSON_OBJECTAGG(i: i),
--- JSON_OBJECTAGG(i VALUE i),
--- JSON_OBJECTAGG(KEY i VALUE i),
- JSON_OBJECTAGG(i: i RETURNING jsonb)
-FROM
- generate_series(1, 5) i;
-
-SELECT
- JSON_OBJECTAGG(k: v),
- JSON_OBJECTAGG(k: v NULL ON NULL),
- JSON_OBJECTAGG(k: v ABSENT ON NULL),
- JSON_OBJECTAGG(k: v RETURNING jsonb),
- JSON_OBJECTAGG(k: v NULL ON NULL RETURNING jsonb),
- JSON_OBJECTAGG(k: v ABSENT ON NULL RETURNING jsonb)
-FROM
- (VALUES (1, 1), (1, NULL), (2, NULL), (3, 3)) foo(k, v);
-
-SELECT JSON_OBJECTAGG(k: v WITH UNIQUE KEYS)
-FROM (VALUES (1, 1), (1, NULL), (2, 2)) foo(k, v);
-
-SELECT JSON_OBJECTAGG(k: v ABSENT ON NULL WITH UNIQUE KEYS)
-FROM (VALUES (1, 1), (1, NULL), (2, 2)) foo(k, v);
-
-SELECT JSON_OBJECTAGG(k: v ABSENT ON NULL WITH UNIQUE KEYS)
-FROM (VALUES (1, 1), (0, NULL), (3, NULL), (2, 2), (4, NULL)) foo(k, v);
-
-SELECT JSON_OBJECTAGG(k: v WITH UNIQUE KEYS RETURNING jsonb)
-FROM (VALUES (1, 1), (1, NULL), (2, 2)) foo(k, v);
-
-SELECT JSON_OBJECTAGG(k: v ABSENT ON NULL WITH UNIQUE KEYS RETURNING jsonb)
-FROM (VALUES (1, 1), (1, NULL), (2, 2)) foo(k, v);
-
-SELECT JSON_OBJECTAGG(k: v ABSENT ON NULL WITH UNIQUE KEYS RETURNING jsonb)
-FROM (VALUES (1, 1), (0, NULL),(4, null), (5, null),(6, null),(2, 2)) foo(k, v);
-
--- Test JSON_OBJECT deparsing
-EXPLAIN (VERBOSE, COSTS OFF)
-SELECT JSON_OBJECT('foo' : '1' FORMAT JSON, 'bar' : 'baz' RETURNING json);
-
-CREATE VIEW json_object_view AS
-SELECT JSON_OBJECT('foo' : '1' FORMAT JSON, 'bar' : 'baz' RETURNING json);
-
-\sv json_object_view
-
-DROP VIEW json_object_view;
-
-SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v WITH UNIQUE KEYS) OVER (ORDER BY k)
-FROM (VALUES (1,1), (2,2)) a(k,v);
-
-SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v WITH UNIQUE KEYS) OVER (ORDER BY k)
-FROM (VALUES (1,1), (1,2), (2,2)) a(k,v);
-
-SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v ABSENT ON NULL WITH UNIQUE KEYS)
- OVER (ORDER BY k)
-FROM (VALUES (1,1), (1,null), (2,2)) a(k,v);
-
-SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v ABSENT ON NULL)
-OVER (ORDER BY k)
-FROM (VALUES (1,1), (1,null), (2,2)) a(k,v);
-
-SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v ABSENT ON NULL)
-OVER (ORDER BY k RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
-FROM (VALUES (1,1), (1,null), (2,2)) a(k,v);
-
--- Test JSON_ARRAY deparsing
-EXPLAIN (VERBOSE, COSTS OFF)
-SELECT JSON_ARRAY('1' FORMAT JSON, 2 RETURNING json);
-
-CREATE VIEW json_array_view AS
-SELECT JSON_ARRAY('1' FORMAT JSON, 2 RETURNING json);
-
-\sv json_array_view
-
-DROP VIEW json_array_view;
-
--- Test JSON_OBJECTAGG deparsing
-EXPLAIN (VERBOSE, COSTS OFF)
-SELECT JSON_OBJECTAGG(i: ('111' || i)::bytea FORMAT JSON WITH UNIQUE RETURNING text) FILTER (WHERE i > 3)
-FROM generate_series(1,5) i;
-
-EXPLAIN (VERBOSE, COSTS OFF)
-SELECT JSON_OBJECTAGG(i: ('111' || i)::bytea FORMAT JSON WITH UNIQUE RETURNING text) OVER (PARTITION BY i % 2)
-FROM generate_series(1,5) i;
-
-CREATE VIEW json_objectagg_view AS
-SELECT JSON_OBJECTAGG(i: ('111' || i)::bytea FORMAT JSON WITH UNIQUE RETURNING text) FILTER (WHERE i > 3)
-FROM generate_series(1,5) i;
-
-\sv json_objectagg_view
-
-DROP VIEW json_objectagg_view;
-
--- Test JSON_ARRAYAGG deparsing
-EXPLAIN (VERBOSE, COSTS OFF)
-SELECT JSON_ARRAYAGG(('111' || i)::bytea FORMAT JSON NULL ON NULL RETURNING text) FILTER (WHERE i > 3)
-FROM generate_series(1,5) i;
-
-EXPLAIN (VERBOSE, COSTS OFF)
-SELECT JSON_ARRAYAGG(('111' || i)::bytea FORMAT JSON NULL ON NULL RETURNING text) OVER (PARTITION BY i % 2)
-FROM generate_series(1,5) i;
-
-CREATE VIEW json_arrayagg_view AS
-SELECT JSON_ARRAYAGG(('111' || i)::bytea FORMAT JSON NULL ON NULL RETURNING text) FILTER (WHERE i > 3)
-FROM generate_series(1,5) i;
-
-\sv json_arrayagg_view
-
-DROP VIEW json_arrayagg_view;
-
--- Test JSON_ARRAY(subquery) deparsing
-EXPLAIN (VERBOSE, COSTS OFF)
-SELECT JSON_ARRAY(SELECT i FROM (VALUES (1), (2), (NULL), (4)) foo(i) RETURNING jsonb);
-
-CREATE VIEW json_array_subquery_view AS
-SELECT JSON_ARRAY(SELECT i FROM (VALUES (1), (2), (NULL), (4)) foo(i) RETURNING jsonb);
-
-\sv json_array_subquery_view
-
-DROP VIEW json_array_subquery_view;
-
--- IS JSON predicate
-SELECT NULL IS JSON;
-SELECT NULL IS NOT JSON;
-SELECT NULL::json IS JSON;
-SELECT NULL::jsonb IS JSON;
-SELECT NULL::text IS JSON;
-SELECT NULL::bytea IS JSON;
-SELECT NULL::int IS JSON;
-
-SELECT '' IS JSON;
-
-SELECT bytea '\x00' IS JSON;
-
-CREATE TABLE test_is_json (js text);
-
-INSERT INTO test_is_json VALUES
- (NULL),
- (''),
- ('123'),
- ('"aaa "'),
- ('true'),
- ('null'),
- ('[]'),
- ('[1, "2", {}]'),
- ('{}'),
- ('{ "a": 1, "b": null }'),
- ('{ "a": 1, "a": null }'),
- ('{ "a": 1, "b": [{ "a": 1 }, { "a": 2 }] }'),
- ('{ "a": 1, "b": [{ "a": 1, "b": 0, "a": 2 }] }'),
- ('aaa'),
- ('{a:1}'),
- ('["a",]');
-
-SELECT
- js,
- js IS JSON "IS JSON",
- js IS NOT JSON "IS NOT JSON",
- js IS JSON VALUE "IS VALUE",
- js IS JSON OBJECT "IS OBJECT",
- js IS JSON ARRAY "IS ARRAY",
- js IS JSON SCALAR "IS SCALAR",
- js IS JSON WITHOUT UNIQUE KEYS "WITHOUT UNIQUE",
- js IS JSON WITH UNIQUE KEYS "WITH UNIQUE"
-FROM
- test_is_json;
-
-SELECT
- js,
- js IS JSON "IS JSON",
- js IS NOT JSON "IS NOT JSON",
- js IS JSON VALUE "IS VALUE",
- js IS JSON OBJECT "IS OBJECT",
- js IS JSON ARRAY "IS ARRAY",
- js IS JSON SCALAR "IS SCALAR",
- js IS JSON WITHOUT UNIQUE KEYS "WITHOUT UNIQUE",
- js IS JSON WITH UNIQUE KEYS "WITH UNIQUE"
-FROM
- (SELECT js::json FROM test_is_json WHERE js IS JSON) foo(js);
-
-SELECT
- js0,
- js IS JSON "IS JSON",
- js IS NOT JSON "IS NOT JSON",
- js IS JSON VALUE "IS VALUE",
- js IS JSON OBJECT "IS OBJECT",
- js IS JSON ARRAY "IS ARRAY",
- js IS JSON SCALAR "IS SCALAR",
- js IS JSON WITHOUT UNIQUE KEYS "WITHOUT UNIQUE",
- js IS JSON WITH UNIQUE KEYS "WITH UNIQUE"
-FROM
- (SELECT js, js::bytea FROM test_is_json WHERE js IS JSON) foo(js0, js);
-
-SELECT
- js,
- js IS JSON "IS JSON",
- js IS NOT JSON "IS NOT JSON",
- js IS JSON VALUE "IS VALUE",
- js IS JSON OBJECT "IS OBJECT",
- js IS JSON ARRAY "IS ARRAY",
- js IS JSON SCALAR "IS SCALAR",
- js IS JSON WITHOUT UNIQUE KEYS "WITHOUT UNIQUE",
- js IS JSON WITH UNIQUE KEYS "WITH UNIQUE"
-FROM
- (SELECT js::jsonb FROM test_is_json WHERE js IS JSON) foo(js);
-
--- Test IS JSON deparsing
-EXPLAIN (VERBOSE, COSTS OFF)
-SELECT '1' IS JSON AS "any", ('1' || i) IS JSON SCALAR AS "scalar", '[]' IS NOT JSON ARRAY AS "array", '{}' IS JSON OBJECT WITH UNIQUE AS "object" FROM generate_series(1, 3) i;
-
-CREATE VIEW is_json_view AS
-SELECT '1' IS JSON AS "any", ('1' || i) IS JSON SCALAR AS "scalar", '[]' IS NOT JSON ARRAY AS "array", '{}' IS JSON OBJECT WITH UNIQUE AS "object" FROM generate_series(1, 3) i;
-
-\sv is_json_view
-
-DROP VIEW is_json_view;
JsonCoercion
JsonCommon
JsonConstructorExpr
-JsonConstructorExprState
JsonConstructorType
JsonEncoding
JsonExpr
JsonExprOp
-JsonExprState
JsonFormat
JsonFormatType
JsonFunc
JsonReturning
JsonScalarExpr
JsonSemAction
-JsonSerializeExpr
-JsonTable
-JsonTableColumn
-JsonTableColumnType
-JsonTableContext
-JsonTableJoinState
-JsonTableParent
-JsonTablePlan
-JsonTablePlanJoinType
-JsonTablePlanType
-JsonTableScanState
-JsonTableSibling
JsonTokenType
JsonTransformStringValuesAction
JsonTypeCategory
TableFuncRoutine
TableFuncScan
TableFuncScanState
-TableFuncType
TableInfo
TableLikeClause
TableSampleClause