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

Generated by: LCOV version 2.0-1