From a6baa4baddd5f111bc59d8f5ed5cadbb2d91e98d Mon Sep 17 00:00:00 2001
From: Andrew Dunstan <andrew@dunslane.net>
Date: Thu, 7 Apr 2022 23:36:50 -0400
Subject: [PATCH] Documentation for SQL/JSON features

This documents the features added in commits f79b803dcc, f4fb45d15c,
33a377608f, 1a36bc9dba, 606948b058, 49082c2cc3, 4e34747c88, and
fadb48b00e.

I have cleaned up the aggregate section of the submitted docs, but there
is still a deal of copy editing required. However, I thought it best to
have some documentation sooner rather than later so testers can have a
better idea what they are playing with.

Nikita Glukhov

Reviewers have included (in no particular order) Andres Freund, Alexander
Korotkov, Pavel Stehule, Andrew Alsup, Erik Rijkers, Zhihong Yu,
Himanshu Upadhyaya, Daniel Gustafsson, Justin Pryzby.

Discussion: https://postgr.es/m/cd0bb935-0158-78a7-08b5-904886deac4b@postgrespro.ru
Discussion: https://postgr.es/m/7e2cb85d-24cf-4abb-30a5-1a33715959bd@postgrespro.ru
---
 doc/src/sgml/func.sgml | 2542 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 2540 insertions(+), 2 deletions(-)

diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 2f7aff9f216..569c78e792a 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -17564,6 +17564,2421 @@ $.* ? (@ like_regex "^\\d+$")
     </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>
