LCOV - code coverage report
Current view: top level - src/backend/executor - nodeSeqscan.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 100.0 % 89 89
Test Date: 2026-03-21 04:16:06 Functions: 100.0 % 14 14
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-2026, 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 pg_attribute_always_inline TupleTableSlot *
      51     63198267 : 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     63198267 :     scandesc = node->ss.ss_currentScanDesc;
      62     63198267 :     estate = node->ss.ps.state;
      63     63198267 :     direction = estate->es_direction;
      64     63198267 :     slot = node->ss.ss_ScanTupleSlot;
      65              : 
      66     63198267 :     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       429828 :         scandesc = table_beginscan(node->ss.ss_currentRelation,
      73              :                                    estate->es_snapshot,
      74              :                                    0, NULL);
      75       429828 :         node->ss.ss_currentScanDesc = scandesc;
      76              :     }
      77              : 
      78              :     /*
      79              :      * get the next tuple from the table
      80              :      */
      81     63198267 :     if (table_scan_getnextslot(scandesc, direction, slot))
      82     62217469 :         return slot;
      83       980773 :     return NULL;
      84              : }
      85              : 
      86              : /*
      87              :  * SeqRecheck -- access method routine to recheck a tuple in EvalPlanQual
      88              :  */
      89              : static pg_attribute_always_inline bool
      90          129 : 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          129 :     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      9091573 : ExecSeqScan(PlanState *pstate)
     111              : {
     112      9091573 :     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      9091573 :     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      4460901 : ExecSeqScanWithQual(PlanState *pstate)
     131              : {
     132      4460901 :     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      4460901 :     pg_assume(pstate->qual != NULL);
     140              :     Assert(pstate->ps_ProjInfo == NULL);
     141              : 
     142      4460901 :     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     16123756 : ExecSeqScanWithProject(PlanState *pstate)
     155              : {
     156     16123756 :     SeqScanState *node = castNode(SeqScanState, pstate);
     157              : 
     158              :     Assert(pstate->state->es_epq_active == NULL);
     159              :     Assert(pstate->qual == NULL);
     160     16123756 :     pg_assume(pstate->ps_ProjInfo != NULL);
     161              : 
     162     16123756 :     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      5536089 : ExecSeqScanWithQualProject(PlanState *pstate)
     176              : {
     177      5536089 :     SeqScanState *node = castNode(SeqScanState, pstate);
     178              : 
     179              :     Assert(pstate->state->es_epq_active == NULL);
     180      5536089 :     pg_assume(pstate->qual != NULL);
     181      5536089 :     pg_assume(pstate->ps_ProjInfo != NULL);
     182              : 
     183      5536089 :     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          258 : ExecSeqScanEPQ(PlanState *pstate)
     198              : {
     199          258 :     SeqScanState *node = castNode(SeqScanState, pstate);
     200              : 
     201          258 :     return ExecScan(&node->ss,
     202              :                     (ExecScanAccessMtd) SeqNext,
     203              :                     (ExecScanRecheckMtd) SeqRecheck);
     204              : }
     205              : 
     206              : /* ----------------------------------------------------------------
     207              :  *      ExecInitSeqScan
     208              :  * ----------------------------------------------------------------
     209              :  */
     210              : SeqScanState *
     211       465742 : 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       465742 :     scanstate = makeNode(SeqScanState);
     226       465742 :     scanstate->ss.ps.plan = (Plan *) node;
     227       465742 :     scanstate->ss.ps.state = estate;
     228              : 
     229              :     /*
     230              :      * Miscellaneous initialization
     231              :      *
     232              :      * create expression context for node
     233              :      */
     234       465742 :     ExecAssignExprContext(estate, &scanstate->ss.ps);
     235              : 
     236              :     /*
     237              :      * open the scan relation
     238              :      */
     239       465734 :     scanstate->ss.ss_currentRelation =
     240       465742 :         ExecOpenScanRelation(estate,
     241              :                              node->scan.scanrelid,
     242              :                              eflags);
     243              : 
     244              :     /* and create slot with the appropriate rowtype */
     245       465734 :     ExecInitScanTupleSlot(estate, &scanstate->ss,
     246       465734 :                           RelationGetDescr(scanstate->ss.ss_currentRelation),
     247              :                           table_slot_callbacks(scanstate->ss.ss_currentRelation),
     248              :                           TTS_FLAG_OBEYS_NOT_NULL_CONSTRAINTS);
     249              : 
     250              :     /*
     251              :      * Initialize result type and projection.
     252              :      */
     253       465734 :     ExecInitResultTypeTL(&scanstate->ss.ps);
     254       465734 :     ExecAssignScanProjectionInfo(&scanstate->ss);
     255              : 
     256              :     /*
     257              :      * initialize child expressions
     258              :      */
     259       465734 :     scanstate->ss.ps.qual =
     260       465734 :         ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
     261              : 
     262              :     /*
     263              :      * When EvalPlanQual() is not in use, assign ExecProcNode for this node
     264              :      * based on the presence of qual and projection. Each ExecSeqScan*()
     265              :      * variant is optimized for the specific combination of these conditions.
     266              :      */
     267       465734 :     if (scanstate->ss.ps.state->es_epq_active != NULL)
     268          143 :         scanstate->ss.ps.ExecProcNode = ExecSeqScanEPQ;
     269       465591 :     else if (scanstate->ss.ps.qual == NULL)
     270              :     {
     271        84055 :         if (scanstate->ss.ps.ps_ProjInfo == NULL)
     272        40398 :             scanstate->ss.ps.ExecProcNode = ExecSeqScan;
     273              :         else
     274        43657 :             scanstate->ss.ps.ExecProcNode = ExecSeqScanWithProject;
     275              :     }
     276              :     else
     277              :     {
     278       381536 :         if (scanstate->ss.ps.ps_ProjInfo == NULL)
     279        39178 :             scanstate->ss.ps.ExecProcNode = ExecSeqScanWithQual;
     280              :         else
     281       342358 :             scanstate->ss.ps.ExecProcNode = ExecSeqScanWithQualProject;
     282              :     }
     283              : 
     284       465734 :     return scanstate;
     285              : }
     286              : 
     287              : /* ----------------------------------------------------------------
     288              :  *      ExecEndSeqScan
     289              :  *
     290              :  *      frees any storage allocated through C routines.
     291              :  * ----------------------------------------------------------------
     292              :  */
     293              : void
     294       463939 : ExecEndSeqScan(SeqScanState *node)
     295              : {
     296              :     TableScanDesc scanDesc;
     297              : 
     298              :     /*
     299              :      * get information from node
     300              :      */
     301       463939 :     scanDesc = node->ss.ss_currentScanDesc;
     302              : 
     303              :     /*
     304              :      * close heap scan
     305              :      */
     306       463939 :     if (scanDesc != NULL)
     307       430845 :         table_endscan(scanDesc);
     308       463939 : }
     309              : 
     310              : /* ----------------------------------------------------------------
     311              :  *                      Join Support
     312              :  * ----------------------------------------------------------------
     313              :  */
     314              : 
     315              : /* ----------------------------------------------------------------
     316              :  *      ExecReScanSeqScan
     317              :  *
     318              :  *      Rescans the relation.
     319              :  * ----------------------------------------------------------------
     320              :  */
     321              : void
     322       881129 : ExecReScanSeqScan(SeqScanState *node)
     323              : {
     324              :     TableScanDesc scan;
     325              : 
     326       881129 :     scan = node->ss.ss_currentScanDesc;
     327              : 
     328       881129 :     if (scan != NULL)
     329       865338 :         table_rescan(scan,      /* scan desc */
     330              :                      NULL);     /* new scan keys */
     331              : 
     332       881129 :     ExecScanReScan((ScanState *) node);
     333       881129 : }
     334              : 
     335              : /* ----------------------------------------------------------------
     336              :  *                      Parallel Scan Support
     337              :  * ----------------------------------------------------------------
     338              :  */
     339              : 
     340              : /* ----------------------------------------------------------------
     341              :  *      ExecSeqScanEstimate
     342              :  *
     343              :  *      Compute the amount of space we'll need in the parallel
     344              :  *      query DSM, and inform pcxt->estimator about our needs.
     345              :  * ----------------------------------------------------------------
     346              :  */
     347              : void
     348          637 : ExecSeqScanEstimate(SeqScanState *node,
     349              :                     ParallelContext *pcxt)
     350              : {
     351          637 :     EState     *estate = node->ss.ps.state;
     352              : 
     353          637 :     node->pscan_len = table_parallelscan_estimate(node->ss.ss_currentRelation,
     354              :                                                   estate->es_snapshot);
     355          637 :     shm_toc_estimate_chunk(&pcxt->estimator, node->pscan_len);
     356          637 :     shm_toc_estimate_keys(&pcxt->estimator, 1);
     357          637 : }
     358              : 
     359              : /* ----------------------------------------------------------------
     360              :  *      ExecSeqScanInitializeDSM
     361              :  *
     362              :  *      Set up a parallel heap scan descriptor.
     363              :  * ----------------------------------------------------------------
     364              :  */
     365              : void
     366          637 : ExecSeqScanInitializeDSM(SeqScanState *node,
     367              :                          ParallelContext *pcxt)
     368              : {
     369          637 :     EState     *estate = node->ss.ps.state;
     370              :     ParallelTableScanDesc pscan;
     371              : 
     372          637 :     pscan = shm_toc_allocate(pcxt->toc, node->pscan_len);
     373          637 :     table_parallelscan_initialize(node->ss.ss_currentRelation,
     374              :                                   pscan,
     375              :                                   estate->es_snapshot);
     376          637 :     shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, pscan);
     377          637 :     node->ss.ss_currentScanDesc =
     378          637 :         table_beginscan_parallel(node->ss.ss_currentRelation, pscan);
     379          637 : }
     380              : 
     381              : /* ----------------------------------------------------------------
     382              :  *      ExecSeqScanReInitializeDSM
     383              :  *
     384              :  *      Reset shared state before beginning a fresh scan.
     385              :  * ----------------------------------------------------------------
     386              :  */
     387              : void
     388          152 : ExecSeqScanReInitializeDSM(SeqScanState *node,
     389              :                            ParallelContext *pcxt)
     390              : {
     391              :     ParallelTableScanDesc pscan;
     392              : 
     393          152 :     pscan = node->ss.ss_currentScanDesc->rs_parallel;
     394          152 :     table_parallelscan_reinitialize(node->ss.ss_currentRelation, pscan);
     395          152 : }
     396              : 
     397              : /* ----------------------------------------------------------------
     398              :  *      ExecSeqScanInitializeWorker
     399              :  *
     400              :  *      Copy relevant information from TOC into planstate.
     401              :  * ----------------------------------------------------------------
     402              :  */
     403              : void
     404         1860 : ExecSeqScanInitializeWorker(SeqScanState *node,
     405              :                             ParallelWorkerContext *pwcxt)
     406              : {
     407              :     ParallelTableScanDesc pscan;
     408              : 
     409         1860 :     pscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
     410         1860 :     node->ss.ss_currentScanDesc =
     411         1860 :         table_beginscan_parallel(node->ss.ss_currentRelation, pscan);
     412         1860 : }
        

Generated by: LCOV version 2.0-1