LCOV - code coverage report
Current view: top level - src/backend/executor - nodeCtescan.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 94.9 % 78 74
Test Date: 2026-07-26 06:15:43 Functions: 100.0 % 6 6
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 70.0 % 30 21

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * nodeCtescan.c
       4                 :             :  *    routines to handle CteScan nodes.
       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/executor/nodeCtescan.c
      12                 :             :  *
      13                 :             :  *-------------------------------------------------------------------------
      14                 :             :  */
      15                 :             : 
      16                 :             : #include "postgres.h"
      17                 :             : 
      18                 :             : #include "executor/executor.h"
      19                 :             : #include "executor/nodeCtescan.h"
      20                 :             : #include "miscadmin.h"
      21                 :             : #include "utils/tuplestore.h"
      22                 :             : 
      23                 :             : static TupleTableSlot *CteScanNext(CteScanState *node);
      24                 :             : 
      25                 :             : /* ----------------------------------------------------------------
      26                 :             :  *      CteScanNext
      27                 :             :  *
      28                 :             :  *      This is a workhorse for ExecCteScan
      29                 :             :  * ----------------------------------------------------------------
      30                 :             :  */
      31                 :             : static TupleTableSlot *
      32                 :      293208 : CteScanNext(CteScanState *node)
      33                 :             : {
      34                 :             :     EState     *estate;
      35                 :             :     ScanDirection dir;
      36                 :             :     bool        forward;
      37                 :             :     Tuplestorestate *tuplestorestate;
      38                 :             :     bool        eof_tuplestore;
      39                 :             :     TupleTableSlot *slot;
      40                 :             : 
      41                 :             :     /*
      42                 :             :      * get state info from node
      43                 :             :      */
      44                 :      293208 :     estate = node->ss.ps.state;
      45                 :      293208 :     dir = estate->es_direction;
      46                 :      293208 :     forward = ScanDirectionIsForward(dir);
      47                 :      293208 :     tuplestorestate = node->leader->cte_table;
      48                 :      293208 :     tuplestore_select_read_pointer(tuplestorestate, node->readptr);
      49                 :      293208 :     slot = node->ss.ss_ScanTupleSlot;
      50                 :             : 
      51                 :             :     /*
      52                 :             :      * If we are not at the end of the tuplestore, or are going backwards, try
      53                 :             :      * to fetch a tuple from tuplestore.
      54                 :             :      */
      55                 :      293208 :     eof_tuplestore = tuplestore_ateof(tuplestorestate);
      56                 :             : 
      57   [ -  +  -  - ]:      293208 :     if (!forward && eof_tuplestore)
      58                 :             :     {
      59         [ #  # ]:           0 :         if (!node->leader->eof_cte)
      60                 :             :         {
      61                 :             :             /*
      62                 :             :              * When reversing direction at tuplestore EOF, the first
      63                 :             :              * gettupleslot call will fetch the last-added tuple; but we want
      64                 :             :              * to return the one before that, if possible. So do an extra
      65                 :             :              * fetch.
      66                 :             :              */
      67         [ #  # ]:           0 :             if (!tuplestore_advance(tuplestorestate, forward))
      68                 :           0 :                 return NULL;    /* the tuplestore must be empty */
      69                 :             :         }
      70                 :           0 :         eof_tuplestore = false;
      71                 :             :     }
      72                 :             : 
      73                 :             :     /*
      74                 :             :      * If we can fetch another tuple from the tuplestore, return it.
      75                 :             :      *
      76                 :             :      * Note: we have to use copy=true in the tuplestore_gettupleslot call,
      77                 :             :      * because we are sharing the tuplestore with other nodes that might write
      78                 :             :      * into the tuplestore before we get called again.
      79                 :             :      */
      80         [ +  + ]:      293208 :     if (!eof_tuplestore)
      81                 :             :     {
      82         [ +  + ]:      123735 :         if (tuplestore_gettupleslot(tuplestorestate, forward, true, slot))
      83                 :      117765 :             return slot;
      84         [ +  - ]:        5970 :         if (forward)
      85                 :        5970 :             eof_tuplestore = true;
      86                 :             :     }
      87                 :             : 
      88                 :             :     /*
      89                 :             :      * If necessary, try to fetch another row from the CTE query.
      90                 :             :      *
      91                 :             :      * Note: the eof_cte state variable exists to short-circuit further calls
      92                 :             :      * of the CTE plan.  It's not optional, unfortunately, because some plan
      93                 :             :      * node types are not robust about being called again when they've already
      94                 :             :      * returned NULL.
      95                 :             :      */
      96   [ +  -  +  + ]:      175443 :     if (eof_tuplestore && !node->leader->eof_cte)
      97                 :             :     {
      98                 :             :         TupleTableSlot *cteslot;
      99                 :             : 
     100                 :             :         /*
     101                 :             :          * We can only get here with forward==true, so no need to worry about
     102                 :             :          * which direction the subplan will go.
     103                 :             :          */
     104                 :      171187 :         cteslot = ExecProcNode(node->cteplanstate);
     105   [ +  +  +  + ]:      171175 :         if (TupIsNull(cteslot))
     106                 :             :         {
     107                 :        1605 :             node->leader->eof_cte = true;
     108                 :        1605 :             return NULL;
     109                 :             :         }
     110                 :             : 
     111                 :             :         /*
     112                 :             :          * There are corner cases where the subplan could change which
     113                 :             :          * tuplestore read pointer is active, so be sure to reselect ours
     114                 :             :          * before storing the tuple we got.
     115                 :             :          */
     116                 :      169570 :         tuplestore_select_read_pointer(tuplestorestate, node->readptr);
     117                 :             : 
     118                 :             :         /*
     119                 :             :          * Append a copy of the returned tuple to tuplestore.  NOTE: because
     120                 :             :          * our read pointer is certainly in EOF state, its read position will
     121                 :             :          * move forward over the added tuple.  This is what we want.  Also,
     122                 :             :          * any other readers will *not* move past the new tuple, which is what
     123                 :             :          * they want.
     124                 :             :          */
     125                 :      169570 :         tuplestore_puttupleslot(tuplestorestate, cteslot);
     126                 :             : 
     127                 :             :         /*
     128                 :             :          * We MUST copy the CTE query's output tuple into our own slot. This
     129                 :             :          * is because other CteScan nodes might advance the CTE query before
     130                 :             :          * we are called again, and our output tuple must stay stable over
     131                 :             :          * that.
     132                 :             :          */
     133                 :      169570 :         return ExecCopySlot(slot, cteslot);
     134                 :             :     }
     135                 :             : 
     136                 :             :     /*
     137                 :             :      * Nothing left ...
     138                 :             :      */
     139                 :        4256 :     return ExecClearTuple(slot);
     140                 :             : }
     141                 :             : 
     142                 :             : /*
     143                 :             :  * CteScanRecheck -- access method routine to recheck a tuple in EvalPlanQual
     144                 :             :  */
     145                 :             : static bool
     146                 :           2 : CteScanRecheck(CteScanState *node, TupleTableSlot *slot)
     147                 :             : {
     148                 :             :     /* nothing to check */
     149                 :           2 :     return true;
     150                 :             : }
     151                 :             : 
     152                 :             : /* ----------------------------------------------------------------
     153                 :             :  *      ExecCteScan(node)
     154                 :             :  *
     155                 :             :  *      Scans the CTE sequentially and returns the next qualifying tuple.
     156                 :             :  *      We call the ExecScan() routine and pass it the appropriate
     157                 :             :  *      access method functions.
     158                 :             :  * ----------------------------------------------------------------
     159                 :             :  */
     160                 :             : static TupleTableSlot *
     161                 :      251763 : ExecCteScan(PlanState *pstate)
     162                 :             : {
     163                 :      251763 :     CteScanState *node = castNode(CteScanState, pstate);
     164                 :             : 
     165                 :      251763 :     return ExecScan(&node->ss,
     166                 :             :                     (ExecScanAccessMtd) CteScanNext,
     167                 :             :                     (ExecScanRecheckMtd) CteScanRecheck);
     168                 :             : }
     169                 :             : 
     170                 :             : 
     171                 :             : /* ----------------------------------------------------------------
     172                 :             :  *      ExecInitCteScan
     173                 :             :  * ----------------------------------------------------------------
     174                 :             :  */
     175                 :             : CteScanState *
     176                 :        2648 : ExecInitCteScan(CteScan *node, EState *estate, int eflags)
     177                 :             : {
     178                 :             :     CteScanState *scanstate;
     179                 :             :     ParamExecData *prmdata;
     180                 :             : 
     181                 :             :     /* check for unsupported flags */
     182                 :             :     Assert(!(eflags & EXEC_FLAG_MARK));
     183                 :             : 
     184                 :             :     /*
     185                 :             :      * For the moment we have to force the tuplestore to allow REWIND, because
     186                 :             :      * we might be asked to rescan the CTE even though upper levels didn't
     187                 :             :      * tell us to be prepared to do it efficiently.  Annoying, since this
     188                 :             :      * prevents truncation of the tuplestore.  XXX FIXME
     189                 :             :      *
     190                 :             :      * Note: if we are in an EPQ recheck plan tree, it's likely that no access
     191                 :             :      * to the tuplestore is needed at all, making this even more annoying.
     192                 :             :      * It's not worth improving that as long as all the read pointers would
     193                 :             :      * have REWIND anyway, but if we ever improve this logic then that aspect
     194                 :             :      * should be considered too.
     195                 :             :      */
     196                 :        2648 :     eflags |= EXEC_FLAG_REWIND;
     197                 :             : 
     198                 :             :     /*
     199                 :             :      * CteScan should not have any children.
     200                 :             :      */
     201                 :             :     Assert(outerPlan(node) == NULL);
     202                 :             :     Assert(innerPlan(node) == NULL);
     203                 :             : 
     204                 :             :     /*
     205                 :             :      * create new CteScanState for node
     206                 :             :      */
     207                 :        2648 :     scanstate = makeNode(CteScanState);
     208                 :        2648 :     scanstate->ss.ps.plan = (Plan *) node;
     209                 :        2648 :     scanstate->ss.ps.state = estate;
     210                 :        2648 :     scanstate->ss.ps.ExecProcNode = ExecCteScan;
     211                 :        2648 :     scanstate->eflags = eflags;
     212                 :        2648 :     scanstate->cte_table = NULL;
     213                 :        2648 :     scanstate->eof_cte = false;
     214                 :             : 
     215                 :             :     /*
     216                 :             :      * Find the already-initialized plan for the CTE query.
     217                 :             :      */
     218                 :        5296 :     scanstate->cteplanstate = (PlanState *) list_nth(estate->es_subplanstates,
     219                 :        2648 :                                                      node->ctePlanId - 1);
     220                 :             : 
     221                 :             :     /*
     222                 :             :      * The Param slot associated with the CTE query is used to hold a pointer
     223                 :             :      * to the CteState of the first CteScan node that initializes for this
     224                 :             :      * CTE.  This node will be the one that holds the shared state for all the
     225                 :             :      * CTEs, particularly the shared tuplestore.
     226                 :             :      */
     227                 :        2648 :     prmdata = &(estate->es_param_exec_vals[node->cteParam]);
     228                 :             :     Assert(prmdata->execPlan == NULL);
     229                 :             :     Assert(!prmdata->isnull);
     230                 :        2648 :     scanstate->leader = castNode(CteScanState, DatumGetPointer(prmdata->value));
     231         [ +  + ]:        2648 :     if (scanstate->leader == NULL)
     232                 :             :     {
     233                 :             :         /* I am the leader */
     234                 :        1579 :         prmdata->value = PointerGetDatum(scanstate);
     235                 :        1579 :         scanstate->leader = scanstate;
     236                 :        1579 :         scanstate->cte_table = tuplestore_begin_heap(true, false, work_mem);
     237                 :        1579 :         tuplestore_set_eflags(scanstate->cte_table, scanstate->eflags);
     238                 :        1579 :         scanstate->readptr = 0;
     239                 :             :     }
     240                 :             :     else
     241                 :             :     {
     242                 :             :         /* Not the leader */
     243                 :             :         /* Create my own read pointer, and ensure it is at start */
     244                 :        1069 :         scanstate->readptr =
     245                 :        1069 :             tuplestore_alloc_read_pointer(scanstate->leader->cte_table,
     246                 :             :                                           scanstate->eflags);
     247                 :        1069 :         tuplestore_select_read_pointer(scanstate->leader->cte_table,
     248                 :             :                                        scanstate->readptr);
     249                 :        1069 :         tuplestore_rescan(scanstate->leader->cte_table);
     250                 :             :     }
     251                 :             : 
     252                 :             :     /*
     253                 :             :      * Miscellaneous initialization
     254                 :             :      *
     255                 :             :      * create expression context for node
     256                 :             :      */
     257                 :        2648 :     ExecAssignExprContext(estate, &scanstate->ss.ps);
     258                 :             : 
     259                 :             :     /*
     260                 :             :      * The scan tuple type (ie, the rowtype we expect to find in the work
     261                 :             :      * table) is the same as the result rowtype of the CTE query.
     262                 :             :      */
     263                 :        2648 :     ExecInitScanTupleSlot(estate, &scanstate->ss,
     264                 :             :                           ExecGetResultType(scanstate->cteplanstate),
     265                 :             :                           &TTSOpsMinimalTuple, 0);
     266                 :             : 
     267                 :             :     /*
     268                 :             :      * Initialize result type and projection.
     269                 :             :      */
     270                 :        2648 :     ExecInitResultTypeTL(&scanstate->ss.ps);
     271                 :        2648 :     ExecAssignScanProjectionInfo(&scanstate->ss);
     272                 :             : 
     273                 :             :     /*
     274                 :             :      * initialize child expressions
     275                 :             :      */
     276                 :        2648 :     scanstate->ss.ps.qual =
     277                 :        2648 :         ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
     278                 :             : 
     279                 :        2648 :     return scanstate;
     280                 :             : }
     281                 :             : 
     282                 :             : /* ----------------------------------------------------------------
     283                 :             :  *      ExecEndCteScan
     284                 :             :  *
     285                 :             :  *      frees any storage allocated through C routines.
     286                 :             :  * ----------------------------------------------------------------
     287                 :             :  */
     288                 :             : void
     289                 :        2632 : ExecEndCteScan(CteScanState *node)
     290                 :             : {
     291                 :             :     /*
     292                 :             :      * If I am the leader, free the tuplestore.
     293                 :             :      */
     294         [ +  + ]:        2632 :     if (node->leader == node)
     295                 :             :     {
     296                 :        1564 :         tuplestore_end(node->cte_table);
     297                 :        1564 :         node->cte_table = NULL;
     298                 :             :     }
     299                 :        2632 : }
     300                 :             : 
     301                 :             : /* ----------------------------------------------------------------
     302                 :             :  *      ExecReScanCteScan
     303                 :             :  *
     304                 :             :  *      Rescans the relation.
     305                 :             :  * ----------------------------------------------------------------
     306                 :             :  */
     307                 :             : void
     308                 :        3694 : ExecReScanCteScan(CteScanState *node)
     309                 :             : {
     310                 :        3694 :     Tuplestorestate *tuplestorestate = node->leader->cte_table;
     311                 :             : 
     312         [ +  + ]:        3694 :     if (node->ss.ps.ps_ResultTupleSlot)
     313                 :         121 :         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
     314                 :             : 
     315                 :        3694 :     ExecScanReScan(&node->ss);
     316                 :             : 
     317                 :             :     /*
     318                 :             :      * Clear the tuplestore if a new scan of the underlying CTE is required.
     319                 :             :      * This implicitly resets all the tuplestore's read pointers.  Note that
     320                 :             :      * multiple CTE nodes might redundantly clear the tuplestore; that's OK,
     321                 :             :      * and not unduly expensive.  We'll stop taking this path as soon as
     322                 :             :      * somebody has attempted to read something from the underlying CTE
     323                 :             :      * (thereby causing its chgParam to be cleared).
     324                 :             :      */
     325         [ +  + ]:        3694 :     if (node->leader->cteplanstate->chgParam != NULL)
     326                 :             :     {
     327                 :         304 :         tuplestore_clear(tuplestorestate);
     328                 :         304 :         node->leader->eof_cte = false;
     329                 :             :     }
     330                 :             :     else
     331                 :             :     {
     332                 :             :         /*
     333                 :             :          * Else, just rewind my own pointer.  Either the underlying CTE
     334                 :             :          * doesn't need a rescan (and we can re-read what's in the tuplestore
     335                 :             :          * now), or somebody else already took care of it.
     336                 :             :          */
     337                 :        3390 :         tuplestore_select_read_pointer(tuplestorestate, node->readptr);
     338                 :        3390 :         tuplestore_rescan(tuplestorestate);
     339                 :             :     }
     340                 :        3694 : }
        

Generated by: LCOV version 2.0-1