mirror of
https://github.com/postgres/postgres.git
synced 2025-08-30 06:01:21 +03:00
Implement SQL-standard LATERAL subqueries.
This patch implements the standard syntax of LATERAL attached to a sub-SELECT in FROM, and also allows LATERAL attached to a function in FROM, since set-returning function calls are expected to be one of the principal use-cases. The main change here is a rewrite of the mechanism for keeping track of which relations are visible for column references while the FROM clause is being scanned. The parser "namespace" lists are no longer lists of bare RTEs, but are lists of ParseNamespaceItem structs, which carry an RTE pointer as well as some visibility-controlling flags. Aside from supporting LATERAL correctly, this lets us get rid of the ancient hacks that required rechecking subqueries and JOIN/ON and function-in-FROM expressions for invalid references after they were initially parsed. Invalid column references are now always correctly detected on sight. In passing, remove assorted parser error checks that are now dead code by virtue of our having gotten rid of add_missing_from, as well as some comments that are obsolete for the same reason. (It was mainly add_missing_from that caused so much fudging here in the first place.) The planner support for this feature is very minimal, and will be improved in future patches. It works well enough for testing purposes, though. catversion bump forced due to new field in RangeTblEntry.
This commit is contained in:
@@ -590,7 +590,7 @@ SELECT a.* FROM (my_table AS a JOIN your_table AS b ON ...) AS c
|
||||
<para>
|
||||
Subqueries specifying a derived table must be enclosed in
|
||||
parentheses and <emphasis>must</emphasis> be assigned a table
|
||||
alias name. (See <xref linkend="queries-table-aliases">.) For
|
||||
alias name (as in <xref linkend="queries-table-aliases">). For
|
||||
example:
|
||||
<programlisting>
|
||||
FROM (SELECT * FROM table1) AS alias_name
|
||||
@@ -697,6 +697,87 @@ SELECT *
|
||||
expand to.
|
||||
</para>
|
||||
</sect3>
|
||||
|
||||
<sect3 id="queries-lateral">
|
||||
<title><literal>LATERAL</> Subqueries</title>
|
||||
|
||||
<indexterm zone="queries-lateral">
|
||||
<primary>LATERAL</>
|
||||
<secondary>in the FROM clause</>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
Subqueries and table functions appearing in <literal>FROM</> can be
|
||||
preceded by the key word <literal>LATERAL</>. This allows them to
|
||||
reference columns provided by preceding <literal>FROM</> items.
|
||||
(Without <literal>LATERAL</literal>, each <literal>FROM</> item is
|
||||
evaluated independently and so cannot cross-reference any other
|
||||
<literal>FROM</> item.)
|
||||
A <literal>LATERAL</literal> item can appear at top level in the
|
||||
<literal>FROM</> list, or within a <literal>JOIN</> tree; in the latter
|
||||
case it can also refer to any items that are on the left-hand side of a
|
||||
<literal>JOIN</> that it is on the right-hand side of.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
When a <literal>FROM</> item contains <literal>LATERAL</literal>
|
||||
cross-references, evaluation proceeds as follows: for each row of the
|
||||
<literal>FROM</> item providing the cross-referenced column(s), or
|
||||
set of rows of multiple <literal>FROM</> items providing the
|
||||
columns, the <literal>LATERAL</literal> item is evaluated using that
|
||||
row or row set's values of the columns. The resulting row(s) are
|
||||
joined as usual with the rows they were computed from. This is
|
||||
repeated for each row or set of rows from the column source table(s).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A trivial example of <literal>LATERAL</literal> is
|
||||
<programlisting>
|
||||
SELECT * FROM foo, LATERAL (SELECT * FROM bar WHERE bar.id = foo.bar_id) ss;
|
||||
</programlisting>
|
||||
This is not especially useful since it has exactly the same result as
|
||||
the more conventional
|
||||
<programlisting>
|
||||
SELECT * FROM foo, bar WHERE bar.id = foo.bar_id;
|
||||
</programlisting>
|
||||
<literal>LATERAL</literal> is primarily useful when the cross-referenced
|
||||
column is necessary for computing the row(s) to be joined. A common
|
||||
application is providing an argument value for a set-returning function.
|
||||
For example, supposing that <function>vertices(polygon)</> returns the
|
||||
set of vertices of a polygon, we could identify close-together vertices
|
||||
of polygons stored in a table with:
|
||||
<programlisting>
|
||||
SELECT p1.id, p2.id, v1, v2
|
||||
FROM polygons p1, polygons p2,
|
||||
LATERAL vertices(p1.poly) v1,
|
||||
LATERAL vertices(p2.poly) v2
|
||||
WHERE (v1 <-> v2) < 10 AND p1.id != p2.id;
|
||||
</programlisting>
|
||||
This query could also be written
|
||||
<programlisting>
|
||||
SELECT p1.id, p2.id, v1, v2
|
||||
FROM polygons p1 CROSS JOIN LATERAL vertices(p1.poly) v1,
|
||||
polygons p2 CROSS JOIN LATERAL vertices(p2.poly) v2
|
||||
WHERE (v1 <-> v2) < 10 AND p1.id != p2.id;
|
||||
</programlisting>
|
||||
or in several other equivalent formulations.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
It is often particularly handy to <literal>LEFT JOIN</> to a
|
||||
<literal>LATERAL</literal> subquery, so that source rows will appear in
|
||||
the result even if the <literal>LATERAL</literal> subquery produces no
|
||||
rows for them. For example, if <function>get_product_names()</> returns
|
||||
the names of products made by a manufacturer, but some manufacturers in
|
||||
our table currently produce no products, we could find out which ones
|
||||
those are like this:
|
||||
<programlisting>
|
||||
SELECT m.name
|
||||
FROM manufacturers m LEFT JOIN LATERAL get_product_names(m.id) pname ON true
|
||||
WHERE pname IS NULL;
|
||||
</programlisting>
|
||||
</para>
|
||||
</sect3>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="queries-where">
|
||||
|
Reference in New Issue
Block a user