1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-28 18:48:04 +03:00

Support multi-argument UNNEST(), and TABLE() syntax for multiple functions.

This patch adds the ability to write TABLE( function1(), function2(), ...)
as a single FROM-clause entry.  The result is the concatenation of the
first row from each function, followed by the second row from each
function, etc; with NULLs inserted if any function produces fewer rows than
others.  This is believed to be a much more useful behavior than what
Postgres currently does with multiple SRFs in a SELECT list.

This syntax also provides a reasonable way to combine use of column
definition lists with WITH ORDINALITY: put the column definition list
inside TABLE(), where it's clear that it doesn't control the ordinality
column as well.

Also implement SQL-compliant multiple-argument UNNEST(), by turning
UNNEST(a,b,c) into TABLE(unnest(a), unnest(b), unnest(c)).

The SQL standard specifies TABLE() with only a single function, not
multiple functions, and it seems to require an implicit UNNEST() which is
not what this patch does.  There may be something wrong with that reading
of the spec, though, because if it's right then the spec's TABLE() is just
a pointless alternative spelling of UNNEST().  After further review of
that, we might choose to adopt a different syntax for what this patch does,
but in any case this functionality seems clearly worthwhile.

Andrew Gierth, reviewed by Zoltán Böszörményi and Heikki Linnakangas, and
significantly revised by me
This commit is contained in:
Tom Lane
2013-11-21 19:37:02 -05:00
parent 38f4328981
commit 784e762e88
48 changed files with 2643 additions and 1207 deletions

View File

@@ -643,21 +643,55 @@ FROM (VALUES ('anne', 'smith'), ('bob', 'jones'), ('joe', 'blow'))
the <literal>FROM</> clause of a query. Columns returned by table
functions can be included in <literal>SELECT</>,
<literal>JOIN</>, or <literal>WHERE</> clauses in the same manner
as a table, view, or subquery column.
as columns of a table, view, or subquery.
</para>
<para>
If a table function returns a base data type, the single result
column name matches the function name. If the function returns a
composite type, the result columns get the same names as the
individual attributes of the type.
Table functions may also be combined using the <literal>TABLE</literal>
syntax, with the results returned in parallel columns; the number of
result rows in this case is that of the largest function result, with
smaller results padded with NULLs to match.
</para>
<synopsis>
<replaceable>function_call</replaceable> <optional>WITH ORDINALITY</optional> <optional><optional>AS</optional> <replaceable>table_alias</replaceable> <optional>(<replaceable>column_alias</replaceable> <optional>, ... </optional>)</optional></optional>
TABLE( <replaceable>function_call</replaceable> <optional>, ... </optional> ) <optional>WITH ORDINALITY</optional> <optional><optional>AS</optional> <replaceable>table_alias</replaceable> <optional>(<replaceable>column_alias</replaceable> <optional>, ... </optional>)</optional></optional>
</synopsis>
<para>
If the <literal>WITH ORDINALITY</literal> clause is specified, an
additional column of type <type>bigint</type> will be added to the
function result columns. This column numbers the rows of the function
result set, starting from 1. (This is a generalization of the
SQL-standard syntax for <literal>UNNEST ... WITH ORDINALITY</literal>.)
By default, the ordinal column is called <literal>ordinality</>, but
a different column name can be assigned to it using
an <literal>AS</literal> clause.
</para>
<para>
A table function can be aliased in the <literal>FROM</> clause,
but it also can be left unaliased. If a function is used in the
<literal>FROM</> clause with no alias, the function name is used
as the resulting table name.
The special table function <literal>UNNEST</literal> may be called with
any number of array parameters, and it returns a corresponding number of
columns, as if <literal>UNNEST</literal>
(<xref linkend="functions-array">) had been called on each parameter
separately and combined using the <literal>TABLE</literal> construct.
</para>
<synopsis>
UNNEST( <replaceable>array_expression</replaceable> <optional>, ... </optional> ) <optional>WITH ORDINALITY</optional> <optional><optional>AS</optional> <replaceable>table_alias</replaceable> <optional>(<replaceable>column_alias</replaceable> <optional>, ... </optional>)</optional></optional>
</synopsis>
<para>
If no <replaceable>table_alias</replaceable> is specified, the function
name is used as the table name; in the case of a <literal>TABLE()</>
construct, the first function's name is used.
</para>
<para>
If column aliases are not supplied, then for a function returning a base
data type, the column name is also the same as the function name. For a
function returning a composite type, the result columns get the names
of the individual attributes of the type.
</para>
<para>
@@ -691,7 +725,30 @@ SELECT * FROM vw_getfoo;
the pseudotype <type>record</>. When such a function is used in
a query, the expected row structure must be specified in the
query itself, so that the system can know how to parse and plan
the query. Consider this example:
the query. This syntax looks like:
</para>
<synopsis>
<replaceable>function_call</replaceable> <optional>AS</optional> <replaceable>alias</replaceable> (<replaceable>column_definition</replaceable> <optional>, ... </optional>)
<replaceable>function_call</replaceable> AS <optional><replaceable>alias</replaceable></optional> (<replaceable>column_definition</replaceable> <optional>, ... </optional>)
TABLE( ... <replaceable>function_call</replaceable> AS (<replaceable>column_definition</replaceable> <optional>, ... </optional>) <optional>, ... </optional> )
</synopsis>
<para>
When not using the <literal>TABLE()</> syntax,
the <replaceable>column_definition</replaceable> list replaces the column
alias list that could otherwise be attached to the <literal>FROM</>
item; the names in the column definitions serve as column aliases.
When using the <literal>TABLE()</> syntax,
a <replaceable>column_definition</replaceable> list can be attached to
each member function separately; or if there is only one member function
and no <literal>WITH ORDINALITY</> clause,
a <replaceable>column_definition</replaceable> list can be written in
place of a column alias list following <literal>TABLE()</>.
</para>
<para>
Consider this example:
<programlisting>
SELECT *
FROM dblink('dbname=mydb', 'SELECT proname, prosrc FROM pg_proc')