From 2378d79ab29865f59245744beb8f04a3ce56d2ae Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 26 Jan 2013 16:18:42 -0500 Subject: 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 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. --- src/backend/parser/parse_clause.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'src/backend/parser/parse_clause.c') diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index dd78500aa93..b9655954cde 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -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 -- cgit v1.2.3