+   All SQL/JSON functions fall into one of two groups.
+   <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>
+
+  <sect3 id="functions-sqljson-producing">
+   <title>Producing JSON Content</title>
+
+  <para>
+    <productname>PostgreSQL</productname> provides several functions
+    that generate JSON data. Taking values of SQL types as input, these
+    functions construct JSON objects, JSON arrays or JSON scalars represented
+    as the <type>json</type> or <type>jsonb</type> types, or as
+    SQL character or binary strings.
+  </para>
+
+  <itemizedlist>
+    <listitem>
+      <para>
+       <link linkend="functions-jsonparse"><literal>JSON</literal></link>
+      </para>
+    </listitem>
+    <listitem>
+      <para>
+       <link linkend="functions-jsonscalar"><literal>JSON_SCALAR</literal></link>
+      </para>
+    </listitem>
+    <listitem>
+      <para>
+       <link linkend="functions-jsonobject"><literal>JSON_OBJECT</literal></link>
+      </para>
+    </listitem>
+    <listitem>
+      <para>
+       <link linkend="functions-jsonobjectagg"><literal>JSON_OBJECTAGG</literal></link>
+      </para>
+    </listitem>
+    <listitem>
+      <para>
+       <link linkend="functions-jsonarray"><literal>JSON_ARRAY</literal></link>
+      </para>
+    </listitem>
+    <listitem>
+      <para>
+       <link linkend="functions-jsonarrayagg"><literal>JSON_ARRAYAGG</literal></link>
+      </para>
+    </listitem>
+  </itemizedlist>
+
+  <sect4 id="functions-jsonparse">
+   <title><literal>JSON</literal></title>
+   <indexterm><primary>json</primary></indexterm>
+<synopsis>
+<function>JSON</function> (
+  <parameter>expression</parameter> <optional> FORMAT JSON <optional> ENCODING UTF8 </optional> </optional>
+  <optional> { WITH | WITHOUT } UNIQUE <optional> KEYS </optional> </optional>
+  <optional> RETURNING <replaceable class="parameter">json_data_type</replaceable> </optional>
+)
+</synopsis>
+
+    <sect5>
+     <title>Description</title>
+
+     <para>
+      The <function>JSON</function> function generates <acronym>JSON</acronym>
+      from text data.
+     </para>
+    </sect5>
+
+    <sect5>
+     <title>Parameters</title>
+      <variablelist>
+       <varlistentry>
+        <term>
+         <literal><parameter>expression</parameter> <optional> FORMAT JSON <optional> ENCODING UTF8 </optional> </optional></literal>
+        </term>
+        <listitem>
+         <para>
+          The string <parameter>expression</parameter> provides the
+          <acronym>JSON</acronym> text data.
+          It can be any character string (<type>text</type>,
+          <type>char</type>, etc.) or binary string (<type>bytea</type>)
+          in UTF8 encoding.
+          If the <parameter>expression</parameter> is NULL an
+          <acronym>SQL</acronym> null value is returned.
+         </para>
+         <para>
+           The optional <literal>FORMAT</literal> clause is provided to conform
+           to the SQL/JSON standard.
+         </para>
+        </listitem>
+       </varlistentry>
+       <varlistentry>
+        <term>
+         <literal>{ WITH | WITHOUT } UNIQUE <optional> KEYS </optional></literal>
+        </term>
+        <listitem>
+        <para>
+         Defines whether duplicate keys are allowed:
+        </para>
+        <variablelist>
+         <varlistentry>
+          <term><literal>WITHOUT</literal></term>
+          <listitem>
+           <para>
+            Default. The constructed
+            <acronym>JSON</acronym> object can contain duplicate keys.
+           </para>
+          </listitem>
+         </varlistentry>
+         <varlistentry>
+          <term><literal>WITH</literal></term>
+           <listitem>
+            <para>
+             Duplicate keys are not allowed.
+             If the input data contains duplicate keys, an error is returned.
+            </para>
+           </listitem>
+         </varlistentry>
+        </variablelist>
+        <para>
+         Optionally, you can add the <literal>KEYS</literal> keyword for
+         semantic clarity.
+        </para>
+        </listitem>
+       </varlistentry>
+       <varlistentry>
+        <term>
+         <literal>RETURNING <replaceable class="parameter">json_data_type</replaceable></literal>
+        </term>
+        <listitem>
+        <para>
+         The output clause that specifies the type (<type>json</type> or
+         <type>jsonb</type>) of the generated <acronym>JSON</acronym>.
+         The default is <type>json</type>.
+         </para>
+       </listitem>
+      </varlistentry>
+     </variablelist>
+    </sect5>
+
+    <sect5>
+     <title>Notes</title>
+     <para>
+      Alternatively, you can construct <acronym>JSON</acronym> values simply
+      using <productname>PostgreSQL</productname>-specific casts to 
+      <type>json</type> and <type>jsonb</type> types.
+     </para>
+    </sect5>
+    <sect5>
+     <title>Examples</title>
+     <para>
+      Construct a JSON the provided strings:
+     </para>
+<screen>
+SELECT JSON('{ "a" : 123, "b": [ true, "foo" ], "a" : "bar" }');
+                       json                       
+--------------------------------------------------
+ { "a" : 123, "b": [ true, "foo" ], "a" : "bar" }
+(1 row)
+
+
+SELECT JSON('{"a": 123, "b": [true, "foo"], "a": "bar"}' RETURNING jsonb);
+               json               
+----------------------------------
+ {"a": "bar", "b": [true, "foo"]}
+(1 row)
+
+SELECT JSON('{"a": 123, "b": [true, "foo"], "a": "bar"}' WITH UNIQUE KEYS);
+ERROR:  duplicate JSON object key value
+</screen>
+    </sect5>
+   </sect4>
+
+  <sect4 id="functions-jsonscalar">
+   <title><literal>JSON_SCALAR</literal></title>
+   <indexterm><primary>json_scalar</primary></indexterm>
+
+<synopsis>
+<function>JSON_SCALAR</function> (
+  <parameter>expression</parameter>
+  <optional> RETURNING <replaceable class="parameter">json_data_type</replaceable> </optional>
+)
+</synopsis>
+
+    <sect5>
+     <title>Description</title>
+
+     <para>
+      The <function>JSON_SCALAR</function> function generates a
+      <acronym>JSON</acronym> scalar value from <acronym>SQL</acronym> data.
+     </para>
+    </sect5>
+
+    <sect5>
+     <title>Parameters</title>
+      <variablelist>
+       <varlistentry>
+        <term>
+         <literal><parameter>expression</parameter></literal>
+        </term>
+        <listitem>
+         <para>
+          The <parameter>expression</parameter> provides the data for constructing a
+          <acronym>JSON</acronym> value.
+          For null input, <acronym>SQL</acronym>  null
+          (not a <acronym>JSON</acronym> null) value is returned.
+          For any scalar other than a number or a Boolean the text
+          representation will be used, with escaping as necessary to make
+          it a valid <acronym>JSON</acronym> string value.
+          For details, see
+          <function>to_json()</function>/<function>to_jsonb()</function>
+          in <xref linkend="functions-json-creation-table"/>.
+         </para>
+        </listitem>
+       </varlistentry>
+       <varlistentry>
+        <term>
+         <literal>RETURNING <replaceable class="parameter">json_data_type</replaceable></literal>
+        </term>
+        <listitem>
+        <para>
+         The output clause that specifies the type (<type>json</type> or
+         <type>jsonb</type>) of the generated <acronym>JSON</acronym> scalar.
+         The default is <type>json</type>.
+         </para>
+       </listitem>
+      </varlistentry>
+     </variablelist>
+    </sect5>
+
+    <sect5>
+     <title>Notes</title>
+     <para>
+      Alternatively, you can construct <acronym>JSON</acronym> objects by
+      using the <productname>PostgreSQL</productname>-specific
+      <function>to_json()</function>/<function>to_jsonb()</function> functions.
+      See <xref linkend="functions-json-creation-table"/> for details.
+     </para>
+    </sect5>
+    <sect5>
+     <title>Examples</title>
+     <para>
+      Construct a JSON from the provided values various types:
+     </para>
+<screen>
+SELECT JSON_SCALAR(123.45);
+ json_scalar
+-------------
+ 123.45
+(1 row)
+
+SELECT JSON_SCALAR('123');
+ json_scalar
+-------------
+ "123"
+(1 row)
+
+SELECT JSON_SCALAR(true);
+ json_scalar
+-------------
+ true
+(1 row)
+</screen>
+    </sect5>
+   </sect4>
+
+   <sect4 id="functions-jsonobject">
+    <title><literal>JSON_OBJECT</literal></title>
+    <indexterm><primary>json_object</primary></indexterm>
+
+<synopsis>
+<function>JSON_OBJECT</function> (
+  <optional> { <parameter>key_expression</parameter> { VALUE | ':' }
+      <parameter>value_expression</parameter> <optional> FORMAT JSON <optional> ENCODING UTF8 </optional> </optional> }<optional>, ...</optional> </optional>
+  <optional> { NULL | ABSENT } ON NULL </optional>
+  <optional> { WITH | WITHOUT } UNIQUE <optional> KEYS </optional> </optional>
+  <optional> RETURNING <replaceable class="parameter">data_type</replaceable> <optional> FORMAT JSON <optional> ENCODING UTF8 </optional> </optional> </optional>
+)
+</synopsis>
+
+    <sect5>
+     <title>Description</title>
+
+     <para>
+      The <function>JSON_OBJECT</function> function generates a
+      <acronym>JSON</acronym> object from <acronym>SQL</acronym> or
+      <acronym>JSON</acronym> data.
+     </para>
+    </sect5>
+
+    <sect5>
+     <title>Parameters</title>
+  <variablelist>
+
+   <varlistentry>
+    <term>
+      <literal>
+       <parameter>key_expression</parameter> { VALUE | ':' }
+       <parameter>value_expression</parameter> <optional> FORMAT JSON <optional> ENCODING UTF8 </optional> </optional>
+      </literal>
+    </term>
+    <listitem>
+    <para>
+      The input clause that provides the data for constructing a <acronym>JSON</acronym> object:
+    </para>
+        <itemizedlist>
+          <listitem>
+            <para>
+              <parameter>key_expression</parameter> is a scalar expression
+              defining the <acronym>JSON</acronym> key, which is implicitly
+              converted to the <type>text</type> type.
+              The provided expression cannot be <literal>NULL</literal> or
+              belong to a type that has a cast to <type>json</type>.
+            </para>
+          </listitem>
+          <listitem>
+            <para>
+              <parameter>value_expression</parameter> is an expression
+              that provides the input for the <acronym>JSON</acronym> value.
+            </para>
+          </listitem>
+          <listitem>
+            <para>
+              The optional <literal>FORMAT</literal> clause is provided to
+              conform to the SQL/JSON standard.
+             </para>
+           </listitem>
+           </itemizedlist>
+      <para>
+        You must use a colon or the <literal>VALUE</literal> keyword as a
+        separator between the key and the value. Multiple key/value pairs are
+        separated by commas.
+      </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term>
+     <literal>{ NULL | ABSENT } ON NULL</literal>
+    </term>
+    <listitem>
+      <para>
+        Defines whether <literal>NULL</literal> values are allowed in the constructed
+        <acronym>JSON</acronym> object:
+        </para>
+        <variablelist>
+         <varlistentry>
+           <term><literal>NULL</literal></term>
+           <listitem>
+             <para>
+              Default. <literal>NULL</literal> values are allowed.
+             </para>
+            </listitem>
+          </varlistentry>
+          <varlistentry>
+           <term><literal>ABSENT</literal></term>
+            <listitem>
+             <para>
+              If the value is <literal>NULL</literal>,
+              the corresponding key/value pair is omitted from the generated
+              <acronym>JSON</acronym> object.
+             </para>
+            </listitem>
+          </varlistentry>
+        </variablelist>
+      </listitem>
+    </varlistentry>
+
+    <varlistentry>
+    <term>
+     <literal>{ WITH | WITHOUT } UNIQUE <optional> KEYS </optional></literal>
+    </term>
+    <listitem>
+     <para>Defines whether duplicate keys are allowed:
+     </para>
+       <variablelist>
+         <varlistentry>
+           <term><literal>WITHOUT</literal></term>
+           <listitem>
+             <para>
+              Default. The constructed
+              <acronym>JSON</acronym> object can contain duplicate keys.
+             </para>
+            </listitem>
+          </varlistentry>
+          <varlistentry>
+           <term><literal>WITH</literal></term>
+            <listitem>
+             <para>
+              Duplicate keys are not allowed.
+              If the input data contains duplicate keys, an error is returned.
+              This check is performed before removing JSON items with NULL values.
+             </para>
+            </listitem>
+          </varlistentry>
+        </variablelist>
+      <para>
+       Optionally, you can add the <literal>KEYS</literal> keyword for semantic clarity.
+      </para>
+    </listitem>
+  </varlistentry>
+
+  <varlistentry>
+    <term>
+     <literal>RETURNING <replaceable class="parameter">data_type</replaceable> <optional> FORMAT JSON <optional> ENCODING UTF8 </optional> </optional></literal>
+    </term>
+    <listitem>
+     <para>
+       The output clause that specifies the type of the generated <acronym>JSON</acronym> object.
+       For details, see <xref linkend="sqljson-output-clause"/>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   </variablelist>
+    </sect5>
+
+ <sect5>
+  <title>Notes</title>
+  <para>Alternatively, you can construct <acronym>JSON</acronym> objects by using the
+  <productname>PostgreSQL</productname>-specific <function>json_build_object()</function>/
+  <function>jsonb_build_object()</function> functions.
+  See <xref linkend="functions-json-creation-table"/> for details.
+  </para>
+ </sect5>
+
+    <sect5>
+     <title>Examples</title>
+  <para>
+   Construct a JSON object from the provided key/value pairs of various types:
+  </para>
+<screen>
+SELECT JSON_OBJECT(
+-- scalar JSON types
+ 'key1': 'string',
+ 'key2': '[1, 2]',
+ 'key3' VALUE 123, -- alternative syntax for key-value delimiter
+ 'key4': NULL,
+-- other types
+ 'key5': ARRAY[1, 2, 3], -- postgres array
+ 'key6': jsonb '{"a": ["b", 1]}', -- composite json/jsonb
+ 'key7': date '2017-09-30', -- datetime type
+ 'key8': row(1, 'a'), -- row type
+ 'key9': '[1, 2]' FORMAT JSON, -- same value as for key2, but with FORMAT
+-- key can be an expression
+  'key' || 'last' : TRUE
+ABSENT ON NULL) AS json;
+                       json
+----------------------------------------------------
+{"key1" : "string", "key2" : "[1, 2]", "key3" : 123,
+ "key5" : [1,2,3], "key6" : {"a": ["b", 1]},
+ "key7" : "2017-09-30", "key8" : {"f1":1,"f2":"a"},
+ "key9" : [1, 2], "keylast" : true}
+(1 row)
+</screen>
+
+  <para>
+   From the <structname>films</structname> table, select some data
+   about the films distributed by Paramount Pictures
+   (<literal>did</literal> = 103) and return JSON objects:
+  </para>
+<screen>
+SELECT
+JSON_OBJECT(
+ 'code' VALUE f.code,
+ 'title' VALUE f.title,
+ 'did' VALUE f.did
+) AS paramount
+FROM films AS f
+WHERE f.did = 103;
+                    paramount
+----------------------------------------------------
+{"code" : "P_301", "title" : "Vertigo", "did" : 103}
+{"code" : "P_302", "title" : "Becket", "did" : 103}
+{"code" : "P_303", "title" : "48 Hrs", "did" : 103}
+(3 rows)
+</screen>
+    </sect5>
+   </sect4>
+
+   <sect4 id="functions-jsonobjectagg">
+   <title><literal>JSON_OBJECTAGG</literal></title>
+   <indexterm><primary>json_objectagg</primary></indexterm>
+   
+<synopsis>
+<function>JSON_OBJECTAGG</function> (
+  <optional> { <parameter>key_expression</parameter> { VALUE | ':' } <parameter>value_expression</parameter> } </optional>
+  <optional> { NULL | ABSENT } ON NULL </optional>
+  <optional> { WITH | WITHOUT } UNIQUE <optional> KEYS </optional> </optional>
+  <optional> RETURNING <replaceable class="parameter">data_type</replaceable> <optional> FORMAT JSON <optional> ENCODING UTF8 </optional> </optional> </optional>
+)
+
+</synopsis>
+
+    <sect5>
+     <title>Description</title>
+
+     <para>
+      The <function>JSON_OBJECTAGG</function> function aggregates the provided data
+      into a <acronym>JSON</acronym> object. You can use this function to combine values
+      stored in different table columns into pairs. If you specify a <command>GROUP BY</command>
+      or an <command>ORDER BY</command> clause, this function returns a separate JSON object
+      for each table row.
+    </para>
+    </sect5>
+
+    <sect5>
+     <title>Parameters</title>
+
+  <variablelist>
+   <varlistentry>
+    <term>
+     <literal><parameter>key_expression</parameter> { VALUE | ':' } <parameter>value_expression</parameter></literal>
+    </term>
+    <listitem>
+
+    <para>
+      The input clause that provides the data to be aggregated as a <acronym>JSON</acronym> object:
+    </para>
+        <itemizedlist>
+          <listitem>
+            <para>
+              <parameter>key_expression</parameter> is a scalar expression
+              defining the <acronym>JSON</acronym> key, which is implicitly
+              converted to the <type>text</type> type.
+              The provided expression cannot be <literal>NULL</literal> or
+              belong to a type that has a cast to <type>json</type>.
+            </para>
+          </listitem>
+          <listitem>
+            <para>
+              <parameter>value_expression</parameter> is an expression that
+              provides the input for the <acronym>JSON</acronym> value preceded
+              by its type.
+              For <acronym>JSON</acronym> scalar types, you can omit the type.
+            </para>
+            <note>
+              <para>
+                The input value of the <literal>bytea</literal> type must be stored in <literal>UTF8</literal>
+                and contain a valid <literal>UTF8</literal> string. Otherwise, an error occurs.
+                <productname>PostgreSQL</productname> currently supports only <literal>UTF8</literal>.
+              </para>
+            </note>
+           </listitem>
+           </itemizedlist>
+      <para>
+        You must use a colon or the <literal>VALUE</literal> keyword as a separator between
+        keys and values. Multiple key/value pairs are separated by commas.
+      </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term>
+     <literal>{ NULL | ABSENT } ON NULL</literal>
+    </term>
+    <listitem>
+      <para>
+        Defines whether <literal>NULL</literal> values are allowed in the constructed
+        <acronym>JSON</acronym> object:
+        </para>
+      <variablelist>
+         <varlistentry>
+           <term><literal>NULL</literal></term>
+           <listitem>
+             <para>
+              Default. <literal>NULL</literal> values are allowed.
+             </para>
+            </listitem>
+          </varlistentry>
+          <varlistentry>
+           <term><literal>ABSENT</literal></term>
+            <listitem>
+             <para>
+              If the value is <literal>NULL</literal>,
+              the corresponding key/value pair is omitted from the generated
+              <acronym>JSON</acronym> object.
+             </para>
+            </listitem>
+          </varlistentry>
+        </variablelist>
+      </listitem>
+    </varlistentry>
+
+    <varlistentry>
+    <term>
+     <literal>{ WITH | WITHOUT } UNIQUE <optional> KEYS </optional></literal>
+    </term>
+    <listitem>
+     <para>Defines whether duplicate keys are allowed:
+     </para>
+        <variablelist>
+         <varlistentry>
+           <term><literal>WITHOUT</literal></term>
+           <listitem>
+             <para>
+              Default. The constructed
+              <acronym>JSON</acronym> object can contain duplicate keys.
+             </para>
+            </listitem>
+          </varlistentry>
+          <varlistentry>
+           <term><literal>WITH</literal></term>
+            <listitem>
+             <para>
+              Duplicate keys are not allowed.
+              If the input data contains duplicate keys, an error is returned.
+              This check is performed before removing JSON items with NULL values.
+             </para>
+            </listitem>
+          </varlistentry>
+        </variablelist>
+      <para>
+        Optionally, you can add the <literal>KEYS</literal> keyword for semantic clarity.
+      </para>
+    </listitem>
+  </varlistentry>
+
+  <varlistentry>
+    <term>
+     <literal>RETURNING <replaceable class="parameter">data_type</replaceable> <optional> FORMAT JSON <optional> ENCODING UTF8 </optional> </optional></literal>
+    </term>
+    <listitem>
+     <para>
+       The output clause that specifies the type of the generated <acronym>JSON</acronym> object.
+       For details, see <xref linkend="sqljson-output-clause"/>.
+      </para>
+     </listitem>
+   </varlistentry>
+
+  </variablelist>
+    </sect5>
+
+ <sect5>
+  <title>Notes</title>
+  <para>Alternatively, you can create <acronym>JSON</acronym> objects by using
+  <productname>PostgreSQL</productname>-specific <function>json_object_agg()</function>/
+  <function>jsonb_object_agg()</function> aggregate functions.
+  See <xref linkend="functions-aggregate"/> for details.
+  </para>
+ </sect5>
+
+    <sect5>
+     <title>Examples</title>
+
+  <para>
+    For films with <literal>did</literal> = 103, aggregate key/value pairs
+    of film genre (<literal>f.kind</literal>) and title (<literal>f.title</literal>)
+    into a single object:
+  </para>
+<screen>
+SELECT
+JSON_OBJECTAGG(
+ f.kind VALUE f.title)
+ AS films_list
+FROM films AS f
+where f.did = 103;
+                 films_list
+----------------------------------------------------
+{ "Action" : "Vertigo", "Drama" : "Becket", "Action" : "48 Hrs" }
+</screen>
+
+  <para>
+    Return the same object as <type>jsonb</type>. Note that only a single film of
+    the action genre is included as the <type>jsonb</type> type does not allow duplicate keys.
+  </para>
+<screen>
+SELECT
+JSON_OBJECTAGG(
+  f.kind VALUE f.title
+  RETURNING jsonb)
+AS films_list
+FROM films AS f
+where f.did = 103;
+                 films_list
+----------------------------------------------------
+{"Drama": "Becket", "Action": "48 Hrs"}
+</screen>
+
+  <para>
+    Return objects of film titles and length, grouped by the film genre:
+  </para>
+<screen>
+SELECT
+  f.kind,
+  JSON_OBJECTAGG(
+    f.title VALUE f.len
+) AS films_list
+FROM films AS f
+GROUP BY f.kind;
+
+     kind    |        films_list
+-------------+----------------------------------
+Musical      | { "West Side Story" : "02:32:00", "The King and I" : "02:13:00", "Bed Knobs and Broomsticks" : "01:57:00" }
+Romantic     | { "The African Queen" : "01:43:00", "Une Femme est une Femme" : "01:25:00", "Storia di una donna" : "01:30:00" }
+Comedy       | { "Bananas" : "01:22:00", "There's a Girl in my Soup" : "01:36:00" }
+Drama        | { "The Third Man" : "01:44:00", "Becket" : "02:28:00", "War and Peace" : "05:57:00", "Yojimbo" : "01:50:00", "Das Boot" : "02:29:00" }
+Action       | { "Vertigo" : "02:08:00", "48 Hrs" : "01:37:00", "Taxi Driver" : "01:54:00", "Absence of Malice" : "01:55:00" }
+(5 rows)
+</screen>
+    </sect5>
+   </sect4>
+
+   <sect4 id="functions-jsonarray">
+    <title><literal>JSON_ARRAY</literal></title>
+    <indexterm><primary>json_array</primary></indexterm>
+
+<synopsis>
+<function>JSON_ARRAY</function> (
+  <optional> { <parameter>value_expression</parameter> <optional> FORMAT JSON </optional> } <optional>, ...</optional> </optional>
+  <optional> { NULL | ABSENT } ON NULL </optional>
+  <optional> RETURNING <replaceable class="parameter">data_type</replaceable> <optional> FORMAT JSON <optional> ENCODING UTF8 </optional> </optional> </optional>
+)
+</synopsis>
+<synopsis>JSON_ARRAY (
+  <optional> <replaceable class="parameter">query_expression</replaceable> </optional>
+  <optional> RETURNING <replaceable class="parameter">data_type</replaceable> <optional> FORMAT JSON <optional> ENCODING UTF8 </optional> </optional> </optional>
+)
+</synopsis>
+
+    <sect5>
+     <title>Description</title>
+
+     <para>
+      The <function>JSON_ARRAY</function> function constructs a <acronym>JSON</acronym> array from
+      the provided <acronym>SQL</acronym> or <acronym>JSON</acronym> data.
+     </para>
+    </sect5>
+
+    <sect5>
+     <title>Parameters</title>
+
+  <variablelist>
+    <varlistentry>
+      <term>
+        <literal><parameter>value_expression</parameter></literal>
+      </term>
+      <listitem>
+
+        <para>
+          The input clause that provides the data for constructing a JSON array.
+          The <replaceable class="parameter">value_expression</replaceable> is an expression
+          that provides the input for the <acronym>JSON</acronym> value preceded by its type.
+          For <acronym>JSON</acronym> scalar types, you can omit the type.
+        </para>
+        <note>
+          <para>
+            The input value of the <literal>bytea</literal> type must be stored in <literal>UTF8</literal>
+            and contain a valid <literal>UTF8</literal> string. Otherwise, an error occurs.
+            <productname>PostgreSQL</productname> currently supports only <literal>UTF8</literal>.
+          </para>
+        </note>
+
+    </listitem>
+   </varlistentry>
+
+    <varlistentry>
+      <term>
+        <literal><replaceable class="parameter">query_expression</replaceable></literal>
+      </term>
+      <listitem>
+        <para>
+          An SQL query that provides the data for constructing a JSON array.
+          The query must return a single column that holds the values to be
+          used in the array.
+        </para>
+    </listitem>
+   </varlistentry>
+
+    <varlistentry>
+    <term>
+     <literal>{ NULL | ABSENT } ON NULL</literal>
+    </term>
+    <listitem>
+      <para>
+        Defines whether <literal>NULL</literal> values are allowed in the generated <acronym>JSON</acronym> array:
+      </para>
+       <variablelist>
+         <varlistentry>
+           <term><literal>NULL</literal></term>
+           <listitem>
+             <para>
+              <literal>NULL</literal> values are allowed.
+             </para>
+            </listitem>
+          </varlistentry>
+          <varlistentry>
+           <term><literal>ABSENT</literal></term>
+            <listitem>
+             <para>
+              Default. If the value is <literal>NULL</literal>,
+              the corresponding key/value pair is omitted from the generated
+              <acronym>JSON</acronym> object.
+             </para>
+            </listitem>
+          </varlistentry>
+        </variablelist>
+        <para>
+          This clause is only supported for arrays built from an explicit list of values.
+          If you are using an SQL query to generate an array, NULL values are always
+          omitted.
+        </para>
+      </listitem>
+    </varlistentry>
+
+   <varlistentry>
+    <term>
+     <literal>RETURNING <replaceable class="parameter">data_type</replaceable> <optional> FORMAT JSON <optional> ENCODING UTF8 </optional> </optional></literal>
+    </term>
+    <listitem>
+     <para>
+       The output clause that specifies the return type of the constructed <acronym>JSON</acronym> array.
+       For details, see <xref linkend="sqljson-output-clause"/>.
+      </para>
+     </listitem>
+   </varlistentry>
+
+</variablelist>
+    </sect5>
+
+ <sect5>
+  <title>Notes</title>
+  <para>Alternatively, you can create <acronym>JSON</acronym> arrays by using
+  <productname>PostgreSQL</productname>-specific <function>json_build_array()</function>/
+  <function>jsonb_build_array()</function> functions.
+  See <xref linkend="functions-json"/> for details.
+  </para>
+ </sect5>
+
+    <sect5>
+     <title>Examples</title>
+  <para>
+    From the <structname>films</structname> table, select some data
+    about the films distributed by Paramount Pictures
+    (<literal>did</literal> = 103) and return JSON arrays:
+  </para>
+<screen>
+SELECT
+JSON_ARRAY(
+  f.code,
+  f.title,
+  f.did
+) AS films
+FROM films AS f
+WHERE f.did = 103;
+                       films
+----------------------------------------------------
+["P_301", "Vertigo", 103]
+["P_302", "Becket", 103]
+["P_303", "48 Hrs", 103]
+(3 rows)
+</screen>
+  <para>
+    Construct a JSON array from the list of film titles returned from the
+    <structname>films</structname> table by a subquery:
+  </para>
+<screen>
+SELECT
+JSON_ARRAY(
+  SELECT
+  f.title
+FROM films AS f
+where f.did = 103)
+AS film_titles;
+                    film_titles
+----------------------------------------------------
+["Vertigo", "Becket", "48 Hrs"]
+(1 row)
+</screen>
+    </sect5>
+   </sect4>
+
+   <sect4 id="functions-jsonarrayagg">
+    <title><literal>JSON_ARRAYAGG</literal></title>
+    <indexterm><primary>json_arrayagg</primary></indexterm>
+
+<synopsis>
+<function>JSON_ARRAYAGG</function> (
+  <optional> <parameter>value_expression</parameter> </optional>
+  <optional> ORDER BY <replaceable class="parameter">sort_expression</replaceable> </optional>
+  <optional> { NULL | ABSENT } ON NULL </optional>
+  <optional> RETURNING <replaceable class="parameter">data_type</replaceable> <optional> FORMAT JSON <optional> ENCODING UTF8 </optional> </optional> </optional>
+)
+
+</synopsis>
+
+    <sect5>
+     <title>Description</title>
+
+     <para>
+      The <function>JSON_ARRAYAGG</function> function aggregates the provided <acronym>SQL</acronym>
+      or <acronym>JSON</acronym> data into a <acronym>JSON</acronym> array.
+     </para>
+    </sect5>
+
+    <sect5>
+     <title>Parameters</title>
+
+  <variablelist>
+    <varlistentry>
+      <term>
+        <literal><parameter>value_expression</parameter></literal>
+      </term>
+      <listitem>
+
+        <para>
+          The input clause that provides the input data to be aggregated as
+          a <acronym>JSON</acronym> array.
+          The <parameter>value_expression</parameter> can be a value or a query
+          returning the values to be used as input in array construction.
+          You can provide multiple input values separated by commas.
+        </para>
+    </listitem>
+   </varlistentry>
+
+<varlistentry>
+      <term>
+        <literal>ORDER BY</literal>
+      </term>
+      <listitem>
+        <para>
+          Sorts the input data to be aggregated as a <acronym>JSON</acronym> array.
+          For details on the exact syntax of the <literal>ORDER BY</literal> clause, see <xref linkend="sql-orderby"/>.
+        </para>
+    </listitem>
+   </varlistentry>
+
+    <varlistentry>
+    <term>
+     <literal>{ NULL | ABSENT } ON NULL</literal>
+    </term>
+    <listitem>
+      <para>
+        Defines whether <literal>NULL</literal> values are allowed in the constructed array:
+          <itemizedlist>
+            <listitem>
+              <para>
+                <literal>NULL</literal> &mdash; <literal>NULL</literal> values are allowed.
+              </para>
+            </listitem>
+            <listitem>
+              <para>
+                <literal>ABSENT</literal> (default) &mdash; <literal>NULL</literal>
+                values are omitted from the generated array.
+              </para>
+            </listitem>
+          </itemizedlist>
+        </para>
+      </listitem>
+    </varlistentry>
+
+   <varlistentry>
+    <term>
+     <literal>RETURNING <replaceable class="parameter">data_type</replaceable> <optional> FORMAT JSON <optional> ENCODING UTF8 </optional> </optional></literal>
+    </term>
+    <listitem>
+     <para>
+       The output clause that specifies the return type of the constructed <acronym>JSON</acronym> array.
+       For details, see <xref linkend="sqljson-output-clause"/>.
+     </para>
+     </listitem>
+   </varlistentry>
+
+</variablelist>
+    </sect5>
+
+<sect5>
+  <title>Notes</title>
+  <para>Alternatively, you can create <acronym>JSON</acronym> arrays by using
+  <productname>PostgreSQL</productname>-specific <function>json_agg()</function>/
+  <function>jsonb_agg()</function> functions.
+  See <xref linkend="functions-aggregate"/> for details.
+  </para>
+ </sect5>
+
+    <sect5>
+     <title>Examples</title>
+     <para>
+       Construct an array of film titles sorted in alphabetical order:
+     </para>
+<screen>
+SELECT
+JSON_ARRAYAGG(
+  f.title
+ORDER BY f.title ASC) AS film_titles
+FROM films AS f;
+                    film_titles
+----------------------------------------------------
+["48 Hrs", "Absence of Malice", "Bananas", "Becket", "Bed Knobs and Broomsticks", "Das Boot", "Storia di una donna", "Taxi Driver", "The African Queen", "The King and I", "There's a Girl in my Soup", "The Third Man", "Une Femme est une Femme", "Vertigo", "War and Peace", "West Side Story", "Yojimbo"]
+(1 row)
+</screen>
+    </sect5>
+   </sect4>
+  </sect3>
+
+  <sect3 id="functions-sqljson-querying">
+   <title>Querying JSON</title>
+
+   <para>
+    SQL/JSON query functions evaluate SQL/JSON path language expressions
+    against JSON values, producing values of SQL/JSON types, which are
+    converted to SQL types. All SQL/JSON query functions accept several
+    common clauses described in <xref linkend="sqljson-common-clauses"/>.
+    For details on the SQL/JSON path language,
+    see <xref linkend="functions-sqljson-path"/>.
+   </para>
+
+  <itemizedlist>
+    <listitem>
+      <para>
+       <link linkend="functions-isjson-predicate"><literal>IS JSON</literal></link>
+      </para>
+    </listitem>
+    <listitem>
+      <para>
+       <link linkend="functions-jsonexists"><literal>JSON_EXISTS</literal></link>
+      </para>
+    </listitem>
+    <listitem>
+      <para>
+       <link linkend="functions-jsonvalue"><literal>JSON_VALUE</literal></link>
+      </para>
+    </listitem>
+    <listitem>
+      <para>
+       <link linkend="functions-jsonquery"><literal>JSON_QUERY</literal></link>
+      </para>
+    </listitem>
+    <listitem>
+      <para>
+       <link linkend="functions-jsontable"><literal>JSON_TABLE</literal></link>
+      </para>
+    </listitem>
+  </itemizedlist>
+
+  <para>
+     In some usage examples for these functions,
+     the following small table storing some JSON data will be used:
+<programlisting>
+CREATE TABLE my_films (
+  js       text );
+
+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>
+
+   <sect4 id="functions-jsonexists">
+    <title><literal>JSON_EXISTS</literal></title>
+    <indexterm><primary>json_exists</primary></indexterm>
+
+<synopsis>
+<function>JSON_EXISTS</function> (
+  <replaceable>context_item</replaceable>, <replaceable>path_expression</replaceable> <optional> PASSING { <replaceable>value</replaceable> AS <replaceable>varname</replaceable> } <optional>, ...</optional></optional>
+  <optional> RETURNING <replaceable class="parameter">data_type</replaceable> </optional>
+  <optional> { TRUE | FALSE | UNKNOWN | ERROR } ON ERROR </optional>
+)
+</synopsis>
+
+    <sect5>
+     <title>Description</title>
+
+     <para>
+      <function>JSON_EXISTS</function> function checks whether the provided
+      <acronym>JSON</acronym> path expression can return any <acronym>SQL/JSON</acronym> items.
+     </para>
+    </sect5>
+
+    <sect5>
+     <title>Parameters</title>
+  <variablelist>
+   <varlistentry>
+    <term>
+     <literal><replaceable>context_item</replaceable>, <replaceable>path_expression</replaceable> <optional> PASSING { <replaceable>value</replaceable> AS <replaceable>varname</replaceable> } <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.
+     See <xref linkend="sqljson-input-clause"/> for details.
+    </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term>
+     <literal>RETURNING <replaceable class="parameter">data_type</replaceable></literal>
+    </term>
+    <listitem>
+     <para>
+       The output clause that specifies the data type of the returned value.
+       The specified data type should have a cast from a <literal>boolean</literal>
+       type, which is returned by default.
+     </para>
+     </listitem>
+   </varlistentry>
+
+  <varlistentry>
+    <term>
+     <literal>{ TRUE | FALSE | UNKNOWN | ERROR } ON ERROR</literal>
+    </term>
+    <listitem>
+     <para>
+       Defines the return value if an error occurs. The default value is <literal>FALSE</literal>.
+     </para>
+     </listitem>
+   </varlistentry>
+
+   </variablelist>
+    </sect5>
+
+    <sect5>
+     <title>Examples</title>
+
+  <para>
+    Check whether the provided <type>jsonb</type> data contains a
+    key/value pair with the <literal>key1</literal> key, and its value
+    contains an array with one or more elements bigger than 2:
+  </para>
+<screen>
+SELECT JSON_EXISTS(jsonb '{"key1": [1,2,3]}', 'strict $.key1[*] ? (@ > 2)');
+ json_exists
+-------------
+ t
+(1 row)
+</screen>
+
+  <para>
+   Note the difference between strict and lax modes
+   if the required item does not exist:
+  </para>
+<screen>
+-- Strict mode with ERROR on ERROR clause
+SELECT JSON_EXISTS(jsonb '{"a": [1,2,3]}', 'strict $.a[5]' ERROR ON ERROR);
+ERROR: Invalid SQL/JSON subscript
+(1 row)
+</screen>
+
+<screen>
+-- Lax mode
+SELECT JSON_EXISTS(jsonb '{"a": [1,2,3]}', 'lax $.a[5]' ERROR ON ERROR);
+ json_exists
+-------------
+ f
+(1 row)
+</screen>
+
+<screen>
+-- Strict mode using the default value for the ON ERROR clause
+SELECT JSON_EXISTS(jsonb '{"a": [1,2,3]}', 'strict $.a[5]');
+ json_exists
+-------------
+ f
+(1 row)
+</screen>
+
+    </sect5>
+   </sect4>
+
+   <sect4 id="functions-jsonvalue">
+    <title><literal>JSON_VALUE</literal></title>
+    <indexterm><primary>json_value</primary></indexterm>
+
+<synopsis>
+<function>JSON_VALUE</function> (
+  <replaceable>context_item</replaceable>, <replaceable>path_expression</replaceable> <optional> PASSING { <replaceable>value</replaceable> AS <replaceable>varname</replaceable> } <optional>, ...</optional></optional>
+  <optional> RETURNING <replaceable class="parameter">data_type</replaceable> </optional>
+  <optional> { ERROR | NULL | DEFAULT <replaceable class="parameter">expression</replaceable> } ON EMPTY </optional>
+  <optional> { ERROR | NULL | DEFAULT <replaceable class="parameter">expression</replaceable> } ON ERROR </optional>
+)
+  </synopsis>
+
+    <sect5>
+     <title>Description</title>
+
+  <para>
+   <function>JSON_VALUE</function> function extracts a value from the provided
+   <acronym>JSON</acronym> data and converts it to an <acronym>SQL</acronym> scalar.
+   If the specified JSON path expression returns more than one
+   <acronym>SQL/JSON</acronym> item, an error occurs. To extract
+   an <acronym>SQL/JSON</acronym> array or object, use <xref linkend="functions-jsonquery"/>.
+  </para>
+    </sect5>
+
+    <sect5>
+     <title>Parameters</title>
+
+  <variablelist>
+
+   <varlistentry>
+    <term>
+     <literal><replaceable>context_item</replaceable>, <replaceable>path_expression</replaceable> <optional> PASSING { <replaceable>value</replaceable> AS <replaceable>varname</replaceable> } <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.
+     For details, see <xref linkend="functions-sqljson-path"/>.
+    </para>
+    </listitem>
+   </varlistentry>
+
+  <varlistentry>
+    <term>
+     <literal>RETURNING <replaceable class="parameter">data_type</replaceable></literal>
+    </term>
+    <listitem>
+     <para>
+       The output clause that specifies the data type of the returned value.
+       Out of the box, <productname>PostgreSQL</productname>
+       supports the following types: <literal>json</literal>, <literal>jsonb</literal>,
+       <literal>bytea</literal>, and character string types (<literal>text</literal>, <literal>char</literal>,
+       <literal>varchar</literal>, and <literal>nchar</literal>).
+       The extracted value must be a single <acronym>SQL/JSON</acronym> scalar item
+       and have a cast to the specified type. Otherwise, an error occurs.
+       By default, <function>JSON_VALUE</function> returns a string
+       of the <literal>text</literal> type.
+     </para>
+     </listitem>
+   </varlistentry>
+
+  <varlistentry>
+    <term>
+     <literal>{ ERROR | NULL | DEFAULT <replaceable class="parameter">expression</replaceable> } ON EMPTY</literal>
+    </term>
+    <listitem>
+     <para>
+       Defines the return value if no JSON value is found. The default is
+       <literal>NULL</literal>. If you use
+       <literal>DEFAULT <replaceable class="parameter">expression</replaceable></literal>,
+       the provided <replaceable class="parameter">expression</replaceable> is
+       evaluated and cast to the type specified in the <command>RETURNING</command> clause.
+     </para>
+     </listitem>
+   </varlistentry>
+
+     <varlistentry>
+    <term>
+     <literal>{ ERROR | NULL | DEFAULT <replaceable class="parameter">expression</replaceable> } ON ERROR</literal>
+    </term>
+    <listitem>
+     <para>
+       Defines the return value if an unhandled error occurs. The default is
+       <literal>NULL</literal>. If you use
+       <literal>DEFAULT <replaceable class="parameter">expression</replaceable></literal>,
+       the provided <replaceable class="parameter">expression</replaceable> is
+       evaluated and cast to the type specified in the <command>RETURNING</command> clause.
+     </para>
+     </listitem>
+   </varlistentry>
+
+   </variablelist>
+    </sect5>
+
+    <sect5>
+     <title>Examples</title>
+
+     <para>
+      Extract an SQL/JSON value and return it as an SQL
+      scalar of the specified type. Note that
+      <command>JSON_VALUE</command> can only return a
+      single scalar, and the returned value must have a
+      cast to the specified return type:
+     </para>
+
+<screen>
+SELECT JSON_VALUE('"123.45"', '$' RETURNING float);
+ json_value
+------------
+     123.45
+(1 row)
+
+SELECT JSON_VALUE('123.45', '$' RETURNING int ERROR ON ERROR);
+ json_value
+------------
+        123
+(1 row)
+
+SELECT JSON_VALUE('"03:04 2015-02-01"', '$.datetime("HH24:MI YYYY-MM-DD")' RETURNING date);
+ json_value 
+------------
+ 2015-02-01
+(1 row)
+
+SELECT JSON_VALUE('"123.45"', '$' RETURNING int ERROR ON ERROR);
+ERROR:  invalid input syntax for integer: "123.45"
+
+SELECT JSON_VALUE(jsonb '[1]', 'strict $' ERROR ON ERROR);
+ERROR: SQL/JSON scalar required
+
+SELECT JSON_VALUE(jsonb '[1,2]', 'strict $[*]' ERROR ON ERROR);
+ERROR: more than one SQL/JSON item
+</screen>
+
+     <para>
+       If the path expression returns an array, an object, or
+       multiple SQL/JSON items, an error is returned, as specified
+       in the <command>ON ERROR</command> clause:
+     </para>
+<screen>
+SELECT JSON_VALUE(jsonb '[1]', 'strict $' ERROR ON ERROR);
+ERROR: SQL/JSON scalar required
+
+SELECT JSON_VALUE(jsonb '{"a": 1}', 'strict $' ERROR ON ERROR);
+ERROR: SQL/JSON scalar required
+
+SELECT JSON_VALUE(jsonb '[1,2]', 'strict $[*]' ERROR ON ERROR);
+ERROR: more than one SQL/JSON item
+
+SELECT JSON_VALUE(jsonb '[1,2]', 'strict $[*]' DEFAULT 1 ON ERROR);
+1
+</screen>
+
+    </sect5>
+   </sect4>
+
+   <sect4 id="functions-jsonquery">
+    <title><literal>JSON_QUERY</literal></title>
+    <indexterm><primary>json_query</primary></indexterm>
+
+<synopsis>
+<function>JSON_QUERY</function> (
+  <replaceable>context_item</replaceable>, <replaceable>path_expression</replaceable> <optional> PASSING { <replaceable>value</replaceable> AS <replaceable>varname</replaceable> } <optional>, ...</optional></optional>
+  <optional> RETURNING <replaceable class="parameter">data_type</replaceable> <optional> FORMAT JSON <optional> ENCODING UTF8 </optional> </optional> </optional>
+  <optional> { WITHOUT | WITH { CONDITIONAL | <optional>UNCONDITIONAL</optional> } } <optional> ARRAY </optional> WRAPPER </optional>
+  <optional> { KEEP | OMIT } QUOTES <optional> ON SCALAR STRING </optional> </optional>
+  <optional> { ERROR | NULL | EMPTY { <optional> ARRAY </optional> | OBJECT } | DEFAULT <replaceable class="parameter">expression</replaceable> } ON EMPTY </optional>
+  <optional> { ERROR | NULL | EMPTY { <optional> ARRAY </optional> | OBJECT } | DEFAULT <replaceable class="parameter">expression</replaceable> } ON ERROR </optional>
+)
+  </synopsis>
+
+    <sect5>
+     <title>Description</title>
+
+  <para>
+   <function>JSON_QUERY</function> function extracts an <acronym>SQL/JSON</acronym>
+   array or object from <acronym>JSON</acronym> data. This function must return
+   a JSON string, so if the path expression returns a scalar or multiple SQL/JSON
+   items, you must wrap the result using the <literal>WITH WRAPPER</literal> clause.
+   To extract a single <acronym>SQL/JSON</acronym> value, you can use <xref linkend="functions-jsonvalue"/>.
+  </para>
+    </sect5>
+
+    <sect5>
+     <title>Parameters</title>
+
+   <variablelist>
+
+   <varlistentry>
+    <term>
+     <literal><replaceable>context_item</replaceable>, <replaceable>path_expression</replaceable> <optional> PASSING { <replaceable>value</replaceable> AS <replaceable>varname</replaceable> } <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.
+     For details, see <xref linkend="functions-sqljson-path"/>.
+    </para>
+    </listitem>
+   </varlistentry>
+
+  <varlistentry>
+    <term>
+     <literal>RETURNING <replaceable class="parameter">data_type</replaceable> <optional> FORMAT JSON <optional> ENCODING UTF8 </optional> </optional></literal>
+    </term>
+    <listitem>
+     <para>
+       The output clause that specifies the data type of the returned value.
+       For details, see <xref linkend="sqljson-output-clause"/>.
+     </para>
+     </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term>
+     <literal>{ WITHOUT | WITH { CONDITIONAL | <optional>UNCONDITIONAL</optional> } } <optional> ARRAY </optional> WRAPPER</literal>
+    </term>
+    <listitem>
+     <para>
+       Defines whether to wrap a returned sequence of <acronym>SQL/JSON</acronym>
+       items into a <acronym>SQL/JSON</acronym> array.
+     </para>
+       <variablelist>
+        <varlistentry>
+        <term><literal>WITHOUT WRAPPER</literal></term>
+        <listitem>
+          <para>
+            Do not wrap the result.
+            This is the default behavior if the <literal>WRAPPER</literal>
+            clause is omitted.
+          </para>
+        </listitem>
+        </varlistentry>
+        <varlistentry>
+        <term><literal>WITH <optional>UNCONDITIONAL</optional> WRAPPER</literal></term>
+        <listitem>
+          <para>
+            Always wrap the result.
+          </para>
+        </listitem>
+        </varlistentry>
+        <varlistentry>
+        <term><literal>WITH CONDITIONAL WRAPPER</literal></term>
+        <listitem>
+          <para>
+            Wrap the result if the path
+            expression returns anything other than a single
+            <acronym>SQL/JSON</acronym> array or object.
+          </para>
+        </listitem>
+        </varlistentry>
+       </variablelist>
+     <para>
+       Optionally, you can add the <literal>ARRAY</literal> keyword for semantic clarity.
+     </para>
+     <important>
+      <para>You cannot use this clause together with the <literal>ON EMPTY</literal> clause.
+      </para>
+     </important>
+     </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term>
+     <literal>{ KEEP | OMIT } QUOTES <optional> ON SCALAR STRING </optional></literal>
+    </term>
+    <listitem>
+     <para>
+       Defines whether to keep or omit quotes if a scalar string is returned.
+       By default, scalar strings are returned with quotes. Using this
+       clause together with the <command>WITH WRAPPER</command> clause is not allowed.
+     </para>
+     <para>
+       Optionally, you can add the <literal>ON SCALAR STRING</literal> keywords for semantic clarity.
+     </para>
+     </listitem>
+   </varlistentry>
+
+  <varlistentry>
+    <term>
+     <literal>{ ERROR | NULL | EMPTY { <optional> ARRAY </optional> | OBJECT } | DEFAULT <replaceable class="parameter">expression</replaceable> } ON EMPTY</literal>
+    </term>
+    <listitem>
+     <para>
+       Defines the return value if no JSON value is found. The default is <literal>NULL</literal>.
+       If you use <literal>EMPTY <optional>ARRAY</optional></literal> or <literal>EMPTY OBJECT</literal>,
+       an empty JSON array [] or object {} is returned, respectively.
+       If you use <literal>DEFAULT <replaceable class="parameter">expression</replaceable></literal>,
+       the provided <replaceable class="parameter">expression</replaceable> is evaluated and cast
+       to the type specified in the <command>RETURNING</command> clause.
+     </para>
+     <para>
+       You cannot use this clause together with the <literal>WRAPPER</literal> clause.
+     </para>
+     </listitem>
+   </varlistentry>
+
+     <varlistentry>
+    <term>
+     <literal>{ ERROR | NULL | EMPTY { <optional> ARRAY </optional> | OBJECT } | DEFAULT <replaceable class="parameter">expression</replaceable> } ON ERROR</literal>
+    </term>
+    <listitem>
+     <para>
+       Defines the return value if an unhandled error occurs. The default is <literal>NULL</literal>.
+       If you use <literal>EMPTY <optional>ARRAY</optional></literal> or <literal>EMPTY OBJECT</literal>,
+       an empty JSON array <literal>[]</literal> or object <literal>{}</literal> are returned, respectively.
+       If you use <literal>DEFAULT <replaceable class="parameter">expression</replaceable></literal>,
+       the provided <replaceable class="parameter">expression</replaceable> is evaluated and cast
+       to the type specified in the <command>RETURNING</command> clause.
+     </para>
+     </listitem>
+   </varlistentry>
+
+   </variablelist>
+    </sect5>
+
+    <sect5>
+     <title>Examples</title>
+
+     <para>
+      Extract all film genres listed in the <structname>my_films</structname> table:
+     </para>
+     <screen>
+SELECT
+    JSON_QUERY(js, '$.favorites[*].kind' WITH WRAPPER ERROR ON ERROR)
+FROM my_films;
+ json_query
+------------
+ ["comedy", "horror", "thriller", "drama"]
+(1 row)
+</screen>
+
+     <para>
+      Note that the same query will result in an error if you omit the
+      <command>WITH WRAPPER</command> clause, as it returns multiple SQL/JSON items:
+     </para>
+     <screen>
+SELECT
+    JSON_QUERY(js, '$.favorites[*].kind' ERROR ON ERROR)
+FROM my_films;
+ERROR: more than one SQL/JSON item 
+</screen>
+
+     <para>
+       Compare the effect of different <literal>WRAPPER</literal> clauses:
+     </para>
+     <screen>
+SELECT
+    js,
+    JSON_QUERY(js, 'lax $[*]') AS "without",
+    JSON_QUERY(js, 'lax $[*]' WITH WRAPPER)  AS "with uncond",
+    JSON_QUERY(js, 'lax $[*]' WITH CONDITIONAL WRAPPER) AS "with cond"
+FROM
+    (VALUES (jsonb '[]'), ('[1]'), ('[[1,2,3]]'),  ('[{"a": 1}]'), ('[1, null, "2"]')) foo(js);
+       js       |  without  |  with uncond   |   with cond
+----------------+-----------+----------------+----------------
+ []             | (null)    | (null)         | (null)
+ [1]            | 1         | [1]            | [1]
+ [[1, 2, 3]]    | [1, 2, 3] | [[1, 2, 3]]    | [1, 2, 3]
+ [{"a": 1}]     | {"a": 1}  | [{"a": 1}]     | {"a": 1}
+ [1, null, "2"] | (null)    | [1, null, "2"] | [1, null, "2"]
+(5 rows)
+</screen>
+
+<para>Compare quote handling for scalar types with and without the <command>OMIT QUOTES</command> clause:
+</para>
+     <screen>
+SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text);
+ json_query
+------------
+ "aaa"
+(1 row)
+
+SELECT JSON_QUERY(jsonb '"aaa"', '$' RETURNING text OMIT QUOTES);
+ json_query
+------------
+ aaa
+(1 row)
+</screen>
+    </sect5>
+   </sect4>
+
+   <sect4 id="functions-isjson-predicate">
+    <title><literal>IS JSON</literal></title>
+    <indexterm><primary>is_json</primary></indexterm>
+
+<synopsis>
+<replaceable class="parameter">expression</replaceable>
+  IS <optional> NOT </optional> JSON 
+  <optional> { VALUE | SCALAR | ARRAY | OBJECT } </optional>
+  <optional> { WITH | WITHOUT } UNIQUE <optional> KEYS </optional> </optional>
+</synopsis>
+
+    <sect5>
+     <title>Description</title>
+
+  <para>
+   The <command>IS JSON</command> predicate tests whether the provided value is valid
+   <acronym>JSON</acronym> data. If you provide a specific JSON data type as a parameter,
+   you can check whether the value belongs to this type.
+   You can also use this predicate in the <command>IS NOT JSON</command> form.
+   The return values are:
+   <itemizedlist>
+    <listitem>
+      <para>
+        <literal>t</literal> if the value satisfies the specified condition.
+      </para>
+    </listitem>
+    <listitem>
+      <para>
+        <literal>f</literal> if the value does not satisfy the specified condition.
+      </para>
+    </listitem>
+   </itemizedlist>
+  </para>
+    </sect5>
+
+    <sect5>
+     <title>Parameters</title>
+
+<variablelist>
+
+   <varlistentry>
+    <term>
+     <literal><replaceable class="parameter">expression</replaceable></literal>
+    </term>
+    <listitem>
+
+    <para>
+      The input clause defining the value to test. You can provide the values
+      of <literal>json</literal>, <literal>jsonb</literal>,
+      <literal>bytea</literal>, or character string types.
+    </para>
+  </listitem>
+   </varlistentry>
+   
+   <varlistentry>
+    <term>
+     <literal>VALUE | SCALAR | ARRAY | OBJECT</literal>
+    </term>
+    <listitem>
+
+    <para>
+      Specifies the <acronym>JSON</acronym> data type to test for:
+      <itemizedlist>
+        <listitem>
+          <para>
+            <literal>VALUE</literal> (default) &mdash; any <acronym>JSON</acronym> type.
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            <literal>SCALAR</literal> &mdash; <acronym>JSON</acronym> number, string, or boolean.
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            <literal>ARRAY</literal> &mdash; <acronym>JSON</acronym> array.
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            <literal>OBJECT</literal> &mdash; <acronym>JSON</acronym> object.
+          </para>
+        </listitem>
+      </itemizedlist>
+    </para>
+    </listitem>
+   </varlistentry>
+
+    <varlistentry>
+    <term>
+     <literal>{ WITH | WITHOUT } UNIQUE <optional> KEYS </optional></literal>
+    </term>
+    <listitem>
+     <para>Defines whether duplicate keys are allowed:
+      <itemizedlist>
+        <listitem>
+          <para>
+            <literal>WITHOUT</literal> (default) &mdash; the
+            <acronym>JSON</acronym> object can contain duplicate keys.
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            <literal>WITH</literal> &mdash; duplicate keys are not allowed.
+            If the input data contains duplicate keys, it is considered to be invalid JSON.
+          </para>
+        </listitem>
+      </itemizedlist>
+      Optionally, you can add the <literal>KEYS</literal> keyword for semantic clarity.
+      </para>
+    </listitem>
+  </varlistentry>
+   </variablelist>
+
+    </sect5>
+
+    <sect5>
+     <title>Examples</title>
+
+     <para>
+      Compare the result returned by the <function>IS JSON</function>
+      predicate for different data types:
+     </para>
+     <screen>
+SELECT
+    js, 
+    js IS JSON "is json", 
+    js IS NOT JSON "is not json",
+    js IS JSON SCALAR "is scalar",
+    js IS JSON OBJECT "is object",
+    js IS JSON ARRAY "is array"
+FROM 
+    (VALUES ('123'), ('"abc"'), ('{"a": "b"}'), ('[1,2]'), ('abc')) foo(js);
+
+     js     | is json | is not json | is scalar | is object | is array 
+------------+---------+-------------+-----------+-----------|-------------
+ 123        | t       | f           | t         | f         | f
+ "abc"      | t       | f           | t         | f         | f
+ {"a": "b"} | t       | f           | f         | t         | f
+ [1,2]      | t       | f           | f         | f         | t
+ abc        | f       | t           | f         | f         | f
+(5 rows)
+</screen>
+    </sect5>
+   </sect4>
+
+   <sect4 id="functions-jsontable">
+    <title><literal>JSON_TABLE</literal></title>
+    <indexterm><primary>json_table</primary></indexterm>
+
+<synopsis>
+JSON_TABLE (
+  <replaceable>context_item</replaceable>, <replaceable>path_expression</replaceable> <optional> AS <replaceable>json_path_name</replaceable> </optional> <optional> PASSING { <replaceable>value</replaceable> AS <replaceable>varname</replaceable> } <optional>, ...</optional> </optional>
+  COLUMNS ( <replaceable class="parameter">json_table_column</replaceable> <optional>, ...</optional> )
+  <optional>
+    PLAN ( <replaceable class="parameter">json_table_plan</replaceable> ) |
+    PLAN DEFAULT ( { INNER | OUTER } <optional> , { CROSS | UNION } </optional>
+                 | { CROSS | UNION } <optional> , { INNER | OUTER } </optional> )
+  </optional>
+)
+<phrase>
+where <replaceable class="parameter">json_table_column</replaceable> is:
+</phrase>
+    <replaceable>name</replaceable> <replaceable>type</replaceable> <optional> PATH <replaceable>json_path_specification</replaceable> </optional>
+        <optional> { WITHOUT | WITH { CONDITIONAL | <optional>UNCONDITIONAL</optional> } } <optional> ARRAY </optional> WRAPPER </optional>
+        <optional> { KEEP | OMIT } QUOTES <optional> ON SCALAR STRING </optional> </optional>
+        <optional> { ERROR | NULL | DEFAULT <replaceable>expression</replaceable> } ON EMPTY </optional>
+        <optional> { ERROR | NULL | DEFAULT <replaceable>expression</replaceable> } ON ERROR </optional>
+  | <replaceable>name</replaceable> <replaceable>type</replaceable> FORMAT <replaceable>json_representation</replaceable>
+        <optional> PATH <replaceable>json_path_specification</replaceable> </optional>
+        <optional> { WITHOUT | WITH { CONDITIONAL | <optional>UNCONDITIONAL</optional> } } <optional> ARRAY </optional> WRAPPER </optional>
+        <optional> { KEEP | OMIT } QUOTES <optional> ON SCALAR STRING </optional> </optional>
+        <optional> { ERROR | NULL | EMPTY { ARRAY | OBJECT } | DEFAULT <replaceable>expression</replaceable> } ON EMPTY </optional>
+        <optional> { ERROR | NULL | EMPTY { ARRAY | OBJECT } | DEFAULT <replaceable>expression</replaceable> } ON ERROR </optional>
+  | <replaceable>name</replaceable> <replaceable>type</replaceable> EXISTS <optional> PATH <replaceable>json_path_specification</replaceable> </optional>
+        <optional> { ERROR | TRUE | FALSE | UNKNOWN } ON ERROR </optional>
+  | NESTED PATH <replaceable>json_path_specification</replaceable> <optional> AS <replaceable>path_name</replaceable> </optional>
+        COLUMNS ( <replaceable>json_table_column</replaceable> <optional>, ...</optional> )
+  | <replaceable>name</replaceable> FOR ORDINALITY
+<phrase>
+<replaceable>json_table_plan</replaceable> is:
+</phrase>
+    <replaceable>json_path_name</replaceable> <optional> { OUTER | INNER } <replaceable>json_table_plan_primary</replaceable> </optional>
+  | <replaceable>json_table_plan_primary</replaceable> { UNION <replaceable>json_table_plan_primary</replaceable> } <optional>...</optional>
+  | <replaceable>json_table_plan_primary</replaceable> { CROSS <replaceable>json_table_plan_primary</replaceable> } <optional>...</optional>
+<phrase>
+<replaceable>json_table_plan_primary</replaceable> is:
+</phrase>
+    <replaceable>json_path_name</replaceable> | ( <replaceable>json_table_plan</replaceable> )
+
+</synopsis>
+
+    <sect5>
+     <title>Description</title>
+
+     <para>
+      <function>JSON_TABLE</function> function 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 the <literal>SELECT</literal> statement
+      for an SQL table.
+     </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, which are considered to be <firstterm>siblings</firstterm>
+      to each other. In relation to the columns returned directly from the row
+      expression or by the <literal>NESTED PATH</literal> clause of a
+      higher level, these columns are <firstterm>child</firstterm> columns.
+      Sibling columns are always joined first. Once they are processed,
+      the resulting rows are joined to the parent row.
+     </para>
+
+    </sect5>
+    <sect5>
+     <title>Parameters</title>
+
+  <variablelist>
+   <varlistentry>
+    <term>
+     <literal><replaceable>context_item</replaceable>, <replaceable>path_expression</replaceable> <optional> AS <replaceable>json_path_name</replaceable> </optional> <optional> PASSING { <replaceable>value</replaceable> AS <replaceable>varname</replaceable> } <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, as described in
+     <xref linkend="sqljson-input-clause"/>. 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( <replaceable class="parameter">json_table_column</replaceable> <optional>, ...</optional> )</literal>
+    </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 <replaceable class="parameter">json_table_column</replaceable>
+     expression has the following syntax variants:
+    </para>
+
+  <variablelist>
+   <varlistentry>
+    <term>
+     <literal><replaceable>name</replaceable> <replaceable>type</replaceable>
+          <optional> PATH <replaceable>json_path_specification</replaceable> </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 <replaceable>json_api_common_syntax</replaceable>
+     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>
+      Internally, <xref linkend="functions-jsonvalue"/> and
+      <xref linkend="functions-jsonquery"/> are used to produce resulting values.
+      <xref linkend="functions-jsonquery"/> is used for JSON, array, and
+      composite column types, <xref linkend="functions-jsonvalue"/> is used for
+      other types.
+    </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 in
+     <xref linkend="functions-jsonvalue"/> and
+     <xref linkend="functions-jsonquery"/>.
+    </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term>
+     <literal><replaceable>name</replaceable> <replaceable>type</replaceable> FORMAT <replaceable>json_representation</replaceable>
+          <optional> PATH <replaceable>json_path_specification</replaceable> </optional></literal>
+    </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 <replaceable>json_api_common_syntax</replaceable>
+     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>
+      Internally, <xref linkend="functions-jsonquery"/> is used to produce
+      resulting values.
+    </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
+     in <xref linkend="functions-jsonquery"/>.
+    </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term>
+     <literal>
+       <replaceable>name</replaceable> <replaceable>type</replaceable>
+       EXISTS <optional> PATH <replaceable>json_path_specification</replaceable> </optional>
+     </literal>
+    </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 <replaceable>json_api_common_syntax</replaceable>,
+     checks whether any SQL/JSON items were returned, and fills the column with
+     resulting boolean value, one for each row.
+     The specified <replaceable>type</replaceable> 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 have the same syntax and semantics as in
+     <xref linkend="functions-jsonexists"/>.
+    </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term>
+     <literal>NESTED PATH <replaceable>json_path_specification</replaceable> <optional> AS <replaceable>json_path_name</replaceable> </optional>
+          COLUMNS ( <replaceable>json_table_column</replaceable> <optional>, ...</optional> )</literal>
+    </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 <replaceable>json_table_column</replaceable> 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 <replaceable>NESTED PATH</replaceable> clauses.
+    </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term>
+     <literal><replaceable>name</replaceable> 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 <replaceable>json_path_name</replaceable></literal>
+    </term>
+    <listitem>
+
+    <para>
+     The optional <replaceable>json_path_name</replaceable> serves as an
+     identifier of the provided <replaceable>json_path_specification</replaceable>.
+     The path name must be unique and cannot coincide with 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 ( <replaceable class="parameter">json_table_plan</replaceable> )</literal>
+    </term>
+    <listitem>
+
+    <para>
+     Defines how to join the data returned by <replaceable>NESTED PATH</replaceable>
+     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>
+     Use <literal>FULL OUTER JOIN ON FALSE</literal>, so that both parent and child
+     rows are included into the output, with NULL values inserted
+     into both child and parent columns for all missing values.
+    </para>
+    <para>
+     This is the default option for joining sibling columns.
+    </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term>
+     <literal>CROSS</literal>
+    </term>
+    <listitem>
+
+    <para>
+     Use <literal>CROSS JOIN</literal>, so that the output includes 
+     a row for every possible combination of rows from the left-hand
+     and the right-hand columns.
+    </para>
+    </listitem>
+   </varlistentry>
+
+  </variablelist>
+
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term>
+     <literal>PLAN DEFAULT ( <replaceable>option</replaceable> <optional>, ... </optional> )</literal>
+    </term>
+    <listitem>
+     <para>
+      Overrides the default joining plans. The <literal>INNER</literal> and
+      <literal>OUTER</literal> options define the joining plan for parent/child
+      columns, while <literal>UNION</literal> and <literal>CROSS</literal>
+      affect the sibling columns. You can override the default plans for all columns at once.
+      Even though the path names are not included into the <literal>PLAN DEFAULT</literal>
+      clause, they must be provided for all the paths to conform to
+      the SQL/JSON standard.
+     </para>
+    </listitem>
+   </varlistentry>
+  </variablelist>
+    </sect5>
+
+    <sect5>
+     <title>Examples</title>
+
+     <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          | 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;
+</screen>
+     </para>
+    </sect5>
+   </sect4>
+  </sect3>
+
+  <sect3 id="functions-sqljson-serializing">
+   <title>Serializing JSON data</title>
+   <itemizedlist>
+    <listitem>
+      <para>
+       <link linkend="functions-jsonserialize"><literal>JSON_SERIALIZE</literal></link>
+      </para>
+    </listitem>
+   </itemizedlist>
+
+   <sect4 id="functions-jsonserialize">
+    <title><literal>JSON_SERIALAIZE</literal></title>
+    <indexterm><primary>json_serialize</primary></indexterm>
+
+<synopsis>
+JSON_SERIALIZE (
+  <parameter>expression</parameter> <optional> FORMAT JSON <optional> ENCODING UTF8 </optional> </optional>
+  <optional> RETURNING <replaceable class="parameter">data_type</replaceable> <optional> FORMAT JSON <optional> ENCODING UTF8 </optional> </optional> </optional>
+)
+</synopsis>
+
+    <sect5>
+     <title>Description</title>
+
+     <para>
+      <function>JSON_SERIALIZE</function> function transforms a SQL/JSON value
+      into a character or binary string.
+     </para>
+    </sect5>
+
+    <sect5>
+     <title>Parameters</title>
+      <variablelist>
+       <varlistentry>
+        <term>
+         <literal><parameter>expression</parameter> <optional> FORMAT JSON <optional> ENCODING UTF8 </optional> </optional></literal>
+        </term>
+        <listitem>
+         <para>
+          <acronym>JSON</acronym> typed expression that provides a data for
+          serialization.  Accepted JSON types (<type>json</type> and
+          <type>jsonb</type>), any character string types (<type>text</type>,
+          <type>char</type>, etc.), binary strings (<type>bytea</type>) in
+          UTF8 encoding.
+          For null input, null value is returned.
+         </para>
+         <para>
+           The optional <literal>FORMAT</literal> clause is provided to conform
+           to the SQL/JSON standard.
+         </para>
+        </listitem>
+       </varlistentry>
+       <varlistentry>
+        <term>
+         <literal>RETURNING <replaceable class="parameter">data_type</replaceable> <optional> FORMAT JSON <optional> ENCODING UTF8 </optional> </optional></literal>
+        </term>
+        <listitem>
+        <para>
+         The output clause that specifies the target character or binary string
+         type (<type>text</type>, <type>char</type>, <type>bytea</type>, etc.).
+        </para>
+       </listitem>
+      </varlistentry>
+     </variablelist>
+    </sect5>
+
+    <sect5>
+     <title>Notes</title>
+     <para>
+      Alternatively, you can construct <acronym>JSON</acronym> values simply
+      using <productname>PostgreSQL</productname>-specific casts to 
+      <type>json</type> and <type>jsonb</type> types.
+     </para>
+    </sect5>
+    <sect5>
+     <title>Examples</title>
+     <para>
+      Construct a JSON the provided strings:
+     </para>
+<screen>
+SELECT JSON_SERIALIZE(JSON_SCALAR('foo'));
+ json_serialize 
+----------------
+ "foo"
+(1 row)
+
+SELECT JSON_SERIALIZE('{"foo": "bar", "baz": [1, 2, 3]}' RETURNING bytea);
+                           json_serialize                           
+--------------------------------------------------------------------
+ \x7b22666f6f223a2022626172222c202262617a223a205b312c20322c20335d7d
+(1 row)
+
+</screen>
+    </sect5>
+   </sect4>
+
+  </sect3>
+ 
+  <sect3 id="sqljson-common-clauses">
+   <title>SQL/JSON Common Clauses</title>
+
+   <sect4 id="sqljson-input-clause">
+    <title>SQL/JSON Input Clause</title>
+
+    <variablelist>
+  <varlistentry>
+    <term>
+     <literal><replaceable>context_item</replaceable>, <replaceable>path_expression</replaceable>
+<optional> PASSING { <replaceable>value</replaceable> AS <replaceable>varname</replaceable> } <optional>, ...</optional></optional></literal>
+    </term>
+    <listitem>
+     <para>
+       The input clause specifies the JSON data to query and
+       the exact query path to be passed to SQL/JSON query functions:
+     </para>
+    <itemizedlist>
+     <listitem>
+      <para>
+       The <replaceable>context_item</replaceable> is the JSON data to query.
+      </para>
+      <note>
+       <para>
+        Currently for functions <function>JSON_VALUE</function>,
+        <function>JSON_EXISTS</function>, and <function>JSON_QUERY</function>
+        this must be a value of type <type>jsonb</type>.
+       </para>
+      </note>
+     </listitem>
+     <listitem>
+      <para>
+       The <replaceable>path_expression</replaceable> is an SQL/JSON path
+       expression that specifies the items to be retrieved from the JSON
+       data. For details on path expression syntax, see
+       <xref linkend="functions-sqljson-path"/>.
+      </para>
+      </listitem>
+      <listitem>
+      <para>
+       The optional <command>PASSING</command> clause provides the values for
+       the named variables used in the SQL/JSON path expression.
+      </para>
+     </listitem>
+    </itemizedlist>
+    <para>
+     The input clause is common for all SQL/JSON query functions.
+    </para>
+     </listitem>
+   </varlistentry>
+    </variablelist>
+
+   </sect4>
+
+   <sect4 id="sqljson-output-clause">
+    <title>SQL/JSON Output Clause</title>
+
+    <variablelist>
+  <varlistentry>
+    <term>
+     <literal>RETURNING <replaceable class="parameter">data_type</replaceable> <optional> FORMAT JSON <optional> ENCODING UTF8 </optional> </optional></literal>
+    </term>
+    <listitem>
+     <para>
+       The output clause that specifies the return type of the generated
+       <acronym>JSON</acronym> object. Out of the box, <productname>PostgreSQL</productname>
+       supports the following types: <type>json</type>, <type>jsonb</type>,
+       <type>bytea</type>, and character string types (<type>text</type>, <type>char</type>,
+       <type>varchar</type>, and <type>nchar</type>).
+       To use other types, you must create the <literal>CAST</literal> from <type>json</type> for this type.
+       By default, the <type>json</type> type is returned.
+     </para>
+     <para>
+       The optional <literal>FORMAT</literal> clause is provided to conform to the SQL/JSON standard.
+      </para>
+     <para>
+       The output clause is common for both constructor and query SQL/JSON functions.
+     </para>
+     </listitem>
+   </varlistentry>
+    </variablelist>
+
+   </sect4>
+  </sect3>
+  </sect2>
+
  </sect1>
 
  <sect1 id="functions-sequence">
@@ -19932,6 +22347,29 @@ SELECT NULLIF(value, '(none)') ...
        <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>
@@ -19953,13 +22391,101 @@ SELECT NULLIF(value, '(none)') ...
        </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>.
+        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>
 
+      <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 not keys.
+        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.
+       </para></entry>
+       <entry>No</entry>
+      </row>
+
       <row>
        <entry role="func_table_entry"><para role="func_signature">
         <indexterm>
@@ -20133,7 +22659,12 @@ SELECT NULLIF(value, '(none)') ...
   <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
@@ -20153,6 +22684,13 @@ SELECT xmlagg(x) FROM (SELECT x FROM test ORDER BY y DESC) AS tab;
    subquery's output to be reordered before the aggregate is computed.
   </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>