LCOV - differential code coverage report
Current view: top level - src/backend/executor - nodeCtescan.c (source / functions) Coverage Total Hit UBC CBC
Current: bed3ffbf9d952be6c7d739d068cdce44c046dfb7 vs 574581b50ac9c63dd9e4abebb731a3b67e5b50f6 Lines: 95.2 % 83 79 4 79
Current Date: 2026-05-05 10:23:31 +0900 Functions: 100.0 % 6 6 6
Baseline: lcov-20260505-025707-baseline Branches: 65.0 % 40 26 14 26
Baseline Date: 2026-05-05 10:27:06 +0900 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(360..) days: 95.2 % 83 79 4 79
Function coverage date bins:
(360..) days: 100.0 % 6 6 6
Branch coverage date bins:
(360..) days: 65.0 % 40 26 14 26

 Age         Owner                    Branch data    TLA  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 *
 6422 tgl@sss.pgh.pa.us          32                 :CBC      290888 : 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                 :         290888 :     estate = node->ss.ps.state;
                                 45                 :         290888 :     dir = estate->es_direction;
                                 46                 :         290888 :     forward = ScanDirectionIsForward(dir);
                                 47                 :         290888 :     tuplestorestate = node->leader->cte_table;
                                 48                 :         290888 :     tuplestore_select_read_pointer(tuplestorestate, node->readptr);
                                 49                 :         290888 :     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                 :         290888 :     eof_tuplestore = tuplestore_ateof(tuplestorestate);
                                 56                 :                : 
                                 57   [ -  +  -  - ]:         290888 :     if (!forward && eof_tuplestore)
                                 58                 :                :     {
 6422 tgl@sss.pgh.pa.us          59         [ #  # ]:UBC           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                 :                :      */
 6422 tgl@sss.pgh.pa.us          80         [ +  + ]:CBC      290888 :     if (!eof_tuplestore)
                                 81                 :                :     {
 6248                            82         [ +  + ]:         122643 :         if (tuplestore_gettupleslot(tuplestorestate, forward, true, slot))
 6422                            83                 :         116921 :             return slot;
                                 84         [ +  - ]:           5722 :         if (forward)
                                 85                 :           5722 :             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   [ +  -  +  + ]:         173967 :     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                 :         170011 :         cteslot = ExecProcNode(node->cteplanstate);
                                105   [ +  +  +  + ]:         169999 :         if (TupIsNull(cteslot))
                                106                 :                :         {
                                107                 :           1657 :             node->leader->eof_cte = true;
                                108                 :           1657 :             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                 :                :          */
 2997                           116                 :         168342 :         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                 :                :          */
 6422                           125                 :         168342 :         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                 :         168342 :         return ExecCopySlot(slot, cteslot);
                                134                 :                :     }
                                135                 :                : 
                                136                 :                :     /*
                                137                 :                :      * Nothing left ...
                                138                 :                :      */
                                139                 :           3956 :     return ExecClearTuple(slot);
                                140                 :                : }
                                141                 :                : 
                                142                 :                : /*
                                143                 :                :  * CteScanRecheck -- access method routine to recheck a tuple in EvalPlanQual
                                144                 :                :  */
                                145                 :                : static bool
 6035                           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 *
 3214 andres@anarazel.de        161                 :         249517 : ExecCteScan(PlanState *pstate)
                                162                 :                : {
                                163                 :         249517 :     CteScanState *node = castNode(CteScanState, pstate);
                                164                 :                : 
 6035 tgl@sss.pgh.pa.us         165                 :         249517 :     return ExecScan(&node->ss,
                                166                 :                :                     (ExecScanAccessMtd) CteScanNext,
                                167                 :                :                     (ExecScanRecheckMtd) CteScanRecheck);
                                168                 :                : }
                                169                 :                : 
                                170                 :                : 
                                171                 :                : /* ----------------------------------------------------------------
                                172                 :                :  *      ExecInitCteScan
                                173                 :                :  * ----------------------------------------------------------------
                                174                 :                :  */
                                175                 :                : CteScanState *
 6422                           176                 :           2675 : ExecInitCteScan(CteScan *node, EState *estate, int eflags)
                                177                 :                : {
                                178                 :                :     CteScanState *scanstate;
                                179                 :                :     ParamExecData *prmdata;
                                180                 :                : 
                                181                 :                :     /* check for unsupported flags */
                                182         [ -  + ]:           2675 :     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                 :           2675 :     eflags |= EXEC_FLAG_REWIND;
                                197                 :                : 
                                198                 :                :     /*
                                199                 :                :      * CteScan should not have any children.
                                200                 :                :      */
                                201         [ -  + ]:           2675 :     Assert(outerPlan(node) == NULL);
                                202         [ -  + ]:           2675 :     Assert(innerPlan(node) == NULL);
                                203                 :                : 
                                204                 :                :     /*
                                205                 :                :      * create new CteScanState for node
                                206                 :                :      */
                                207                 :           2675 :     scanstate = makeNode(CteScanState);
                                208                 :           2675 :     scanstate->ss.ps.plan = (Plan *) node;
                                209                 :           2675 :     scanstate->ss.ps.state = estate;
 3214 andres@anarazel.de        210                 :           2675 :     scanstate->ss.ps.ExecProcNode = ExecCteScan;
 6422 tgl@sss.pgh.pa.us         211                 :           2675 :     scanstate->eflags = eflags;
                                212                 :           2675 :     scanstate->cte_table = NULL;
                                213                 :           2675 :     scanstate->eof_cte = false;
                                214                 :                : 
                                215                 :                :     /*
                                216                 :                :      * Find the already-initialized plan for the CTE query.
                                217                 :                :      */
                                218                 :           5350 :     scanstate->cteplanstate = (PlanState *) list_nth(estate->es_subplanstates,
                                219                 :           2675 :                                                      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                 :           2675 :     prmdata = &(estate->es_param_exec_vals[node->cteParam]);
                                228         [ -  + ]:           2675 :     Assert(prmdata->execPlan == NULL);
                                229         [ -  + ]:           2675 :     Assert(!prmdata->isnull);
 3386 andres@anarazel.de        230                 :           2675 :     scanstate->leader = castNode(CteScanState, DatumGetPointer(prmdata->value));
 6422 tgl@sss.pgh.pa.us         231         [ +  + ]:           2675 :     if (scanstate->leader == NULL)
                                232                 :                :     {
                                233                 :                :         /* I am the leader */
                                234                 :           1624 :         prmdata->value = PointerGetDatum(scanstate);
                                235                 :           1624 :         scanstate->leader = scanstate;
                                236                 :           1624 :         scanstate->cte_table = tuplestore_begin_heap(true, false, work_mem);
                                237                 :           1624 :         tuplestore_set_eflags(scanstate->cte_table, scanstate->eflags);
                                238                 :           1624 :         scanstate->readptr = 0;
                                239                 :                :     }
                                240                 :                :     else
                                241                 :                :     {
                                242                 :                :         /* Not the leader */
                                243                 :                :         /* Create my own read pointer, and ensure it is at start */
                                244                 :           1051 :         scanstate->readptr =
                                245                 :           1051 :             tuplestore_alloc_read_pointer(scanstate->leader->cte_table,
                                246                 :                :                                           scanstate->eflags);
 3512                           247                 :           1051 :         tuplestore_select_read_pointer(scanstate->leader->cte_table,
                                248                 :                :                                        scanstate->readptr);
                                249                 :           1051 :         tuplestore_rescan(scanstate->leader->cte_table);
                                250                 :                :     }
                                251                 :                : 
                                252                 :                :     /*
                                253                 :                :      * Miscellaneous initialization
                                254                 :                :      *
                                255                 :                :      * create expression context for node
                                256                 :                :      */
 6422                           257                 :           2675 :     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                 :                :      */
 3000 andres@anarazel.de        263                 :           2675 :     ExecInitScanTupleSlot(estate, &scanstate->ss,
                                264                 :                :                           ExecGetResultType(scanstate->cteplanstate),
                                265                 :                :                           &TTSOpsMinimalTuple, 0);
                                266                 :                : 
                                267                 :                :     /*
                                268                 :                :      * Initialize result type and projection.
                                269                 :                :      */
 2734                           270                 :           2675 :     ExecInitResultTypeTL(&scanstate->ss.ps);
 6422 tgl@sss.pgh.pa.us         271                 :           2675 :     ExecAssignScanProjectionInfo(&scanstate->ss);
                                272                 :                : 
                                273                 :                :     /*
                                274                 :                :      * initialize child expressions
                                275                 :                :      */
 3000 andres@anarazel.de        276                 :           2675 :     scanstate->ss.ps.qual =
                                277                 :           2675 :         ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
                                278                 :                : 
 6422 tgl@sss.pgh.pa.us         279                 :           2675 :     return scanstate;
                                280                 :                : }
                                281                 :                : 
                                282                 :                : /* ----------------------------------------------------------------
                                283                 :                :  *      ExecEndCteScan
                                284                 :                :  *
                                285                 :                :  *      frees any storage allocated through C routines.
                                286                 :                :  * ----------------------------------------------------------------
                                287                 :                :  */
                                288                 :                : void
                                289                 :           2659 : ExecEndCteScan(CteScanState *node)
                                290                 :                : {
                                291                 :                :     /*
                                292                 :                :      * If I am the leader, free the tuplestore.
                                293                 :                :      */
                                294         [ +  + ]:           2659 :     if (node->leader == node)
                                295                 :                :     {
                                296                 :           1609 :         tuplestore_end(node->cte_table);
 5011                           297                 :           1609 :         node->cte_table = NULL;
                                298                 :                :     }
 6422                           299                 :           2659 : }
                                300                 :                : 
                                301                 :                : /* ----------------------------------------------------------------
                                302                 :                :  *      ExecReScanCteScan
                                303                 :                :  *
                                304                 :                :  *      Rescans the relation.
                                305                 :                :  * ----------------------------------------------------------------
                                306                 :                :  */
                                307                 :                : void
 5776                           308                 :           3401 : ExecReScanCteScan(CteScanState *node)
                                309                 :                : {
 6403                           310                 :           3401 :     Tuplestorestate *tuplestorestate = node->leader->cte_table;
                                311                 :                : 
 2734 andres@anarazel.de        312         [ +  + ]:           3401 :     if (node->ss.ps.ps_ResultTupleSlot)
                                313                 :            121 :         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
                                314                 :                : 
 6035 tgl@sss.pgh.pa.us         315                 :           3401 :     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                 :                :      */
 5011                           325         [ +  + ]:           3401 :     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                 :                :          */
 6422                           337                 :           3097 :         tuplestore_select_read_pointer(tuplestorestate, node->readptr);
                                338                 :           3097 :         tuplestore_rescan(tuplestorestate);
                                339                 :                :     }
                                340                 :           3401 : }
        

Generated by: LCOV version 2.5.0-beta