LCOV - code coverage report
Current view: top level - src/backend/parser - parse_cte.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 89.9 % 415 373
Test Date: 2026-07-03 19:57:34 Functions: 100.0 % 10 10
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 78.3 % 387 303

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * parse_cte.c
       4                 :             :  *    handle CTEs (common table expressions) in parser
       5                 :             :  *
       6                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :             :  *
       9                 :             :  *
      10                 :             :  * IDENTIFICATION
      11                 :             :  *    src/backend/parser/parse_cte.c
      12                 :             :  *
      13                 :             :  *-------------------------------------------------------------------------
      14                 :             :  */
      15                 :             : #include "postgres.h"
      16                 :             : 
      17                 :             : #include "catalog/pg_collation.h"
      18                 :             : #include "catalog/pg_type.h"
      19                 :             : #include "nodes/nodeFuncs.h"
      20                 :             : #include "parser/analyze.h"
      21                 :             : #include "parser/parse_coerce.h"
      22                 :             : #include "parser/parse_collate.h"
      23                 :             : #include "parser/parse_cte.h"
      24                 :             : #include "parser/parse_expr.h"
      25                 :             : #include "utils/builtins.h"
      26                 :             : #include "utils/lsyscache.h"
      27                 :             : #include "utils/typcache.h"
      28                 :             : 
      29                 :             : 
      30                 :             : /* Enumeration of contexts in which a self-reference is disallowed */
      31                 :             : typedef enum
      32                 :             : {
      33                 :             :     RECURSION_OK,
      34                 :             :     RECURSION_NONRECURSIVETERM, /* inside the left-hand term */
      35                 :             :     RECURSION_SUBLINK,          /* inside a sublink */
      36                 :             :     RECURSION_OUTERJOIN,        /* inside nullable side of an outer join */
      37                 :             :     RECURSION_INTERSECT,        /* underneath INTERSECT (ALL) */
      38                 :             :     RECURSION_EXCEPT,           /* underneath EXCEPT (ALL) */
      39                 :             : } RecursionContext;
      40                 :             : 
      41                 :             : /* Associated error messages --- each must have one %s for CTE name */
      42                 :             : static const char *const recursion_errormsgs[] = {
      43                 :             :     /* RECURSION_OK */
      44                 :             :     NULL,
      45                 :             :     /* RECURSION_NONRECURSIVETERM */
      46                 :             :     gettext_noop("recursive reference to query \"%s\" must not appear within its non-recursive term"),
      47                 :             :     /* RECURSION_SUBLINK */
      48                 :             :     gettext_noop("recursive reference to query \"%s\" must not appear within a subquery"),
      49                 :             :     /* RECURSION_OUTERJOIN */
      50                 :             :     gettext_noop("recursive reference to query \"%s\" must not appear within an outer join"),
      51                 :             :     /* RECURSION_INTERSECT */
      52                 :             :     gettext_noop("recursive reference to query \"%s\" must not appear within INTERSECT"),
      53                 :             :     /* RECURSION_EXCEPT */
      54                 :             :     gettext_noop("recursive reference to query \"%s\" must not appear within EXCEPT")
      55                 :             : };
      56                 :             : 
      57                 :             : /*
      58                 :             :  * For WITH RECURSIVE, we have to find an ordering of the clause members
      59                 :             :  * with no forward references, and determine which members are recursive
      60                 :             :  * (i.e., self-referential).  It is convenient to do this with an array
      61                 :             :  * of CteItems instead of a list of CommonTableExprs.
      62                 :             :  */
      63                 :             : typedef struct CteItem
      64                 :             : {
      65                 :             :     CommonTableExpr *cte;       /* One CTE to examine */
      66                 :             :     int         id;             /* Its ID number for dependencies */
      67                 :             :     Bitmapset  *depends_on;     /* CTEs depended on (not including self) */
      68                 :             : } CteItem;
      69                 :             : 
      70                 :             : /* CteState is what we need to pass around in the tree walkers */
      71                 :             : typedef struct CteState
      72                 :             : {
      73                 :             :     /* global state: */
      74                 :             :     ParseState *pstate;         /* global parse state */
      75                 :             :     CteItem    *items;          /* array of CTEs and extra data */
      76                 :             :     int         numitems;       /* number of CTEs */
      77                 :             :     /* working state during a tree walk: */
      78                 :             :     int         curitem;        /* index of item currently being examined */
      79                 :             :     List       *innerwiths;     /* list of lists of CommonTableExpr */
      80                 :             :     /* working state for checkWellFormedRecursion walk only: */
      81                 :             :     int         selfrefcount;   /* number of self-references detected */
      82                 :             :     RecursionContext context;   /* context to allow or disallow self-ref */
      83                 :             : } CteState;
      84                 :             : 
      85                 :             : 
      86                 :             : static void analyzeCTE(ParseState *pstate, CommonTableExpr *cte);
      87                 :             : 
      88                 :             : /* Dependency processing functions */
      89                 :             : static void makeDependencyGraph(CteState *cstate);
      90                 :             : static bool makeDependencyGraphWalker(Node *node, CteState *cstate);
      91                 :             : static void WalkInnerWith(Node *stmt, WithClause *withClause, CteState *cstate);
      92                 :             : static void TopologicalSort(ParseState *pstate, CteItem *items, int numitems);
      93                 :             : 
      94                 :             : /* Recursion validity checker functions */
      95                 :             : static void checkWellFormedRecursion(CteState *cstate);
      96                 :             : static bool checkWellFormedRecursionWalker(Node *node, CteState *cstate);
      97                 :             : static void checkWellFormedSelectStmt(SelectStmt *stmt, CteState *cstate);
      98                 :             : 
      99                 :             : 
     100                 :             : /*
     101                 :             :  * transformWithClause -
     102                 :             :  *    Transform the list of WITH clause "common table expressions" into
     103                 :             :  *    Query nodes.
     104                 :             :  *
     105                 :             :  * The result is the list of transformed CTEs to be put into the output
     106                 :             :  * Query.  (This is in fact the same as the ending value of p_ctenamespace,
     107                 :             :  * but it seems cleaner to not expose that in the function's API.)
     108                 :             :  */
     109                 :             : List *
     110                 :        2162 : 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   [ +  -  +  +  :        5036 :     foreach(lc, withClause->ctes)
                   +  + ]
     126                 :             :     {
     127                 :        2874 :         CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
     128                 :             :         ListCell   *rest;
     129                 :             : 
     130   [ +  -  +  +  :        4172 :         for_each_cell(rest, withClause->ctes, lnext(withClause->ctes, lc))
                   +  + ]
     131                 :             :         {
     132                 :        1298 :             CommonTableExpr *cte2 = (CommonTableExpr *) lfirst(rest);
     133                 :             : 
     134         [ -  + ]:        1298 :             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                 :        2874 :         cte->cterecursive = false;
     143                 :        2874 :         cte->cterefcount = 0;
     144                 :             : 
     145         [ +  + ]:        2874 :         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                 :         289 :             pstate->p_hasModifyingCTE = true;
     154                 :             :         }
     155                 :             :     }
     156                 :             : 
     157         [ +  + ]:        2162 :     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                 :         768 :         cstate.pstate = pstate;
     168                 :         768 :         cstate.numitems = list_length(withClause->ctes);
     169                 :         768 :         cstate.items = (CteItem *) palloc0(cstate.numitems * sizeof(CteItem));
     170                 :         768 :         i = 0;
     171   [ +  -  +  +  :        1600 :         foreach(lc, withClause->ctes)
                   +  + ]
     172                 :             :         {
     173                 :         832 :             cstate.items[i].cte = (CommonTableExpr *) lfirst(lc);
     174                 :         832 :             cstate.items[i].id = i;
     175                 :         832 :             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                 :         768 :         makeDependencyGraph(&cstate);
     183                 :             : 
     184                 :             :         /*
     185                 :             :          * Check that recursive queries are well-formed.
     186                 :             :          */
     187                 :         764 :         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         [ +  + ]:        1388 :         for (i = 0; i < cstate.numitems; i++)
     196                 :             :         {
     197                 :         724 :             CommonTableExpr *cte = cstate.items[i].cte;
     198                 :             : 
     199                 :         724 :             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         [ +  + ]:        1304 :         for (i = 0; i < cstate.numitems; i++)
     206                 :             :         {
     207                 :         724 :             CommonTableExpr *cte = cstate.items[i].cte;
     208                 :             : 
     209                 :         724 :             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                 :        1394 :         pstate->p_future_ctes = list_copy(withClause->ctes);
     222                 :             : 
     223   [ +  -  +  +  :        3423 :         foreach(lc, withClause->ctes)
                   +  + ]
     224                 :             :         {
     225                 :        2042 :             CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
     226                 :             : 
     227                 :        2042 :             analyzeCTE(pstate, cte);
     228                 :        2029 :             pstate->p_ctenamespace = lappend(pstate->p_ctenamespace, cte);
     229                 :        2029 :             pstate->p_future_ctes = list_delete_first(pstate->p_future_ctes);
     230                 :             :         }
     231                 :             :     }
     232                 :             : 
     233                 :        1961 :     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                 :        2766 : analyzeCTE(ParseState *pstate, CommonTableExpr *cte)
     244                 :             : {
     245                 :             :     Query      *query;
     246                 :        2766 :     CTESearchClause *search_clause = cte->search_clause;
     247                 :        2766 :     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         [ +  + ]:        2766 :     if (cycle_clause)
     258                 :             :     {
     259                 :             :         TypeCacheEntry *typentry;
     260                 :             :         Oid         op;
     261                 :             : 
     262                 :          84 :         cycle_clause->cycle_mark_value =
     263                 :          84 :             transformExpr(pstate, cycle_clause->cycle_mark_value,
     264                 :             :                           EXPR_KIND_CYCLE_MARK);
     265                 :          84 :         cycle_clause->cycle_mark_default =
     266                 :          84 :             transformExpr(pstate, cycle_clause->cycle_mark_default,
     267                 :             :                           EXPR_KIND_CYCLE_MARK);
     268                 :             : 
     269                 :          80 :         cycle_clause->cycle_mark_type =
     270                 :          84 :             select_common_type(pstate,
     271                 :          84 :                                list_make2(cycle_clause->cycle_mark_value,
     272                 :             :                                           cycle_clause->cycle_mark_default),
     273                 :             :                                "CYCLE", NULL);
     274                 :          80 :         cycle_clause->cycle_mark_value =
     275                 :          80 :             coerce_to_common_type(pstate,
     276                 :             :                                   cycle_clause->cycle_mark_value,
     277                 :             :                                   cycle_clause->cycle_mark_type,
     278                 :             :                                   "CYCLE/SET/TO");
     279                 :          80 :         cycle_clause->cycle_mark_default =
     280                 :          80 :             coerce_to_common_type(pstate,
     281                 :             :                                   cycle_clause->cycle_mark_default,
     282                 :             :                                   cycle_clause->cycle_mark_type,
     283                 :             :                                   "CYCLE/SET/DEFAULT");
     284                 :             : 
     285                 :          80 :         cycle_clause->cycle_mark_typmod =
     286                 :          80 :             select_common_typmod(pstate,
     287                 :          80 :                                  list_make2(cycle_clause->cycle_mark_value,
     288                 :             :                                             cycle_clause->cycle_mark_default),
     289                 :             :                                  cycle_clause->cycle_mark_type);
     290                 :             : 
     291                 :          80 :         cycle_clause->cycle_mark_collation =
     292                 :          80 :             select_common_collation(pstate,
     293                 :          80 :                                     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                 :          80 :         typentry = lookup_type_cache(cycle_clause->cycle_mark_type,
     299                 :             :                                      TYPECACHE_EQ_OPR);
     300         [ +  + ]:          80 :         if (!OidIsValid(typentry->eq_opr))
     301         [ +  - ]:           4 :             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                 :          76 :         op = get_negator(typentry->eq_opr);
     306         [ -  + ]:          76 :         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                 :          76 :         cycle_clause->cycle_mark_neop = op;
     313                 :             :     }
     314                 :             : 
     315                 :             :     /* Now we can get on with analyzing the CTE's query */
     316                 :        2758 :     query = parse_sub_analyze(cte->ctequery, pstate, cte, false, true);
     317                 :        2741 :     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         [ -  + ]:        2741 :     if (!IsA(query, Query))
     324         [ #  # ]:           0 :         elog(ERROR, "unexpected non-Query statement in WITH");
     325         [ -  + ]:        2741 :     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         [ +  + ]:        2741 :     if (query->commandType != CMD_SELECT &&
     333         [ +  + ]:         277 :         pstate->parentParseState != NULL)
     334         [ +  - ]:           4 :         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                 :        2737 :     query->canSetTag = false;
     345                 :             : 
     346         [ +  + ]:        2737 :     if (!cte->cterecursive)
     347                 :             :     {
     348                 :             :         /* Compute the output column names/types if not done yet */
     349         [ +  + ]:        2109 :         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                 :         628 :         lctyp = list_head(cte->ctecoltypes);
     366                 :         628 :         lctypmod = list_head(cte->ctecoltypmods);
     367                 :         628 :         lccoll = list_head(cte->ctecolcollations);
     368                 :         628 :         varattno = 0;
     369   [ +  -  +  -  :        1940 :         foreach(lctlist, GetCTETargetList(cte))
             +  +  +  + ]
     370                 :             :         {
     371                 :        1328 :             TargetEntry *te = (TargetEntry *) lfirst(lctlist);
     372                 :             :             Node       *texpr;
     373                 :             : 
     374         [ -  + ]:        1328 :             if (te->resjunk)
     375                 :           0 :                 continue;
     376                 :        1328 :             varattno++;
     377                 :             :             Assert(varattno == te->resno);
     378   [ +  -  +  -  :        1328 :             if (lctyp == NULL || lctypmod == NULL || lccoll == NULL)    /* shouldn't happen */
                   -  + ]
     379         [ #  # ]:           0 :                 elog(ERROR, "wrong number of output columns in WITH");
     380                 :        1328 :             texpr = (Node *) te->expr;
     381         [ +  + ]:        1328 :             if (exprType(texpr) != lfirst_oid(lctyp) ||
     382         [ +  + ]:        1324 :                 exprTypmod(texpr) != lfirst_int(lctypmod))
     383         [ +  - ]:           8 :                 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         [ +  + ]:        1320 :             if (exprCollation(texpr) != lfirst_oid(lccoll))
     394         [ +  - ]:           8 :                 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                 :        1312 :             lctyp = lnext(cte->ctecoltypes, lctyp);
     403                 :        1312 :             lctypmod = lnext(cte->ctecoltypmods, lctypmod);
     404                 :        1312 :             lccoll = lnext(cte->ctecolcollations, lccoll);
     405                 :             :         }
     406   [ +  -  +  -  :         612 :         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   [ +  +  +  + ]:        2717 :     if (search_clause || cycle_clause)
     414                 :             :     {
     415                 :             :         Query      *ctequery;
     416                 :             :         SetOperationStmt *sos;
     417                 :             : 
     418         [ -  + ]:         144 :         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                 :         144 :         ctequery = castNode(Query, cte->ctequery);
     441                 :             :         Assert(ctequery->setOperations);
     442                 :         144 :         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         [ +  + ]:         144 :         if (!IsA(sos->larg, RangeTblRef))
     450         [ +  - ]:           4 :             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         [ +  + ]:         140 :         if (!IsA(sos->rarg, RangeTblRef))
     455         [ +  - ]:           4 :             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         [ +  + ]:        2709 :     if (search_clause)
     461                 :             :     {
     462                 :             :         ListCell   *lc;
     463                 :          76 :         List       *seen = NIL;
     464                 :             : 
     465   [ +  -  +  +  :         200 :         foreach(lc, search_clause->search_col_list)
                   +  + ]
     466                 :             :         {
     467                 :         132 :             String     *colname = lfirst_node(String, lc);
     468                 :             : 
     469         [ +  + ]:         132 :             if (!list_member(cte->ctecolnames, colname))
     470         [ +  - ]:           4 :                 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         [ +  + ]:         128 :             if (list_member(seen, colname))
     477         [ +  - ]:           4 :                 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                 :         124 :             seen = lappend(seen, colname);
     483                 :             :         }
     484                 :             : 
     485         [ +  + ]:          68 :         if (list_member(cte->ctecolnames, makeString(search_clause->search_seq_column)))
     486         [ +  - ]:           4 :             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         [ +  + ]:        2697 :     if (cycle_clause)
     494                 :             :     {
     495                 :             :         ListCell   *lc;
     496                 :          76 :         List       *seen = NIL;
     497                 :             : 
     498   [ +  -  +  +  :         204 :         foreach(lc, cycle_clause->cycle_col_list)
                   +  + ]
     499                 :             :         {
     500                 :         136 :             String     *colname = lfirst_node(String, lc);
     501                 :             : 
     502         [ +  + ]:         136 :             if (!list_member(cte->ctecolnames, colname))
     503         [ +  - ]:           4 :                 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         [ +  + ]:         132 :             if (list_member(seen, colname))
     510         [ +  - ]:           4 :                 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                 :         128 :             seen = lappend(seen, colname);
     516                 :             :         }
     517                 :             : 
     518         [ +  + ]:          68 :         if (list_member(cte->ctecolnames, makeString(cycle_clause->cycle_mark_column)))
     519         [ +  - ]:           4 :             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         [ +  + ]:          64 :         if (list_member(cte->ctecolnames, makeString(cycle_clause->cycle_path_column)))
     526         [ +  - ]:           4 :             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                 :          60 :         if (strcmp(cycle_clause->cycle_mark_column,
     533         [ +  + ]:          60 :                    cycle_clause->cycle_path_column) == 0)
     534         [ +  - ]:           4 :             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   [ +  +  +  + ]:        2677 :     if (search_clause && cycle_clause)
     541                 :             :     {
     542                 :          16 :         if (strcmp(search_clause->search_seq_column,
     543         [ +  + ]:          16 :                    cycle_clause->cycle_mark_column) == 0)
     544         [ +  - ]:           4 :             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                 :          12 :         if (strcmp(search_clause->search_seq_column,
     550         [ +  + ]:          12 :                    cycle_clause->cycle_path_column) == 0)
     551         [ +  - ]:           4 :             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                 :        2669 : }
     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                 :        2749 : 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                 :        2749 :     cte->ctecolnames = copyObject(cte->aliascolnames);
     588                 :        2749 :     cte->ctecoltypes = cte->ctecoltypmods = cte->ctecolcollations = NIL;
     589                 :        2749 :     numaliases = list_length(cte->aliascolnames);
     590                 :        2749 :     varattno = 0;
     591   [ +  +  +  +  :        9302 :     foreach(tlistitem, tlist)
                   +  + ]
     592                 :             :     {
     593                 :        6553 :         TargetEntry *te = (TargetEntry *) lfirst(tlistitem);
     594                 :             :         Oid         coltype;
     595                 :             :         int32       coltypmod;
     596                 :             :         Oid         colcoll;
     597                 :             : 
     598         [ +  + ]:        6553 :         if (te->resjunk)
     599                 :          56 :             continue;
     600                 :        6497 :         varattno++;
     601                 :             :         Assert(varattno == te->resno);
     602         [ +  + ]:        6497 :         if (varattno > numaliases)
     603                 :             :         {
     604                 :             :             char       *attrname;
     605                 :             : 
     606                 :        2973 :             attrname = pstrdup(te->resname);
     607                 :        2973 :             cte->ctecolnames = lappend(cte->ctecolnames, makeString(attrname));
     608                 :             :         }
     609                 :        6497 :         coltype = exprType((Node *) te->expr);
     610                 :        6497 :         coltypmod = exprTypmod((Node *) te->expr);
     611                 :        6497 :         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   [ +  +  +  + ]:        6497 :         if (cte->cterecursive && coltype == UNKNOWNOID)
     624                 :             :         {
     625                 :          22 :             coltype = TEXTOID;
     626                 :          22 :             coltypmod = -1;     /* should be -1 already, but be sure */
     627         [ +  - ]:          22 :             if (!OidIsValid(colcoll))
     628                 :          22 :                 colcoll = DEFAULT_COLLATION_OID;
     629                 :             :         }
     630                 :        6497 :         cte->ctecoltypes = lappend_oid(cte->ctecoltypes, coltype);
     631                 :        6497 :         cte->ctecoltypmods = lappend_int(cte->ctecoltypmods, coltypmod);
     632                 :        6497 :         cte->ctecolcollations = lappend_oid(cte->ctecolcollations, colcoll);
     633                 :             :     }
     634         [ +  + ]:        2749 :     if (varattno < numaliases)
     635         [ +  - ]:           4 :         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                 :        2745 : }
     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                 :         768 : makeDependencyGraph(CteState *cstate)
     649                 :             : {
     650                 :             :     int         i;
     651                 :             : 
     652         [ +  + ]:        1600 :     for (i = 0; i < cstate->numitems; i++)
     653                 :             :     {
     654                 :         832 :         CommonTableExpr *cte = cstate->items[i].cte;
     655                 :             : 
     656                 :         832 :         cstate->curitem = i;
     657                 :         832 :         cstate->innerwiths = NIL;
     658                 :         832 :         makeDependencyGraphWalker((Node *) cte->ctequery, cstate);
     659                 :             :         Assert(cstate->innerwiths == NIL);
     660                 :             :     }
     661                 :             : 
     662                 :         768 :     TopologicalSort(cstate->pstate, cstate->items, cstate->numitems);
     663                 :         764 : }
     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                 :       92587 : makeDependencyGraphWalker(Node *node, CteState *cstate)
     671                 :             : {
     672         [ +  + ]:       92587 :     if (node == NULL)
     673                 :       53818 :         return false;
     674         [ +  + ]:       38769 :     if (IsA(node, RangeVar))
     675                 :             :     {
     676                 :        3866 :         RangeVar   *rv = (RangeVar *) node;
     677                 :             : 
     678                 :             :         /* If unqualified name, might be a CTE reference */
     679         [ +  + ]:        3866 :         if (!rv->schemaname)
     680                 :             :         {
     681                 :             :             ListCell   *lc;
     682                 :             :             int         i;
     683                 :             : 
     684                 :             :             /* ... but first see if it's captured by an inner WITH */
     685   [ +  +  +  +  :        3172 :             foreach(lc, cstate->innerwiths)
                   +  + ]
     686                 :             :             {
     687                 :         732 :                 List       *withlist = (List *) lfirst(lc);
     688                 :             :                 ListCell   *lc2;
     689                 :             : 
     690   [ +  +  +  +  :         808 :                 foreach(lc2, withlist)
                   +  + ]
     691                 :             :                 {
     692                 :         620 :                     CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc2);
     693                 :             : 
     694         [ +  + ]:         620 :                     if (strcmp(rv->relname, cte->ctename) == 0)
     695                 :         544 :                         return false;   /* yes, so bail out */
     696                 :             :                 }
     697                 :             :             }
     698                 :             : 
     699                 :             :             /* No, could be a reference to the query level we are working on */
     700         [ +  + ]:        4112 :             for (i = 0; i < cstate->numitems; i++)
     701                 :             :             {
     702                 :        2532 :                 CommonTableExpr *cte = cstate->items[i].cte;
     703                 :             : 
     704         [ +  + ]:        2532 :                 if (strcmp(rv->relname, cte->ctename) == 0)
     705                 :             :                 {
     706                 :         860 :                     int         myindex = cstate->curitem;
     707                 :             : 
     708         [ +  + ]:         860 :                     if (i != myindex)
     709                 :             :                     {
     710                 :             :                         /* Add cross-item dependency */
     711                 :          84 :                         cstate->items[myindex].depends_on =
     712                 :          84 :                             bms_add_member(cstate->items[myindex].depends_on,
     713                 :          84 :                                            cstate->items[i].id);
     714                 :             :                     }
     715                 :             :                     else
     716                 :             :                     {
     717                 :             :                         /* Found out this one is self-referential */
     718                 :         776 :                         cte->cterecursive = true;
     719                 :             :                     }
     720                 :         860 :                     break;
     721                 :             :                 }
     722                 :             :             }
     723                 :             :         }
     724                 :        3322 :         return false;
     725                 :             :     }
     726         [ +  + ]:       34903 :     if (IsA(node, SelectStmt))
     727                 :             :     {
     728                 :        3502 :         SelectStmt *stmt = (SelectStmt *) node;
     729                 :             : 
     730         [ +  + ]:        3502 :         if (stmt->withClause)
     731                 :             :         {
     732                 :             :             /* Examine the WITH clause and the SelectStmt */
     733                 :         216 :             WalkInnerWith(node, stmt->withClause, cstate);
     734                 :             :             /* We're done examining the SelectStmt */
     735                 :         216 :             return false;
     736                 :             :         }
     737                 :             :         /* if no WITH clause, just fall through for normal processing */
     738                 :             :     }
     739         [ +  + ]:       31401 :     else if (IsA(node, InsertStmt))
     740                 :             :     {
     741                 :          28 :         InsertStmt *stmt = (InsertStmt *) node;
     742                 :             : 
     743         [ -  + ]:          28 :         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         [ +  + ]:       31373 :     else if (IsA(node, DeleteStmt))
     753                 :             :     {
     754                 :           4 :         DeleteStmt *stmt = (DeleteStmt *) node;
     755                 :             : 
     756         [ +  - ]:           4 :         if (stmt->withClause)
     757                 :             :         {
     758                 :             :             /* Examine the WITH clause and the DeleteStmt */
     759                 :           4 :             WalkInnerWith(node, stmt->withClause, cstate);
     760                 :             :             /* We're done examining the DeleteStmt */
     761                 :           4 :             return false;
     762                 :             :         }
     763                 :             :         /* if no WITH clause, just fall through for normal processing */
     764                 :             :     }
     765         [ +  + ]:       31369 :     else if (IsA(node, UpdateStmt))
     766                 :             :     {
     767                 :           4 :         UpdateStmt *stmt = (UpdateStmt *) node;
     768                 :             : 
     769         [ -  + ]:           4 :         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         [ +  + ]:       31365 :     else if (IsA(node, MergeStmt))
     779                 :             :     {
     780                 :           4 :         MergeStmt  *stmt = (MergeStmt *) node;
     781                 :             : 
     782         [ -  + ]:           4 :         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         [ +  + ]:       31361 :     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                 :         220 :         return false;
     799                 :             :     }
     800                 :       34463 :     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                 :         220 : WalkInnerWith(Node *stmt, WithClause *withClause, CteState *cstate)
     813                 :             : {
     814                 :             :     ListCell   *lc;
     815                 :             : 
     816         [ +  + ]:         220 :     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                 :          12 :         cstate->innerwiths = lcons(withClause->ctes, cstate->innerwiths);
     824   [ +  -  +  +  :          24 :         foreach(lc, withClause->ctes)
                   +  + ]
     825                 :             :         {
     826                 :          12 :             CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
     827                 :             : 
     828                 :          12 :             (void) makeDependencyGraphWalker(cte->ctequery, cstate);
     829                 :             :         }
     830                 :          12 :         (void) raw_expression_tree_walker(stmt,
     831                 :             :                                           makeDependencyGraphWalker,
     832                 :             :                                           cstate);
     833                 :          12 :         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                 :         208 :         cstate->innerwiths = lcons(NIL, cstate->innerwiths);
     842   [ +  -  +  +  :         432 :         foreach(lc, withClause->ctes)
                   +  + ]
     843                 :             :         {
     844                 :         224 :             CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
     845                 :             :             ListCell   *cell1;
     846                 :             : 
     847                 :         224 :             (void) makeDependencyGraphWalker(cte->ctequery, cstate);
     848                 :             :             /* note that recursion could mutate innerwiths list */
     849                 :         224 :             cell1 = list_head(cstate->innerwiths);
     850                 :         224 :             lfirst(cell1) = lappend((List *) lfirst(cell1), cte);
     851                 :             :         }
     852                 :         208 :         (void) raw_expression_tree_walker(stmt,
     853                 :             :                                           makeDependencyGraphWalker,
     854                 :             :                                           cstate);
     855                 :         208 :         cstate->innerwiths = list_delete_first(cstate->innerwiths);
     856                 :             :     }
     857                 :         220 : }
     858                 :             : 
     859                 :             : /*
     860                 :             :  * Sort by dependencies, using a standard topological sort operation
     861                 :             :  */
     862                 :             : static void
     863                 :         768 : TopologicalSort(ParseState *pstate, CteItem *items, int numitems)
     864                 :             : {
     865                 :             :     int         i,
     866                 :             :                 j;
     867                 :             : 
     868                 :             :     /* for each position in sequence ... */
     869         [ +  + ]:        1592 :     for (i = 0; i < numitems; i++)
     870                 :             :     {
     871                 :             :         /* ... scan the remaining items to find one that has no dependencies */
     872         [ +  + ]:         848 :         for (j = i; j < numitems; j++)
     873                 :             :         {
     874         [ +  + ]:         844 :             if (bms_is_empty(items[j].depends_on))
     875                 :         824 :                 break;
     876                 :             :         }
     877                 :             : 
     878                 :             :         /* if we didn't find one, the dependency graph has a cycle */
     879         [ +  + ]:         828 :         if (j >= numitems)
     880         [ +  - ]:           4 :             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         [ +  + ]:         824 :         if (i != j)
     890                 :             :         {
     891                 :             :             CteItem     tmp;
     892                 :             : 
     893                 :          12 :             tmp = items[i];
     894                 :          12 :             items[i] = items[j];
     895                 :          12 :             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         [ +  + ]:         892 :         for (j = i + 1; j < numitems; j++)
     903                 :             :         {
     904                 :          68 :             items[j].depends_on = bms_del_member(items[j].depends_on,
     905                 :          68 :                                                  items[i].id);
     906                 :             :         }
     907                 :             :     }
     908                 :         764 : }
     909                 :             : 
     910                 :             : 
     911                 :             : /*
     912                 :             :  * Check that recursive queries are well-formed.
     913                 :             :  */
     914                 :             : static void
     915                 :         764 : checkWellFormedRecursion(CteState *cstate)
     916                 :             : {
     917                 :             :     int         i;
     918                 :             : 
     919         [ +  + ]:        1488 :     for (i = 0; i < cstate->numitems; i++)
     920                 :             :     {
     921                 :         824 :         CommonTableExpr *cte = cstate->items[i].cte;
     922                 :         824 :         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         [ +  + ]:         824 :         if (!cte->cterecursive)
     928                 :          76 :             continue;
     929                 :             : 
     930                 :             :         /* Must be a SELECT statement */
     931         [ +  + ]:         748 :         if (!IsA(stmt, SelectStmt))
     932         [ +  - ]:          12 :             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         [ +  + ]:         736 :         if (stmt->op != SETOP_UNION)
     940         [ +  - ]:          20 :             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         [ +  + ]:         716 :         if (stmt->withClause)
     955                 :             :         {
     956                 :          12 :             cstate->curitem = i;
     957                 :          12 :             cstate->innerwiths = NIL;
     958                 :          12 :             cstate->selfrefcount = 0;
     959                 :          12 :             cstate->context = RECURSION_SUBLINK;
     960                 :          12 :             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         [ +  + ]:         708 :         if (stmt->sortClause)
     975         [ +  - ]:           8 :             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         [ +  + ]:         700 :         if (stmt->limitOffset)
     981         [ +  - ]:           4 :             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         [ -  + ]:         696 :         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         [ +  + ]:         696 :         if (stmt->lockingClause)
     993         [ +  - ]:           4 :             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                 :         692 :         cstate->curitem = i;
    1005                 :         692 :         cstate->innerwiths = NIL;
    1006                 :         692 :         cstate->selfrefcount = 0;
    1007                 :         692 :         cstate->context = RECURSION_NONRECURSIVETERM;
    1008                 :         692 :         checkWellFormedRecursionWalker((Node *) stmt->larg, cstate);
    1009                 :             :         Assert(cstate->innerwiths == NIL);
    1010                 :             : 
    1011                 :             :         /* Right-hand operand should contain one reference in a valid place */
    1012                 :         684 :         cstate->curitem = i;
    1013                 :         684 :         cstate->innerwiths = NIL;
    1014                 :         684 :         cstate->selfrefcount = 0;
    1015                 :         684 :         cstate->context = RECURSION_OK;
    1016                 :         684 :         checkWellFormedRecursionWalker((Node *) stmt->rarg, cstate);
    1017                 :             :         Assert(cstate->innerwiths == NIL);
    1018         [ -  + ]:         648 :         if (cstate->selfrefcount != 1)   /* shouldn't happen */
    1019         [ #  # ]:           0 :             elog(ERROR, "missing recursive reference");
    1020                 :             :     }
    1021                 :         664 : }
    1022                 :             : 
    1023                 :             : /*
    1024                 :             :  * Tree walker function to detect invalid self-references in a recursive query.
    1025                 :             :  */
    1026                 :             : static bool
    1027                 :       72936 : checkWellFormedRecursionWalker(Node *node, CteState *cstate)
    1028                 :             : {
    1029                 :       72936 :     RecursionContext save_context = cstate->context;
    1030                 :             : 
    1031         [ +  + ]:       72936 :     if (node == NULL)
    1032                 :       37163 :         return false;
    1033         [ +  + ]:       35773 :     if (IsA(node, RangeVar))
    1034                 :             :     {
    1035                 :        3654 :         RangeVar   *rv = (RangeVar *) node;
    1036                 :             : 
    1037                 :             :         /* If unqualified name, might be a CTE reference */
    1038         [ +  + ]:        3654 :         if (!rv->schemaname)
    1039                 :             :         {
    1040                 :             :             ListCell   *lc;
    1041                 :             :             CommonTableExpr *mycte;
    1042                 :             : 
    1043                 :             :             /* ... but first see if it's captured by an inner WITH */
    1044   [ +  +  +  +  :        2936 :             foreach(lc, cstate->innerwiths)
                   +  + ]
    1045                 :             :             {
    1046                 :         648 :                 List       *withlist = (List *) lfirst(lc);
    1047                 :             :                 ListCell   *lc2;
    1048                 :             : 
    1049   [ +  +  +  +  :         712 :                 foreach(lc2, withlist)
                   +  + ]
    1050                 :             :                 {
    1051                 :         548 :                     CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc2);
    1052                 :             : 
    1053         [ +  + ]:         548 :                     if (strcmp(rv->relname, cte->ctename) == 0)
    1054                 :         484 :                         return false;   /* yes, so bail out */
    1055                 :             :                 }
    1056                 :             :             }
    1057                 :             : 
    1058                 :             :             /* No, could be a reference to the query level we are working on */
    1059                 :        2288 :             mycte = cstate->items[cstate->curitem].cte;
    1060         [ +  + ]:        2288 :             if (strcmp(rv->relname, mycte->ctename) == 0)
    1061                 :             :             {
    1062                 :             :                 /* Found a recursive reference to the active query */
    1063         [ +  + ]:         720 :                 if (cstate->context != RECURSION_OK)
    1064         [ +  - ]:          40 :                     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         [ +  + ]:         680 :                 if (++(cstate->selfrefcount) > 1)
    1072         [ +  - ]:          12 :                     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                 :        3118 :         return false;
    1081                 :             :     }
    1082         [ +  + ]:       32119 :     if (IsA(node, SelectStmt))
    1083                 :             :     {
    1084                 :        2490 :         SelectStmt *stmt = (SelectStmt *) node;
    1085                 :             :         ListCell   *lc;
    1086                 :             : 
    1087         [ +  + ]:        2490 :         if (stmt->withClause)
    1088                 :             :         {
    1089         [ +  + ]:         164 :             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                 :           4 :                 cstate->innerwiths = lcons(stmt->withClause->ctes,
    1097                 :             :                                            cstate->innerwiths);
    1098   [ +  -  +  +  :           8 :                 foreach(lc, stmt->withClause->ctes)
                   +  + ]
    1099                 :             :                 {
    1100                 :           4 :                     CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
    1101                 :             : 
    1102                 :           4 :                     (void) checkWellFormedRecursionWalker(cte->ctequery, cstate);
    1103                 :             :                 }
    1104                 :           4 :                 checkWellFormedSelectStmt(stmt, cstate);
    1105                 :           4 :                 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                 :         160 :                 cstate->innerwiths = lcons(NIL, cstate->innerwiths);
    1114   [ +  -  +  +  :         332 :                 foreach(lc, stmt->withClause->ctes)
                   +  + ]
    1115                 :             :                 {
    1116                 :         176 :                     CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
    1117                 :             :                     ListCell   *cell1;
    1118                 :             : 
    1119                 :         176 :                     (void) checkWellFormedRecursionWalker(cte->ctequery, cstate);
    1120                 :             :                     /* note that recursion could mutate innerwiths list */
    1121                 :         172 :                     cell1 = list_head(cstate->innerwiths);
    1122                 :         172 :                     lfirst(cell1) = lappend((List *) lfirst(cell1), cte);
    1123                 :             :                 }
    1124                 :         156 :                 checkWellFormedSelectStmt(stmt, cstate);
    1125                 :         156 :                 cstate->innerwiths = list_delete_first(cstate->innerwiths);
    1126                 :             :             }
    1127                 :             :         }
    1128                 :             :         else
    1129                 :        2326 :             checkWellFormedSelectStmt(stmt, cstate);
    1130                 :             :         /* We're done examining the SelectStmt */
    1131                 :        2406 :         return false;
    1132                 :             :     }
    1133         [ +  + ]:       29629 :     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                 :         160 :         return false;
    1141                 :             :     }
    1142         [ +  + ]:       29469 :     if (IsA(node, JoinExpr))
    1143                 :             :     {
    1144                 :        1135 :         JoinExpr   *j = (JoinExpr *) node;
    1145                 :             : 
    1146   [ +  +  +  +  :        1135 :         switch (j->jointype)
                      - ]
    1147                 :             :         {
    1148                 :        1069 :             case JOIN_INNER:
    1149                 :        1069 :                 checkWellFormedRecursionWalker(j->larg, cstate);
    1150                 :        1069 :                 checkWellFormedRecursionWalker(j->rarg, cstate);
    1151                 :        1069 :                 checkWellFormedRecursionWalker(j->quals, cstate);
    1152                 :        1069 :                 break;
    1153                 :          58 :             case JOIN_LEFT:
    1154                 :          58 :                 checkWellFormedRecursionWalker(j->larg, cstate);
    1155         [ +  + ]:          58 :                 if (save_context == RECURSION_OK)
    1156                 :           4 :                     cstate->context = RECURSION_OUTERJOIN;
    1157                 :          58 :                 checkWellFormedRecursionWalker(j->rarg, cstate);
    1158                 :          54 :                 cstate->context = save_context;
    1159                 :          54 :                 checkWellFormedRecursionWalker(j->quals, cstate);
    1160                 :          54 :                 break;
    1161                 :           4 :             case JOIN_FULL:
    1162         [ +  - ]:           4 :                 if (save_context == RECURSION_OK)
    1163                 :           4 :                     cstate->context = RECURSION_OUTERJOIN;
    1164                 :           4 :                 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                 :           4 :             case JOIN_RIGHT:
    1170         [ +  - ]:           4 :                 if (save_context == RECURSION_OK)
    1171                 :           4 :                     cstate->context = RECURSION_OUTERJOIN;
    1172                 :           4 :                 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                 :        1123 :         return false;
    1182                 :             :     }
    1183         [ +  + ]:       28334 :     if (IsA(node, SubLink))
    1184                 :             :     {
    1185                 :          60 :         SubLink    *sl = (SubLink *) node;
    1186                 :             : 
    1187                 :             :         /*
    1188                 :             :          * we intentionally override outer context, since subquery is
    1189                 :             :          * independent
    1190                 :             :          */
    1191                 :          60 :         cstate->context = RECURSION_SUBLINK;
    1192                 :          60 :         checkWellFormedRecursionWalker(sl->subselect, cstate);
    1193                 :          52 :         cstate->context = save_context;
    1194                 :          52 :         checkWellFormedRecursionWalker(sl->testexpr, cstate);
    1195                 :          52 :         return false;
    1196                 :             :     }
    1197                 :       28274 :     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                 :        2486 : checkWellFormedSelectStmt(SelectStmt *stmt, CteState *cstate)
    1208                 :             : {
    1209                 :        2486 :     RecursionContext save_context = cstate->context;
    1210                 :             : 
    1211         [ +  + ]:        2486 :     if (save_context != RECURSION_OK)
    1212                 :             :     {
    1213                 :             :         /* just recurse without changing state */
    1214                 :         806 :         raw_expression_tree_walker((Node *) stmt,
    1215                 :             :                                    checkWellFormedRecursionWalker,
    1216                 :             :                                    cstate);
    1217                 :             :     }
    1218                 :             :     else
    1219                 :             :     {
    1220   [ +  +  +  - ]:        1680 :         switch (stmt->op)
    1221                 :             :         {
    1222                 :        1672 :             case SETOP_NONE:
    1223                 :             :             case SETOP_UNION:
    1224                 :        1672 :                 raw_expression_tree_walker((Node *) stmt,
    1225                 :             :                                            checkWellFormedRecursionWalker,
    1226                 :             :                                            cstate);
    1227                 :        1628 :                 break;
    1228                 :           4 :             case SETOP_INTERSECT:
    1229         [ -  + ]:           4 :                 if (stmt->all)
    1230                 :           0 :                     cstate->context = RECURSION_INTERSECT;
    1231                 :           4 :                 checkWellFormedRecursionWalker((Node *) stmt->larg,
    1232                 :             :                                                cstate);
    1233                 :           4 :                 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                 :           4 :             case SETOP_EXCEPT:
    1247         [ -  + ]:           4 :                 if (stmt->all)
    1248                 :           0 :                     cstate->context = RECURSION_EXCEPT;
    1249                 :           4 :                 checkWellFormedRecursionWalker((Node *) stmt->larg,
    1250                 :             :                                                cstate);
    1251                 :           4 :                 cstate->context = RECURSION_EXCEPT;
    1252                 :           4 :                 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                 :        2406 : }
        

Generated by: LCOV version 2.0-1