Fix xslt_process() to ensure that it inserts a NULL terminator after the
[PostgreSQL.git] / src / backend / parser / parse_cte.c
blob988e8eb7097cbd76d53611f62a415557c8c96a8a
1 /*-------------------------------------------------------------------------
3 * parse_cte.c
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
10 * IDENTIFICATION
11 * $PostgreSQL$
13 *-------------------------------------------------------------------------
15 #include "postgres.h"
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 */
25 typedef enum
27 RECURSION_OK,
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) */
33 } RecursionContext;
35 /* Associated error messages --- each must have one %s for CTE name */
36 static const char *const recursion_errormsgs[] = {
37 /* RECURSION_OK */
38 NULL,
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
62 * identified */
63 Bitmapset *depends_on; /* CTEs depended on (not including self) */
64 } CteItem;
66 /* CteState is what we need to pass around in the tree walkers */
67 typedef struct CteState
69 /* global state: */
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 */
79 } CteState;
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
99 * Query nodes.
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.)
105 List *
106 transformWithClause(ParseState *pstate, WithClause *withClause)
108 ListCell *lc;
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);
124 ListCell *rest;
126 for_each_cell(rest, lnext(lc))
128 CommonTableExpr *cte2 = (CommonTableExpr *) lfirst(rest);
130 if (strcmp(cte->ctename, cte2->ctename) == 0)
131 ereport(ERROR,
132 (errcode(ERRCODE_DUPLICATE_ALIAS),
133 errmsg("WITH query name \"%s\" specified more than once",
134 cte2->ctename),
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.
149 CteState cstate;
150 int i;
152 cstate.pstate = pstate;
153 cstate.numitems = list_length(withClause->ctes);
154 cstate.items = (CteItem *) palloc0(cstate.numitems * sizeof(CteItem));
155 i = 0;
156 foreach(lc, withClause->ctes)
158 cstate.items[i].cte = (CommonTableExpr *) lfirst(lc);
159 cstate.items[i].id = i;
160 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)
201 Node *nrt;
202 Query *nrq;
204 if (!cstate.items[i].non_recursive_term)
205 elog(ERROR, "could not find non-recursive term for %s",
206 cte->ctename);
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);
216 else
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.
246 static void
247 analyzeCTE(ParseState *pstate, CommonTableExpr *cte)
249 Query *query;
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)
267 ereport(ERROR,
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);
278 else
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.
286 ListCell *lctlist,
287 *lctyp,
288 *lctypmod;
289 int varattno;
291 lctyp = list_head(cte->ctecoltypes);
292 lctypmod = list_head(cte->ctecoltypmods);
293 varattno = 0;
294 foreach(lctlist, query->targetList)
296 TargetEntry *te = (TargetEntry *) lfirst(lctlist);
297 Node *texpr;
299 if (te->resjunk)
300 continue;
301 varattno++;
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))
308 ereport(ERROR,
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),
315 exprTypmod(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
329 static void
330 analyzeCTETargetList(ParseState *pstate, CommonTableExpr *cte, List *tlist)
332 int numaliases;
333 int varattno;
334 ListCell *tlistitem;
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
341 * handling.)
343 cte->ctecolnames = copyObject(cte->aliascolnames);
344 cte->ctecoltypes = cte->ctecoltypmods = NIL;
345 numaliases = list_length(cte->aliascolnames);
346 varattno = 0;
347 foreach(tlistitem, tlist)
349 TargetEntry *te = (TargetEntry *) lfirst(tlistitem);
350 Oid coltype;
351 int32 coltypmod;
353 if (te->resjunk)
354 continue;
355 varattno++;
356 Assert(varattno == te->resno);
357 if (varattno > numaliases)
359 char *attrname;
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)
377 coltype = TEXTOID;
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)
384 ereport(ERROR,
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.
396 static void
397 makeDependencyGraph(CteState *cstate)
399 int i;
401 for (i = 0; i < cstate->numitems; i++)
403 CommonTableExpr *cte = cstate->items[i].cte;
405 cstate->curitem = i;
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.
418 static bool
419 makeDependencyGraphWalker(Node *node, CteState *cstate)
421 if (node == NULL)
422 return false;
423 if (IsA(node, RangeVar))
425 RangeVar *rv = (RangeVar *) node;
427 /* If unqualified name, might be a CTE reference */
428 if (!rv->schemaname)
430 ListCell *lc;
431 int i;
433 /* ... but first see if it's captured by an inner WITH */
434 foreach(lc, cstate->innerwiths)
436 List *withlist = (List *) lfirst(lc);
437 ListCell *lc2;
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;
457 if (i != myindex)
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);
464 else
466 /* Found out this one is self-referential */
467 cte->cterecursive = true;
469 break;
473 return false;
475 if (IsA(node, SelectStmt))
477 SelectStmt *stmt = (SelectStmt *) node;
478 ListCell *lc;
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,
490 cstate->innerwiths);
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,
499 (void *) cstate);
500 cstate->innerwiths = list_delete_first(cstate->innerwiths);
502 else
505 * In the non-RECURSIVE case, query names are visible to the
506 * WITH items after them and to the main query.
508 ListCell *cell1;
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,
521 (void *) cstate);
522 cstate->innerwiths = list_delete_first(cstate->innerwiths);
524 /* We're done examining the SelectStmt */
525 return false;
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
534 * code above.
536 return false;
538 return raw_expression_tree_walker(node,
539 makeDependencyGraphWalker,
540 (void *) cstate);
544 * Sort by dependencies, using a standard topological sort operation
546 static void
547 TopologicalSort(ParseState *pstate, CteItem *items, int numitems)
549 int i,
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))
559 break;
562 /* if we didn't find one, the dependency graph has a cycle */
563 if (j >= numitems)
564 ereport(ERROR,
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
571 * dependencies.
573 if (i != j)
575 CteItem tmp;
577 tmp = items[i];
578 items[i] = items[j];
579 items[j] = tmp;
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,
589 items[i].id);
596 * Check that recursive queries are well-formed.
598 static void
599 checkWellFormedRecursion(CteState *cstate)
601 int i;
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)
612 continue;
614 /* Must have top-level UNION */
615 if (stmt->op != SETOP_UNION)
616 ereport(ERROR,
617 (errcode(ERRCODE_INVALID_RECURSION),
618 errmsg("recursive query \"%s\" does not have the form non-recursive-term UNION [ALL] recursive-term",
619 cte->ctename),
620 parser_errposition(cstate->pstate, cte->location)));
622 /* The left-hand operand mustn't contain self-reference at all */
623 cstate->curitem = i;
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 */
631 cstate->curitem = i;
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)
648 ereport(ERROR,
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)
654 ereport(ERROR,
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)
660 ereport(ERROR,
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)
666 ereport(ERROR,
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.
682 static bool
683 checkWellFormedRecursionWalker(Node *node, CteState *cstate)
685 RecursionContext save_context = cstate->context;
687 if (node == NULL)
688 return false;
689 if (IsA(node, RangeVar))
691 RangeVar *rv = (RangeVar *) node;
693 /* If unqualified name, might be a CTE reference */
694 if (!rv->schemaname)
696 ListCell *lc;
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);
703 ListCell *lc2;
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)
720 ereport(ERROR,
721 (errcode(ERRCODE_INVALID_RECURSION),
722 errmsg(recursion_errormsgs[cstate->context],
723 mycte->ctename),
724 parser_errposition(cstate->pstate,
725 rv->location)));
726 /* Count references */
727 if (++(cstate->selfrefcount) > 1)
728 ereport(ERROR,
729 (errcode(ERRCODE_INVALID_RECURSION),
730 errmsg("recursive reference to query \"%s\" must not appear more than once",
731 mycte->ctename),
732 parser_errposition(cstate->pstate,
733 rv->location)));
736 return false;
738 if (IsA(node, SelectStmt))
740 SelectStmt *stmt = (SelectStmt *) node;
741 ListCell *lc;
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,
753 cstate->innerwiths);
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);
763 else
766 * In the non-RECURSIVE case, query names are visible to the
767 * WITH items after them and to the main query.
769 ListCell *cell1;
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);
784 else
785 checkWellFormedSelectStmt(stmt, cstate);
786 /* We're done examining the SelectStmt */
787 return false;
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
794 * code above.
796 return false;
798 if (IsA(node, JoinExpr))
800 JoinExpr *j = (JoinExpr *) node;
802 switch (j->jointype)
804 case JOIN_INNER:
805 checkWellFormedRecursionWalker(j->larg, cstate);
806 checkWellFormedRecursionWalker(j->rarg, cstate);
807 checkWellFormedRecursionWalker(j->quals, cstate);
808 break;
809 case JOIN_LEFT:
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);
816 break;
817 case JOIN_FULL:
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);
824 break;
825 case JOIN_RIGHT:
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);
832 break;
833 default:
834 elog(ERROR, "unrecognized join type: %d",
835 (int) j->jointype);
837 return false;
839 if (IsA(node, SubLink))
841 SubLink *sl = (SubLink *) node;
844 * we intentionally override outer context, since subquery is
845 * independent
847 cstate->context = RECURSION_SUBLINK;
848 checkWellFormedRecursionWalker(sl->subselect, cstate);
849 cstate->context = save_context;
850 checkWellFormedRecursionWalker(sl->testexpr, cstate);
851 return false;
853 return raw_expression_tree_walker(node,
854 checkWellFormedRecursionWalker,
855 (void *) cstate);
859 * subroutine for checkWellFormedRecursionWalker: process a SelectStmt
860 * without worrying about its WITH clause
862 static void
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,
872 (void *) cstate);
874 else
876 switch (stmt->op)
878 case SETOP_NONE:
879 case SETOP_UNION:
880 raw_expression_tree_walker((Node *) stmt,
881 checkWellFormedRecursionWalker,
882 (void *) cstate);
883 break;
884 case SETOP_INTERSECT:
885 if (stmt->all)
886 cstate->context = RECURSION_INTERSECT;
887 checkWellFormedRecursionWalker((Node *) stmt->larg,
888 cstate);
889 checkWellFormedRecursionWalker((Node *) stmt->rarg,
890 cstate);
891 cstate->context = save_context;
892 checkWellFormedRecursionWalker((Node *) stmt->sortClause,
893 cstate);
894 checkWellFormedRecursionWalker((Node *) stmt->limitOffset,
895 cstate);
896 checkWellFormedRecursionWalker((Node *) stmt->limitCount,
897 cstate);
898 checkWellFormedRecursionWalker((Node *) stmt->lockingClause,
899 cstate);
900 break;
901 break;
902 case SETOP_EXCEPT:
903 if (stmt->all)
904 cstate->context = RECURSION_EXCEPT;
905 checkWellFormedRecursionWalker((Node *) stmt->larg,
906 cstate);
907 cstate->context = RECURSION_EXCEPT;
908 checkWellFormedRecursionWalker((Node *) stmt->rarg,
909 cstate);
910 cstate->context = save_context;
911 checkWellFormedRecursionWalker((Node *) stmt->sortClause,
912 cstate);
913 checkWellFormedRecursionWalker((Node *) stmt->limitOffset,
914 cstate);
915 checkWellFormedRecursionWalker((Node *) stmt->limitCount,
916 cstate);
917 checkWellFormedRecursionWalker((Node *) stmt->lockingClause,
918 cstate);
919 break;
920 default:
921 elog(ERROR, "unrecognized set op: %d",
922 (int) stmt->op);