LCOV - code coverage report
Current view: top level - src/backend/parser - parse_cte.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 356 392 90.8 %
Date: 2024-03-28 23:11:20 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        2790 : 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        6624 :     foreach(lc, withClause->ctes)
     125             :     {
     126        3834 :         CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
     127             :         ListCell   *rest;
     128             : 
     129        5992 :         for_each_cell(rest, withClause->ctes, lnext(withClause->ctes, lc))
     130             :         {
     131        2158 :             CommonTableExpr *cte2 = (CommonTableExpr *) lfirst(rest);
     132             : 
     133        2158 :             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        3834 :         cte->cterecursive = false;
     142        3834 :         cte->cterefcount = 0;
     143             : 
     144        3834 :         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        2790 :     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        1102 :         cstate.pstate = pstate;
     167        1102 :         cstate.numitems = list_length(withClause->ctes);
     168        1102 :         cstate.items = (CteItem *) palloc0(cstate.numitems * sizeof(CteItem));
     169        1102 :         i = 0;
     170        2300 :         foreach(lc, withClause->ctes)
     171             :         {
     172        1198 :             cstate.items[i].cte = (CommonTableExpr *) lfirst(lc);
     173        1198 :             cstate.items[i].id = i;
     174        1198 :             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        1102 :         makeDependencyGraph(&cstate);
     182             : 
     183             :         /*
     184             :          * Check that recursive queries are well-formed.
     185             :          */
     186        1096 :         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        2030 :         for (i = 0; i < cstate.numitems; i++)
     195             :         {
     196        1060 :             CommonTableExpr *cte = cstate.items[i].cte;
     197             : 
     198        1060 :             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        1904 :         for (i = 0; i < cstate.numitems; i++)
     205             :         {
     206        1060 :             CommonTableExpr *cte = cstate.items[i].cte;
     207             : 
     208        1060 :             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        1688 :         pstate->p_future_ctes = list_copy(withClause->ctes);
     221             : 
     222        4304 :         foreach(lc, withClause->ctes)
     223             :         {
     224        2636 :             CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
     225             : 
     226        2636 :             analyzeCTE(pstate, cte);
     227        2616 :             pstate->p_ctenamespace = lappend(pstate->p_ctenamespace, cte);
     228        2616 :             pstate->p_future_ctes = list_delete_first(pstate->p_future_ctes);
     229             :         }
     230             :     }
     231             : 
     232        2512 :     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        3696 : analyzeCTE(ParseState *pstate, CommonTableExpr *cte)
     243             : {
     244             :     Query      *query;
     245        3696 :     CTESearchClause *search_clause = cte->search_clause;
     246        3696 :     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        3696 :     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        3684 :     query = parse_sub_analyze(cte->ctequery, pstate, cte, false, true);
     316        3658 :     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        3658 :     if (!IsA(query, Query))
     323           0 :         elog(ERROR, "unexpected non-Query statement in WITH");
     324        3658 :     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        3658 :     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        3652 :     query->canSetTag = false;
     344             : 
     345        3652 :     if (!cte->cterecursive)
     346             :     {
     347             :         /* Compute the output column names/types if not done yet */
     348        2730 :         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         922 :         lctyp = list_head(cte->ctecoltypes);
     365         922 :         lctypmod = list_head(cte->ctecoltypmods);
     366         922 :         lccoll = list_head(cte->ctecolcollations);
     367         922 :         varattno = 0;
     368        2946 :         foreach(lctlist, GetCTETargetList(cte))
     369             :         {
     370        2048 :             TargetEntry *te = (TargetEntry *) lfirst(lctlist);
     371             :             Node       *texpr;
     372             : 
     373        2048 :             if (te->resjunk)
     374           0 :                 continue;
     375        2048 :             varattno++;
     376             :             Assert(varattno == te->resno);
     377        2048 :             if (lctyp == NULL || lctypmod == NULL || lccoll == NULL)    /* shouldn't happen */
     378           0 :                 elog(ERROR, "wrong number of output columns in WITH");
     379        2048 :             texpr = (Node *) te->expr;
     380        2048 :             if (exprType(texpr) != lfirst_oid(lctyp) ||
     381        2042 :                 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        2036 :             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        2024 :             lctyp = lnext(cte->ctecoltypes, lctyp);
     402        2024 :             lctypmod = lnext(cte->ctecoltypmods, lctypmod);
     403        2024 :             lccoll = lnext(cte->ctecolcollations, lccoll);
     404             :         }
     405         898 :         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        3622 :     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        3610 :     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        3592 :     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        3562 :     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        3550 : }
     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        3670 : 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        3670 :     cte->ctecolnames = copyObject(cte->aliascolnames);
     587        3670 :     cte->ctecoltypes = cte->ctecoltypmods = cte->ctecolcollations = NIL;
     588        3670 :     numaliases = list_length(cte->aliascolnames);
     589        3670 :     varattno = 0;
     590       12306 :     foreach(tlistitem, tlist)
     591             :     {
     592        8636 :         TargetEntry *te = (TargetEntry *) lfirst(tlistitem);
     593             :         Oid         coltype;
     594             :         int32       coltypmod;
     595             :         Oid         colcoll;
     596             : 
     597        8636 :         if (te->resjunk)
     598           6 :             continue;
     599        8630 :         varattno++;
     600             :         Assert(varattno == te->resno);
     601        8630 :         if (varattno > numaliases)
     602             :         {
     603             :             char       *attrname;
     604             : 
     605        3332 :             attrname = pstrdup(te->resname);
     606        3332 :             cte->ctecolnames = lappend(cte->ctecolnames, makeString(attrname));
     607             :         }
     608        8630 :         coltype = exprType((Node *) te->expr);
     609        8630 :         coltypmod = exprTypmod((Node *) te->expr);
     610        8630 :         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        8630 :         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        8630 :         cte->ctecoltypes = lappend_oid(cte->ctecoltypes, coltype);
     630        8630 :         cte->ctecoltypmods = lappend_int(cte->ctecoltypmods, coltypmod);
     631        8630 :         cte->ctecolcollations = lappend_oid(cte->ctecolcollations, colcoll);
     632             :     }
     633        3670 :     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        3664 : }
     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        1102 : makeDependencyGraph(CteState *cstate)
     648             : {
     649             :     int         i;
     650             : 
     651        2300 :     for (i = 0; i < cstate->numitems; i++)
     652             :     {
     653        1198 :         CommonTableExpr *cte = cstate->items[i].cte;
     654             : 
     655        1198 :         cstate->curitem = i;
     656        1198 :         cstate->innerwiths = NIL;
     657        1198 :         makeDependencyGraphWalker((Node *) cte->ctequery, cstate);
     658             :         Assert(cstate->innerwiths == NIL);
     659             :     }
     660             : 
     661        1102 :     TopologicalSort(cstate->pstate, cstate->items, cstate->numitems);
     662        1096 : }
     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      126590 : makeDependencyGraphWalker(Node *node, CteState *cstate)
     670             : {
     671      126590 :     if (node == NULL)
     672       71510 :         return false;
     673       55080 :     if (IsA(node, RangeVar))
     674             :     {
     675        5314 :         RangeVar   *rv = (RangeVar *) node;
     676             : 
     677             :         /* If unqualified name, might be a CTE reference */
     678        5314 :         if (!rv->schemaname)
     679             :         {
     680             :             ListCell   *lc;
     681             :             int         i;
     682             : 
     683             :             /* ... but first see if it's captured by an inner WITH */
     684        4752 :             foreach(lc, cstate->innerwiths)
     685             :             {
     686         736 :                 List       *withlist = (List *) lfirst(lc);
     687             :                 ListCell   *lc2;
     688             : 
     689         844 :                 foreach(lc2, withlist)
     690             :                 {
     691         650 :                     CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc2);
     692             : 
     693         650 :                     if (strcmp(rv->relname, cte->ctename) == 0)
     694         542 :                         return false;   /* yes, so bail out */
     695             :                 }
     696             :             }
     697             : 
     698             :             /* No, could be a reference to the query level we are working on */
     699        6924 :             for (i = 0; i < cstate->numitems; i++)
     700             :             {
     701        4154 :                 CommonTableExpr *cte = cstate->items[i].cte;
     702             : 
     703        4154 :                 if (strcmp(rv->relname, cte->ctename) == 0)
     704             :                 {
     705        1246 :                     int         myindex = cstate->curitem;
     706             : 
     707        1246 :                     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        1120 :                         cte->cterecursive = true;
     718             :                     }
     719        1246 :                     break;
     720             :                 }
     721             :             }
     722             :         }
     723        4772 :         return false;
     724             :     }
     725       49766 :     if (IsA(node, SelectStmt))
     726             :     {
     727        4550 :         SelectStmt *stmt = (SelectStmt *) node;
     728             :         ListCell   *lc;
     729             : 
     730        4550 :         if (stmt->withClause)
     731             :         {
     732         242 :             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         224 :                 cstate->innerwiths = lcons(NIL, cstate->innerwiths);
     759         472 :                 foreach(lc, stmt->withClause->ctes)
     760             :                 {
     761         248 :                     CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
     762             :                     ListCell   *cell1;
     763             : 
     764         248 :                     (void) makeDependencyGraphWalker(cte->ctequery, cstate);
     765             :                     /* note that recursion could mutate innerwiths list */
     766         248 :                     cell1 = list_head(cstate->innerwiths);
     767         248 :                     lfirst(cell1) = lappend((List *) lfirst(cell1), cte);
     768             :                 }
     769         224 :                 (void) raw_expression_tree_walker(node,
     770             :                                                   makeDependencyGraphWalker,
     771             :                                                   (void *) cstate);
     772         224 :                 cstate->innerwiths = list_delete_first(cstate->innerwiths);
     773             :             }
     774             :             /* We're done examining the SelectStmt */
     775         242 :             return false;
     776             :         }
     777             :         /* if no WITH clause, just fall through for normal processing */
     778             :     }
     779       49524 :     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         242 :         return false;
     787             :     }
     788       49282 :     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        1102 : TopologicalSort(ParseState *pstate, CteItem *items, int numitems)
     798             : {
     799             :     int         i,
     800             :                 j;
     801             : 
     802             :     /* for each position in sequence ... */
     803        2288 :     for (i = 0; i < numitems; i++)
     804             :     {
     805             :         /* ... scan the remaining items to find one that has no dependencies */
     806        1222 :         for (j = i; j < numitems; j++)
     807             :         {
     808        1216 :             if (bms_is_empty(items[j].depends_on))
     809        1186 :                 break;
     810             :         }
     811             : 
     812             :         /* if we didn't find one, the dependency graph has a cycle */
     813        1192 :         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        1186 :         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        1288 :         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        1096 : }
     843             : 
     844             : 
     845             : /*
     846             :  * Check that recursive queries are well-formed.
     847             :  */
     848             : static void
     849        1096 : checkWellFormedRecursion(CteState *cstate)
     850             : {
     851             :     int         i;
     852             : 
     853        2156 :     for (i = 0; i < cstate->numitems; i++)
     854             :     {
     855        1186 :         CommonTableExpr *cte = cstate->items[i].cte;
     856        1186 :         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        1186 :         if (!cte->cterecursive)
     862         108 :             continue;
     863             : 
     864             :         /* Must be a SELECT statement */
     865        1078 :         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        1066 :         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             :         /* The left-hand operand mustn't contain self-reference at all */
     881        1036 :         cstate->curitem = i;
     882        1036 :         cstate->innerwiths = NIL;
     883        1036 :         cstate->selfrefcount = 0;
     884        1036 :         cstate->context = RECURSION_NONRECURSIVETERM;
     885        1036 :         checkWellFormedRecursionWalker((Node *) stmt->larg, cstate);
     886             :         Assert(cstate->innerwiths == NIL);
     887             : 
     888             :         /* Right-hand operand should contain one reference in a valid place */
     889        1030 :         cstate->curitem = i;
     890        1030 :         cstate->innerwiths = NIL;
     891        1030 :         cstate->selfrefcount = 0;
     892        1030 :         cstate->context = RECURSION_OK;
     893        1030 :         checkWellFormedRecursionWalker((Node *) stmt->rarg, cstate);
     894             :         Assert(cstate->innerwiths == NIL);
     895         976 :         if (cstate->selfrefcount != 1)   /* shouldn't happen */
     896           0 :             elog(ERROR, "missing recursive reference");
     897             : 
     898             :         /* WITH mustn't contain self-reference, either */
     899         976 :         if (stmt->withClause)
     900             :         {
     901          12 :             cstate->curitem = i;
     902          12 :             cstate->innerwiths = NIL;
     903          12 :             cstate->selfrefcount = 0;
     904          12 :             cstate->context = RECURSION_SUBLINK;
     905          12 :             checkWellFormedRecursionWalker((Node *) stmt->withClause->ctes,
     906             :                                            cstate);
     907             :             Assert(cstate->innerwiths == NIL);
     908             :         }
     909             : 
     910             :         /*
     911             :          * Disallow ORDER BY and similar decoration atop the UNION. These
     912             :          * don't make sense because it's impossible to figure out what they
     913             :          * mean when we have only part of the recursive query's results. (If
     914             :          * we did allow them, we'd have to check for recursive references
     915             :          * inside these subtrees.)
     916             :          */
     917         970 :         if (stmt->sortClause)
     918           6 :             ereport(ERROR,
     919             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     920             :                      errmsg("ORDER BY in a recursive query is not implemented"),
     921             :                      parser_errposition(cstate->pstate,
     922             :                                         exprLocation((Node *) stmt->sortClause))));
     923         964 :         if (stmt->limitOffset)
     924           6 :             ereport(ERROR,
     925             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     926             :                      errmsg("OFFSET in a recursive query is not implemented"),
     927             :                      parser_errposition(cstate->pstate,
     928             :                                         exprLocation(stmt->limitOffset))));
     929         958 :         if (stmt->limitCount)
     930           0 :             ereport(ERROR,
     931             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     932             :                      errmsg("LIMIT in a recursive query is not implemented"),
     933             :                      parser_errposition(cstate->pstate,
     934             :                                         exprLocation(stmt->limitCount))));
     935         958 :         if (stmt->lockingClause)
     936           6 :             ereport(ERROR,
     937             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     938             :                      errmsg("FOR UPDATE/SHARE in a recursive query is not implemented"),
     939             :                      parser_errposition(cstate->pstate,
     940             :                                         exprLocation((Node *) stmt->lockingClause))));
     941             :     }
     942         970 : }
     943             : 
     944             : /*
     945             :  * Tree walker function to detect invalid self-references in a recursive query.
     946             :  */
     947             : static bool
     948      100112 : checkWellFormedRecursionWalker(Node *node, CteState *cstate)
     949             : {
     950      100112 :     RecursionContext save_context = cstate->context;
     951             : 
     952      100112 :     if (node == NULL)
     953       48762 :         return false;
     954       51350 :     if (IsA(node, RangeVar))
     955             :     {
     956        5062 :         RangeVar   *rv = (RangeVar *) node;
     957             : 
     958             :         /* If unqualified name, might be a CTE reference */
     959        5062 :         if (!rv->schemaname)
     960             :         {
     961             :             ListCell   *lc;
     962             :             CommonTableExpr *mycte;
     963             : 
     964             :             /* ... but first see if it's captured by an inner WITH */
     965        4482 :             foreach(lc, cstate->innerwiths)
     966             :             {
     967         646 :                 List       *withlist = (List *) lfirst(lc);
     968             :                 ListCell   *lc2;
     969             : 
     970         742 :                 foreach(lc2, withlist)
     971             :                 {
     972         566 :                     CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc2);
     973             : 
     974         566 :                     if (strcmp(rv->relname, cte->ctename) == 0)
     975         470 :                         return false;   /* yes, so bail out */
     976             :                 }
     977             :             }
     978             : 
     979             :             /* No, could be a reference to the query level we are working on */
     980        3836 :             mycte = cstate->items[cstate->curitem].cte;
     981        3836 :             if (strcmp(rv->relname, mycte->ctename) == 0)
     982             :             {
     983             :                 /* Found a recursive reference to the active query */
     984        1072 :                 if (cstate->context != RECURSION_OK)
     985          48 :                     ereport(ERROR,
     986             :                             (errcode(ERRCODE_INVALID_RECURSION),
     987             :                              errmsg(recursion_errormsgs[cstate->context],
     988             :                                     mycte->ctename),
     989             :                              parser_errposition(cstate->pstate,
     990             :                                                 rv->location)));
     991             :                 /* Count references */
     992        1024 :                 if (++(cstate->selfrefcount) > 1)
     993          18 :                     ereport(ERROR,
     994             :                             (errcode(ERRCODE_INVALID_RECURSION),
     995             :                              errmsg("recursive reference to query \"%s\" must not appear more than once",
     996             :                                     mycte->ctename),
     997             :                              parser_errposition(cstate->pstate,
     998             :                                                 rv->location)));
     999             :             }
    1000             :         }
    1001        4526 :         return false;
    1002             :     }
    1003       46288 :     if (IsA(node, SelectStmt))
    1004             :     {
    1005        3184 :         SelectStmt *stmt = (SelectStmt *) node;
    1006             :         ListCell   *lc;
    1007             : 
    1008        3184 :         if (stmt->withClause)
    1009             :         {
    1010         176 :             if (stmt->withClause->recursive)
    1011             :             {
    1012             :                 /*
    1013             :                  * In the RECURSIVE case, all query names of the WITH are
    1014             :                  * visible to all WITH items as well as the main query. So
    1015             :                  * push them all on, process, pop them all off.
    1016             :                  */
    1017           6 :                 cstate->innerwiths = lcons(stmt->withClause->ctes,
    1018             :                                            cstate->innerwiths);
    1019          12 :                 foreach(lc, stmt->withClause->ctes)
    1020             :                 {
    1021           6 :                     CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
    1022             : 
    1023           6 :                     (void) checkWellFormedRecursionWalker(cte->ctequery, cstate);
    1024             :                 }
    1025           6 :                 checkWellFormedSelectStmt(stmt, cstate);
    1026           6 :                 cstate->innerwiths = list_delete_first(cstate->innerwiths);
    1027             :             }
    1028             :             else
    1029             :             {
    1030             :                 /*
    1031             :                  * In the non-RECURSIVE case, query names are visible to the
    1032             :                  * WITH items after them and to the main query.
    1033             :                  */
    1034         170 :                 cstate->innerwiths = lcons(NIL, cstate->innerwiths);
    1035         364 :                 foreach(lc, stmt->withClause->ctes)
    1036             :                 {
    1037         194 :                     CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
    1038             :                     ListCell   *cell1;
    1039             : 
    1040         194 :                     (void) checkWellFormedRecursionWalker(cte->ctequery, cstate);
    1041             :                     /* note that recursion could mutate innerwiths list */
    1042         194 :                     cell1 = list_head(cstate->innerwiths);
    1043         194 :                     lfirst(cell1) = lappend((List *) lfirst(cell1), cte);
    1044             :                 }
    1045         170 :                 checkWellFormedSelectStmt(stmt, cstate);
    1046         170 :                 cstate->innerwiths = list_delete_first(cstate->innerwiths);
    1047             :             }
    1048             :         }
    1049             :         else
    1050        3008 :             checkWellFormedSelectStmt(stmt, cstate);
    1051             :         /* We're done examining the SelectStmt */
    1052        3076 :         return false;
    1053             :     }
    1054       43104 :     if (IsA(node, WithClause))
    1055             :     {
    1056             :         /*
    1057             :          * Prevent raw_expression_tree_walker from recursing directly into a
    1058             :          * WITH clause.  We need that to happen only under the control of the
    1059             :          * code above.
    1060             :          */
    1061         176 :         return false;
    1062             :     }
    1063       42928 :     if (IsA(node, JoinExpr))
    1064             :     {
    1065        2046 :         JoinExpr   *j = (JoinExpr *) node;
    1066             : 
    1067        2046 :         switch (j->jointype)
    1068             :         {
    1069        1976 :             case JOIN_INNER:
    1070        1976 :                 checkWellFormedRecursionWalker(j->larg, cstate);
    1071        1976 :                 checkWellFormedRecursionWalker(j->rarg, cstate);
    1072        1976 :                 checkWellFormedRecursionWalker(j->quals, cstate);
    1073        1976 :                 break;
    1074          58 :             case JOIN_LEFT:
    1075          58 :                 checkWellFormedRecursionWalker(j->larg, cstate);
    1076          58 :                 if (save_context == RECURSION_OK)
    1077           6 :                     cstate->context = RECURSION_OUTERJOIN;
    1078          58 :                 checkWellFormedRecursionWalker(j->rarg, cstate);
    1079          52 :                 cstate->context = save_context;
    1080          52 :                 checkWellFormedRecursionWalker(j->quals, cstate);
    1081          52 :                 break;
    1082           6 :             case JOIN_FULL:
    1083           6 :                 if (save_context == RECURSION_OK)
    1084           6 :                     cstate->context = RECURSION_OUTERJOIN;
    1085           6 :                 checkWellFormedRecursionWalker(j->larg, cstate);
    1086           0 :                 checkWellFormedRecursionWalker(j->rarg, cstate);
    1087           0 :                 cstate->context = save_context;
    1088           0 :                 checkWellFormedRecursionWalker(j->quals, cstate);
    1089           0 :                 break;
    1090           6 :             case JOIN_RIGHT:
    1091           6 :                 if (save_context == RECURSION_OK)
    1092           6 :                     cstate->context = RECURSION_OUTERJOIN;
    1093           6 :                 checkWellFormedRecursionWalker(j->larg, cstate);
    1094           0 :                 cstate->context = save_context;
    1095           0 :                 checkWellFormedRecursionWalker(j->rarg, cstate);
    1096           0 :                 checkWellFormedRecursionWalker(j->quals, cstate);
    1097           0 :                 break;
    1098           0 :             default:
    1099           0 :                 elog(ERROR, "unrecognized join type: %d",
    1100             :                      (int) j->jointype);
    1101             :         }
    1102        2028 :         return false;
    1103             :     }
    1104       40882 :     if (IsA(node, SubLink))
    1105             :     {
    1106          58 :         SubLink    *sl = (SubLink *) node;
    1107             : 
    1108             :         /*
    1109             :          * we intentionally override outer context, since subquery is
    1110             :          * independent
    1111             :          */
    1112          58 :         cstate->context = RECURSION_SUBLINK;
    1113          58 :         checkWellFormedRecursionWalker(sl->subselect, cstate);
    1114          46 :         cstate->context = save_context;
    1115          46 :         checkWellFormedRecursionWalker(sl->testexpr, cstate);
    1116          46 :         return false;
    1117             :     }
    1118       40824 :     return raw_expression_tree_walker(node,
    1119             :                                       checkWellFormedRecursionWalker,
    1120             :                                       (void *) cstate);
    1121             : }
    1122             : 
    1123             : /*
    1124             :  * subroutine for checkWellFormedRecursionWalker: process a SelectStmt
    1125             :  * without worrying about its WITH clause
    1126             :  */
    1127             : static void
    1128        3184 : checkWellFormedSelectStmt(SelectStmt *stmt, CteState *cstate)
    1129             : {
    1130        3184 :     RecursionContext save_context = cstate->context;
    1131             : 
    1132        3184 :     if (save_context != RECURSION_OK)
    1133             :     {
    1134             :         /* just recurse without changing state */
    1135        1172 :         raw_expression_tree_walker((Node *) stmt,
    1136             :                                    checkWellFormedRecursionWalker,
    1137             :                                    (void *) cstate);
    1138             :     }
    1139             :     else
    1140             :     {
    1141        2012 :         switch (stmt->op)
    1142             :         {
    1143        2000 :             case SETOP_NONE:
    1144             :             case SETOP_UNION:
    1145        2000 :                 raw_expression_tree_walker((Node *) stmt,
    1146             :                                            checkWellFormedRecursionWalker,
    1147             :                                            (void *) cstate);
    1148        1934 :                 break;
    1149           6 :             case SETOP_INTERSECT:
    1150           6 :                 if (stmt->all)
    1151           0 :                     cstate->context = RECURSION_INTERSECT;
    1152           6 :                 checkWellFormedRecursionWalker((Node *) stmt->larg,
    1153             :                                                cstate);
    1154           6 :                 checkWellFormedRecursionWalker((Node *) stmt->rarg,
    1155             :                                                cstate);
    1156           0 :                 cstate->context = save_context;
    1157           0 :                 checkWellFormedRecursionWalker((Node *) stmt->sortClause,
    1158             :                                                cstate);
    1159           0 :                 checkWellFormedRecursionWalker((Node *) stmt->limitOffset,
    1160             :                                                cstate);
    1161           0 :                 checkWellFormedRecursionWalker((Node *) stmt->limitCount,
    1162             :                                                cstate);
    1163           0 :                 checkWellFormedRecursionWalker((Node *) stmt->lockingClause,
    1164             :                                                cstate);
    1165             :                 /* stmt->withClause is intentionally ignored here */
    1166           0 :                 break;
    1167           6 :             case SETOP_EXCEPT:
    1168           6 :                 if (stmt->all)
    1169           0 :                     cstate->context = RECURSION_EXCEPT;
    1170           6 :                 checkWellFormedRecursionWalker((Node *) stmt->larg,
    1171             :                                                cstate);
    1172           6 :                 cstate->context = RECURSION_EXCEPT;
    1173           6 :                 checkWellFormedRecursionWalker((Node *) stmt->rarg,
    1174             :                                                cstate);
    1175           0 :                 cstate->context = save_context;
    1176           0 :                 checkWellFormedRecursionWalker((Node *) stmt->sortClause,
    1177             :                                                cstate);
    1178           0 :                 checkWellFormedRecursionWalker((Node *) stmt->limitOffset,
    1179             :                                                cstate);
    1180           0 :                 checkWellFormedRecursionWalker((Node *) stmt->limitCount,
    1181             :                                                cstate);
    1182           0 :                 checkWellFormedRecursionWalker((Node *) stmt->lockingClause,
    1183             :                                                cstate);
    1184             :                 /* stmt->withClause is intentionally ignored here */
    1185           0 :                 break;
    1186           0 :             default:
    1187           0 :                 elog(ERROR, "unrecognized set op: %d",
    1188             :                      (int) stmt->op);
    1189             :         }
    1190             :     }
    1191        3076 : }

Generated by: LCOV version 1.14