1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-14 08:21:07 +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:
Tom Lane
2012-08-07 19:02:54 -04:00
parent 5078be4804
commit 5ebaaa4944
41 changed files with 1301 additions and 482 deletions

View File

@ -204,6 +204,64 @@ add_vars_to_targetlist(PlannerInfo *root, List *vars,
}
}
/*
* extract_lateral_references
* If the specified RTE is a LATERAL subquery, extract all its references
* to Vars of the current query level, and make sure those Vars will be
* available for evaluation of the RTE.
*
* XXX this is rather duplicative of processing that has to happen elsewhere.
* Maybe it'd be a good idea to do this type of extraction further upstream
* and save the results?
*/
static void
extract_lateral_references(PlannerInfo *root, int rtindex)
{
RangeTblEntry *rte = root->simple_rte_array[rtindex];
List *vars;
List *newvars;
Relids where_needed;
ListCell *lc;
/* No cross-references are possible if it's not LATERAL */
if (!rte->lateral)
return;
/* Fetch the appropriate variables */
if (rte->rtekind == RTE_SUBQUERY)
vars = pull_vars_of_level((Node *) rte->subquery, 1);
else if (rte->rtekind == RTE_FUNCTION)
vars = pull_vars_of_level(rte->funcexpr, 0);
else
return;
/* Copy each Var and adjust it to match our level */
newvars = NIL;
foreach(lc, vars)
{
Var *var = (Var *) lfirst(lc);
var = copyObject(var);
var->varlevelsup = 0;
newvars = lappend(newvars, var);
}
/*
* We mark the Vars as being "needed" at the LATERAL RTE. This is a bit
* of a cheat: a more formal approach would be to mark each one as needed
* at the join of the LATERAL RTE with its source RTE. But it will work,
* and it's much less tedious than computing a separate where_needed for
* each Var.
*/
where_needed = bms_make_singleton(rtindex);
/* Push the Vars into their source relations' targetlists */
add_vars_to_targetlist(root, newvars, where_needed, false);
list_free(newvars);
list_free(vars);
}
/*****************************************************************************
*
@ -286,7 +344,9 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
int varno = ((RangeTblRef *) jtnode)->rtindex;
/* No quals to deal with, just return correct result */
/* No quals to deal with, but do check for LATERAL subqueries */
extract_lateral_references(root, varno);
/* Result qualscope is just the one Relid */
*qualscope = bms_make_singleton(varno);
/* A single baserel does not create an inner join */
*inner_join_rels = NULL;