LCOV - differential code coverage report
Current view: top level - src/backend/executor - nodeCtescan.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 95.4 % 87 83 4 83
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 6 6 6
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a