aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_cte.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/parse_cte.c')
-rw-r--r--src/backend/parser/parse_cte.c53
1 files changed, 33 insertions, 20 deletions
diff --git a/src/backend/parser/parse_cte.c b/src/backend/parser/parse_cte.c
index 6826d4f36a1..de9ae9b4834 100644
--- a/src/backend/parser/parse_cte.c
+++ b/src/backend/parser/parse_cte.c
@@ -877,25 +877,14 @@ checkWellFormedRecursion(CteState *cstate)
cte->ctename),
parser_errposition(cstate->pstate, cte->location)));
- /* The left-hand operand mustn't contain self-reference at all */
- cstate->curitem = i;
- cstate->innerwiths = NIL;
- cstate->selfrefcount = 0;
- cstate->context = RECURSION_NONRECURSIVETERM;
- checkWellFormedRecursionWalker((Node *) stmt->larg, cstate);
- Assert(cstate->innerwiths == NIL);
-
- /* Right-hand operand should contain one reference in a valid place */
- cstate->curitem = i;
- cstate->innerwiths = NIL;
- cstate->selfrefcount = 0;
- cstate->context = RECURSION_OK;
- checkWellFormedRecursionWalker((Node *) stmt->rarg, cstate);
- Assert(cstate->innerwiths == NIL);
- if (cstate->selfrefcount != 1) /* shouldn't happen */
- elog(ERROR, "missing recursive reference");
-
- /* WITH mustn't contain self-reference, either */
+ /*
+ * Really, we should insist that there not be a top-level WITH, since
+ * syntactically that would enclose the UNION. However, we've not
+ * done so in the past and it's probably too late to change. Settle
+ * for insisting that WITH not contain a self-reference. Test this
+ * before examining the UNION arms, to avoid issuing confusing errors
+ * in such cases.
+ */
if (stmt->withClause)
{
cstate->curitem = i;
@@ -912,7 +901,9 @@ checkWellFormedRecursion(CteState *cstate)
* don't make sense because it's impossible to figure out what they
* mean when we have only part of the recursive query's results. (If
* we did allow them, we'd have to check for recursive references
- * inside these subtrees.)
+ * inside these subtrees. As for WITH, we have to do this before
+ * examining the UNION arms, to avoid issuing confusing errors if
+ * there is a recursive reference here.)
*/
if (stmt->sortClause)
ereport(ERROR,
@@ -938,6 +929,28 @@ checkWellFormedRecursion(CteState *cstate)
errmsg("FOR UPDATE/SHARE in a recursive query is not implemented"),
parser_errposition(cstate->pstate,
exprLocation((Node *) stmt->lockingClause))));
+
+ /*
+ * Now we can get on with checking the UNION operands themselves.
+ *
+ * The left-hand operand mustn't contain a self-reference at all.
+ */
+ cstate->curitem = i;
+ cstate->innerwiths = NIL;
+ cstate->selfrefcount = 0;
+ cstate->context = RECURSION_NONRECURSIVETERM;
+ checkWellFormedRecursionWalker((Node *) stmt->larg, cstate);
+ Assert(cstate->innerwiths == NIL);
+
+ /* Right-hand operand should contain one reference in a valid place */
+ cstate->curitem = i;
+ cstate->innerwiths = NIL;
+ cstate->selfrefcount = 0;
+ cstate->context = RECURSION_OK;
+ checkWellFormedRecursionWalker((Node *) stmt->rarg, cstate);
+ Assert(cstate->innerwiths == NIL);
+ if (cstate->selfrefcount != 1) /* shouldn't happen */
+ elog(ERROR, "missing recursive reference");
}
}