LCOV - code coverage report
Current view: top level - src/backend/executor - nodeSeqscan.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 89 89 100.0 %
Date: 2025-08-16 18:17:32 Functions: 14 14 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * nodeSeqscan.c
       4             :  *    Support routines for sequential scans of relations.
       5             :  *
       6             :  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/executor/nodeSeqscan.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : /*
      16             :  * INTERFACE ROUTINES
      17             :  *      ExecSeqScan             sequentially scans a relation.
      18             :  *      ExecSeqNext             retrieve next tuple in sequential order.
      19             :  *      ExecInitSeqScan         creates and initializes a seqscan node.
      20             :  *      ExecEndSeqScan          releases any storage allocated.
      21             :  *      ExecReScanSeqScan       rescans the relation
      22             :  *
      23             :  *      ExecSeqScanEstimate     estimates DSM space needed for parallel scan
      24             :  *      ExecSeqScanInitializeDSM initialize DSM for parallel scan
      25             :  *      ExecSeqScanReInitializeDSM reinitialize DSM for fresh parallel scan
      26             :  *      ExecSeqScanInitializeWorker attach to DSM info in parallel worker
      27             :  */
      28             : #include "postgres.h"
      29             : 
      30             : #include "access/relscan.h"
      31             : #include "access/tableam.h"
      32             : #include "executor/execScan.h"
      33             : #include "executor/executor.h"
      34             : #include "executor/nodeSeqscan.h"
      35             : #include "utils/rel.h"
      36             : 
      37             : static TupleTableSlot *SeqNext(SeqScanState *node);
      38             : 
      39             : /* ----------------------------------------------------------------
      40             :  *                      Scan Support
      41             :  * ----------------------------------------------------------------
      42             :  */
      43             : 
      44             : /* ----------------------------------------------------------------
      45             :  *      SeqNext
      46             :  *
      47             :  *      This is a workhorse for ExecSeqScan
      48             :  * ----------------------------------------------------------------
      49             :  */
      50             : static TupleTableSlot *
      51    84692596 : SeqNext(SeqScanState *node)
      52             : {
      53             :     TableScanDesc scandesc;
      54             :     EState     *estate;
      55             :     ScanDirection direction;
      56             :     TupleTableSlot *slot;
      57             : 
      58             :     /*
      59             :      * get information from the estate and scan state
      60             :      */
      61    84692596 :     scandesc = node->ss.ss_currentScanDesc;
      62    84692596 :     estate = node->ss.ps.state;
      63    84692596 :     direction = estate->es_direction;
      64    84692596 :     slot = node->ss.ss_ScanTupleSlot;
      65             : 
      66    84692596 :     if (scandesc == NULL)
      67             :     {
      68             :         /*
      69             :          * We reach here if the scan is not parallel, or if we're serially
      70             :          * executing a scan that was planned to be parallel.
      71             :          */
      72      181324 :         scandesc = table_beginscan(node->ss.ss_currentRelation,
      73             :                                    estate->es_snapshot,
      74             :                                    0, NULL);
      75      181324 :         node->ss.ss_currentScanDesc = scandesc;
      76             :     }
      77             : 
      78             :     /*
      79             :      * get the next tuple from the table
      80             :      */
      81    84692596 :     if (table_scan_getnextslot(scandesc, direction, slot))
      82    83338150 :         return slot;
      83     1354396 :     return NULL;
      84             : }
      85             : 
      86             : /*
      87             :  * SeqRecheck -- access method routine to recheck a tuple in EvalPlanQual
      88             :  */
      89             : static bool
      90         236 : SeqRecheck(SeqScanState *node, TupleTableSlot *slot)
      91             : {
      92             :     /*
      93             :      * Note that unlike IndexScan, SeqScan never use keys in heap_beginscan
      94             :      * (and this is very bad) - so, here we do not check are keys ok or not.
      95             :      */
      96         236 :     return true;
      97             : }
      98             : 
      99             : /* ----------------------------------------------------------------
     100             :  *      ExecSeqScan(node)
     101             :  *
     102             :  *      Scans the relation sequentially and returns the next qualifying
     103             :  *      tuple. This variant is used when there is no es_epq_active, no qual
     104             :  *      and no projection.  Passing const-NULLs for these to ExecScanExtended
     105             :  *      allows the compiler to eliminate the additional code that would
     106             :  *      ordinarily be required for the evaluation of these.
     107             :  * ----------------------------------------------------------------
     108             :  */
     109             : static TupleTableSlot *
     110    13639936 : ExecSeqScan(PlanState *pstate)
     111             : {
     112    13639936 :     SeqScanState *node = castNode(SeqScanState, pstate);
     113             : 
     114             :     Assert(pstate->state->es_epq_active == NULL);
     115             :     Assert(pstate->qual == NULL);
     116             :     Assert(pstate->ps_ProjInfo == NULL);
     117             : 
     118    13639936 :     return ExecScanExtended(&node->ss,
     119             :                             (ExecScanAccessMtd) SeqNext,
     120             :                             (ExecScanRecheckMtd) SeqRecheck,
     121             :                             NULL,
     122             :                             NULL,
     123             :                             NULL);
     124             : }
     125             : 
     126             : /*
     127             :  * Variant of ExecSeqScan() but when qual evaluation is required.
     128             :  */
     129             : static TupleTableSlot *
     130     6609126 : ExecSeqScanWithQual(PlanState *pstate)
     131             : {
     132     6609126 :     SeqScanState *node = castNode(SeqScanState, pstate);
     133             : 
     134             :     /*
     135             :      * Use pg_assume() for != NULL tests to make the compiler realize no
     136             :      * runtime check for the field is needed in ExecScanExtended().
     137             :      */
     138             :     Assert(pstate->state->es_epq_active == NULL);
     139     6609126 :     pg_assume(pstate->qual != NULL);
     140             :     Assert(pstate->ps_ProjInfo == NULL);
     141             : 
     142     6609126 :     return ExecScanExtended(&node->ss,
     143             :                             (ExecScanAccessMtd) SeqNext,
     144             :                             (ExecScanRecheckMtd) SeqRecheck,
     145             :                             NULL,
     146             :                             pstate->qual,
     147             :                             NULL);
     148             : }
     149             : 
     150             : /*
     151             :  * Variant of ExecSeqScan() but when projection is required.
     152             :  */
     153             : static TupleTableSlot *
     154    23628042 : ExecSeqScanWithProject(PlanState *pstate)
     155             : {
     156    23628042 :     SeqScanState *node = castNode(SeqScanState, pstate);
     157             : 
     158             :     Assert(pstate->state->es_epq_active == NULL);
     159             :     Assert(pstate->qual == NULL);
     160    23628042 :     pg_assume(pstate->ps_ProjInfo != NULL);
     161             : 
     162    23628042 :     return ExecScanExtended(&node->ss,
     163             :                             (ExecScanAccessMtd) SeqNext,
     164             :                             (ExecScanRecheckMtd) SeqRecheck,
     165             :                             NULL,
     166             :                             NULL,
     167             :                             pstate->ps_ProjInfo);
     168             : }
     169             : 
     170             : /*
     171             :  * Variant of ExecSeqScan() but when qual evaluation and projection are
     172             :  * required.
     173             :  */
     174             : static TupleTableSlot *
     175     7238010 : ExecSeqScanWithQualProject(PlanState *pstate)
     176             : {
     177     7238010 :     SeqScanState *node = castNode(SeqScanState, pstate);
     178             : 
     179             :     Assert(pstate->state->es_epq_active == NULL);
     180     7238010 :     pg_assume(pstate->qual != NULL);
     181     7238010 :     pg_assume(pstate->ps_ProjInfo != NULL);
     182             : 
     183     7238010 :     return ExecScanExtended(&node->ss,
     184             :                             (ExecScanAccessMtd) SeqNext,
     185             :                             (ExecScanRecheckMtd) SeqRecheck,
     186             :                             NULL,
     187             :                             pstate->qual,
     188             :                             pstate->ps_ProjInfo);
     189             : }
     190             : 
     191             : /*
     192             :  * Variant of ExecSeqScan for when EPQ evaluation is required.  We don't
     193             :  * bother adding variants of this for with/without qual and projection as
     194             :  * EPQ doesn't seem as exciting a case to optimize for.
     195             :  */
     196             : static TupleTableSlot *
     197         490 : ExecSeqScanEPQ(PlanState *pstate)
     198             : {
     199         490 :     SeqScanState *node = castNode(SeqScanState, pstate);
     200             : 
     201         490 :     return ExecScan(&node->ss,
     202             :                     (ExecScanAccessMtd) SeqNext,
     203             :                     (ExecScanRecheckMtd) SeqRecheck);
     204             : }
     205             : 
     206             : /* ----------------------------------------------------------------
     207             :  *      ExecInitSeqScan
     208             :  * ----------------------------------------------------------------
     209             :  */
     210             : SeqScanState *
     211      221844 : ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
     212             : {
     213             :     SeqScanState *scanstate;
     214             : 
     215             :     /*
     216             :      * Once upon a time it was possible to have an outerPlan of a SeqScan, but
     217             :      * not any more.
     218             :      */
     219             :     Assert(outerPlan(node) == NULL);
     220             :     Assert(innerPlan(node) == NULL);
     221             : 
     222             :     /*
     223             :      * create state structure
     224             :      */
     225      221844 :     scanstate = makeNode(SeqScanState);
     226      221844 :     scanstate->ss.ps.plan = (Plan *) node;
     227      221844 :     scanstate->ss.ps.state = estate;
     228             : 
     229             :     /*
     230             :      * Miscellaneous initialization
     231             :      *
     232             :      * create expression context for node
     233             :      */
     234      221844 :     ExecAssignExprContext(estate, &scanstate->ss.ps);
     235             : 
     236             :     /*
     237             :      * open the scan relation
     238             :      */
     239      221832 :     scanstate->ss.ss_currentRelation =
     240      221844 :         ExecOpenScanRelation(estate,
     241             :                              node->scan.scanrelid,
     242             :                              eflags);
     243             : 
     244             :     /* and create slot with the appropriate rowtype */
     245      221832 :     ExecInitScanTupleSlot(estate, &scanstate->ss,
     246      221832 :                           RelationGetDescr(scanstate->ss.ss_currentRelation),
     247             :                           table_slot_callbacks(scanstate->ss.ss_currentRelation));
     248             : 
     249             :     /*
     250             :      * Initialize result type and projection.
     251             :      */
     252      221832 :     ExecInitResultTypeTL(&scanstate->ss.ps);
     253      221832 :     ExecAssignScanProjectionInfo(&scanstate->ss);
     254             : 
     255             :     /*
     256             :      * initialize child expressions
     257             :      */
     258      221832 :     scanstate->ss.ps.qual =
     259      221832 :         ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
     260             : 
     261             :     /*
     262             :      * When EvalPlanQual() is not in use, assign ExecProcNode for this node
     263             :      * based on the presence of qual and projection. Each ExecSeqScan*()
     264             :      * variant is optimized for the specific combination of these conditions.
     265             :      */
     266      221832 :     if (scanstate->ss.ps.state->es_epq_active != NULL)
     267         252 :         scanstate->ss.ps.ExecProcNode = ExecSeqScanEPQ;
     268      221580 :     else if (scanstate->ss.ps.qual == NULL)
     269             :     {
     270      111224 :         if (scanstate->ss.ps.ps_ProjInfo == NULL)
     271       52516 :             scanstate->ss.ps.ExecProcNode = ExecSeqScan;
     272             :         else
     273       58708 :             scanstate->ss.ps.ExecProcNode = ExecSeqScanWithProject;
     274             :     }
     275             :     else
     276             :     {
     277      110356 :         if (scanstate->ss.ps.ps_ProjInfo == NULL)
     278       52274 :             scanstate->ss.ps.ExecProcNode = ExecSeqScanWithQual;
     279             :         else
     280       58082 :             scanstate->ss.ps.ExecProcNode = ExecSeqScanWithQualProject;
     281             :     }
     282             : 
     283      221832 :     return scanstate;
     284             : }
     285             : 
     286             : /* ----------------------------------------------------------------
     287             :  *      ExecEndSeqScan
     288             :  *
     289             :  *      frees any storage allocated through C routines.
     290             :  * ----------------------------------------------------------------
     291             :  */
     292             : void
     293      219208 : ExecEndSeqScan(SeqScanState *node)
     294             : {
     295             :     TableScanDesc scanDesc;
     296             : 
     297             :     /*
     298             :      * get information from node
     299             :      */
     300      219208 :     scanDesc = node->ss.ss_currentScanDesc;
     301             : 
     302             :     /*
     303             :      * close heap scan
     304             :      */
     305      219208 :     if (scanDesc != NULL)
     306      182758 :         table_endscan(scanDesc);
     307      219208 : }
     308             : 
     309             : /* ----------------------------------------------------------------
     310             :  *                      Join Support
     311             :  * ----------------------------------------------------------------
     312             :  */
     313             : 
     314             : /* ----------------------------------------------------------------
     315             :  *      ExecReScanSeqScan
     316             :  *
     317             :  *      Rescans the relation.
     318             :  * ----------------------------------------------------------------
     319             :  */
     320             : void
     321     1215516 : ExecReScanSeqScan(SeqScanState *node)
     322             : {
     323             :     TableScanDesc scan;
     324             : 
     325     1215516 :     scan = node->ss.ss_currentScanDesc;
     326             : 
     327     1215516 :     if (scan != NULL)
     328     1191334 :         table_rescan(scan,      /* scan desc */
     329             :                      NULL);     /* new scan keys */
     330             : 
     331     1215516 :     ExecScanReScan((ScanState *) node);
     332     1215516 : }
     333             : 
     334             : /* ----------------------------------------------------------------
     335             :  *                      Parallel Scan Support
     336             :  * ----------------------------------------------------------------
     337             :  */
     338             : 
     339             : /* ----------------------------------------------------------------
     340             :  *      ExecSeqScanEstimate
     341             :  *
     342             :  *      Compute the amount of space we'll need in the parallel
     343             :  *      query DSM, and inform pcxt->estimator about our needs.
     344             :  * ----------------------------------------------------------------
     345             :  */
     346             : void
     347         906 : ExecSeqScanEstimate(SeqScanState *node,
     348             :                     ParallelContext *pcxt)
     349             : {
     350         906 :     EState     *estate = node->ss.ps.state;
     351             : 
     352         906 :     node->pscan_len = table_parallelscan_estimate(node->ss.ss_currentRelation,
     353             :                                                   estate->es_snapshot);
     354         906 :     shm_toc_estimate_chunk(&pcxt->estimator, node->pscan_len);
     355         906 :     shm_toc_estimate_keys(&pcxt->estimator, 1);
     356         906 : }
     357             : 
     358             : /* ----------------------------------------------------------------
     359             :  *      ExecSeqScanInitializeDSM
     360             :  *
     361             :  *      Set up a parallel heap scan descriptor.
     362             :  * ----------------------------------------------------------------
     363             :  */
     364             : void
     365         906 : ExecSeqScanInitializeDSM(SeqScanState *node,
     366             :                          ParallelContext *pcxt)
     367             : {
     368         906 :     EState     *estate = node->ss.ps.state;
     369             :     ParallelTableScanDesc pscan;
     370             : 
     371         906 :     pscan = shm_toc_allocate(pcxt->toc, node->pscan_len);
     372         906 :     table_parallelscan_initialize(node->ss.ss_currentRelation,
     373             :                                   pscan,
     374             :                                   estate->es_snapshot);
     375         906 :     shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, pscan);
     376         906 :     node->ss.ss_currentScanDesc =
     377         906 :         table_beginscan_parallel(node->ss.ss_currentRelation, pscan);
     378         906 : }
     379             : 
     380             : /* ----------------------------------------------------------------
     381             :  *      ExecSeqScanReInitializeDSM
     382             :  *
     383             :  *      Reset shared state before beginning a fresh scan.
     384             :  * ----------------------------------------------------------------
     385             :  */
     386             : void
     387         228 : ExecSeqScanReInitializeDSM(SeqScanState *node,
     388             :                            ParallelContext *pcxt)
     389             : {
     390             :     ParallelTableScanDesc pscan;
     391             : 
     392         228 :     pscan = node->ss.ss_currentScanDesc->rs_parallel;
     393         228 :     table_parallelscan_reinitialize(node->ss.ss_currentRelation, pscan);
     394         228 : }
     395             : 
     396             : /* ----------------------------------------------------------------
     397             :  *      ExecSeqScanInitializeWorker
     398             :  *
     399             :  *      Copy relevant information from TOC into planstate.
     400             :  * ----------------------------------------------------------------
     401             :  */
     402             : void
     403        2690 : ExecSeqScanInitializeWorker(SeqScanState *node,
     404             :                             ParallelWorkerContext *pwcxt)
     405             : {
     406             :     ParallelTableScanDesc pscan;
     407             : 
     408        2690 :     pscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
     409        2690 :     node->ss.ss_currentScanDesc =
     410        2690 :         table_beginscan_parallel(node->ss.ss_currentRelation, pscan);
     411        2690 : }

Generated by: LCOV version 1.16