LCOV - code coverage report
Current view: top level - src/backend/parser - parse_cte.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 373 415 89.9 %
Date: 2025-04-24 12:15:10 Functions: 10 10 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-2025, 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        3330 : 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        7848 :     foreach(lc, withClause->ctes)
     126             :     {
     127        4518 :         CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
     128             :         ListCell   *rest;
     129             : 
     130        6854 :         for_each_cell(rest, withClause->ctes, lnext(withClause->ctes, lc))
     131             :         {
     132        2336 :             CommonTableExpr *cte2 = (CommonTableExpr *) lfirst(rest);
     133             : 
     134        2336 :             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        4518 :         cte->cterecursive = false;
     143        4518 :         cte->cterefcount = 0;
     144             : 
     145        4518 :         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         402 :             pstate->p_hasModifyingCTE = true;
     154             :         }
     155             :     }
     156             : 
     157        3330 :     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        1338 :         cstate.pstate = pstate;
     168        1338 :         cstate.numitems = list_length(withClause->ctes);
     169        1338 :         cstate.items = (CteItem *) palloc0(cstate.numitems * sizeof(CteItem));
     170        1338 :         i = 0;
     171        2772 :         foreach(lc, withClause->ctes)
     172             :         {
     173        1434 :             cstate.items[i].cte = (CommonTableExpr *) lfirst(lc);
     174        1434 :             cstate.items[i].id = i;
     175        1434 :             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        1338 :         makeDependencyGraph(&cstate);
     183             : 
     184             :         /*
     185             :          * Check that recursive queries are well-formed.
     186             :          */
     187        1332 :         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        2454 :         for (i = 0; i < cstate.numitems; i++)
     196             :         {
     197        1272 :             CommonTableExpr *cte = cstate.items[i].cte;
     198             : 
     199        1272 :             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        2328 :         for (i = 0; i < cstate.numitems; i++)
     206             :         {
     207        1272 :             CommonTableExpr *cte = cstate.items[i].cte;
     208             : 
     209        1272 :             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        1992 :         pstate->p_future_ctes = list_copy(withClause->ctes);
     222             : 
     223        5056 :         foreach(lc, withClause->ctes)
     224             :         {
     225        3084 :             CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
     226             : 
     227        3084 :             analyzeCTE(pstate, cte);
     228        3064 :             pstate->p_ctenamespace = lappend(pstate->p_ctenamespace, cte);
     229        3064 :             pstate->p_future_ctes = list_delete_first(pstate->p_future_ctes);
     230             :         }
     231             :     }
     232             : 
     233        3028 :     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        4356 : analyzeCTE(ParseState *pstate, CommonTableExpr *cte)
     244             : {
     245             :     Query      *query;
     246        4356 :     CTESearchClause *search_clause = cte->search_clause;
     247        4356 :     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        4356 :     if (cycle_clause)
     258             :     {
     259             :         TypeCacheEntry *typentry;
     260             :         Oid         op;
     261             : 
     262         126 :         cycle_clause->cycle_mark_value =
     263         126 :             transformExpr(pstate, cycle_clause->cycle_mark_value,
     264             :                           EXPR_KIND_CYCLE_MARK);
     265         126 :         cycle_clause->cycle_mark_default =
     266         126 :             transformExpr(pstate, cycle_clause->cycle_mark_default,
     267             :                           EXPR_KIND_CYCLE_MARK);
     268             : 
     269         120 :         cycle_clause->cycle_mark_type =
     270         126 :             select_common_type(pstate,
     271         126 :                                list_make2(cycle_clause->cycle_mark_value,
     272             :                                           cycle_clause->cycle_mark_default),
     273             :                                "CYCLE", NULL);
     274         120 :         cycle_clause->cycle_mark_value =
     275         120 :             coerce_to_common_type(pstate,
     276             :                                   cycle_clause->cycle_mark_value,
     277             :                                   cycle_clause->cycle_mark_type,
     278             :                                   "CYCLE/SET/TO");
     279         120 :         cycle_clause->cycle_mark_default =
     280         120 :             coerce_to_common_type(pstate,
     281             :                                   cycle_clause->cycle_mark_default,
     282             :                                   cycle_clause->cycle_mark_type,
     283             :                                   "CYCLE/SET/DEFAULT");
     284             : 
     285         120 :         cycle_clause->cycle_mark_typmod =
     286         120 :             select_common_typmod(pstate,
     287         120 :                                  list_make2(cycle_clause->cycle_mark_value,
     288             :                                             cycle_clause->cycle_mark_default),
     289             :                                  cycle_clause->cycle_mark_type);
     290             : 
     291         120 :         cycle_clause->cycle_mark_collation =
     292         120 :             select_common_collation(pstate,
     293         120 :                                     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         120 :         typentry = lookup_type_cache(cycle_clause->cycle_mark_type,
     299             :                                      TYPECACHE_EQ_OPR);
     300         120 :         if (!OidIsValid(typentry->eq_opr))
     301           6 :             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         114 :         op = get_negator(typentry->eq_opr);
     306         114 :         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         114 :         cycle_clause->cycle_mark_neop = op;
     313             :     }
     314             : 
     315             :     /* Now we can get on with analyzing the CTE's query */
     316        4344 :     query = parse_sub_analyze(cte->ctequery, pstate, cte, false, true);
     317        4318 :     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        4318 :     if (!IsA(query, Query))
     324           0 :         elog(ERROR, "unexpected non-Query statement in WITH");
     325        4318 :     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        4318 :     if (query->commandType != CMD_SELECT &&
     333         384 :         pstate->parentParseState != NULL)
     334           6 :         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        4312 :     query->canSetTag = false;
     345             : 
     346        4312 :     if (!cte->cterecursive)
     347             :     {
     348             :         /* Compute the output column names/types if not done yet */
     349        3184 :         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        1128 :         lctyp = list_head(cte->ctecoltypes);
     366        1128 :         lctypmod = list_head(cte->ctecoltypmods);
     367        1128 :         lccoll = list_head(cte->ctecolcollations);
     368        1128 :         varattno = 0;
     369        3614 :         foreach(lctlist, GetCTETargetList(cte))
     370             :         {
     371        2510 :             TargetEntry *te = (TargetEntry *) lfirst(lctlist);
     372             :             Node       *texpr;
     373             : 
     374        2510 :             if (te->resjunk)
     375           0 :                 continue;
     376        2510 :             varattno++;
     377             :             Assert(varattno == te->resno);
     378        2510 :             if (lctyp == NULL || lctypmod == NULL || lccoll == NULL)    /* shouldn't happen */
     379           0 :                 elog(ERROR, "wrong number of output columns in WITH");
     380        2510 :             texpr = (Node *) te->expr;
     381        2510 :             if (exprType(texpr) != lfirst_oid(lctyp) ||
     382        2504 :                 exprTypmod(texpr) != lfirst_int(lctypmod))
     383          12 :                 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        2498 :             if (exprCollation(texpr) != lfirst_oid(lccoll))
     394          12 :                 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        2486 :             lctyp = lnext(cte->ctecoltypes, lctyp);
     403        2486 :             lctypmod = lnext(cte->ctecoltypmods, lctypmod);
     404        2486 :             lccoll = lnext(cte->ctecolcollations, lccoll);
     405             :         }
     406        1104 :         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        4282 :     if (search_clause || cycle_clause)
     414             :     {
     415             :         Query      *ctequery;
     416             :         SetOperationStmt *sos;
     417             : 
     418         216 :         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         216 :         ctequery = castNode(Query, cte->ctequery);
     441             :         Assert(ctequery->setOperations);
     442         216 :         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         216 :         if (!IsA(sos->larg, RangeTblRef))
     450           6 :             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         210 :         if (!IsA(sos->rarg, RangeTblRef))
     455           6 :             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        4270 :     if (search_clause)
     461             :     {
     462             :         ListCell   *lc;
     463         114 :         List       *seen = NIL;
     464             : 
     465         300 :         foreach(lc, search_clause->search_col_list)
     466             :         {
     467         198 :             String     *colname = lfirst_node(String, lc);
     468             : 
     469         198 :             if (!list_member(cte->ctecolnames, colname))
     470           6 :                 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         192 :             if (list_member(seen, colname))
     477           6 :                 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         186 :             seen = lappend(seen, colname);
     483             :         }
     484             : 
     485         102 :         if (list_member(cte->ctecolnames, makeString(search_clause->search_seq_column)))
     486           6 :             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        4252 :     if (cycle_clause)
     494             :     {
     495             :         ListCell   *lc;
     496         114 :         List       *seen = NIL;
     497             : 
     498         306 :         foreach(lc, cycle_clause->cycle_col_list)
     499             :         {
     500         204 :             String     *colname = lfirst_node(String, lc);
     501             : 
     502         204 :             if (!list_member(cte->ctecolnames, colname))
     503           6 :                 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         198 :             if (list_member(seen, colname))
     510           6 :                 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         192 :             seen = lappend(seen, colname);
     516             :         }
     517             : 
     518         102 :         if (list_member(cte->ctecolnames, makeString(cycle_clause->cycle_mark_column)))
     519           6 :             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          96 :         if (list_member(cte->ctecolnames, makeString(cycle_clause->cycle_path_column)))
     526           6 :             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          90 :         if (strcmp(cycle_clause->cycle_mark_column,
     533          90 :                    cycle_clause->cycle_path_column) == 0)
     534           6 :             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        4222 :     if (search_clause && cycle_clause)
     541             :     {
     542          24 :         if (strcmp(search_clause->search_seq_column,
     543          24 :                    cycle_clause->cycle_mark_column) == 0)
     544           6 :             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          18 :         if (strcmp(search_clause->search_seq_column,
     550          18 :                    cycle_clause->cycle_path_column) == 0)
     551           6 :             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        4210 : }
     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        4330 : 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        4330 :     cte->ctecolnames = copyObject(cte->aliascolnames);
     588        4330 :     cte->ctecoltypes = cte->ctecoltypmods = cte->ctecolcollations = NIL;
     589        4330 :     numaliases = list_length(cte->aliascolnames);
     590        4330 :     varattno = 0;
     591       14644 :     foreach(tlistitem, tlist)
     592             :     {
     593       10314 :         TargetEntry *te = (TargetEntry *) lfirst(tlistitem);
     594             :         Oid         coltype;
     595             :         int32       coltypmod;
     596             :         Oid         colcoll;
     597             : 
     598       10314 :         if (te->resjunk)
     599           6 :             continue;
     600       10308 :         varattno++;
     601             :         Assert(varattno == te->resno);
     602       10308 :         if (varattno > numaliases)
     603             :         {
     604             :             char       *attrname;
     605             : 
     606        4268 :             attrname = pstrdup(te->resname);
     607        4268 :             cte->ctecolnames = lappend(cte->ctecolnames, makeString(attrname));
     608             :         }
     609       10308 :         coltype = exprType((Node *) te->expr);
     610       10308 :         coltypmod = exprTypmod((Node *) te->expr);
     611       10308 :         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       10308 :         if (cte->cterecursive && coltype == UNKNOWNOID)
     624             :         {
     625          36 :             coltype = TEXTOID;
     626          36 :             coltypmod = -1;     /* should be -1 already, but be sure */
     627          36 :             if (!OidIsValid(colcoll))
     628          36 :                 colcoll = DEFAULT_COLLATION_OID;
     629             :         }
     630       10308 :         cte->ctecoltypes = lappend_oid(cte->ctecoltypes, coltype);
     631       10308 :         cte->ctecoltypmods = lappend_int(cte->ctecoltypmods, coltypmod);
     632       10308 :         cte->ctecolcollations = lappend_oid(cte->ctecolcollations, colcoll);
     633             :     }
     634        4330 :     if (varattno < numaliases)
     635           6 :         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        4324 : }
     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        1338 : makeDependencyGraph(CteState *cstate)
     649             : {
     650             :     int         i;
     651             : 
     652        2772 :     for (i = 0; i < cstate->numitems; i++)
     653             :     {
     654        1434 :         CommonTableExpr *cte = cstate->items[i].cte;
     655             : 
     656        1434 :         cstate->curitem = i;
     657        1434 :         cstate->innerwiths = NIL;
     658        1434 :         makeDependencyGraphWalker((Node *) cte->ctequery, cstate);
     659             :         Assert(cstate->innerwiths == NIL);
     660             :     }
     661             : 
     662        1338 :     TopologicalSort(cstate->pstate, cstate->items, cstate->numitems);
     663        1332 : }
     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      168570 : makeDependencyGraphWalker(Node *node, CteState *cstate)
     671             : {
     672      168570 :     if (node == NULL)
     673       92234 :         return false;
     674       76336 :     if (IsA(node, RangeVar))
     675             :     {
     676        7446 :         RangeVar   *rv = (RangeVar *) node;
     677             : 
     678             :         /* If unqualified name, might be a CTE reference */
     679        7446 :         if (!rv->schemaname)
     680             :         {
     681             :             ListCell   *lc;
     682             :             int         i;
     683             : 
     684             :             /* ... but first see if it's captured by an inner WITH */
     685        6364 :             foreach(lc, cstate->innerwiths)
     686             :             {
     687        1118 :                 List       *withlist = (List *) lfirst(lc);
     688             :                 ListCell   *lc2;
     689             : 
     690        1232 :                 foreach(lc2, withlist)
     691             :                 {
     692         946 :                     CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc2);
     693             : 
     694         946 :                     if (strcmp(rv->relname, cte->ctename) == 0)
     695         832 :                         return false;   /* yes, so bail out */
     696             :                 }
     697             :             }
     698             : 
     699             :             /* No, could be a reference to the query level we are working on */
     700        9154 :             for (i = 0; i < cstate->numitems; i++)
     701             :             {
     702        5384 :                 CommonTableExpr *cte = cstate->items[i].cte;
     703             : 
     704        5384 :                 if (strcmp(rv->relname, cte->ctename) == 0)
     705             :                 {
     706        1476 :                     int         myindex = cstate->curitem;
     707             : 
     708        1476 :                     if (i != myindex)
     709             :                     {
     710             :                         /* Add cross-item dependency */
     711         126 :                         cstate->items[myindex].depends_on =
     712         126 :                             bms_add_member(cstate->items[myindex].depends_on,
     713         126 :                                            cstate->items[i].id);
     714             :                     }
     715             :                     else
     716             :                     {
     717             :                         /* Found out this one is self-referential */
     718        1350 :                         cte->cterecursive = true;
     719             :                     }
     720        1476 :                     break;
     721             :                 }
     722             :             }
     723             :         }
     724        6614 :         return false;
     725             :     }
     726       68890 :     if (IsA(node, SelectStmt))
     727             :     {
     728        5848 :         SelectStmt *stmt = (SelectStmt *) node;
     729             : 
     730        5848 :         if (stmt->withClause)
     731             :         {
     732             :             /* Examine the WITH clause and the SelectStmt */
     733         328 :             WalkInnerWith(node, stmt->withClause, cstate);
     734             :             /* We're done examining the SelectStmt */
     735         328 :             return false;
     736             :         }
     737             :         /* if no WITH clause, just fall through for normal processing */
     738             :     }
     739       63042 :     else if (IsA(node, InsertStmt))
     740             :     {
     741          42 :         InsertStmt *stmt = (InsertStmt *) node;
     742             : 
     743          42 :         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       63000 :     else if (IsA(node, DeleteStmt))
     753             :     {
     754           6 :         DeleteStmt *stmt = (DeleteStmt *) node;
     755             : 
     756           6 :         if (stmt->withClause)
     757             :         {
     758             :             /* Examine the WITH clause and the DeleteStmt */
     759           6 :             WalkInnerWith(node, stmt->withClause, cstate);
     760             :             /* We're done examining the DeleteStmt */
     761           6 :             return false;
     762             :         }
     763             :         /* if no WITH clause, just fall through for normal processing */
     764             :     }
     765       62994 :     else if (IsA(node, UpdateStmt))
     766             :     {
     767           6 :         UpdateStmt *stmt = (UpdateStmt *) node;
     768             : 
     769           6 :         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       62988 :     else if (IsA(node, MergeStmt))
     779             :     {
     780           6 :         MergeStmt  *stmt = (MergeStmt *) node;
     781             : 
     782           6 :         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       62982 :     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         334 :         return false;
     799             :     }
     800       68222 :     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         334 : WalkInnerWith(Node *stmt, WithClause *withClause, CteState *cstate)
     813             : {
     814             :     ListCell   *lc;
     815             : 
     816         334 :     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          18 :         cstate->innerwiths = lcons(withClause->ctes, cstate->innerwiths);
     824          36 :         foreach(lc, withClause->ctes)
     825             :         {
     826          18 :             CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
     827             : 
     828          18 :             (void) makeDependencyGraphWalker(cte->ctequery, cstate);
     829             :         }
     830          18 :         (void) raw_expression_tree_walker(stmt,
     831             :                                           makeDependencyGraphWalker,
     832             :                                           cstate);
     833          18 :         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         316 :         cstate->innerwiths = lcons(NIL, cstate->innerwiths);
     842         656 :         foreach(lc, withClause->ctes)
     843             :         {
     844         340 :             CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
     845             :             ListCell   *cell1;
     846             : 
     847         340 :             (void) makeDependencyGraphWalker(cte->ctequery, cstate);
     848             :             /* note that recursion could mutate innerwiths list */
     849         340 :             cell1 = list_head(cstate->innerwiths);
     850         340 :             lfirst(cell1) = lappend((List *) lfirst(cell1), cte);
     851             :         }
     852         316 :         (void) raw_expression_tree_walker(stmt,
     853             :                                           makeDependencyGraphWalker,
     854             :                                           cstate);
     855         316 :         cstate->innerwiths = list_delete_first(cstate->innerwiths);
     856             :     }
     857         334 : }
     858             : 
     859             : /*
     860             :  * Sort by dependencies, using a standard topological sort operation
     861             :  */
     862             : static void
     863        1338 : TopologicalSort(ParseState *pstate, CteItem *items, int numitems)
     864             : {
     865             :     int         i,
     866             :                 j;
     867             : 
     868             :     /* for each position in sequence ... */
     869        2760 :     for (i = 0; i < numitems; i++)
     870             :     {
     871             :         /* ... scan the remaining items to find one that has no dependencies */
     872        1458 :         for (j = i; j < numitems; j++)
     873             :         {
     874        1452 :             if (bms_is_empty(items[j].depends_on))
     875        1422 :                 break;
     876             :         }
     877             : 
     878             :         /* if we didn't find one, the dependency graph has a cycle */
     879        1428 :         if (j >= numitems)
     880           6 :             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        1422 :         if (i != j)
     890             :         {
     891             :             CteItem     tmp;
     892             : 
     893          18 :             tmp = items[i];
     894          18 :             items[i] = items[j];
     895          18 :             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        1524 :         for (j = i + 1; j < numitems; j++)
     903             :         {
     904         102 :             items[j].depends_on = bms_del_member(items[j].depends_on,
     905         102 :                                                  items[i].id);
     906             :         }
     907             :     }
     908        1332 : }
     909             : 
     910             : 
     911             : /*
     912             :  * Check that recursive queries are well-formed.
     913             :  */
     914             : static void
     915        1332 : checkWellFormedRecursion(CteState *cstate)
     916             : {
     917             :     int         i;
     918             : 
     919        2604 :     for (i = 0; i < cstate->numitems; i++)
     920             :     {
     921        1422 :         CommonTableExpr *cte = cstate->items[i].cte;
     922        1422 :         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        1422 :         if (!cte->cterecursive)
     928         114 :             continue;
     929             : 
     930             :         /* Must be a SELECT statement */
     931        1308 :         if (!IsA(stmt, SelectStmt))
     932          18 :             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        1290 :         if (stmt->op != SETOP_UNION)
     940          30 :             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        1260 :         if (stmt->withClause)
     955             :         {
     956          18 :             cstate->curitem = i;
     957          18 :             cstate->innerwiths = NIL;
     958          18 :             cstate->selfrefcount = 0;
     959          18 :             cstate->context = RECURSION_SUBLINK;
     960          18 :             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        1248 :         if (stmt->sortClause)
     975          12 :             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        1236 :         if (stmt->limitOffset)
     981           6 :             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        1230 :         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        1230 :         if (stmt->lockingClause)
     993           6 :             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        1224 :         cstate->curitem = i;
    1005        1224 :         cstate->innerwiths = NIL;
    1006        1224 :         cstate->selfrefcount = 0;
    1007        1224 :         cstate->context = RECURSION_NONRECURSIVETERM;
    1008        1224 :         checkWellFormedRecursionWalker((Node *) stmt->larg, cstate);
    1009             :         Assert(cstate->innerwiths == NIL);
    1010             : 
    1011             :         /* Right-hand operand should contain one reference in a valid place */
    1012        1212 :         cstate->curitem = i;
    1013        1212 :         cstate->innerwiths = NIL;
    1014        1212 :         cstate->selfrefcount = 0;
    1015        1212 :         cstate->context = RECURSION_OK;
    1016        1212 :         checkWellFormedRecursionWalker((Node *) stmt->rarg, cstate);
    1017             :         Assert(cstate->innerwiths == NIL);
    1018        1158 :         if (cstate->selfrefcount != 1)   /* shouldn't happen */
    1019           0 :             elog(ERROR, "missing recursive reference");
    1020             :     }
    1021        1182 : }
    1022             : 
    1023             : /*
    1024             :  * Tree walker function to detect invalid self-references in a recursive query.
    1025             :  */
    1026             : static bool
    1027      135066 : checkWellFormedRecursionWalker(Node *node, CteState *cstate)
    1028             : {
    1029      135066 :     RecursionContext save_context = cstate->context;
    1030             : 
    1031      135066 :     if (node == NULL)
    1032       63410 :         return false;
    1033       71656 :     if (IsA(node, RangeVar))
    1034             :     {
    1035        7128 :         RangeVar   *rv = (RangeVar *) node;
    1036             : 
    1037             :         /* If unqualified name, might be a CTE reference */
    1038        7128 :         if (!rv->schemaname)
    1039             :         {
    1040             :             ListCell   *lc;
    1041             :             CommonTableExpr *mycte;
    1042             : 
    1043             :             /* ... but first see if it's captured by an inner WITH */
    1044        6010 :             foreach(lc, cstate->innerwiths)
    1045             :             {
    1046         992 :                 List       *withlist = (List *) lfirst(lc);
    1047             :                 ListCell   *lc2;
    1048             : 
    1049        1088 :                 foreach(lc2, withlist)
    1050             :                 {
    1051         838 :                     CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc2);
    1052             : 
    1053         838 :                     if (strcmp(rv->relname, cte->ctename) == 0)
    1054         742 :                         return false;   /* yes, so bail out */
    1055             :                 }
    1056             :             }
    1057             : 
    1058             :             /* No, could be a reference to the query level we are working on */
    1059        5018 :             mycte = cstate->items[cstate->curitem].cte;
    1060        5018 :             if (strcmp(rv->relname, mycte->ctename) == 0)
    1061             :             {
    1062             :                 /* Found a recursive reference to the active query */
    1063        1266 :                 if (cstate->context != RECURSION_OK)
    1064          60 :                     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        1206 :                 if (++(cstate->selfrefcount) > 1)
    1072          18 :                     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        6308 :         return false;
    1081             :     }
    1082       64528 :     if (IsA(node, SelectStmt))
    1083             :     {
    1084        4144 :         SelectStmt *stmt = (SelectStmt *) node;
    1085             :         ListCell   *lc;
    1086             : 
    1087        4144 :         if (stmt->withClause)
    1088             :         {
    1089         250 :             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           6 :                 cstate->innerwiths = lcons(stmt->withClause->ctes,
    1097             :                                            cstate->innerwiths);
    1098          12 :                 foreach(lc, stmt->withClause->ctes)
    1099             :                 {
    1100           6 :                     CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
    1101             : 
    1102           6 :                     (void) checkWellFormedRecursionWalker(cte->ctequery, cstate);
    1103             :                 }
    1104           6 :                 checkWellFormedSelectStmt(stmt, cstate);
    1105           6 :                 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         244 :                 cstate->innerwiths = lcons(NIL, cstate->innerwiths);
    1114         506 :                 foreach(lc, stmt->withClause->ctes)
    1115             :                 {
    1116         268 :                     CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
    1117             :                     ListCell   *cell1;
    1118             : 
    1119         268 :                     (void) checkWellFormedRecursionWalker(cte->ctequery, cstate);
    1120             :                     /* note that recursion could mutate innerwiths list */
    1121         262 :                     cell1 = list_head(cstate->innerwiths);
    1122         262 :                     lfirst(cell1) = lappend((List *) lfirst(cell1), cte);
    1123             :                 }
    1124         238 :                 checkWellFormedSelectStmt(stmt, cstate);
    1125         238 :                 cstate->innerwiths = list_delete_first(cstate->innerwiths);
    1126             :             }
    1127             :         }
    1128             :         else
    1129        3894 :             checkWellFormedSelectStmt(stmt, cstate);
    1130             :         /* We're done examining the SelectStmt */
    1131        4018 :         return false;
    1132             :     }
    1133       60384 :     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         244 :         return false;
    1141             :     }
    1142       60140 :     if (IsA(node, JoinExpr))
    1143             :     {
    1144        2940 :         JoinExpr   *j = (JoinExpr *) node;
    1145             : 
    1146        2940 :         switch (j->jointype)
    1147             :         {
    1148        2836 :             case JOIN_INNER:
    1149        2836 :                 checkWellFormedRecursionWalker(j->larg, cstate);
    1150        2836 :                 checkWellFormedRecursionWalker(j->rarg, cstate);
    1151        2836 :                 checkWellFormedRecursionWalker(j->quals, cstate);
    1152        2836 :                 break;
    1153          92 :             case JOIN_LEFT:
    1154          92 :                 checkWellFormedRecursionWalker(j->larg, cstate);
    1155          92 :                 if (save_context == RECURSION_OK)
    1156           6 :                     cstate->context = RECURSION_OUTERJOIN;
    1157          92 :                 checkWellFormedRecursionWalker(j->rarg, cstate);
    1158          86 :                 cstate->context = save_context;
    1159          86 :                 checkWellFormedRecursionWalker(j->quals, cstate);
    1160          86 :                 break;
    1161           6 :             case JOIN_FULL:
    1162           6 :                 if (save_context == RECURSION_OK)
    1163           6 :                     cstate->context = RECURSION_OUTERJOIN;
    1164           6 :                 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           6 :             case JOIN_RIGHT:
    1170           6 :                 if (save_context == RECURSION_OK)
    1171           6 :                     cstate->context = RECURSION_OUTERJOIN;
    1172           6 :                 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        2922 :         return false;
    1182             :     }
    1183       57200 :     if (IsA(node, SubLink))
    1184             :     {
    1185          92 :         SubLink    *sl = (SubLink *) node;
    1186             : 
    1187             :         /*
    1188             :          * we intentionally override outer context, since subquery is
    1189             :          * independent
    1190             :          */
    1191          92 :         cstate->context = RECURSION_SUBLINK;
    1192          92 :         checkWellFormedRecursionWalker(sl->subselect, cstate);
    1193          80 :         cstate->context = save_context;
    1194          80 :         checkWellFormedRecursionWalker(sl->testexpr, cstate);
    1195          80 :         return false;
    1196             :     }
    1197       57108 :     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        4138 : checkWellFormedSelectStmt(SelectStmt *stmt, CteState *cstate)
    1208             : {
    1209        4138 :     RecursionContext save_context = cstate->context;
    1210             : 
    1211        4138 :     if (save_context != RECURSION_OK)
    1212             :     {
    1213             :         /* just recurse without changing state */
    1214        1400 :         raw_expression_tree_walker((Node *) stmt,
    1215             :                                    checkWellFormedRecursionWalker,
    1216             :                                    cstate);
    1217             :     }
    1218             :     else
    1219             :     {
    1220        2738 :         switch (stmt->op)
    1221             :         {
    1222        2726 :             case SETOP_NONE:
    1223             :             case SETOP_UNION:
    1224        2726 :                 raw_expression_tree_walker((Node *) stmt,
    1225             :                                            checkWellFormedRecursionWalker,
    1226             :                                            cstate);
    1227        2660 :                 break;
    1228           6 :             case SETOP_INTERSECT:
    1229           6 :                 if (stmt->all)
    1230           0 :                     cstate->context = RECURSION_INTERSECT;
    1231           6 :                 checkWellFormedRecursionWalker((Node *) stmt->larg,
    1232             :                                                cstate);
    1233           6 :                 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           6 :             case SETOP_EXCEPT:
    1247           6 :                 if (stmt->all)
    1248           0 :                     cstate->context = RECURSION_EXCEPT;
    1249           6 :                 checkWellFormedRecursionWalker((Node *) stmt->larg,
    1250             :                                                cstate);
    1251           6 :                 cstate->context = RECURSION_EXCEPT;
    1252           6 :                 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        4018 : }

Generated by: LCOV version 1.14