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

Generated by: LCOV version 1.14