aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/analyze.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/analyze.c')
-rw-r--r--src/backend/parser/analyze.c107
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);