From 3786b9b4668743b99e837fe276e14be1f1bdfde9 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 31 Jul 2012 17:56:27 -0400 Subject: 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. --- src/backend/parser/analyze.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'src/backend/parser/analyze.c') diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index bfd3ab941a7..263edb5a7a6 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -1322,6 +1322,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt) Node *limitOffset; Node *limitCount; List *lockingClause; + WithClause *withClause; Node *node; ListCell *left_tlist, *lct, @@ -1338,14 +1339,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. We currently only need to do this in * order to deliver a suitable error message if there's an INTO clause @@ -1375,11 +1368,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) @@ -1387,6 +1382,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. */ @@ -1572,10 +1575,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) { @@ -1586,7 +1589,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; -- cgit v1.2.3