diff options
Diffstat (limited to 'src/backend/parser/analyze.c')
-rw-r--r-- | src/backend/parser/analyze.c | 107 |
1 files changed, 98 insertions, 9 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 18585b860b4..8934c04bb24 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -17,7 +17,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.379 2008/09/01 20:42:44 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.380 2008/10/04 21:56:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -32,6 +32,7 @@ #include "parser/parse_agg.h" #include "parser/parse_clause.h" #include "parser/parse_coerce.h" +#include "parser/parse_cte.h" #include "parser/parse_oper.h" #include "parser/parse_relation.h" #include "parser/parse_target.h" @@ -309,6 +310,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt) pstate->p_relnamespace = NIL; sub_varnamespace = pstate->p_varnamespace; pstate->p_varnamespace = NIL; + /* There can't be any outer WITH to worry about */ + Assert(pstate->p_ctenamespace == NIL); } else { @@ -447,6 +450,13 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt) List *exprsLists = NIL; int sublist_length = -1; + /* process the WITH clause */ + if (selectStmt->withClause) + { + qry->hasRecursive = selectStmt->withClause->recursive; + qry->cteList = transformWithClause(pstate, selectStmt->withClause); + } + foreach(lc, selectStmt->valuesLists) { List *sublist = (List *) lfirst(lc); @@ -540,6 +550,13 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt) Assert(list_length(valuesLists) == 1); + /* process the WITH clause */ + if (selectStmt->withClause) + { + qry->hasRecursive = selectStmt->withClause->recursive; + qry->cteList = transformWithClause(pstate, selectStmt->withClause); + } + /* Do basic expression transformation (same as a ROW() expr) */ exprList = transformExpressionList(pstate, (List *) linitial(valuesLists)); @@ -694,6 +711,13 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt) /* make FOR UPDATE/FOR SHARE info available to addRangeTableEntry */ pstate->p_locking_clause = stmt->lockingClause; + /* process the WITH clause */ + if (stmt->withClause) + { + qry->hasRecursive = stmt->withClause->recursive; + qry->cteList = transformWithClause(pstate, stmt->withClause); + } + /* process the FROM clause */ transformFromClause(pstate, stmt->fromClause); @@ -814,6 +838,13 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt) Assert(stmt->havingClause == NULL); Assert(stmt->op == SETOP_NONE); + /* process the WITH clause */ + if (stmt->withClause) + { + qry->hasRecursive = stmt->withClause->recursive; + qry->cteList = transformWithClause(pstate, stmt->withClause); + } + /* * For each row of VALUES, transform the raw expressions and gather type * information. This is also a handy place to reject DEFAULT nodes, which @@ -1059,6 +1090,13 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("SELECT FOR UPDATE/SHARE is not allowed with UNION/INTERSECT/EXCEPT"))); + /* process the WITH clause */ + if (stmt->withClause) + { + qry->hasRecursive = stmt->withClause->recursive; + qry->cteList = transformWithClause(pstate, stmt->withClause); + } + /* * Recursively transform the components of the tree. */ @@ -1101,21 +1139,22 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt) TargetEntry *lefttle = (TargetEntry *) lfirst(left_tlist); char *colName; TargetEntry *tle; - Expr *expr; + Var *var; Assert(!lefttle->resjunk); colName = pstrdup(lefttle->resname); - expr = (Expr *) makeVar(leftmostRTI, - lefttle->resno, - colType, - colTypmod, - 0); - tle = makeTargetEntry(expr, + var = makeVar(leftmostRTI, + lefttle->resno, + colType, + colTypmod, + 0); + var->location = exprLocation((Node *) lefttle->expr); + tle = makeTargetEntry((Expr *) var, (AttrNumber) pstate->p_next_resno++, colName, false); qry->targetList = lappend(qry->targetList, tle); - targetvars = lappend(targetvars, expr); + targetvars = lappend(targetvars, var); targetnames = lappend(targetnames, makeString(colName)); left_tlist = lnext(left_tlist); } @@ -1841,6 +1880,30 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc) */ transformLockingClause(pstate, rte->subquery, allrels); break; + case RTE_CTE: + { + /* + * We allow FOR UPDATE/SHARE of a WITH query to be + * propagated into the WITH, but it doesn't seem + * very sane to allow this for a reference to an + * outer-level WITH. And it definitely wouldn't + * work for a self-reference, since we're not done + * analyzing the CTE anyway. + */ + CommonTableExpr *cte; + + if (rte->ctelevelsup > 0 || rte->self_reference) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("SELECT FOR UPDATE/SHARE cannot be applied to an outer-level WITH query"))); + cte = GetCTEForRTE(pstate, rte); + /* should be analyzed by now */ + Assert(IsA(cte->ctequery, Query)); + transformLockingClause(pstate, + (Query *) cte->ctequery, + allrels); + } + break; default: /* ignore JOIN, SPECIAL, FUNCTION RTEs */ break; @@ -1908,6 +1971,32 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc) errmsg("SELECT FOR UPDATE/SHARE cannot be applied to VALUES"), parser_errposition(pstate, thisrel->location))); break; + case RTE_CTE: + { + /* + * We allow FOR UPDATE/SHARE of a WITH query + * to be propagated into the WITH, but it + * doesn't seem very sane to allow this for a + * reference to an outer-level WITH. And it + * definitely wouldn't work for a + * self-reference, since we're not done + * analyzing the CTE anyway. + */ + CommonTableExpr *cte; + + if (rte->ctelevelsup > 0 || rte->self_reference) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("SELECT FOR UPDATE/SHARE cannot be applied to an outer-level WITH query"), + parser_errposition(pstate, thisrel->location))); + cte = GetCTEForRTE(pstate, rte); + /* should be analyzed by now */ + Assert(IsA(cte->ctequery, Query)); + transformLockingClause(pstate, + (Query *) cte->ctequery, + allrels); + } + break; default: elog(ERROR, "unrecognized RTE type: %d", (int) rte->rtekind); |