diff options
Diffstat (limited to 'src/backend/parser/parse_clause.c')
-rw-r--r-- | src/backend/parser/parse_clause.c | 58 |
1 files changed, 54 insertions, 4 deletions
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index 2f547f29be6..dbf17759617 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.179 2008/09/01 20:42:44 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.180 2008/10/04 21:56:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -54,6 +54,8 @@ static Node *transformJoinOnClause(ParseState *pstate, JoinExpr *j, List *relnamespace, Relids containedRels); static RangeTblEntry *transformTableEntry(ParseState *pstate, RangeVar *r); +static RangeTblEntry *transformCTEReference(ParseState *pstate, RangeVar *r, + CommonTableExpr *cte, Index levelsup); static RangeTblEntry *transformRangeSubselect(ParseState *pstate, RangeSubselect *r); static RangeTblEntry *transformRangeFunction(ParseState *pstate, @@ -422,6 +424,20 @@ transformTableEntry(ParseState *pstate, RangeVar *r) return rte; } +/* + * transformCTEReference --- transform a RangeVar that references a common + * table expression (ie, a sub-SELECT defined in a WITH clause) + */ +static RangeTblEntry * +transformCTEReference(ParseState *pstate, RangeVar *r, + CommonTableExpr *cte, Index levelsup) +{ + RangeTblEntry *rte; + + rte = addRangeTableEntryForCTE(pstate, cte, levelsup, r->alias, true); + + return rte; +} /* * transformRangeSubselect --- transform a sub-SELECT appearing in FROM @@ -609,12 +625,46 @@ transformFromClauseItem(ParseState *pstate, Node *n, { if (IsA(n, RangeVar)) { - /* Plain relation reference */ + /* Plain relation reference, or perhaps a CTE reference */ + RangeVar *rv = (RangeVar *) n; RangeTblRef *rtr; - RangeTblEntry *rte; + RangeTblEntry *rte = NULL; int rtindex; - rte = transformTableEntry(pstate, (RangeVar *) n); + /* + * If it is an unqualified name, it might be a reference to some + * CTE visible in this or a parent query. + */ + if (!rv->schemaname) + { + ParseState *ps; + Index levelsup; + + for (ps = pstate, levelsup = 0; + ps != NULL; + ps = ps->parentParseState, levelsup++) + { + ListCell *lc; + + foreach(lc, ps->p_ctenamespace) + { + CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc); + + if (strcmp(rv->relname, cte->ctename) == 0) + { + rte = transformCTEReference(pstate, rv, cte, levelsup); + break; + } + } + if (rte) + break; + } + } + + /* if not found as a CTE, must be a table reference */ + if (!rte) + rte = transformTableEntry(pstate, rv); + /* assume new rte is at end */ rtindex = list_length(pstate->p_rtable); Assert(rte == rt_fetch(rtindex, pstate->p_rtable)); |