LCOV - code coverage report
Current view: top level - src/backend/parser - parse_cte.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 89.9 % 415 373
Test Date: 2026-03-02 14:15:04 Functions: 100.0 % 10 10
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * parse_cte.c
       4              :  *    handle CTEs (common table expressions) in parser
       5              :  *
       6              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7              :  * Portions Copyright (c) 1994, Regents of the University of California
       8              :  *
       9              :  *
      10              :  * IDENTIFICATION
      11              :  *    src/backend/parser/parse_cte.c
      12              :  *
      13              :  *-------------------------------------------------------------------------
      14              :  */
      15              : #include "postgres.h"
      16              : 
      17              : #include "catalog/pg_collation.h"
      18              : #include "catalog/pg_type.h"
      19              : #include "nodes/nodeFuncs.h"
      20              : #include "parser/analyze.h"
      21              : #include "parser/parse_coerce.h"
      22              : #include "parser/parse_collate.h"
      23              : #include "parser/parse_cte.h"
      24              : #include "parser/parse_expr.h"
      25              : #include "utils/builtins.h"
      26              : #include "utils/lsyscache.h"
      27              : #include "utils/typcache.h"
      28              : 
      29              : 
      30              : /* Enumeration of contexts in which a self-reference is disallowed */
      31              : typedef enum
      32              : {
      33              :     RECURSION_OK,
      34              :     RECURSION_NONRECURSIVETERM, /* inside the left-hand term */
      35              :     RECURSION_SUBLINK,          /* inside a sublink */
      36              :     RECURSION_OUTERJOIN,        /* inside nullable side of an outer join */
      37              :     RECURSION_INTERSECT,        /* underneath INTERSECT (ALL) */
      38              :     RECURSION_EXCEPT,           /* underneath EXCEPT (ALL) */
      39              : } RecursionContext;
      40              : 
      41              : /* Associated error messages --- each must have one %s for CTE name */
      42              : static const char *const recursion_errormsgs[] = {
      43              :     /* RECURSION_OK */
      44              :     NULL,
      45              :     /* RECURSION_NONRECURSIVETERM */
      46              :     gettext_noop("recursive reference to query \"%s\" must not appear within its non-recursive term"),
      47              :     /* RECURSION_SUBLINK */
      48              :     gettext_noop("recursive reference to query \"%s\" must not appear within a subquery"),
      49              :     /* RECURSION_OUTERJOIN */
      50              :     gettext_noop("recursive reference to query \"%s\" must not appear within an outer join"),
      51              :     /* RECURSION_INTERSECT */
      52              :     gettext_noop("recursive reference to query \"%s\" must not appear within INTERSECT"),
      53              :     /* RECURSION_EXCEPT */
      54              :     gettext_noop("recursive reference to query \"%s\" must not appear within EXCEPT")
      55              : };
      56              : 
      57              : /*
      58              :  * For WITH RECURSIVE, we have to find an ordering of the clause members
      59              :  * with no forward references, and determine which members are recursive
      60              :  * (i.e., self-referential).  It is convenient to do this with an array
      61              :  * of CteItems instead of a list of CommonTableExprs.
      62              :  */
      63              : typedef struct CteItem
      64              : {
      65              :     CommonTableExpr *cte;       /* One CTE to examine */
      66              :     int         id;             /* Its ID number for dependencies */
      67              :     Bitmapset  *depends_on;     /* CTEs depended on (not including self) */
      68              : } CteItem;
      69              : 
      70              : /* CteState is what we need to pass around in the tree walkers */
      71              : typedef struct CteState
      72              : {
      73              :     /* global state: */
      74              :     ParseState *pstate;         /* global parse state */
      75              :     CteItem    *items;          /* array of CTEs and extra data */
      76              :     int         numitems;       /* number of CTEs */
      77              :     /* working state during a tree walk: */
      78              :     int         curitem;        /* index of item currently being examined */
      79              :     List       *innerwiths;     /* list of lists of CommonTableExpr */
      80              :     /* working state for checkWellFormedRecursion walk only: */
      81              :     int         selfrefcount;   /* number of self-references detected */
      82              :     RecursionContext context;   /* context to allow or disallow self-ref */
      83              : } CteState;
      84              : 
      85              : 
      86              : static void analyzeCTE(ParseState *pstate, CommonTableExpr *cte);
      87              : 
      88              : /* Dependency processing functions */
      89              : static void makeDependencyGraph(CteState *cstate);
      90              : static bool makeDependencyGraphWalker(Node *node, CteState *cstate);
      91              : static void WalkInnerWith(Node *stmt, WithClause *withClause, CteState *cstate);
      92              : static void TopologicalSort(ParseState *pstate, CteItem *items, int numitems);
      93              : 
      94              : /* Recursion validity checker functions */
      95              : static void checkWellFormedRecursion(CteState *cstate);
      96              : static bool checkWellFormedRecursionWalker(Node *node, CteState *cstate);
      97              : static void checkWellFormedSelectStmt(SelectStmt *stmt, CteState *cstate);
      98              : 
      99              : 
     100              : /*
     101              :  * transformWithClause -
     102              :  *    Transform the list of WITH clause "common table expressions" into
     103              :  *    Query nodes.
     104              :  *
     105              :  * The result is the list of transformed CTEs to be put into the output
     106              :  * Query.  (This is in fact the same as the ending value of p_ctenamespace,
     107              :  * but it seems cleaner to not expose that in the function's API.)
     108              :  */
     109              : List *
     110         1812 : transformWithClause(ParseState *pstate, WithClause *withClause)
     111              : {
     112              :     ListCell   *lc;
     113              : 
     114              :     /* Only one WITH clause per query level */
     115              :     Assert(pstate->p_ctenamespace == NIL);
     116              :     Assert(pstate->p_future_ctes == NIL);
     117              : 
     118              :     /*
     119              :      * For either type of WITH, there must not be duplicate CTE names in the
     120              :      * list.  Check this right away so we needn't worry later.
     121              :      *
     122              :      * Also, tentatively mark each CTE as non-recursive, and initialize its
     123              :      * reference count to zero, and set pstate->p_hasModifyingCTE if needed.
     124              :      */
     125         4268 :     foreach(lc, withClause->ctes)
     126              :     {
     127         2456 :         CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
     128              :         ListCell   *rest;
     129              : 
     130         3695 :         for_each_cell(rest, withClause->ctes, lnext(withClause->ctes, lc))
     131              :         {
     132         1239 :             CommonTableExpr *cte2 = (CommonTableExpr *) lfirst(rest);
     133              : 
     134         1239 :             if (strcmp(cte->ctename, cte2->ctename) == 0)
     135            0 :                 ereport(ERROR,
     136              :                         (errcode(ERRCODE_DUPLICATE_ALIAS),
     137              :                          errmsg("WITH query name \"%s\" specified more than once",
     138              :                                 cte2->ctename),
     139              :                          parser_errposition(pstate, cte2->location)));
     140              :         }
     141              : 
     142         2456 :         cte->cterecursive = false;
     143         2456 :         cte->cterefcount = 0;
     144              : 
     145         2456 :         if (!IsA(cte->ctequery, SelectStmt))
     146              :         {
     147              :             /* must be a data-modifying statement */
     148              :             Assert(IsA(cte->ctequery, InsertStmt) ||
     149              :                    IsA(cte->ctequery, UpdateStmt) ||
     150              :                    IsA(cte->ctequery, DeleteStmt) ||
     151              :                    IsA(cte->ctequery, MergeStmt));
     152              : 
     153          219 :             pstate->p_hasModifyingCTE = true;
     154              :         }
     155              :     }
     156              : 
     157         1812 :     if (withClause->recursive)
     158              :     {
     159              :         /*
     160              :          * For WITH RECURSIVE, we rearrange the list elements if needed to
     161              :          * eliminate forward references.  First, build a work array and set up
     162              :          * the data structure needed by the tree walkers.
     163              :          */
     164              :         CteState    cstate;
     165              :         int         i;
     166              : 
     167          694 :         cstate.pstate = pstate;
     168          694 :         cstate.numitems = list_length(withClause->ctes);
     169          694 :         cstate.items = (CteItem *) palloc0(cstate.numitems * sizeof(CteItem));
     170          694 :         i = 0;
     171         1436 :         foreach(lc, withClause->ctes)
     172              :         {
     173          742 :             cstate.items[i].cte = (CommonTableExpr *) lfirst(lc);
     174          742 :             cstate.items[i].id = i;
     175          742 :             i++;
     176              :         }
     177              : 
     178              :         /*
     179              :          * Find all the dependencies and sort the CteItems into a safe
     180              :          * processing order.  Also, mark CTEs that contain self-references.
     181              :          */
     182          694 :         makeDependencyGraph(&cstate);
     183              : 
     184              :         /*
     185              :          * Check that recursive queries are well-formed.
     186              :          */
     187          691 :         checkWellFormedRecursion(&cstate);
     188              : 
     189              :         /*
     190              :          * Set up the ctenamespace for parse analysis.  Per spec, all the WITH
     191              :          * items are visible to all others, so stuff them all in before parse
     192              :          * analysis.  We build the list in safe processing order so that the
     193              :          * planner can process the queries in sequence.
     194              :          */
     195         1277 :         for (i = 0; i < cstate.numitems; i++)
     196              :         {
     197          661 :             CommonTableExpr *cte = cstate.items[i].cte;
     198              : 
     199          661 :             pstate->p_ctenamespace = lappend(pstate->p_ctenamespace, cte);
     200              :         }
     201              : 
     202              :         /*
     203              :          * Do parse analysis in the order determined by the topological sort.
     204              :          */
     205         1214 :         for (i = 0; i < cstate.numitems; i++)
     206              :         {
     207          661 :             CommonTableExpr *cte = cstate.items[i].cte;
     208              : 
     209          661 :             analyzeCTE(pstate, cte);
     210              :         }
     211              :     }
     212              :     else
     213              :     {
     214              :         /*
     215              :          * For non-recursive WITH, just analyze each CTE in sequence and then
     216              :          * add it to the ctenamespace.  This corresponds to the spec's
     217              :          * definition of the scope of each WITH name.  However, to allow error
     218              :          * reports to be aware of the possibility of an erroneous reference,
     219              :          * we maintain a list in p_future_ctes of the not-yet-visible CTEs.
     220              :          */
     221         1118 :         pstate->p_future_ctes = list_copy(withClause->ctes);
     222              : 
     223         2822 :         foreach(lc, withClause->ctes)
     224              :         {
     225         1714 :             CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
     226              : 
     227         1714 :             analyzeCTE(pstate, cte);
     228         1704 :             pstate->p_ctenamespace = lappend(pstate->p_ctenamespace, cte);
     229         1704 :             pstate->p_future_ctes = list_delete_first(pstate->p_future_ctes);
     230              :         }
     231              :     }
     232              : 
     233         1661 :     return pstate->p_ctenamespace;
     234              : }
     235              : 
     236              : 
     237              : /*
     238              :  * Perform the actual parse analysis transformation of one CTE.  All
     239              :  * CTEs it depends on have already been loaded into pstate->p_ctenamespace,
     240              :  * and have been marked with the correct output column names/types.
     241              :  */
     242              : static void
     243         2375 : analyzeCTE(ParseState *pstate, CommonTableExpr *cte)
     244              : {
     245              :     Query      *query;
     246         2375 :     CTESearchClause *search_clause = cte->search_clause;
     247         2375 :     CTECycleClause *cycle_clause = cte->cycle_clause;
     248              : 
     249              :     /* Analysis not done already */
     250              :     Assert(!IsA(cte->ctequery, Query));
     251              : 
     252              :     /*
     253              :      * Before analyzing the CTE's query, we'd better identify the data type of
     254              :      * the cycle mark column if any, since the query could refer to that.
     255              :      * Other validity checks on the cycle clause will be done afterwards.
     256              :      */
     257         2375 :     if (cycle_clause)
     258              :     {
     259              :         TypeCacheEntry *typentry;
     260              :         Oid         op;
     261              : 
     262           63 :         cycle_clause->cycle_mark_value =
     263           63 :             transformExpr(pstate, cycle_clause->cycle_mark_value,
     264              :                           EXPR_KIND_CYCLE_MARK);
     265           63 :         cycle_clause->cycle_mark_default =
     266           63 :             transformExpr(pstate, cycle_clause->cycle_mark_default,
     267              :                           EXPR_KIND_CYCLE_MARK);
     268              : 
     269           60 :         cycle_clause->cycle_mark_type =
     270           63 :             select_common_type(pstate,
     271           63 :                                list_make2(cycle_clause->cycle_mark_value,
     272              :                                           cycle_clause->cycle_mark_default),
     273              :                                "CYCLE", NULL);
     274           60 :         cycle_clause->cycle_mark_value =
     275           60 :             coerce_to_common_type(pstate,
     276              :                                   cycle_clause->cycle_mark_value,
     277              :                                   cycle_clause->cycle_mark_type,
     278              :                                   "CYCLE/SET/TO");
     279           60 :         cycle_clause->cycle_mark_default =
     280           60 :             coerce_to_common_type(pstate,
     281              :                                   cycle_clause->cycle_mark_default,
     282              :                                   cycle_clause->cycle_mark_type,
     283              :                                   "CYCLE/SET/DEFAULT");
     284              : 
     285           60 :         cycle_clause->cycle_mark_typmod =
     286           60 :             select_common_typmod(pstate,
     287           60 :                                  list_make2(cycle_clause->cycle_mark_value,
     288              :                                             cycle_clause->cycle_mark_default),
     289              :                                  cycle_clause->cycle_mark_type);
     290              : 
     291           60 :         cycle_clause->cycle_mark_collation =
     292           60 :             select_common_collation(pstate,
     293           60 :                                     list_make2(cycle_clause->cycle_mark_value,
     294              :                                                cycle_clause->cycle_mark_default),
     295              :                                     true);
     296              : 
     297              :         /* Might as well look up the relevant <> operator while we are at it */
     298           60 :         typentry = lookup_type_cache(cycle_clause->cycle_mark_type,
     299              :                                      TYPECACHE_EQ_OPR);
     300           60 :         if (!OidIsValid(typentry->eq_opr))
     301            3 :             ereport(ERROR,
     302              :                     errcode(ERRCODE_UNDEFINED_FUNCTION),
     303              :                     errmsg("could not identify an equality operator for type %s",
     304              :                            format_type_be(cycle_clause->cycle_mark_type)));
     305           57 :         op = get_negator(typentry->eq_opr);
     306           57 :         if (!OidIsValid(op))
     307            0 :             ereport(ERROR,
     308              :                     errcode(ERRCODE_UNDEFINED_FUNCTION),
     309              :                     errmsg("could not identify an inequality operator for type %s",
     310              :                            format_type_be(cycle_clause->cycle_mark_type)));
     311              : 
     312           57 :         cycle_clause->cycle_mark_neop = op;
     313              :     }
     314              : 
     315              :     /* Now we can get on with analyzing the CTE's query */
     316         2369 :     query = parse_sub_analyze(cte->ctequery, pstate, cte, false, true);
     317         2356 :     cte->ctequery = (Node *) query;
     318              : 
     319              :     /*
     320              :      * Check that we got something reasonable.  These first two cases should
     321              :      * be prevented by the grammar.
     322              :      */
     323         2356 :     if (!IsA(query, Query))
     324            0 :         elog(ERROR, "unexpected non-Query statement in WITH");
     325         2356 :     if (query->utilityStmt != NULL)
     326            0 :         elog(ERROR, "unexpected utility statement in WITH");
     327              : 
     328              :     /*
     329              :      * We disallow data-modifying WITH except at the top level of a query,
     330              :      * because it's not clear when such a modification should be executed.
     331              :      */
     332         2356 :     if (query->commandType != CMD_SELECT &&
     333          210 :         pstate->parentParseState != NULL)
     334            3 :         ereport(ERROR,
     335              :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     336              :                  errmsg("WITH clause containing a data-modifying statement must be at the top level"),
     337              :                  parser_errposition(pstate, cte->location)));
     338              : 
     339              :     /*
     340              :      * CTE queries are always marked not canSetTag.  (Currently this only
     341              :      * matters for data-modifying statements, for which the flag will be
     342              :      * propagated to the ModifyTable plan node.)
     343              :      */
     344         2353 :     query->canSetTag = false;
     345              : 
     346         2353 :     if (!cte->cterecursive)
     347              :     {
     348              :         /* Compute the output column names/types if not done yet */
     349         1764 :         analyzeCTETargetList(pstate, cte, GetCTETargetList(cte));
     350              :     }
     351              :     else
     352              :     {
     353              :         /*
     354              :          * Verify that the previously determined output column types and
     355              :          * collations match what the query really produced.  We have to check
     356              :          * this because the recursive term could have overridden the
     357              :          * non-recursive term, and we don't have any easy way to fix that.
     358              :          */
     359              :         ListCell   *lctlist,
     360              :                    *lctyp,
     361              :                    *lctypmod,
     362              :                    *lccoll;
     363              :         int         varattno;
     364              : 
     365          589 :         lctyp = list_head(cte->ctecoltypes);
     366          589 :         lctypmod = list_head(cte->ctecoltypmods);
     367          589 :         lccoll = list_head(cte->ctecolcollations);
     368          589 :         varattno = 0;
     369         1875 :         foreach(lctlist, GetCTETargetList(cte))
     370              :         {
     371         1298 :             TargetEntry *te = (TargetEntry *) lfirst(lctlist);
     372              :             Node       *texpr;
     373              : 
     374         1298 :             if (te->resjunk)
     375            0 :                 continue;
     376         1298 :             varattno++;
     377              :             Assert(varattno == te->resno);
     378         1298 :             if (lctyp == NULL || lctypmod == NULL || lccoll == NULL)    /* shouldn't happen */
     379            0 :                 elog(ERROR, "wrong number of output columns in WITH");
     380         1298 :             texpr = (Node *) te->expr;
     381         1298 :             if (exprType(texpr) != lfirst_oid(lctyp) ||
     382         1295 :                 exprTypmod(texpr) != lfirst_int(lctypmod))
     383            6 :                 ereport(ERROR,
     384              :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
     385              :                          errmsg("recursive query \"%s\" column %d has type %s in non-recursive term but type %s overall",
     386              :                                 cte->ctename, varattno,
     387              :                                 format_type_with_typemod(lfirst_oid(lctyp),
     388              :                                                          lfirst_int(lctypmod)),
     389              :                                 format_type_with_typemod(exprType(texpr),
     390              :                                                          exprTypmod(texpr))),
     391              :                          errhint("Cast the output of the non-recursive term to the correct type."),
     392              :                          parser_errposition(pstate, exprLocation(texpr))));
     393         1292 :             if (exprCollation(texpr) != lfirst_oid(lccoll))
     394            6 :                 ereport(ERROR,
     395              :                         (errcode(ERRCODE_COLLATION_MISMATCH),
     396              :                          errmsg("recursive query \"%s\" column %d has collation \"%s\" in non-recursive term but collation \"%s\" overall",
     397              :                                 cte->ctename, varattno,
     398              :                                 get_collation_name(lfirst_oid(lccoll)),
     399              :                                 get_collation_name(exprCollation(texpr))),
     400              :                          errhint("Use the COLLATE clause to set the collation of the non-recursive term."),
     401              :                          parser_errposition(pstate, exprLocation(texpr))));
     402         1286 :             lctyp = lnext(cte->ctecoltypes, lctyp);
     403         1286 :             lctypmod = lnext(cte->ctecoltypmods, lctypmod);
     404         1286 :             lccoll = lnext(cte->ctecolcollations, lccoll);
     405              :         }
     406          577 :         if (lctyp != NULL || lctypmod != NULL || lccoll != NULL)    /* shouldn't happen */
     407            0 :             elog(ERROR, "wrong number of output columns in WITH");
     408              :     }
     409              : 
     410              :     /*
     411              :      * Now make validity checks on the SEARCH and CYCLE clauses, if present.
     412              :      */
     413         2338 :     if (search_clause || cycle_clause)
     414              :     {
     415              :         Query      *ctequery;
     416              :         SetOperationStmt *sos;
     417              : 
     418          108 :         if (!cte->cterecursive)
     419            0 :             ereport(ERROR,
     420              :                     (errcode(ERRCODE_SYNTAX_ERROR),
     421              :                      errmsg("WITH query is not recursive"),
     422              :                      parser_errposition(pstate, cte->location)));
     423              : 
     424              :         /*
     425              :          * SQL requires a WITH list element (CTE) to be "expandable" in order
     426              :          * to allow a search or cycle clause.  That is a stronger requirement
     427              :          * than just being recursive.  It basically means the query expression
     428              :          * looks like
     429              :          *
     430              :          * non-recursive query UNION [ALL] recursive query
     431              :          *
     432              :          * and that the recursive query is not itself a set operation.
     433              :          *
     434              :          * As of this writing, most of these criteria are already satisfied by
     435              :          * all recursive CTEs allowed by PostgreSQL.  In the future, if
     436              :          * further variants recursive CTEs are accepted, there might be
     437              :          * further checks required here to determine what is "expandable".
     438              :          */
     439              : 
     440          108 :         ctequery = castNode(Query, cte->ctequery);
     441              :         Assert(ctequery->setOperations);
     442          108 :         sos = castNode(SetOperationStmt, ctequery->setOperations);
     443              : 
     444              :         /*
     445              :          * This left side check is not required for expandability, but
     446              :          * rewriteSearchAndCycle() doesn't currently have support for it, so
     447              :          * we catch it here.
     448              :          */
     449          108 :         if (!IsA(sos->larg, RangeTblRef))
     450            3 :             ereport(ERROR,
     451              :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     452              :                      errmsg("with a SEARCH or CYCLE clause, the left side of the UNION must be a SELECT")));
     453              : 
     454          105 :         if (!IsA(sos->rarg, RangeTblRef))
     455            3 :             ereport(ERROR,
     456              :                     (errcode(ERRCODE_SYNTAX_ERROR),
     457              :                      errmsg("with a SEARCH or CYCLE clause, the right side of the UNION must be a SELECT")));
     458              :     }
     459              : 
     460         2332 :     if (search_clause)
     461              :     {
     462              :         ListCell   *lc;
     463           57 :         List       *seen = NIL;
     464              : 
     465          150 :         foreach(lc, search_clause->search_col_list)
     466              :         {
     467           99 :             String     *colname = lfirst_node(String, lc);
     468              : 
     469           99 :             if (!list_member(cte->ctecolnames, colname))
     470            3 :                 ereport(ERROR,
     471              :                         (errcode(ERRCODE_SYNTAX_ERROR),
     472              :                          errmsg("search column \"%s\" not in WITH query column list",
     473              :                                 strVal(colname)),
     474              :                          parser_errposition(pstate, search_clause->location)));
     475              : 
     476           96 :             if (list_member(seen, colname))
     477            3 :                 ereport(ERROR,
     478              :                         (errcode(ERRCODE_DUPLICATE_COLUMN),
     479              :                          errmsg("search column \"%s\" specified more than once",
     480              :                                 strVal(colname)),
     481              :                          parser_errposition(pstate, search_clause->location)));
     482           93 :             seen = lappend(seen, colname);
     483              :         }
     484              : 
     485           51 :         if (list_member(cte->ctecolnames, makeString(search_clause->search_seq_column)))
     486            3 :             ereport(ERROR,
     487              :                     errcode(ERRCODE_SYNTAX_ERROR),
     488              :                     errmsg("search sequence column name \"%s\" already used in WITH query column list",
     489              :                            search_clause->search_seq_column),
     490              :                     parser_errposition(pstate, search_clause->location));
     491              :     }
     492              : 
     493         2323 :     if (cycle_clause)
     494              :     {
     495              :         ListCell   *lc;
     496           57 :         List       *seen = NIL;
     497              : 
     498          153 :         foreach(lc, cycle_clause->cycle_col_list)
     499              :         {
     500          102 :             String     *colname = lfirst_node(String, lc);
     501              : 
     502          102 :             if (!list_member(cte->ctecolnames, colname))
     503            3 :                 ereport(ERROR,
     504              :                         (errcode(ERRCODE_SYNTAX_ERROR),
     505              :                          errmsg("cycle column \"%s\" not in WITH query column list",
     506              :                                 strVal(colname)),
     507              :                          parser_errposition(pstate, cycle_clause->location)));
     508              : 
     509           99 :             if (list_member(seen, colname))
     510            3 :                 ereport(ERROR,
     511              :                         (errcode(ERRCODE_DUPLICATE_COLUMN),
     512              :                          errmsg("cycle column \"%s\" specified more than once",
     513              :                                 strVal(colname)),
     514              :                          parser_errposition(pstate, cycle_clause->location)));
     515           96 :             seen = lappend(seen, colname);
     516              :         }
     517              : 
     518           51 :         if (list_member(cte->ctecolnames, makeString(cycle_clause->cycle_mark_column)))
     519            3 :             ereport(ERROR,
     520              :                     errcode(ERRCODE_SYNTAX_ERROR),
     521              :                     errmsg("cycle mark column name \"%s\" already used in WITH query column list",
     522              :                            cycle_clause->cycle_mark_column),
     523              :                     parser_errposition(pstate, cycle_clause->location));
     524              : 
     525           48 :         if (list_member(cte->ctecolnames, makeString(cycle_clause->cycle_path_column)))
     526            3 :             ereport(ERROR,
     527              :                     errcode(ERRCODE_SYNTAX_ERROR),
     528              :                     errmsg("cycle path column name \"%s\" already used in WITH query column list",
     529              :                            cycle_clause->cycle_path_column),
     530              :                     parser_errposition(pstate, cycle_clause->location));
     531              : 
     532           45 :         if (strcmp(cycle_clause->cycle_mark_column,
     533           45 :                    cycle_clause->cycle_path_column) == 0)
     534            3 :             ereport(ERROR,
     535              :                     errcode(ERRCODE_SYNTAX_ERROR),
     536              :                     errmsg("cycle mark column name and cycle path column name are the same"),
     537              :                     parser_errposition(pstate, cycle_clause->location));
     538              :     }
     539              : 
     540         2308 :     if (search_clause && cycle_clause)
     541              :     {
     542           12 :         if (strcmp(search_clause->search_seq_column,
     543           12 :                    cycle_clause->cycle_mark_column) == 0)
     544            3 :             ereport(ERROR,
     545              :                     errcode(ERRCODE_SYNTAX_ERROR),
     546              :                     errmsg("search sequence column name and cycle mark column name are the same"),
     547              :                     parser_errposition(pstate, search_clause->location));
     548              : 
     549            9 :         if (strcmp(search_clause->search_seq_column,
     550            9 :                    cycle_clause->cycle_path_column) == 0)
     551            3 :             ereport(ERROR,
     552              :                     errcode(ERRCODE_SYNTAX_ERROR),
     553              :                     errmsg("search sequence column name and cycle path column name are the same"),
     554              :                     parser_errposition(pstate, search_clause->location));
     555              :     }
     556         2302 : }
     557              : 
     558              : /*
     559              :  * Compute derived fields of a CTE, given the transformed output targetlist
     560              :  *
     561              :  * For a nonrecursive CTE, this is called after transforming the CTE's query.
     562              :  * For a recursive CTE, we call it after transforming the non-recursive term,
     563              :  * and pass the targetlist emitted by the non-recursive term only.
     564              :  *
     565              :  * Note: in the recursive case, the passed pstate is actually the one being
     566              :  * used to analyze the CTE's query, so it is one level lower down than in
     567              :  * the nonrecursive case.  This doesn't matter since we only use it for
     568              :  * error message context anyway.
     569              :  */
     570              : void
     571         2362 : analyzeCTETargetList(ParseState *pstate, CommonTableExpr *cte, List *tlist)
     572              : {
     573              :     int         numaliases;
     574              :     int         varattno;
     575              :     ListCell   *tlistitem;
     576              : 
     577              :     /* Not done already ... */
     578              :     Assert(cte->ctecolnames == NIL);
     579              : 
     580              :     /*
     581              :      * We need to determine column names, types, and collations.  The alias
     582              :      * column names override anything coming from the query itself.  (Note:
     583              :      * the SQL spec says that the alias list must be empty or exactly as long
     584              :      * as the output column set; but we allow it to be shorter for consistency
     585              :      * with Alias handling.)
     586              :      */
     587         2362 :     cte->ctecolnames = copyObject(cte->aliascolnames);
     588         2362 :     cte->ctecoltypes = cte->ctecoltypmods = cte->ctecolcollations = NIL;
     589         2362 :     numaliases = list_length(cte->aliascolnames);
     590         2362 :     varattno = 0;
     591         7938 :     foreach(tlistitem, tlist)
     592              :     {
     593         5576 :         TargetEntry *te = (TargetEntry *) lfirst(tlistitem);
     594              :         Oid         coltype;
     595              :         int32       coltypmod;
     596              :         Oid         colcoll;
     597              : 
     598         5576 :         if (te->resjunk)
     599           53 :             continue;
     600         5523 :         varattno++;
     601              :         Assert(varattno == te->resno);
     602         5523 :         if (varattno > numaliases)
     603              :         {
     604              :             char       *attrname;
     605              : 
     606         2302 :             attrname = pstrdup(te->resname);
     607         2302 :             cte->ctecolnames = lappend(cte->ctecolnames, makeString(attrname));
     608              :         }
     609         5523 :         coltype = exprType((Node *) te->expr);
     610         5523 :         coltypmod = exprTypmod((Node *) te->expr);
     611         5523 :         colcoll = exprCollation((Node *) te->expr);
     612              : 
     613              :         /*
     614              :          * If the CTE is recursive, force the exposed column type of any
     615              :          * "unknown" column to "text".  We must deal with this here because
     616              :          * we're called on the non-recursive term before there's been any
     617              :          * attempt to force unknown output columns to some other type.  We
     618              :          * have to resolve unknowns before looking at the recursive term.
     619              :          *
     620              :          * The column might contain 'foo' COLLATE "bar", so don't override
     621              :          * collation if it's already set.
     622              :          */
     623         5523 :         if (cte->cterecursive && coltype == UNKNOWNOID)
     624              :         {
     625           18 :             coltype = TEXTOID;
     626           18 :             coltypmod = -1;     /* should be -1 already, but be sure */
     627           18 :             if (!OidIsValid(colcoll))
     628           18 :                 colcoll = DEFAULT_COLLATION_OID;
     629              :         }
     630         5523 :         cte->ctecoltypes = lappend_oid(cte->ctecoltypes, coltype);
     631         5523 :         cte->ctecoltypmods = lappend_int(cte->ctecoltypmods, coltypmod);
     632         5523 :         cte->ctecolcollations = lappend_oid(cte->ctecolcollations, colcoll);
     633              :     }
     634         2362 :     if (varattno < numaliases)
     635            3 :         ereport(ERROR,
     636              :                 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
     637              :                  errmsg("WITH query \"%s\" has %d columns available but %d columns specified",
     638              :                         cte->ctename, varattno, numaliases),
     639              :                  parser_errposition(pstate, cte->location)));
     640         2359 : }
     641              : 
     642              : 
     643              : /*
     644              :  * Identify the cross-references of a list of WITH RECURSIVE items,
     645              :  * and sort into an order that has no forward references.
     646              :  */
     647              : static void
     648          694 : makeDependencyGraph(CteState *cstate)
     649              : {
     650              :     int         i;
     651              : 
     652         1436 :     for (i = 0; i < cstate->numitems; i++)
     653              :     {
     654          742 :         CommonTableExpr *cte = cstate->items[i].cte;
     655              : 
     656          742 :         cstate->curitem = i;
     657          742 :         cstate->innerwiths = NIL;
     658          742 :         makeDependencyGraphWalker((Node *) cte->ctequery, cstate);
     659              :         Assert(cstate->innerwiths == NIL);
     660              :     }
     661              : 
     662          694 :     TopologicalSort(cstate->pstate, cstate->items, cstate->numitems);
     663          691 : }
     664              : 
     665              : /*
     666              :  * Tree walker function to detect cross-references and self-references of the
     667              :  * CTEs in a WITH RECURSIVE list.
     668              :  */
     669              : static bool
     670        90710 : makeDependencyGraphWalker(Node *node, CteState *cstate)
     671              : {
     672        90710 :     if (node == NULL)
     673        49505 :         return false;
     674        41205 :     if (IsA(node, RangeVar))
     675              :     {
     676         4054 :         RangeVar   *rv = (RangeVar *) node;
     677              : 
     678              :         /* If unqualified name, might be a CTE reference */
     679         4054 :         if (!rv->schemaname)
     680              :         {
     681              :             ListCell   *lc;
     682              :             int         i;
     683              : 
     684              :             /* ... but first see if it's captured by an inner WITH */
     685         3369 :             foreach(lc, cstate->innerwiths)
     686              :             {
     687          649 :                 List       *withlist = (List *) lfirst(lc);
     688              :                 ListCell   *lc2;
     689              : 
     690          706 :                 foreach(lc2, withlist)
     691              :                 {
     692          545 :                     CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc2);
     693              : 
     694          545 :                     if (strcmp(rv->relname, cte->ctename) == 0)
     695          488 :                         return false;   /* yes, so bail out */
     696              :                 }
     697              :             }
     698              : 
     699              :             /* No, could be a reference to the query level we are working on */
     700         4746 :             for (i = 0; i < cstate->numitems; i++)
     701              :             {
     702         2789 :                 CommonTableExpr *cte = cstate->items[i].cte;
     703              : 
     704         2789 :                 if (strcmp(rv->relname, cte->ctename) == 0)
     705              :                 {
     706          763 :                     int         myindex = cstate->curitem;
     707              : 
     708          763 :                     if (i != myindex)
     709              :                     {
     710              :                         /* Add cross-item dependency */
     711           63 :                         cstate->items[myindex].depends_on =
     712           63 :                             bms_add_member(cstate->items[myindex].depends_on,
     713           63 :                                            cstate->items[i].id);
     714              :                     }
     715              :                     else
     716              :                     {
     717              :                         /* Found out this one is self-referential */
     718          700 :                         cte->cterecursive = true;
     719              :                     }
     720          763 :                     break;
     721              :                 }
     722              :             }
     723              :         }
     724         3566 :         return false;
     725              :     }
     726        37151 :     if (IsA(node, SelectStmt))
     727              :     {
     728         3152 :         SelectStmt *stmt = (SelectStmt *) node;
     729              : 
     730         3152 :         if (stmt->withClause)
     731              :         {
     732              :             /* Examine the WITH clause and the SelectStmt */
     733          182 :             WalkInnerWith(node, stmt->withClause, cstate);
     734              :             /* We're done examining the SelectStmt */
     735          182 :             return false;
     736              :         }
     737              :         /* if no WITH clause, just fall through for normal processing */
     738              :     }
     739        33999 :     else if (IsA(node, InsertStmt))
     740              :     {
     741           21 :         InsertStmt *stmt = (InsertStmt *) node;
     742              : 
     743           21 :         if (stmt->withClause)
     744              :         {
     745              :             /* Examine the WITH clause and the InsertStmt */
     746            0 :             WalkInnerWith(node, stmt->withClause, cstate);
     747              :             /* We're done examining the InsertStmt */
     748            0 :             return false;
     749              :         }
     750              :         /* if no WITH clause, just fall through for normal processing */
     751              :     }
     752        33978 :     else if (IsA(node, DeleteStmt))
     753              :     {
     754            3 :         DeleteStmt *stmt = (DeleteStmt *) node;
     755              : 
     756            3 :         if (stmt->withClause)
     757              :         {
     758              :             /* Examine the WITH clause and the DeleteStmt */
     759            3 :             WalkInnerWith(node, stmt->withClause, cstate);
     760              :             /* We're done examining the DeleteStmt */
     761            3 :             return false;
     762              :         }
     763              :         /* if no WITH clause, just fall through for normal processing */
     764              :     }
     765        33975 :     else if (IsA(node, UpdateStmt))
     766              :     {
     767            3 :         UpdateStmt *stmt = (UpdateStmt *) node;
     768              : 
     769            3 :         if (stmt->withClause)
     770              :         {
     771              :             /* Examine the WITH clause and the UpdateStmt */
     772            0 :             WalkInnerWith(node, stmt->withClause, cstate);
     773              :             /* We're done examining the UpdateStmt */
     774            0 :             return false;
     775              :         }
     776              :         /* if no WITH clause, just fall through for normal processing */
     777              :     }
     778        33972 :     else if (IsA(node, MergeStmt))
     779              :     {
     780            3 :         MergeStmt  *stmt = (MergeStmt *) node;
     781              : 
     782            3 :         if (stmt->withClause)
     783              :         {
     784              :             /* Examine the WITH clause and the MergeStmt */
     785            0 :             WalkInnerWith(node, stmt->withClause, cstate);
     786              :             /* We're done examining the MergeStmt */
     787            0 :             return false;
     788              :         }
     789              :         /* if no WITH clause, just fall through for normal processing */
     790              :     }
     791        33969 :     else if (IsA(node, WithClause))
     792              :     {
     793              :         /*
     794              :          * Prevent raw_expression_tree_walker from recursing directly into a
     795              :          * WITH clause.  We need that to happen only under the control of the
     796              :          * code above.
     797              :          */
     798          185 :         return false;
     799              :     }
     800        36781 :     return raw_expression_tree_walker(node,
     801              :                                       makeDependencyGraphWalker,
     802              :                                       cstate);
     803              : }
     804              : 
     805              : /*
     806              :  * makeDependencyGraphWalker's recursion into a statement having a WITH clause.
     807              :  *
     808              :  * This subroutine is concerned with updating the innerwiths list correctly
     809              :  * based on the visibility rules for CTE names.
     810              :  */
     811              : static void
     812          185 : WalkInnerWith(Node *stmt, WithClause *withClause, CteState *cstate)
     813              : {
     814              :     ListCell   *lc;
     815              : 
     816          185 :     if (withClause->recursive)
     817              :     {
     818              :         /*
     819              :          * In the RECURSIVE case, all query names of the WITH are visible to
     820              :          * all WITH items as well as the main query.  So push them all on,
     821              :          * process, pop them all off.
     822              :          */
     823            9 :         cstate->innerwiths = lcons(withClause->ctes, cstate->innerwiths);
     824           18 :         foreach(lc, withClause->ctes)
     825              :         {
     826            9 :             CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
     827              : 
     828            9 :             (void) makeDependencyGraphWalker(cte->ctequery, cstate);
     829              :         }
     830            9 :         (void) raw_expression_tree_walker(stmt,
     831              :                                           makeDependencyGraphWalker,
     832              :                                           cstate);
     833            9 :         cstate->innerwiths = list_delete_first(cstate->innerwiths);
     834              :     }
     835              :     else
     836              :     {
     837              :         /*
     838              :          * In the non-RECURSIVE case, query names are visible to the WITH
     839              :          * items after them and to the main query.
     840              :          */
     841          176 :         cstate->innerwiths = lcons(NIL, cstate->innerwiths);
     842          364 :         foreach(lc, withClause->ctes)
     843              :         {
     844          188 :             CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
     845              :             ListCell   *cell1;
     846              : 
     847          188 :             (void) makeDependencyGraphWalker(cte->ctequery, cstate);
     848              :             /* note that recursion could mutate innerwiths list */
     849          188 :             cell1 = list_head(cstate->innerwiths);
     850          188 :             lfirst(cell1) = lappend((List *) lfirst(cell1), cte);
     851              :         }
     852          176 :         (void) raw_expression_tree_walker(stmt,
     853              :                                           makeDependencyGraphWalker,
     854              :                                           cstate);
     855          176 :         cstate->innerwiths = list_delete_first(cstate->innerwiths);
     856              :     }
     857          185 : }
     858              : 
     859              : /*
     860              :  * Sort by dependencies, using a standard topological sort operation
     861              :  */
     862              : static void
     863          694 : TopologicalSort(ParseState *pstate, CteItem *items, int numitems)
     864              : {
     865              :     int         i,
     866              :                 j;
     867              : 
     868              :     /* for each position in sequence ... */
     869         1430 :     for (i = 0; i < numitems; i++)
     870              :     {
     871              :         /* ... scan the remaining items to find one that has no dependencies */
     872          754 :         for (j = i; j < numitems; j++)
     873              :         {
     874          751 :             if (bms_is_empty(items[j].depends_on))
     875          736 :                 break;
     876              :         }
     877              : 
     878              :         /* if we didn't find one, the dependency graph has a cycle */
     879          739 :         if (j >= numitems)
     880            3 :             ereport(ERROR,
     881              :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     882              :                      errmsg("mutual recursion between WITH items is not implemented"),
     883              :                      parser_errposition(pstate, items[i].cte->location)));
     884              : 
     885              :         /*
     886              :          * Found one.  Move it to front and remove it from every other item's
     887              :          * dependencies.
     888              :          */
     889          736 :         if (i != j)
     890              :         {
     891              :             CteItem     tmp;
     892              : 
     893            9 :             tmp = items[i];
     894            9 :             items[i] = items[j];
     895            9 :             items[j] = tmp;
     896              :         }
     897              : 
     898              :         /*
     899              :          * Items up through i are known to have no dependencies left, so we
     900              :          * can skip them in this loop.
     901              :          */
     902          787 :         for (j = i + 1; j < numitems; j++)
     903              :         {
     904           51 :             items[j].depends_on = bms_del_member(items[j].depends_on,
     905           51 :                                                  items[i].id);
     906              :         }
     907              :     }
     908          691 : }
     909              : 
     910              : 
     911              : /*
     912              :  * Check that recursive queries are well-formed.
     913              :  */
     914              : static void
     915          691 : checkWellFormedRecursion(CteState *cstate)
     916              : {
     917              :     int         i;
     918              : 
     919         1352 :     for (i = 0; i < cstate->numitems; i++)
     920              :     {
     921          736 :         CommonTableExpr *cte = cstate->items[i].cte;
     922          736 :         SelectStmt *stmt = (SelectStmt *) cte->ctequery;
     923              : 
     924              :         Assert(!IsA(stmt, Query));  /* not analyzed yet */
     925              : 
     926              :         /* Ignore items that weren't found to be recursive */
     927          736 :         if (!cte->cterecursive)
     928           57 :             continue;
     929              : 
     930              :         /* Must be a SELECT statement */
     931          679 :         if (!IsA(stmt, SelectStmt))
     932            9 :             ereport(ERROR,
     933              :                     (errcode(ERRCODE_INVALID_RECURSION),
     934              :                      errmsg("recursive query \"%s\" must not contain data-modifying statements",
     935              :                             cte->ctename),
     936              :                      parser_errposition(cstate->pstate, cte->location)));
     937              : 
     938              :         /* Must have top-level UNION */
     939          670 :         if (stmt->op != SETOP_UNION)
     940           15 :             ereport(ERROR,
     941              :                     (errcode(ERRCODE_INVALID_RECURSION),
     942              :                      errmsg("recursive query \"%s\" does not have the form non-recursive-term UNION [ALL] recursive-term",
     943              :                             cte->ctename),
     944              :                      parser_errposition(cstate->pstate, cte->location)));
     945              : 
     946              :         /*
     947              :          * Really, we should insist that there not be a top-level WITH, since
     948              :          * syntactically that would enclose the UNION.  However, we've not
     949              :          * done so in the past and it's probably too late to change.  Settle
     950              :          * for insisting that WITH not contain a self-reference.  Test this
     951              :          * before examining the UNION arms, to avoid issuing confusing errors
     952              :          * in such cases.
     953              :          */
     954          655 :         if (stmt->withClause)
     955              :         {
     956            9 :             cstate->curitem = i;
     957            9 :             cstate->innerwiths = NIL;
     958            9 :             cstate->selfrefcount = 0;
     959            9 :             cstate->context = RECURSION_SUBLINK;
     960            9 :             checkWellFormedRecursionWalker((Node *) stmt->withClause->ctes,
     961              :                                            cstate);
     962              :             Assert(cstate->innerwiths == NIL);
     963              :         }
     964              : 
     965              :         /*
     966              :          * Disallow ORDER BY and similar decoration atop the UNION. These
     967              :          * don't make sense because it's impossible to figure out what they
     968              :          * mean when we have only part of the recursive query's results. (If
     969              :          * we did allow them, we'd have to check for recursive references
     970              :          * inside these subtrees.  As for WITH, we have to do this before
     971              :          * examining the UNION arms, to avoid issuing confusing errors if
     972              :          * there is a recursive reference here.)
     973              :          */
     974          649 :         if (stmt->sortClause)
     975            6 :             ereport(ERROR,
     976              :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     977              :                      errmsg("ORDER BY in a recursive query is not implemented"),
     978              :                      parser_errposition(cstate->pstate,
     979              :                                         exprLocation((Node *) stmt->sortClause))));
     980          643 :         if (stmt->limitOffset)
     981            3 :             ereport(ERROR,
     982              :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     983              :                      errmsg("OFFSET in a recursive query is not implemented"),
     984              :                      parser_errposition(cstate->pstate,
     985              :                                         exprLocation(stmt->limitOffset))));
     986          640 :         if (stmt->limitCount)
     987            0 :             ereport(ERROR,
     988              :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     989              :                      errmsg("LIMIT in a recursive query is not implemented"),
     990              :                      parser_errposition(cstate->pstate,
     991              :                                         exprLocation(stmt->limitCount))));
     992          640 :         if (stmt->lockingClause)
     993            3 :             ereport(ERROR,
     994              :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     995              :                      errmsg("FOR UPDATE/SHARE in a recursive query is not implemented"),
     996              :                      parser_errposition(cstate->pstate,
     997              :                                         exprLocation((Node *) stmt->lockingClause))));
     998              : 
     999              :         /*
    1000              :          * Now we can get on with checking the UNION operands themselves.
    1001              :          *
    1002              :          * The left-hand operand mustn't contain a self-reference at all.
    1003              :          */
    1004          637 :         cstate->curitem = i;
    1005          637 :         cstate->innerwiths = NIL;
    1006          637 :         cstate->selfrefcount = 0;
    1007          637 :         cstate->context = RECURSION_NONRECURSIVETERM;
    1008          637 :         checkWellFormedRecursionWalker((Node *) stmt->larg, cstate);
    1009              :         Assert(cstate->innerwiths == NIL);
    1010              : 
    1011              :         /* Right-hand operand should contain one reference in a valid place */
    1012          631 :         cstate->curitem = i;
    1013          631 :         cstate->innerwiths = NIL;
    1014          631 :         cstate->selfrefcount = 0;
    1015          631 :         cstate->context = RECURSION_OK;
    1016          631 :         checkWellFormedRecursionWalker((Node *) stmt->rarg, cstate);
    1017              :         Assert(cstate->innerwiths == NIL);
    1018          604 :         if (cstate->selfrefcount != 1)   /* shouldn't happen */
    1019            0 :             elog(ERROR, "missing recursive reference");
    1020              :     }
    1021          616 : }
    1022              : 
    1023              : /*
    1024              :  * Tree walker function to detect invalid self-references in a recursive query.
    1025              :  */
    1026              : static bool
    1027        73511 : checkWellFormedRecursionWalker(Node *node, CteState *cstate)
    1028              : {
    1029        73511 :     RecursionContext save_context = cstate->context;
    1030              : 
    1031        73511 :     if (node == NULL)
    1032        34671 :         return false;
    1033        38840 :     if (IsA(node, RangeVar))
    1034              :     {
    1035         3895 :         RangeVar   *rv = (RangeVar *) node;
    1036              : 
    1037              :         /* If unqualified name, might be a CTE reference */
    1038         3895 :         if (!rv->schemaname)
    1039              :         {
    1040              :             ListCell   *lc;
    1041              :             CommonTableExpr *mycte;
    1042              : 
    1043              :             /* ... but first see if it's captured by an inner WITH */
    1044         3192 :             foreach(lc, cstate->innerwiths)
    1045              :             {
    1046          586 :                 List       *withlist = (List *) lfirst(lc);
    1047              :                 ListCell   *lc2;
    1048              : 
    1049          634 :                 foreach(lc2, withlist)
    1050              :                 {
    1051          491 :                     CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc2);
    1052              : 
    1053          491 :                     if (strcmp(rv->relname, cte->ctename) == 0)
    1054          443 :                         return false;   /* yes, so bail out */
    1055              :                 }
    1056              :             }
    1057              : 
    1058              :             /* No, could be a reference to the query level we are working on */
    1059         2606 :             mycte = cstate->items[cstate->curitem].cte;
    1060         2606 :             if (strcmp(rv->relname, mycte->ctename) == 0)
    1061              :             {
    1062              :                 /* Found a recursive reference to the active query */
    1063          658 :                 if (cstate->context != RECURSION_OK)
    1064           30 :                     ereport(ERROR,
    1065              :                             (errcode(ERRCODE_INVALID_RECURSION),
    1066              :                              errmsg(recursion_errormsgs[cstate->context],
    1067              :                                     mycte->ctename),
    1068              :                              parser_errposition(cstate->pstate,
    1069              :                                                 rv->location)));
    1070              :                 /* Count references */
    1071          628 :                 if (++(cstate->selfrefcount) > 1)
    1072            9 :                     ereport(ERROR,
    1073              :                             (errcode(ERRCODE_INVALID_RECURSION),
    1074              :                              errmsg("recursive reference to query \"%s\" must not appear more than once",
    1075              :                                     mycte->ctename),
    1076              :                              parser_errposition(cstate->pstate,
    1077              :                                                 rv->location)));
    1078              :             }
    1079              :         }
    1080         3413 :         return false;
    1081              :     }
    1082        34945 :     if (IsA(node, SelectStmt))
    1083              :     {
    1084         2275 :         SelectStmt *stmt = (SelectStmt *) node;
    1085              :         ListCell   *lc;
    1086              : 
    1087         2275 :         if (stmt->withClause)
    1088              :         {
    1089          143 :             if (stmt->withClause->recursive)
    1090              :             {
    1091              :                 /*
    1092              :                  * In the RECURSIVE case, all query names of the WITH are
    1093              :                  * visible to all WITH items as well as the main query. So
    1094              :                  * push them all on, process, pop them all off.
    1095              :                  */
    1096            3 :                 cstate->innerwiths = lcons(stmt->withClause->ctes,
    1097              :                                            cstate->innerwiths);
    1098            6 :                 foreach(lc, stmt->withClause->ctes)
    1099              :                 {
    1100            3 :                     CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
    1101              : 
    1102            3 :                     (void) checkWellFormedRecursionWalker(cte->ctequery, cstate);
    1103              :                 }
    1104            3 :                 checkWellFormedSelectStmt(stmt, cstate);
    1105            3 :                 cstate->innerwiths = list_delete_first(cstate->innerwiths);
    1106              :             }
    1107              :             else
    1108              :             {
    1109              :                 /*
    1110              :                  * In the non-RECURSIVE case, query names are visible to the
    1111              :                  * WITH items after them and to the main query.
    1112              :                  */
    1113          140 :                 cstate->innerwiths = lcons(NIL, cstate->innerwiths);
    1114          289 :                 foreach(lc, stmt->withClause->ctes)
    1115              :                 {
    1116          152 :                     CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
    1117              :                     ListCell   *cell1;
    1118              : 
    1119          152 :                     (void) checkWellFormedRecursionWalker(cte->ctequery, cstate);
    1120              :                     /* note that recursion could mutate innerwiths list */
    1121          149 :                     cell1 = list_head(cstate->innerwiths);
    1122          149 :                     lfirst(cell1) = lappend((List *) lfirst(cell1), cte);
    1123              :                 }
    1124          137 :                 checkWellFormedSelectStmt(stmt, cstate);
    1125          137 :                 cstate->innerwiths = list_delete_first(cstate->innerwiths);
    1126              :             }
    1127              :         }
    1128              :         else
    1129         2132 :             checkWellFormedSelectStmt(stmt, cstate);
    1130              :         /* We're done examining the SelectStmt */
    1131         2212 :         return false;
    1132              :     }
    1133        32670 :     if (IsA(node, WithClause))
    1134              :     {
    1135              :         /*
    1136              :          * Prevent raw_expression_tree_walker from recursing directly into a
    1137              :          * WITH clause.  We need that to happen only under the control of the
    1138              :          * code above.
    1139              :          */
    1140          140 :         return false;
    1141              :     }
    1142        32530 :     if (IsA(node, JoinExpr))
    1143              :     {
    1144         1542 :         JoinExpr   *j = (JoinExpr *) node;
    1145              : 
    1146         1542 :         switch (j->jointype)
    1147              :         {
    1148         1481 :             case JOIN_INNER:
    1149         1481 :                 checkWellFormedRecursionWalker(j->larg, cstate);
    1150         1481 :                 checkWellFormedRecursionWalker(j->rarg, cstate);
    1151         1481 :                 checkWellFormedRecursionWalker(j->quals, cstate);
    1152         1481 :                 break;
    1153           55 :             case JOIN_LEFT:
    1154           55 :                 checkWellFormedRecursionWalker(j->larg, cstate);
    1155           55 :                 if (save_context == RECURSION_OK)
    1156            3 :                     cstate->context = RECURSION_OUTERJOIN;
    1157           55 :                 checkWellFormedRecursionWalker(j->rarg, cstate);
    1158           52 :                 cstate->context = save_context;
    1159           52 :                 checkWellFormedRecursionWalker(j->quals, cstate);
    1160           52 :                 break;
    1161            3 :             case JOIN_FULL:
    1162            3 :                 if (save_context == RECURSION_OK)
    1163            3 :                     cstate->context = RECURSION_OUTERJOIN;
    1164            3 :                 checkWellFormedRecursionWalker(j->larg, cstate);
    1165            0 :                 checkWellFormedRecursionWalker(j->rarg, cstate);
    1166            0 :                 cstate->context = save_context;
    1167            0 :                 checkWellFormedRecursionWalker(j->quals, cstate);
    1168            0 :                 break;
    1169            3 :             case JOIN_RIGHT:
    1170            3 :                 if (save_context == RECURSION_OK)
    1171            3 :                     cstate->context = RECURSION_OUTERJOIN;
    1172            3 :                 checkWellFormedRecursionWalker(j->larg, cstate);
    1173            0 :                 cstate->context = save_context;
    1174            0 :                 checkWellFormedRecursionWalker(j->rarg, cstate);
    1175            0 :                 checkWellFormedRecursionWalker(j->quals, cstate);
    1176            0 :                 break;
    1177            0 :             default:
    1178            0 :                 elog(ERROR, "unrecognized join type: %d",
    1179              :                      (int) j->jointype);
    1180              :         }
    1181         1533 :         return false;
    1182              :     }
    1183        30988 :     if (IsA(node, SubLink))
    1184              :     {
    1185           55 :         SubLink    *sl = (SubLink *) node;
    1186              : 
    1187              :         /*
    1188              :          * we intentionally override outer context, since subquery is
    1189              :          * independent
    1190              :          */
    1191           55 :         cstate->context = RECURSION_SUBLINK;
    1192           55 :         checkWellFormedRecursionWalker(sl->subselect, cstate);
    1193           49 :         cstate->context = save_context;
    1194           49 :         checkWellFormedRecursionWalker(sl->testexpr, cstate);
    1195           49 :         return false;
    1196              :     }
    1197        30933 :     return raw_expression_tree_walker(node,
    1198              :                                       checkWellFormedRecursionWalker,
    1199              :                                       cstate);
    1200              : }
    1201              : 
    1202              : /*
    1203              :  * subroutine for checkWellFormedRecursionWalker: process a SelectStmt
    1204              :  * without worrying about its WITH clause
    1205              :  */
    1206              : static void
    1207         2272 : checkWellFormedSelectStmt(SelectStmt *stmt, CteState *cstate)
    1208              : {
    1209         2272 :     RecursionContext save_context = cstate->context;
    1210              : 
    1211         2272 :     if (save_context != RECURSION_OK)
    1212              :     {
    1213              :         /* just recurse without changing state */
    1214          734 :         raw_expression_tree_walker((Node *) stmt,
    1215              :                                    checkWellFormedRecursionWalker,
    1216              :                                    cstate);
    1217              :     }
    1218              :     else
    1219              :     {
    1220         1538 :         switch (stmt->op)
    1221              :         {
    1222         1532 :             case SETOP_NONE:
    1223              :             case SETOP_UNION:
    1224         1532 :                 raw_expression_tree_walker((Node *) stmt,
    1225              :                                            checkWellFormedRecursionWalker,
    1226              :                                            cstate);
    1227         1499 :                 break;
    1228            3 :             case SETOP_INTERSECT:
    1229            3 :                 if (stmt->all)
    1230            0 :                     cstate->context = RECURSION_INTERSECT;
    1231            3 :                 checkWellFormedRecursionWalker((Node *) stmt->larg,
    1232              :                                                cstate);
    1233            3 :                 checkWellFormedRecursionWalker((Node *) stmt->rarg,
    1234              :                                                cstate);
    1235            0 :                 cstate->context = save_context;
    1236            0 :                 checkWellFormedRecursionWalker((Node *) stmt->sortClause,
    1237              :                                                cstate);
    1238            0 :                 checkWellFormedRecursionWalker((Node *) stmt->limitOffset,
    1239              :                                                cstate);
    1240            0 :                 checkWellFormedRecursionWalker((Node *) stmt->limitCount,
    1241              :                                                cstate);
    1242            0 :                 checkWellFormedRecursionWalker((Node *) stmt->lockingClause,
    1243              :                                                cstate);
    1244              :                 /* stmt->withClause is intentionally ignored here */
    1245            0 :                 break;
    1246            3 :             case SETOP_EXCEPT:
    1247            3 :                 if (stmt->all)
    1248            0 :                     cstate->context = RECURSION_EXCEPT;
    1249            3 :                 checkWellFormedRecursionWalker((Node *) stmt->larg,
    1250              :                                                cstate);
    1251            3 :                 cstate->context = RECURSION_EXCEPT;
    1252            3 :                 checkWellFormedRecursionWalker((Node *) stmt->rarg,
    1253              :                                                cstate);
    1254            0 :                 cstate->context = save_context;
    1255            0 :                 checkWellFormedRecursionWalker((Node *) stmt->sortClause,
    1256              :                                                cstate);
    1257            0 :                 checkWellFormedRecursionWalker((Node *) stmt->limitOffset,
    1258              :                                                cstate);
    1259            0 :                 checkWellFormedRecursionWalker((Node *) stmt->limitCount,
    1260              :                                                cstate);
    1261            0 :                 checkWellFormedRecursionWalker((Node *) stmt->lockingClause,
    1262              :                                                cstate);
    1263              :                 /* stmt->withClause is intentionally ignored here */
    1264            0 :                 break;
    1265            0 :             default:
    1266            0 :                 elog(ERROR, "unrecognized set op: %d",
    1267              :                      (int) stmt->op);
    1268              :         }
    1269              :     }
    1270         2212 : }
        

Generated by: LCOV version 2.0-1