LCOV - code coverage report
Current view: top level - src/backend/executor - nodeWorktablescan.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 94.9 % 39 37
Test Date: 2026-03-21 04:16:06 Functions: 80.0 % 5 4
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * nodeWorktablescan.c
       4              :  *    routines to handle WorkTableScan 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/nodeWorktablescan.c
      12              :  *
      13              :  *-------------------------------------------------------------------------
      14              :  */
      15              : 
      16              : #include "postgres.h"
      17              : 
      18              : #include "executor/executor.h"
      19              : #include "executor/nodeWorktablescan.h"
      20              : #include "utils/tuplestore.h"
      21              : 
      22              : static TupleTableSlot *WorkTableScanNext(WorkTableScanState *node);
      23              : 
      24              : /* ----------------------------------------------------------------
      25              :  *      WorkTableScanNext
      26              :  *
      27              :  *      This is a workhorse for ExecWorkTableScan
      28              :  * ----------------------------------------------------------------
      29              :  */
      30              : static TupleTableSlot *
      31        45416 : WorkTableScanNext(WorkTableScanState *node)
      32              : {
      33              :     TupleTableSlot *slot;
      34              :     Tuplestorestate *tuplestorestate;
      35              : 
      36              :     /*
      37              :      * get information from the estate and scan state
      38              :      *
      39              :      * Note: we intentionally do not support backward scan.  Although it would
      40              :      * take only a couple more lines here, it would force nodeRecursiveunion.c
      41              :      * to create the tuplestore with backward scan enabled, which has a
      42              :      * performance cost.  In practice backward scan is never useful for a
      43              :      * worktable plan node, since it cannot appear high enough in the plan
      44              :      * tree of a scrollable cursor to be exposed to a backward-scan
      45              :      * requirement.  So it's not worth expending effort to support it.
      46              :      *
      47              :      * Note: we are also assuming that this node is the only reader of the
      48              :      * worktable.  Therefore, we don't need a private read pointer for the
      49              :      * tuplestore, nor do we need to tell tuplestore_gettupleslot to copy.
      50              :      */
      51              :     Assert(ScanDirectionIsForward(node->ss.ps.state->es_direction));
      52              : 
      53        45416 :     tuplestorestate = node->rustate->working_table;
      54              : 
      55              :     /*
      56              :      * Get the next tuple from tuplestore. Return NULL if no more tuples.
      57              :      */
      58        45416 :     slot = node->ss.ss_ScanTupleSlot;
      59        45416 :     (void) tuplestore_gettupleslot(tuplestorestate, true, false, slot);
      60        45416 :     return slot;
      61              : }
      62              : 
      63              : /*
      64              :  * WorkTableScanRecheck -- access method routine to recheck a tuple in EvalPlanQual
      65              :  */
      66              : static bool
      67            0 : WorkTableScanRecheck(WorkTableScanState *node, TupleTableSlot *slot)
      68              : {
      69              :     /* nothing to check */
      70            0 :     return true;
      71              : }
      72              : 
      73              : /* ----------------------------------------------------------------
      74              :  *      ExecWorkTableScan(node)
      75              :  *
      76              :  *      Scans the worktable sequentially and returns the next qualifying tuple.
      77              :  *      We call the ExecScan() routine and pass it the appropriate
      78              :  *      access method functions.
      79              :  * ----------------------------------------------------------------
      80              :  */
      81              : static TupleTableSlot *
      82        37890 : ExecWorkTableScan(PlanState *pstate)
      83              : {
      84        37890 :     WorkTableScanState *node = castNode(WorkTableScanState, pstate);
      85              : 
      86              :     /*
      87              :      * On the first call, find the ancestor RecursiveUnion's state via the
      88              :      * Param slot reserved for it.  (We can't do this during node init because
      89              :      * there are corner cases where we'll get the init call before the
      90              :      * RecursiveUnion does.)
      91              :      */
      92        37890 :     if (node->rustate == NULL)
      93              :     {
      94          579 :         WorkTableScan *plan = (WorkTableScan *) node->ss.ps.plan;
      95          579 :         EState     *estate = node->ss.ps.state;
      96              :         ParamExecData *param;
      97              : 
      98          579 :         param = &(estate->es_param_exec_vals[plan->wtParam]);
      99              :         Assert(param->execPlan == NULL);
     100              :         Assert(!param->isnull);
     101          579 :         node->rustate = castNode(RecursiveUnionState, DatumGetPointer(param->value));
     102              :         Assert(node->rustate);
     103              : 
     104              :         /*
     105              :          * The scan tuple type (ie, the rowtype we expect to find in the work
     106              :          * table) is the same as the result rowtype of the ancestor
     107              :          * RecursiveUnion node.  Note this depends on the assumption that
     108              :          * RecursiveUnion doesn't allow projection.
     109              :          */
     110          579 :         ExecAssignScanType(&node->ss,
     111          579 :                            ExecGetResultType(&node->rustate->ps));
     112              : 
     113              :         /*
     114              :          * Now we can initialize the projection info.  This must be completed
     115              :          * before we can call ExecScan().
     116              :          */
     117          579 :         ExecAssignScanProjectionInfo(&node->ss);
     118              :     }
     119              : 
     120        37890 :     return ExecScan(&node->ss,
     121              :                     (ExecScanAccessMtd) WorkTableScanNext,
     122              :                     (ExecScanRecheckMtd) WorkTableScanRecheck);
     123              : }
     124              : 
     125              : 
     126              : /* ----------------------------------------------------------------
     127              :  *      ExecInitWorkTableScan
     128              :  * ----------------------------------------------------------------
     129              :  */
     130              : WorkTableScanState *
     131          615 : ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags)
     132              : {
     133              :     WorkTableScanState *scanstate;
     134              : 
     135              :     /* check for unsupported flags */
     136              :     Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
     137              : 
     138              :     /*
     139              :      * WorkTableScan should not have any children.
     140              :      */
     141              :     Assert(outerPlan(node) == NULL);
     142              :     Assert(innerPlan(node) == NULL);
     143              : 
     144              :     /*
     145              :      * create new WorkTableScanState for node
     146              :      */
     147          615 :     scanstate = makeNode(WorkTableScanState);
     148          615 :     scanstate->ss.ps.plan = (Plan *) node;
     149          615 :     scanstate->ss.ps.state = estate;
     150          615 :     scanstate->ss.ps.ExecProcNode = ExecWorkTableScan;
     151          615 :     scanstate->rustate = NULL;   /* we'll set this later */
     152              : 
     153              :     /*
     154              :      * Miscellaneous initialization
     155              :      *
     156              :      * create expression context for node
     157              :      */
     158          615 :     ExecAssignExprContext(estate, &scanstate->ss.ps);
     159              : 
     160              :     /*
     161              :      * tuple table initialization
     162              :      */
     163          615 :     ExecInitResultTypeTL(&scanstate->ss.ps);
     164              : 
     165              :     /* signal that return type is not yet known */
     166          615 :     scanstate->ss.ps.resultopsset = true;
     167          615 :     scanstate->ss.ps.resultopsfixed = false;
     168              : 
     169          615 :     ExecInitScanTupleSlot(estate, &scanstate->ss, NULL, &TTSOpsMinimalTuple, 0);
     170              : 
     171              :     /*
     172              :      * initialize child expressions
     173              :      */
     174          615 :     scanstate->ss.ps.qual =
     175          615 :         ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
     176              : 
     177              :     /*
     178              :      * Do not yet initialize projection info, see ExecWorkTableScan() for
     179              :      * details.
     180              :      */
     181              : 
     182          615 :     return scanstate;
     183              : }
     184              : 
     185              : /* ----------------------------------------------------------------
     186              :  *      ExecReScanWorkTableScan
     187              :  *
     188              :  *      Rescans the relation.
     189              :  * ----------------------------------------------------------------
     190              :  */
     191              : void
     192         4280 : ExecReScanWorkTableScan(WorkTableScanState *node)
     193              : {
     194         4280 :     if (node->ss.ps.ps_ResultTupleSlot)
     195         3913 :         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
     196              : 
     197         4280 :     ExecScanReScan(&node->ss);
     198              : 
     199              :     /* No need (or way) to rescan if ExecWorkTableScan not called yet */
     200         4280 :     if (node->rustate)
     201         4276 :         tuplestore_rescan(node->rustate->working_table);
     202         4280 : }
        

Generated by: LCOV version 2.0-1