LCOV - code coverage report
Current view: top level - src/backend/executor - nodeSeqscan.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 85 85 100.0 %
Date: 2025-02-22 07:14:56 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    78707128 : 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    78707128 :     scandesc = node->ss.ss_currentScanDesc;
      62    78707128 :     estate = node->ss.ps.state;
      63    78707128 :     direction = estate->es_direction;
      64    78707128 :     slot = node->ss.ss_ScanTupleSlot;
      65             : 
      66    78707128 :     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      187774 :         scandesc = table_beginscan(node->ss.ss_currentRelation,
      73             :                                    estate->es_snapshot,
      74             :                                    0, NULL);
      75      187774 :         node->ss.ss_currentScanDesc = scandesc;
      76             :     }
      77             : 
      78             :     /*
      79             :      * get the next tuple from the table
      80             :      */
      81    78707128 :     if (table_scan_getnextslot(scandesc, direction, slot))
      82    77501720 :         return slot;
      83     1205392 :     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_eqp_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    12172534 : ExecSeqScan(PlanState *pstate)
     111             : {
     112    12172534 :     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    12172534 :     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     5581342 : ExecSeqScanWithQual(PlanState *pstate)
     131             : {
     132     5581342 :     SeqScanState *node = castNode(SeqScanState, pstate);
     133             : 
     134             :     Assert(pstate->state->es_epq_active == NULL);
     135             :     Assert(pstate->qual != NULL);
     136             :     Assert(pstate->ps_ProjInfo == NULL);
     137             : 
     138     5581342 :     return ExecScanExtended(&node->ss,
     139             :                             (ExecScanAccessMtd) SeqNext,
     140             :                             (ExecScanRecheckMtd) SeqRecheck,
     141             :                             NULL,
     142             :                             pstate->qual,
     143             :                             NULL);
     144             : }
     145             : 
     146             : /*
     147             :  * Variant of ExecSeqScan() but when projection is required.
     148             :  */
     149             : static TupleTableSlot *
     150    21961364 : ExecSeqScanWithProject(PlanState *pstate)
     151             : {
     152    21961364 :     SeqScanState *node = castNode(SeqScanState, pstate);
     153             : 
     154             :     Assert(pstate->state->es_epq_active == NULL);
     155             :     Assert(pstate->qual == NULL);
     156             :     Assert(pstate->ps_ProjInfo != NULL);
     157             : 
     158    21961364 :     return ExecScanExtended(&node->ss,
     159             :                             (ExecScanAccessMtd) SeqNext,
     160             :                             (ExecScanRecheckMtd) SeqRecheck,
     161             :                             NULL,
     162             :                             NULL,
     163             :                             pstate->ps_ProjInfo);
     164             : }
     165             : 
     166             : /*
     167             :  * Variant of ExecSeqScan() but when qual evaluation and projection are
     168             :  * required.
     169             :  */
     170             : static TupleTableSlot *
     171     6663712 : ExecSeqScanWithQualProject(PlanState *pstate)
     172             : {
     173     6663712 :     SeqScanState *node = castNode(SeqScanState, pstate);
     174             : 
     175             :     Assert(pstate->state->es_epq_active == NULL);
     176             :     Assert(pstate->qual != NULL);
     177             :     Assert(pstate->ps_ProjInfo != NULL);
     178             : 
     179     6663712 :     return ExecScanExtended(&node->ss,
     180             :                             (ExecScanAccessMtd) SeqNext,
     181             :                             (ExecScanRecheckMtd) SeqRecheck,
     182             :                             NULL,
     183             :                             pstate->qual,
     184             :                             pstate->ps_ProjInfo);
     185             : }
     186             : 
     187             : /*
     188             :  * Variant of ExecSeqScan for when EPQ evaluation is required.  We don't
     189             :  * bother adding variants of this for with/without qual and projection as
     190             :  * EPQ doesn't seem as exciting a case to optimize for.
     191             :  */
     192             : static TupleTableSlot *
     193         490 : ExecSeqScanEPQ(PlanState *pstate)
     194             : {
     195         490 :     SeqScanState *node = castNode(SeqScanState, pstate);
     196             : 
     197         490 :     return ExecScan(&node->ss,
     198             :                     (ExecScanAccessMtd) SeqNext,
     199             :                     (ExecScanRecheckMtd) SeqRecheck);
     200             : }
     201             : 
     202             : /* ----------------------------------------------------------------
     203             :  *      ExecInitSeqScan
     204             :  * ----------------------------------------------------------------
     205             :  */
     206             : SeqScanState *
     207      246870 : ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
     208             : {
     209             :     SeqScanState *scanstate;
     210             : 
     211             :     /*
     212             :      * Once upon a time it was possible to have an outerPlan of a SeqScan, but
     213             :      * not any more.
     214             :      */
     215             :     Assert(outerPlan(node) == NULL);
     216             :     Assert(innerPlan(node) == NULL);
     217             : 
     218             :     /*
     219             :      * create state structure
     220             :      */
     221      246870 :     scanstate = makeNode(SeqScanState);
     222      246870 :     scanstate->ss.ps.plan = (Plan *) node;
     223      246870 :     scanstate->ss.ps.state = estate;
     224             : 
     225             :     /*
     226             :      * Miscellaneous initialization
     227             :      *
     228             :      * create expression context for node
     229             :      */
     230      246870 :     ExecAssignExprContext(estate, &scanstate->ss.ps);
     231             : 
     232             :     /*
     233             :      * open the scan relation
     234             :      */
     235      246858 :     scanstate->ss.ss_currentRelation =
     236      246870 :         ExecOpenScanRelation(estate,
     237             :                              node->scan.scanrelid,
     238             :                              eflags);
     239             : 
     240             :     /* and create slot with the appropriate rowtype */
     241      246858 :     ExecInitScanTupleSlot(estate, &scanstate->ss,
     242      246858 :                           RelationGetDescr(scanstate->ss.ss_currentRelation),
     243             :                           table_slot_callbacks(scanstate->ss.ss_currentRelation));
     244             : 
     245             :     /*
     246             :      * Initialize result type and projection.
     247             :      */
     248      246858 :     ExecInitResultTypeTL(&scanstate->ss.ps);
     249      246858 :     ExecAssignScanProjectionInfo(&scanstate->ss);
     250             : 
     251             :     /*
     252             :      * initialize child expressions
     253             :      */
     254      246852 :     scanstate->ss.ps.qual =
     255      246852 :         ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
     256             : 
     257             :     /*
     258             :      * When EvalPlanQual() is not in use, assign ExecProcNode for this node
     259             :      * based on the presence of qual and projection. Each ExecSeqScan*()
     260             :      * variant is optimized for the specific combination of these conditions.
     261             :      */
     262      246852 :     if (scanstate->ss.ps.state->es_epq_active != NULL)
     263         252 :         scanstate->ss.ps.ExecProcNode = ExecSeqScanEPQ;
     264      246600 :     else if (scanstate->ss.ps.qual == NULL)
     265             :     {
     266      107988 :         if (scanstate->ss.ps.ps_ProjInfo == NULL)
     267       51736 :             scanstate->ss.ps.ExecProcNode = ExecSeqScan;
     268             :         else
     269       56252 :             scanstate->ss.ps.ExecProcNode = ExecSeqScanWithProject;
     270             :     }
     271             :     else
     272             :     {
     273      138612 :         if (scanstate->ss.ps.ps_ProjInfo == NULL)
     274       83122 :             scanstate->ss.ps.ExecProcNode = ExecSeqScanWithQual;
     275             :         else
     276       55490 :             scanstate->ss.ps.ExecProcNode = ExecSeqScanWithQualProject;
     277             :     }
     278             : 
     279      246852 :     return scanstate;
     280             : }
     281             : 
     282             : /* ----------------------------------------------------------------
     283             :  *      ExecEndSeqScan
     284             :  *
     285             :  *      frees any storage allocated through C routines.
     286             :  * ----------------------------------------------------------------
     287             :  */
     288             : void
     289      244290 : ExecEndSeqScan(SeqScanState *node)
     290             : {
     291             :     TableScanDesc scanDesc;
     292             : 
     293             :     /*
     294             :      * get information from node
     295             :      */
     296      244290 :     scanDesc = node->ss.ss_currentScanDesc;
     297             : 
     298             :     /*
     299             :      * close heap scan
     300             :      */
     301      244290 :     if (scanDesc != NULL)
     302      189256 :         table_endscan(scanDesc);
     303      244290 : }
     304             : 
     305             : /* ----------------------------------------------------------------
     306             :  *                      Join Support
     307             :  * ----------------------------------------------------------------
     308             :  */
     309             : 
     310             : /* ----------------------------------------------------------------
     311             :  *      ExecReScanSeqScan
     312             :  *
     313             :  *      Rescans the relation.
     314             :  * ----------------------------------------------------------------
     315             :  */
     316             : void
     317     1095366 : ExecReScanSeqScan(SeqScanState *node)
     318             : {
     319             :     TableScanDesc scan;
     320             : 
     321     1095366 :     scan = node->ss.ss_currentScanDesc;
     322             : 
     323     1095366 :     if (scan != NULL)
     324     1054426 :         table_rescan(scan,      /* scan desc */
     325             :                      NULL);     /* new scan keys */
     326             : 
     327     1095366 :     ExecScanReScan((ScanState *) node);
     328     1095366 : }
     329             : 
     330             : /* ----------------------------------------------------------------
     331             :  *                      Parallel Scan Support
     332             :  * ----------------------------------------------------------------
     333             :  */
     334             : 
     335             : /* ----------------------------------------------------------------
     336             :  *      ExecSeqScanEstimate
     337             :  *
     338             :  *      Compute the amount of space we'll need in the parallel
     339             :  *      query DSM, and inform pcxt->estimator about our needs.
     340             :  * ----------------------------------------------------------------
     341             :  */
     342             : void
     343         900 : ExecSeqScanEstimate(SeqScanState *node,
     344             :                     ParallelContext *pcxt)
     345             : {
     346         900 :     EState     *estate = node->ss.ps.state;
     347             : 
     348         900 :     node->pscan_len = table_parallelscan_estimate(node->ss.ss_currentRelation,
     349             :                                                   estate->es_snapshot);
     350         900 :     shm_toc_estimate_chunk(&pcxt->estimator, node->pscan_len);
     351         900 :     shm_toc_estimate_keys(&pcxt->estimator, 1);
     352         900 : }
     353             : 
     354             : /* ----------------------------------------------------------------
     355             :  *      ExecSeqScanInitializeDSM
     356             :  *
     357             :  *      Set up a parallel heap scan descriptor.
     358             :  * ----------------------------------------------------------------
     359             :  */
     360             : void
     361         900 : ExecSeqScanInitializeDSM(SeqScanState *node,
     362             :                          ParallelContext *pcxt)
     363             : {
     364         900 :     EState     *estate = node->ss.ps.state;
     365             :     ParallelTableScanDesc pscan;
     366             : 
     367         900 :     pscan = shm_toc_allocate(pcxt->toc, node->pscan_len);
     368         900 :     table_parallelscan_initialize(node->ss.ss_currentRelation,
     369             :                                   pscan,
     370             :                                   estate->es_snapshot);
     371         900 :     shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, pscan);
     372         900 :     node->ss.ss_currentScanDesc =
     373         900 :         table_beginscan_parallel(node->ss.ss_currentRelation, pscan);
     374         900 : }
     375             : 
     376             : /* ----------------------------------------------------------------
     377             :  *      ExecSeqScanReInitializeDSM
     378             :  *
     379             :  *      Reset shared state before beginning a fresh scan.
     380             :  * ----------------------------------------------------------------
     381             :  */
     382             : void
     383         228 : ExecSeqScanReInitializeDSM(SeqScanState *node,
     384             :                            ParallelContext *pcxt)
     385             : {
     386             :     ParallelTableScanDesc pscan;
     387             : 
     388         228 :     pscan = node->ss.ss_currentScanDesc->rs_parallel;
     389         228 :     table_parallelscan_reinitialize(node->ss.ss_currentRelation, pscan);
     390         228 : }
     391             : 
     392             : /* ----------------------------------------------------------------
     393             :  *      ExecSeqScanInitializeWorker
     394             :  *
     395             :  *      Copy relevant information from TOC into planstate.
     396             :  * ----------------------------------------------------------------
     397             :  */
     398             : void
     399        2682 : ExecSeqScanInitializeWorker(SeqScanState *node,
     400             :                             ParallelWorkerContext *pwcxt)
     401             : {
     402             :     ParallelTableScanDesc pscan;
     403             : 
     404        2682 :     pscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
     405        2682 :     node->ss.ss_currentScanDesc =
     406        2682 :         table_beginscan_parallel(node->ss.ss_currentRelation, pscan);
     407        2682 : }

Generated by: LCOV version 1.14