aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/analyze.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2012-07-31 17:56:32 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2012-07-31 17:56:32 -0400
commitb1c891e90b748a5c5aec3504bfac50f2fe7398db (patch)
tree8bc02e2c5276f2bd8f967de181f6b40331dca170 /src/backend/parser/analyze.c
parent118b941614cece1946d7eee31040061397102e05 (diff)
downloadpostgresql-b1c891e90b748a5c5aec3504bfac50f2fe7398db.tar.gz
postgresql-b1c891e90b748a5c5aec3504bfac50f2fe7398db.zip
Fix WITH attached to a nested set operation (UNION/INTERSECT/EXCEPT).
Parse analysis neglected to cover the case of a WITH clause attached to an intermediate-level set operation; it only handled WITH at the top level or WITH attached to a leaf-level SELECT. Per report from Adam Mackler. In HEAD, I rearranged the order of SelectStmt's fields to put withClause with the other fields that can appear on non-leaf SelectStmts. In back branches, leave it alone to avoid a possible ABI break for third-party code. Back-patch to 8.4 where WITH support was added.
Diffstat (limited to 'src/backend/parser/analyze.c')
-rw-r--r--src/backend/parser/analyze.c29
1 files changed, 16 insertions, 13 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index e4a4e3a5e48..114454951d1 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -1273,6 +1273,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
Node *limitOffset;
Node *limitCount;
List *lockingClause;
+ WithClause *withClause;
Node *node;
ListCell *left_tlist,
*lct,
@@ -1289,14 +1290,6 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
qry->commandType = CMD_SELECT;
- /* process the WITH clause independently of all else */
- if (stmt->withClause)
- {
- qry->hasRecursive = stmt->withClause->recursive;
- qry->cteList = transformWithClause(pstate, stmt->withClause);
- qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
- }
-
/*
* Find leftmost leaf SelectStmt; extract the one-time-only items from it
* and from the top-level node.
@@ -1324,11 +1317,13 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
limitOffset = stmt->limitOffset;
limitCount = stmt->limitCount;
lockingClause = stmt->lockingClause;
+ withClause = stmt->withClause;
stmt->sortClause = NIL;
stmt->limitOffset = NULL;
stmt->limitCount = NULL;
stmt->lockingClause = NIL;
+ stmt->withClause = NULL;
/* We don't support FOR UPDATE/SHARE with set ops at the moment. */
if (lockingClause)
@@ -1336,6 +1331,14 @@ 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 independently of all else */
+ if (withClause)
+ {
+ qry->hasRecursive = withClause->recursive;
+ qry->cteList = transformWithClause(pstate, withClause);
+ qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
+ }
+
/*
* Recursively transform the components of the tree.
*/
@@ -1534,10 +1537,10 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
errmsg("SELECT FOR UPDATE/SHARE is not allowed with UNION/INTERSECT/EXCEPT")));
/*
- * If an internal node of a set-op tree has ORDER BY, LIMIT, or FOR UPDATE
- * clauses attached, we need to treat it like a leaf node to generate an
- * independent sub-Query tree. Otherwise, it can be represented by a
- * SetOperationStmt node underneath the parent Query.
+ * If an internal node of a set-op tree has ORDER BY, LIMIT, FOR UPDATE,
+ * or WITH clauses attached, we need to treat it like a leaf node to
+ * generate an independent sub-Query tree. Otherwise, it can be
+ * represented by a SetOperationStmt node underneath the parent Query.
*/
if (stmt->op == SETOP_NONE)
{
@@ -1548,7 +1551,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
{
Assert(stmt->larg != NULL && stmt->rarg != NULL);
if (stmt->sortClause || stmt->limitOffset || stmt->limitCount ||
- stmt->lockingClause)
+ stmt->lockingClause || stmt->withClause)
isLeaf = true;
else
isLeaf = false;