1 /*-------------------------------------------------------------------------
4 * handle CTEs (common table expressions) in parser
6 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
13 *-------------------------------------------------------------------------
17 #include "catalog/pg_type.h"
18 #include "nodes/nodeFuncs.h"
19 #include "parser/analyze.h"
20 #include "parser/parse_cte.h"
21 #include "utils/builtins.h"
24 /* Enumeration of contexts in which a self-reference is disallowed */
28 RECURSION_NONRECURSIVETERM
, /* inside the left-hand term */
29 RECURSION_SUBLINK
, /* inside a sublink */
30 RECURSION_OUTERJOIN
, /* inside nullable side of an outer join */
31 RECURSION_INTERSECT
, /* underneath INTERSECT (ALL) */
32 RECURSION_EXCEPT
/* underneath EXCEPT (ALL) */
35 /* Associated error messages --- each must have one %s for CTE name */
36 static const char *const recursion_errormsgs
[] = {
39 /* RECURSION_NONRECURSIVETERM */
40 gettext_noop("recursive reference to query \"%s\" must not appear within its non-recursive term"),
41 /* RECURSION_SUBLINK */
42 gettext_noop("recursive reference to query \"%s\" must not appear within a subquery"),
43 /* RECURSION_OUTERJOIN */
44 gettext_noop("recursive reference to query \"%s\" must not appear within an outer join"),
45 /* RECURSION_INTERSECT */
46 gettext_noop("recursive reference to query \"%s\" must not appear within INTERSECT"),
47 /* RECURSION_EXCEPT */
48 gettext_noop("recursive reference to query \"%s\" must not appear within EXCEPT")
52 * For WITH RECURSIVE, we have to find an ordering of the clause members
53 * with no forward references, and determine which members are recursive
54 * (i.e., self-referential). It is convenient to do this with an array
55 * of CteItems instead of a list of CommonTableExprs.
57 typedef struct CteItem
59 CommonTableExpr
*cte
; /* One CTE to examine */
60 int id
; /* Its ID number for dependencies */
61 Node
*non_recursive_term
; /* Its nonrecursive part, if
63 Bitmapset
*depends_on
; /* CTEs depended on (not including self) */
66 /* CteState is what we need to pass around in the tree walkers */
67 typedef struct CteState
70 ParseState
*pstate
; /* global parse state */
71 CteItem
*items
; /* array of CTEs and extra data */
72 int numitems
; /* number of CTEs */
73 /* working state during a tree walk: */
74 int curitem
; /* index of item currently being examined */
75 List
*innerwiths
; /* list of lists of CommonTableExpr */
76 /* working state for checkWellFormedRecursion walk only: */
77 int selfrefcount
; /* number of self-references detected */
78 RecursionContext context
; /* context to allow or disallow self-ref */
82 static void analyzeCTE(ParseState
*pstate
, CommonTableExpr
*cte
);
83 static void analyzeCTETargetList(ParseState
*pstate
, CommonTableExpr
*cte
, List
*tlist
);
85 /* Dependency processing functions */
86 static void makeDependencyGraph(CteState
*cstate
);
87 static bool makeDependencyGraphWalker(Node
*node
, CteState
*cstate
);
88 static void TopologicalSort(ParseState
*pstate
, CteItem
*items
, int numitems
);
90 /* Recursion validity checker functions */
91 static void checkWellFormedRecursion(CteState
*cstate
);
92 static bool checkWellFormedRecursionWalker(Node
*node
, CteState
*cstate
);
93 static void checkWellFormedSelectStmt(SelectStmt
*stmt
, CteState
*cstate
);
97 * transformWithClause -
98 * Transform the list of WITH clause "common table expressions" into
101 * The result is the list of transformed CTEs to be put into the output
102 * Query. (This is in fact the same as the ending value of p_ctenamespace,
103 * but it seems cleaner to not expose that in the function's API.)
106 transformWithClause(ParseState
*pstate
, WithClause
*withClause
)
110 /* Only one WITH clause per query level */
111 Assert(pstate
->p_ctenamespace
== NIL
);
112 Assert(pstate
->p_future_ctes
== NIL
);
115 * For either type of WITH, there must not be duplicate CTE names in the
116 * list. Check this right away so we needn't worry later.
118 * Also, tentatively mark each CTE as non-recursive, and initialize its
119 * reference count to zero.
121 foreach(lc
, withClause
->ctes
)
123 CommonTableExpr
*cte
= (CommonTableExpr
*) lfirst(lc
);
126 for_each_cell(rest
, lnext(lc
))
128 CommonTableExpr
*cte2
= (CommonTableExpr
*) lfirst(rest
);
130 if (strcmp(cte
->ctename
, cte2
->ctename
) == 0)
132 (errcode(ERRCODE_DUPLICATE_ALIAS
),
133 errmsg("WITH query name \"%s\" specified more than once",
135 parser_errposition(pstate
, cte2
->location
)));
138 cte
->cterecursive
= false;
139 cte
->cterefcount
= 0;
142 if (withClause
->recursive
)
145 * For WITH RECURSIVE, we rearrange the list elements if needed to
146 * eliminate forward references. First, build a work array and set up
147 * the data structure needed by the tree walkers.
152 cstate
.pstate
= pstate
;
153 cstate
.numitems
= list_length(withClause
->ctes
);
154 cstate
.items
= (CteItem
*) palloc0(cstate
.numitems
* sizeof(CteItem
));
156 foreach(lc
, withClause
->ctes
)
158 cstate
.items
[i
].cte
= (CommonTableExpr
*) lfirst(lc
);
159 cstate
.items
[i
].id
= i
;
164 * Find all the dependencies and sort the CteItems into a safe
165 * processing order. Also, mark CTEs that contain self-references.
167 makeDependencyGraph(&cstate
);
170 * Check that recursive queries are well-formed.
172 checkWellFormedRecursion(&cstate
);
175 * Set up the ctenamespace for parse analysis. Per spec, all the WITH
176 * items are visible to all others, so stuff them all in before parse
177 * analysis. We build the list in safe processing order so that the
178 * planner can process the queries in sequence.
180 for (i
= 0; i
< cstate
.numitems
; i
++)
182 CommonTableExpr
*cte
= cstate
.items
[i
].cte
;
184 pstate
->p_ctenamespace
= lappend(pstate
->p_ctenamespace
, cte
);
188 * Do parse analysis in the order determined by the topological sort.
190 for (i
= 0; i
< cstate
.numitems
; i
++)
192 CommonTableExpr
*cte
= cstate
.items
[i
].cte
;
195 * If it's recursive, we have to do a throwaway parse analysis of
196 * the non-recursive term in order to determine the set of output
197 * columns for the recursive CTE.
199 if (cte
->cterecursive
)
204 if (!cstate
.items
[i
].non_recursive_term
)
205 elog(ERROR
, "could not find non-recursive term for %s",
207 /* copy the term to be sure we don't modify original query */
208 nrt
= copyObject(cstate
.items
[i
].non_recursive_term
);
209 nrq
= parse_sub_analyze(nrt
, pstate
);
210 analyzeCTETargetList(pstate
, cte
, nrq
->targetList
);
213 analyzeCTE(pstate
, cte
);
219 * For non-recursive WITH, just analyze each CTE in sequence and then
220 * add it to the ctenamespace. This corresponds to the spec's
221 * definition of the scope of each WITH name. However, to allow error
222 * reports to be aware of the possibility of an erroneous reference,
223 * we maintain a list in p_future_ctes of the not-yet-visible CTEs.
225 pstate
->p_future_ctes
= list_copy(withClause
->ctes
);
227 foreach(lc
, withClause
->ctes
)
229 CommonTableExpr
*cte
= (CommonTableExpr
*) lfirst(lc
);
231 analyzeCTE(pstate
, cte
);
232 pstate
->p_ctenamespace
= lappend(pstate
->p_ctenamespace
, cte
);
233 pstate
->p_future_ctes
= list_delete_first(pstate
->p_future_ctes
);
237 return pstate
->p_ctenamespace
;
242 * Perform the actual parse analysis transformation of one CTE. All
243 * CTEs it depends on have already been loaded into pstate->p_ctenamespace,
244 * and have been marked with the correct output column names/types.
247 analyzeCTE(ParseState
*pstate
, CommonTableExpr
*cte
)
251 /* Analysis not done already */
252 Assert(IsA(cte
->ctequery
, SelectStmt
));
254 query
= parse_sub_analyze(cte
->ctequery
, pstate
);
255 cte
->ctequery
= (Node
*) query
;
258 * Check that we got something reasonable. Many of these conditions are
259 * impossible given restrictions of the grammar, but check 'em anyway.
260 * (These are the same checks as in transformRangeSubselect.)
262 if (!IsA(query
, Query
) ||
263 query
->commandType
!= CMD_SELECT
||
264 query
->utilityStmt
!= NULL
)
265 elog(ERROR
, "unexpected non-SELECT command in subquery in WITH");
266 if (query
->intoClause
)
268 (errcode(ERRCODE_SYNTAX_ERROR
),
269 errmsg("subquery in WITH cannot have SELECT INTO"),
270 parser_errposition(pstate
,
271 exprLocation((Node
*) query
->intoClause
))));
273 if (!cte
->cterecursive
)
275 /* Compute the output column names/types if not done yet */
276 analyzeCTETargetList(pstate
, cte
, query
->targetList
);
281 * Verify that the previously determined output column types match
282 * what the query really produced. We have to check this because the
283 * recursive term could have overridden the non-recursive term, and we
284 * don't have any easy way to fix that.
291 lctyp
= list_head(cte
->ctecoltypes
);
292 lctypmod
= list_head(cte
->ctecoltypmods
);
294 foreach(lctlist
, query
->targetList
)
296 TargetEntry
*te
= (TargetEntry
*) lfirst(lctlist
);
302 Assert(varattno
== te
->resno
);
303 if (lctyp
== NULL
|| lctypmod
== NULL
) /* shouldn't happen */
304 elog(ERROR
, "wrong number of output columns in WITH");
305 texpr
= (Node
*) te
->expr
;
306 if (exprType(texpr
) != lfirst_oid(lctyp
) ||
307 exprTypmod(texpr
) != lfirst_int(lctypmod
))
309 (errcode(ERRCODE_DATATYPE_MISMATCH
),
310 errmsg("recursive query \"%s\" column %d has type %s in non-recursive term but type %s overall",
311 cte
->ctename
, varattno
,
312 format_type_with_typemod(lfirst_oid(lctyp
),
313 lfirst_int(lctypmod
)),
314 format_type_with_typemod(exprType(texpr
),
316 errhint("Cast the output of the non-recursive term to the correct type."),
317 parser_errposition(pstate
, exprLocation(texpr
))));
318 lctyp
= lnext(lctyp
);
319 lctypmod
= lnext(lctypmod
);
321 if (lctyp
!= NULL
|| lctypmod
!= NULL
) /* shouldn't happen */
322 elog(ERROR
, "wrong number of output columns in WITH");
327 * Compute derived fields of a CTE, given the transformed output targetlist
330 analyzeCTETargetList(ParseState
*pstate
, CommonTableExpr
*cte
, List
*tlist
)
337 * We need to determine column names and types. The alias column names
338 * override anything coming from the query itself. (Note: the SQL spec
339 * says that the alias list must be empty or exactly as long as the output
340 * column set; but we allow it to be shorter for consistency with Alias
343 cte
->ctecolnames
= copyObject(cte
->aliascolnames
);
344 cte
->ctecoltypes
= cte
->ctecoltypmods
= NIL
;
345 numaliases
= list_length(cte
->aliascolnames
);
347 foreach(tlistitem
, tlist
)
349 TargetEntry
*te
= (TargetEntry
*) lfirst(tlistitem
);
356 Assert(varattno
== te
->resno
);
357 if (varattno
> numaliases
)
361 attrname
= pstrdup(te
->resname
);
362 cte
->ctecolnames
= lappend(cte
->ctecolnames
, makeString(attrname
));
364 coltype
= exprType((Node
*) te
->expr
);
365 coltypmod
= exprTypmod((Node
*) te
->expr
);
368 * If the CTE is recursive, force the exposed column type of any
369 * "unknown" column to "text". This corresponds to the fact that
370 * SELECT 'foo' UNION SELECT 'bar' will ultimately produce text. We
371 * might see "unknown" as a result of an untyped literal in the
372 * non-recursive term's select list, and if we don't convert to text
373 * then we'll have a mismatch against the UNION result.
375 if (cte
->cterecursive
&& coltype
== UNKNOWNOID
)
378 coltypmod
= -1; /* should be -1 already, but be sure */
380 cte
->ctecoltypes
= lappend_oid(cte
->ctecoltypes
, coltype
);
381 cte
->ctecoltypmods
= lappend_int(cte
->ctecoltypmods
, coltypmod
);
383 if (varattno
< numaliases
)
385 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE
),
386 errmsg("WITH query \"%s\" has %d columns available but %d columns specified",
387 cte
->ctename
, varattno
, numaliases
),
388 parser_errposition(pstate
, cte
->location
)));
393 * Identify the cross-references of a list of WITH RECURSIVE items,
394 * and sort into an order that has no forward references.
397 makeDependencyGraph(CteState
*cstate
)
401 for (i
= 0; i
< cstate
->numitems
; i
++)
403 CommonTableExpr
*cte
= cstate
->items
[i
].cte
;
406 cstate
->innerwiths
= NIL
;
407 makeDependencyGraphWalker((Node
*) cte
->ctequery
, cstate
);
408 Assert(cstate
->innerwiths
== NIL
);
411 TopologicalSort(cstate
->pstate
, cstate
->items
, cstate
->numitems
);
415 * Tree walker function to detect cross-references and self-references of the
416 * CTEs in a WITH RECURSIVE list.
419 makeDependencyGraphWalker(Node
*node
, CteState
*cstate
)
423 if (IsA(node
, RangeVar
))
425 RangeVar
*rv
= (RangeVar
*) node
;
427 /* If unqualified name, might be a CTE reference */
433 /* ... but first see if it's captured by an inner WITH */
434 foreach(lc
, cstate
->innerwiths
)
436 List
*withlist
= (List
*) lfirst(lc
);
439 foreach(lc2
, withlist
)
441 CommonTableExpr
*cte
= (CommonTableExpr
*) lfirst(lc2
);
443 if (strcmp(rv
->relname
, cte
->ctename
) == 0)
444 return false; /* yes, so bail out */
448 /* No, could be a reference to the query level we are working on */
449 for (i
= 0; i
< cstate
->numitems
; i
++)
451 CommonTableExpr
*cte
= cstate
->items
[i
].cte
;
453 if (strcmp(rv
->relname
, cte
->ctename
) == 0)
455 int myindex
= cstate
->curitem
;
459 /* Add cross-item dependency */
460 cstate
->items
[myindex
].depends_on
=
461 bms_add_member(cstate
->items
[myindex
].depends_on
,
462 cstate
->items
[i
].id
);
466 /* Found out this one is self-referential */
467 cte
->cterecursive
= true;
475 if (IsA(node
, SelectStmt
))
477 SelectStmt
*stmt
= (SelectStmt
*) node
;
480 if (stmt
->withClause
)
482 if (stmt
->withClause
->recursive
)
485 * In the RECURSIVE case, all query names of the WITH are
486 * visible to all WITH items as well as the main query. So
487 * push them all on, process, pop them all off.
489 cstate
->innerwiths
= lcons(stmt
->withClause
->ctes
,
491 foreach(lc
, stmt
->withClause
->ctes
)
493 CommonTableExpr
*cte
= (CommonTableExpr
*) lfirst(lc
);
495 (void) makeDependencyGraphWalker(cte
->ctequery
, cstate
);
497 (void) raw_expression_tree_walker(node
,
498 makeDependencyGraphWalker
,
500 cstate
->innerwiths
= list_delete_first(cstate
->innerwiths
);
505 * In the non-RECURSIVE case, query names are visible to the
506 * WITH items after them and to the main query.
510 cstate
->innerwiths
= lcons(NIL
, cstate
->innerwiths
);
511 cell1
= list_head(cstate
->innerwiths
);
512 foreach(lc
, stmt
->withClause
->ctes
)
514 CommonTableExpr
*cte
= (CommonTableExpr
*) lfirst(lc
);
516 (void) makeDependencyGraphWalker(cte
->ctequery
, cstate
);
517 lfirst(cell1
) = lappend((List
*) lfirst(cell1
), cte
);
519 (void) raw_expression_tree_walker(node
,
520 makeDependencyGraphWalker
,
522 cstate
->innerwiths
= list_delete_first(cstate
->innerwiths
);
524 /* We're done examining the SelectStmt */
527 /* if no WITH clause, just fall through for normal processing */
529 if (IsA(node
, WithClause
))
532 * Prevent raw_expression_tree_walker from recursing directly into a
533 * WITH clause. We need that to happen only under the control of the
538 return raw_expression_tree_walker(node
,
539 makeDependencyGraphWalker
,
544 * Sort by dependencies, using a standard topological sort operation
547 TopologicalSort(ParseState
*pstate
, CteItem
*items
, int numitems
)
552 /* for each position in sequence ... */
553 for (i
= 0; i
< numitems
; i
++)
555 /* ... scan the remaining items to find one that has no dependencies */
556 for (j
= i
; j
< numitems
; j
++)
558 if (bms_is_empty(items
[j
].depends_on
))
562 /* if we didn't find one, the dependency graph has a cycle */
565 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
566 errmsg("mutual recursion between WITH items is not implemented"),
567 parser_errposition(pstate
, items
[i
].cte
->location
)));
570 * Found one. Move it to front and remove it from every other item's
583 * Items up through i are known to have no dependencies left, so we
584 * can skip them in this loop.
586 for (j
= i
+ 1; j
< numitems
; j
++)
588 items
[j
].depends_on
= bms_del_member(items
[j
].depends_on
,
596 * Check that recursive queries are well-formed.
599 checkWellFormedRecursion(CteState
*cstate
)
603 for (i
= 0; i
< cstate
->numitems
; i
++)
605 CommonTableExpr
*cte
= cstate
->items
[i
].cte
;
606 SelectStmt
*stmt
= (SelectStmt
*) cte
->ctequery
;
608 Assert(IsA(stmt
, SelectStmt
)); /* not analyzed yet */
610 /* Ignore items that weren't found to be recursive */
611 if (!cte
->cterecursive
)
614 /* Must have top-level UNION */
615 if (stmt
->op
!= SETOP_UNION
)
617 (errcode(ERRCODE_INVALID_RECURSION
),
618 errmsg("recursive query \"%s\" does not have the form non-recursive-term UNION [ALL] recursive-term",
620 parser_errposition(cstate
->pstate
, cte
->location
)));
622 /* The left-hand operand mustn't contain self-reference at all */
624 cstate
->innerwiths
= NIL
;
625 cstate
->selfrefcount
= 0;
626 cstate
->context
= RECURSION_NONRECURSIVETERM
;
627 checkWellFormedRecursionWalker((Node
*) stmt
->larg
, cstate
);
628 Assert(cstate
->innerwiths
== NIL
);
630 /* Right-hand operand should contain one reference in a valid place */
632 cstate
->innerwiths
= NIL
;
633 cstate
->selfrefcount
= 0;
634 cstate
->context
= RECURSION_OK
;
635 checkWellFormedRecursionWalker((Node
*) stmt
->rarg
, cstate
);
636 Assert(cstate
->innerwiths
== NIL
);
637 if (cstate
->selfrefcount
!= 1) /* shouldn't happen */
638 elog(ERROR
, "missing recursive reference");
641 * Disallow ORDER BY and similar decoration atop the UNION. These
642 * don't make sense because it's impossible to figure out what they
643 * mean when we have only part of the recursive query's results. (If
644 * we did allow them, we'd have to check for recursive references
645 * inside these subtrees.)
647 if (stmt
->sortClause
)
649 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
650 errmsg("ORDER BY in a recursive query is not implemented"),
651 parser_errposition(cstate
->pstate
,
652 exprLocation((Node
*) stmt
->sortClause
))));
653 if (stmt
->limitOffset
)
655 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
656 errmsg("OFFSET in a recursive query is not implemented"),
657 parser_errposition(cstate
->pstate
,
658 exprLocation(stmt
->limitOffset
))));
659 if (stmt
->limitCount
)
661 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
662 errmsg("LIMIT in a recursive query is not implemented"),
663 parser_errposition(cstate
->pstate
,
664 exprLocation(stmt
->limitCount
))));
665 if (stmt
->lockingClause
)
667 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
668 errmsg("FOR UPDATE/SHARE in a recursive query is not implemented"),
669 parser_errposition(cstate
->pstate
,
670 exprLocation((Node
*) stmt
->lockingClause
))));
673 * Save non_recursive_term.
675 cstate
->items
[i
].non_recursive_term
= (Node
*) stmt
->larg
;
680 * Tree walker function to detect invalid self-references in a recursive query.
683 checkWellFormedRecursionWalker(Node
*node
, CteState
*cstate
)
685 RecursionContext save_context
= cstate
->context
;
689 if (IsA(node
, RangeVar
))
691 RangeVar
*rv
= (RangeVar
*) node
;
693 /* If unqualified name, might be a CTE reference */
697 CommonTableExpr
*mycte
;
699 /* ... but first see if it's captured by an inner WITH */
700 foreach(lc
, cstate
->innerwiths
)
702 List
*withlist
= (List
*) lfirst(lc
);
705 foreach(lc2
, withlist
)
707 CommonTableExpr
*cte
= (CommonTableExpr
*) lfirst(lc2
);
709 if (strcmp(rv
->relname
, cte
->ctename
) == 0)
710 return false; /* yes, so bail out */
714 /* No, could be a reference to the query level we are working on */
715 mycte
= cstate
->items
[cstate
->curitem
].cte
;
716 if (strcmp(rv
->relname
, mycte
->ctename
) == 0)
718 /* Found a recursive reference to the active query */
719 if (cstate
->context
!= RECURSION_OK
)
721 (errcode(ERRCODE_INVALID_RECURSION
),
722 errmsg(recursion_errormsgs
[cstate
->context
],
724 parser_errposition(cstate
->pstate
,
726 /* Count references */
727 if (++(cstate
->selfrefcount
) > 1)
729 (errcode(ERRCODE_INVALID_RECURSION
),
730 errmsg("recursive reference to query \"%s\" must not appear more than once",
732 parser_errposition(cstate
->pstate
,
738 if (IsA(node
, SelectStmt
))
740 SelectStmt
*stmt
= (SelectStmt
*) node
;
743 if (stmt
->withClause
)
745 if (stmt
->withClause
->recursive
)
748 * In the RECURSIVE case, all query names of the WITH are
749 * visible to all WITH items as well as the main query. So
750 * push them all on, process, pop them all off.
752 cstate
->innerwiths
= lcons(stmt
->withClause
->ctes
,
754 foreach(lc
, stmt
->withClause
->ctes
)
756 CommonTableExpr
*cte
= (CommonTableExpr
*) lfirst(lc
);
758 (void) checkWellFormedRecursionWalker(cte
->ctequery
, cstate
);
760 checkWellFormedSelectStmt(stmt
, cstate
);
761 cstate
->innerwiths
= list_delete_first(cstate
->innerwiths
);
766 * In the non-RECURSIVE case, query names are visible to the
767 * WITH items after them and to the main query.
771 cstate
->innerwiths
= lcons(NIL
, cstate
->innerwiths
);
772 cell1
= list_head(cstate
->innerwiths
);
773 foreach(lc
, stmt
->withClause
->ctes
)
775 CommonTableExpr
*cte
= (CommonTableExpr
*) lfirst(lc
);
777 (void) checkWellFormedRecursionWalker(cte
->ctequery
, cstate
);
778 lfirst(cell1
) = lappend((List
*) lfirst(cell1
), cte
);
780 checkWellFormedSelectStmt(stmt
, cstate
);
781 cstate
->innerwiths
= list_delete_first(cstate
->innerwiths
);
785 checkWellFormedSelectStmt(stmt
, cstate
);
786 /* We're done examining the SelectStmt */
789 if (IsA(node
, WithClause
))
792 * Prevent raw_expression_tree_walker from recursing directly into a
793 * WITH clause. We need that to happen only under the control of the
798 if (IsA(node
, JoinExpr
))
800 JoinExpr
*j
= (JoinExpr
*) node
;
805 checkWellFormedRecursionWalker(j
->larg
, cstate
);
806 checkWellFormedRecursionWalker(j
->rarg
, cstate
);
807 checkWellFormedRecursionWalker(j
->quals
, cstate
);
810 checkWellFormedRecursionWalker(j
->larg
, cstate
);
811 if (save_context
== RECURSION_OK
)
812 cstate
->context
= RECURSION_OUTERJOIN
;
813 checkWellFormedRecursionWalker(j
->rarg
, cstate
);
814 cstate
->context
= save_context
;
815 checkWellFormedRecursionWalker(j
->quals
, cstate
);
818 if (save_context
== RECURSION_OK
)
819 cstate
->context
= RECURSION_OUTERJOIN
;
820 checkWellFormedRecursionWalker(j
->larg
, cstate
);
821 checkWellFormedRecursionWalker(j
->rarg
, cstate
);
822 cstate
->context
= save_context
;
823 checkWellFormedRecursionWalker(j
->quals
, cstate
);
826 if (save_context
== RECURSION_OK
)
827 cstate
->context
= RECURSION_OUTERJOIN
;
828 checkWellFormedRecursionWalker(j
->larg
, cstate
);
829 cstate
->context
= save_context
;
830 checkWellFormedRecursionWalker(j
->rarg
, cstate
);
831 checkWellFormedRecursionWalker(j
->quals
, cstate
);
834 elog(ERROR
, "unrecognized join type: %d",
839 if (IsA(node
, SubLink
))
841 SubLink
*sl
= (SubLink
*) node
;
844 * we intentionally override outer context, since subquery is
847 cstate
->context
= RECURSION_SUBLINK
;
848 checkWellFormedRecursionWalker(sl
->subselect
, cstate
);
849 cstate
->context
= save_context
;
850 checkWellFormedRecursionWalker(sl
->testexpr
, cstate
);
853 return raw_expression_tree_walker(node
,
854 checkWellFormedRecursionWalker
,
859 * subroutine for checkWellFormedRecursionWalker: process a SelectStmt
860 * without worrying about its WITH clause
863 checkWellFormedSelectStmt(SelectStmt
*stmt
, CteState
*cstate
)
865 RecursionContext save_context
= cstate
->context
;
867 if (save_context
!= RECURSION_OK
)
869 /* just recurse without changing state */
870 raw_expression_tree_walker((Node
*) stmt
,
871 checkWellFormedRecursionWalker
,
880 raw_expression_tree_walker((Node
*) stmt
,
881 checkWellFormedRecursionWalker
,
884 case SETOP_INTERSECT
:
886 cstate
->context
= RECURSION_INTERSECT
;
887 checkWellFormedRecursionWalker((Node
*) stmt
->larg
,
889 checkWellFormedRecursionWalker((Node
*) stmt
->rarg
,
891 cstate
->context
= save_context
;
892 checkWellFormedRecursionWalker((Node
*) stmt
->sortClause
,
894 checkWellFormedRecursionWalker((Node
*) stmt
->limitOffset
,
896 checkWellFormedRecursionWalker((Node
*) stmt
->limitCount
,
898 checkWellFormedRecursionWalker((Node
*) stmt
->lockingClause
,
904 cstate
->context
= RECURSION_EXCEPT
;
905 checkWellFormedRecursionWalker((Node
*) stmt
->larg
,
907 cstate
->context
= RECURSION_EXCEPT
;
908 checkWellFormedRecursionWalker((Node
*) stmt
->rarg
,
910 cstate
->context
= save_context
;
911 checkWellFormedRecursionWalker((Node
*) stmt
->sortClause
,
913 checkWellFormedRecursionWalker((Node
*) stmt
->limitOffset
,
915 checkWellFormedRecursionWalker((Node
*) stmt
->limitCount
,
917 checkWellFormedRecursionWalker((Node
*) stmt
->lockingClause
,
921 elog(ERROR
, "unrecognized set op: %d",