mirror of
https://github.com/postgres/postgres.git
synced 2025-06-13 07:41:39 +03:00
Make LATERAL implicit for functions in FROM.
The SQL standard does not have general functions-in-FROM, but it does allow UNNEST() there (see the <collection derived table> production), and the semantics of that are defined to include lateral references. So spec compliance requires allowing lateral references within UNNEST() even without an explicit LATERAL keyword. Rather than making UNNEST() a special case, it seems best to extend this flexibility to any function-in-FROM. We'll still allow LATERAL to be written explicitly for clarity's sake, but it's now a noise word in this context. In theory this change could result in a change in behavior of existing queries, by allowing what had been an outer reference in a function-in-FROM to be captured by an earlier FROM-item at the same level. However, all pre-9.3 PG releases have a bug that causes them to match variable references to earlier FROM-items in preference to outer references (and then throw an error). So no previously-working query could contain the type of ambiguity that would risk a change of behavior. Per a suggestion from Andrew Gierth, though I didn't use his patch.
This commit is contained in:
@ -503,6 +503,7 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
|
||||
{
|
||||
Node *funcexpr;
|
||||
char *funcname;
|
||||
bool is_lateral;
|
||||
RangeTblEntry *rte;
|
||||
|
||||
/*
|
||||
@ -514,12 +515,16 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
|
||||
funcname = FigureColname(r->funccallnode);
|
||||
|
||||
/*
|
||||
* If the function is LATERAL, make lateral_only names of this level
|
||||
* visible to it. (LATERAL can't nest within a single pstate level, so we
|
||||
* don't need save/restore logic here.)
|
||||
* We make lateral_only names of this level visible, whether or not the
|
||||
* function is explicitly marked LATERAL. This is needed for SQL spec
|
||||
* compliance in the case of UNNEST(), and seems useful on convenience
|
||||
* grounds for all functions in FROM.
|
||||
*
|
||||
* (LATERAL can't nest within a single pstate level, so we don't need
|
||||
* save/restore logic here.)
|
||||
*/
|
||||
Assert(!pstate->p_lateral_active);
|
||||
pstate->p_lateral_active = r->lateral;
|
||||
pstate->p_lateral_active = true;
|
||||
|
||||
/*
|
||||
* Transform the raw expression.
|
||||
@ -533,11 +538,17 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
|
||||
*/
|
||||
assign_expr_collations(pstate, funcexpr);
|
||||
|
||||
/*
|
||||
* Mark the RTE as LATERAL if the user said LATERAL explicitly, or if
|
||||
* there are any lateral cross-references in it.
|
||||
*/
|
||||
is_lateral = r->lateral || contain_vars_of_level(funcexpr, 0);
|
||||
|
||||
/*
|
||||
* OK, build an RTE for the function.
|
||||
*/
|
||||
rte = addRangeTableEntryForFunction(pstate, funcname, funcexpr,
|
||||
r, r->lateral, true);
|
||||
r, is_lateral, true);
|
||||
|
||||
/*
|
||||
* If a coldeflist was supplied, ensure it defines a legal set of names
|
||||
|
Reference in New Issue
Block a user