LCOV - code coverage report
Current view: top level - src/backend/executor - nodeSeqscan.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 94.6 % 129 122
Test Date: 2026-01-26 10:56:24 Functions: 85.7 % 14 12
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 65.9 % 44 29

             Branch data     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                 :    15781215 : SeqNext(SeqScanState *node)
      52                 :             : {
      53                 :    15781215 :         TableScanDesc scandesc;
      54                 :    15781215 :         EState     *estate;
      55                 :    15781215 :         ScanDirection direction;
      56                 :    15781215 :         TupleTableSlot *slot;
      57                 :             : 
      58                 :             :         /*
      59                 :             :          * get information from the estate and scan state
      60                 :             :          */
      61                 :    15781215 :         scandesc = node->ss.ss_currentScanDesc;
      62                 :    15781215 :         estate = node->ss.ps.state;
      63                 :    15781215 :         direction = estate->es_direction;
      64                 :    15781215 :         slot = node->ss.ss_ScanTupleSlot;
      65                 :             : 
      66         [ +  + ]:    15781215 :         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                 :      644196 :                 scandesc = table_beginscan(node->ss.ss_currentRelation,
      73                 :      322098 :                                                                    estate->es_snapshot,
      74                 :             :                                                                    0, NULL);
      75                 :      322098 :                 node->ss.ss_currentScanDesc = scandesc;
      76                 :      322098 :         }
      77                 :             : 
      78                 :             :         /*
      79                 :             :          * get the next tuple from the table
      80                 :             :          */
      81         [ +  + ]:    15781215 :         if (table_scan_getnextslot(scandesc, direction, slot))
      82                 :    15758483 :                 return slot;
      83                 :       22732 :         return NULL;
      84                 :    15781215 : }
      85                 :             : 
      86                 :             : /*
      87                 :             :  * SeqRecheck -- access method routine to recheck a tuple in EvalPlanQual
      88                 :             :  */
      89                 :             : static pg_attribute_always_inline bool
      90                 :           0 : 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                 :           0 :         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                 :     1879474 : ExecSeqScan(PlanState *pstate)
     111                 :             : {
     112                 :     1879474 :         SeqScanState *node = castNode(SeqScanState, pstate);
     113                 :             : 
     114         [ +  - ]:     1879474 :         Assert(pstate->state->es_epq_active == NULL);
     115         [ +  - ]:     1879474 :         Assert(pstate->qual == NULL);
     116         [ +  - ]:     1879474 :         Assert(pstate->ps_ProjInfo == NULL);
     117                 :             : 
     118                 :     3758948 :         return ExecScanExtended(&node->ss,
     119                 :             :                                                         (ExecScanAccessMtd) SeqNext,
     120                 :             :                                                         (ExecScanRecheckMtd) SeqRecheck,
     121                 :             :                                                         NULL,
     122                 :             :                                                         NULL,
     123                 :             :                                                         NULL);
     124                 :     1879474 : }
     125                 :             : 
     126                 :             : /*
     127                 :             :  * Variant of ExecSeqScan() but when qual evaluation is required.
     128                 :             :  */
     129                 :             : static TupleTableSlot *
     130                 :      434500 : ExecSeqScanWithQual(PlanState *pstate)
     131                 :             : {
     132                 :      434500 :         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         [ +  - ]:      434500 :         Assert(pstate->state->es_epq_active == NULL);
     139         [ +  - ]:      434500 :         pg_assume(pstate->qual != NULL);
     140         [ +  - ]:      434500 :         Assert(pstate->ps_ProjInfo == NULL);
     141                 :             : 
     142                 :     1303500 :         return ExecScanExtended(&node->ss,
     143                 :             :                                                         (ExecScanAccessMtd) SeqNext,
     144                 :             :                                                         (ExecScanRecheckMtd) SeqRecheck,
     145                 :             :                                                         NULL,
     146                 :      434500 :                                                         pstate->qual,
     147                 :             :                                                         NULL);
     148                 :      434500 : }
     149                 :             : 
     150                 :             : /*
     151                 :             :  * Variant of ExecSeqScan() but when projection is required.
     152                 :             :  */
     153                 :             : static TupleTableSlot *
     154                 :     3323436 : ExecSeqScanWithProject(PlanState *pstate)
     155                 :             : {
     156                 :     3323436 :         SeqScanState *node = castNode(SeqScanState, pstate);
     157                 :             : 
     158         [ +  - ]:     3323436 :         Assert(pstate->state->es_epq_active == NULL);
     159         [ +  - ]:     3323436 :         Assert(pstate->qual == NULL);
     160         [ +  - ]:     3323436 :         pg_assume(pstate->ps_ProjInfo != NULL);
     161                 :             : 
     162                 :     9970308 :         return ExecScanExtended(&node->ss,
     163                 :             :                                                         (ExecScanAccessMtd) SeqNext,
     164                 :             :                                                         (ExecScanRecheckMtd) SeqRecheck,
     165                 :             :                                                         NULL,
     166                 :             :                                                         NULL,
     167                 :     3323436 :                                                         pstate->ps_ProjInfo);
     168                 :     3323436 : }
     169                 :             : 
     170                 :             : /*
     171                 :             :  * Variant of ExecSeqScan() but when qual evaluation and projection are
     172                 :             :  * required.
     173                 :             :  */
     174                 :             : static TupleTableSlot *
     175                 :      828159 : ExecSeqScanWithQualProject(PlanState *pstate)
     176                 :             : {
     177                 :      828159 :         SeqScanState *node = castNode(SeqScanState, pstate);
     178                 :             : 
     179         [ +  - ]:      828159 :         Assert(pstate->state->es_epq_active == NULL);
     180         [ +  - ]:      828159 :         pg_assume(pstate->qual != NULL);
     181         [ +  - ]:      828159 :         pg_assume(pstate->ps_ProjInfo != NULL);
     182                 :             : 
     183                 :     2484477 :         return ExecScanExtended(&node->ss,
     184                 :             :                                                         (ExecScanAccessMtd) SeqNext,
     185                 :             :                                                         (ExecScanRecheckMtd) SeqRecheck,
     186                 :             :                                                         NULL,
     187                 :      828159 :                                                         pstate->qual,
     188                 :      828159 :                                                         pstate->ps_ProjInfo);
     189                 :      828159 : }
     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                 :           0 : ExecSeqScanEPQ(PlanState *pstate)
     198                 :             : {
     199                 :           0 :         SeqScanState *node = castNode(SeqScanState, pstate);
     200                 :             : 
     201                 :           0 :         return ExecScan(&node->ss,
     202                 :             :                                         (ExecScanAccessMtd) SeqNext,
     203                 :             :                                         (ExecScanRecheckMtd) SeqRecheck);
     204                 :           0 : }
     205                 :             : 
     206                 :             : /* ----------------------------------------------------------------
     207                 :             :  *              ExecInitSeqScan
     208                 :             :  * ----------------------------------------------------------------
     209                 :             :  */
     210                 :             : SeqScanState *
     211                 :      328055 : ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
     212                 :             : {
     213                 :      328055 :         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         [ +  - ]:      328055 :         Assert(outerPlan(node) == NULL);
     220         [ +  - ]:      328055 :         Assert(innerPlan(node) == NULL);
     221                 :             : 
     222                 :             :         /*
     223                 :             :          * create state structure
     224                 :             :          */
     225                 :      328055 :         scanstate = makeNode(SeqScanState);
     226                 :      328055 :         scanstate->ss.ps.plan = (Plan *) node;
     227                 :      328055 :         scanstate->ss.ps.state = estate;
     228                 :             : 
     229                 :             :         /*
     230                 :             :          * Miscellaneous initialization
     231                 :             :          *
     232                 :             :          * create expression context for node
     233                 :             :          */
     234                 :      328055 :         ExecAssignExprContext(estate, &scanstate->ss.ps);
     235                 :             : 
     236                 :             :         /*
     237                 :             :          * open the scan relation
     238                 :             :          */
     239                 :      328055 :         scanstate->ss.ss_currentRelation =
     240                 :      656110 :                 ExecOpenScanRelation(estate,
     241                 :      328055 :                                                          node->scan.scanrelid,
     242                 :      328055 :                                                          eflags);
     243                 :             : 
     244                 :             :         /* and create slot with the appropriate rowtype */
     245                 :      656110 :         ExecInitScanTupleSlot(estate, &scanstate->ss,
     246                 :      328055 :                                                   RelationGetDescr(scanstate->ss.ss_currentRelation),
     247                 :      328055 :                                                   table_slot_callbacks(scanstate->ss.ss_currentRelation));
     248                 :             : 
     249                 :             :         /*
     250                 :             :          * Initialize result type and projection.
     251                 :             :          */
     252                 :      328055 :         ExecInitResultTypeTL(&scanstate->ss.ps);
     253                 :      328055 :         ExecAssignScanProjectionInfo(&scanstate->ss);
     254                 :             : 
     255                 :             :         /*
     256                 :             :          * initialize child expressions
     257                 :             :          */
     258                 :      328055 :         scanstate->ss.ps.qual =
     259                 :      328055 :                 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         [ -  + ]:      328055 :         if (scanstate->ss.ps.state->es_epq_active != NULL)
     267                 :           0 :                 scanstate->ss.ps.ExecProcNode = ExecSeqScanEPQ;
     268         [ +  + ]:      328055 :         else if (scanstate->ss.ps.qual == NULL)
     269                 :             :         {
     270         [ +  + ]:       15653 :                 if (scanstate->ss.ps.ps_ProjInfo == NULL)
     271                 :        8757 :                         scanstate->ss.ps.ExecProcNode = ExecSeqScan;
     272                 :             :                 else
     273                 :        6896 :                         scanstate->ss.ps.ExecProcNode = ExecSeqScanWithProject;
     274                 :       15653 :         }
     275                 :             :         else
     276                 :             :         {
     277         [ +  + ]:      312402 :                 if (scanstate->ss.ps.ps_ProjInfo == NULL)
     278                 :        6525 :                         scanstate->ss.ps.ExecProcNode = ExecSeqScanWithQual;
     279                 :             :                 else
     280                 :      305877 :                         scanstate->ss.ps.ExecProcNode = ExecSeqScanWithQualProject;
     281                 :             :         }
     282                 :             : 
     283                 :      656110 :         return scanstate;
     284                 :      328055 : }
     285                 :             : 
     286                 :             : /* ----------------------------------------------------------------
     287                 :             :  *              ExecEndSeqScan
     288                 :             :  *
     289                 :             :  *              frees any storage allocated through C routines.
     290                 :             :  * ----------------------------------------------------------------
     291                 :             :  */
     292                 :             : void
     293                 :      327668 : ExecEndSeqScan(SeqScanState *node)
     294                 :             : {
     295                 :      327668 :         TableScanDesc scanDesc;
     296                 :             : 
     297                 :             :         /*
     298                 :             :          * get information from node
     299                 :             :          */
     300                 :      327668 :         scanDesc = node->ss.ss_currentScanDesc;
     301                 :             : 
     302                 :             :         /*
     303                 :             :          * close heap scan
     304                 :             :          */
     305         [ +  + ]:      327668 :         if (scanDesc != NULL)
     306                 :      322384 :                 table_endscan(scanDesc);
     307                 :      327668 : }
     308                 :             : 
     309                 :             : /* ----------------------------------------------------------------
     310                 :             :  *                                              Join Support
     311                 :             :  * ----------------------------------------------------------------
     312                 :             :  */
     313                 :             : 
     314                 :             : /* ----------------------------------------------------------------
     315                 :             :  *              ExecReScanSeqScan
     316                 :             :  *
     317                 :             :  *              Rescans the relation.
     318                 :             :  * ----------------------------------------------------------------
     319                 :             :  */
     320                 :             : void
     321                 :        4607 : ExecReScanSeqScan(SeqScanState *node)
     322                 :             : {
     323                 :        4607 :         TableScanDesc scan;
     324                 :             : 
     325                 :        4607 :         scan = node->ss.ss_currentScanDesc;
     326                 :             : 
     327         [ +  + ]:        4607 :         if (scan != NULL)
     328                 :        2588 :                 table_rescan(scan,              /* scan desc */
     329                 :             :                                          NULL);         /* new scan keys */
     330                 :             : 
     331                 :        4607 :         ExecScanReScan((ScanState *) node);
     332                 :        4607 : }
     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                 :         151 : ExecSeqScanEstimate(SeqScanState *node,
     348                 :             :                                         ParallelContext *pcxt)
     349                 :             : {
     350                 :         151 :         EState     *estate = node->ss.ps.state;
     351                 :             : 
     352                 :         302 :         node->pscan_len = table_parallelscan_estimate(node->ss.ss_currentRelation,
     353                 :         151 :                                                                                                   estate->es_snapshot);
     354                 :         151 :         shm_toc_estimate_chunk(&pcxt->estimator, node->pscan_len);
     355                 :         151 :         shm_toc_estimate_keys(&pcxt->estimator, 1);
     356                 :         151 : }
     357                 :             : 
     358                 :             : /* ----------------------------------------------------------------
     359                 :             :  *              ExecSeqScanInitializeDSM
     360                 :             :  *
     361                 :             :  *              Set up a parallel heap scan descriptor.
     362                 :             :  * ----------------------------------------------------------------
     363                 :             :  */
     364                 :             : void
     365                 :         151 : ExecSeqScanInitializeDSM(SeqScanState *node,
     366                 :             :                                                  ParallelContext *pcxt)
     367                 :             : {
     368                 :         151 :         EState     *estate = node->ss.ps.state;
     369                 :         151 :         ParallelTableScanDesc pscan;
     370                 :             : 
     371                 :         151 :         pscan = shm_toc_allocate(pcxt->toc, node->pscan_len);
     372                 :         302 :         table_parallelscan_initialize(node->ss.ss_currentRelation,
     373                 :         151 :                                                                   pscan,
     374                 :         151 :                                                                   estate->es_snapshot);
     375                 :         151 :         shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, pscan);
     376                 :         151 :         node->ss.ss_currentScanDesc =
     377                 :         151 :                 table_beginscan_parallel(node->ss.ss_currentRelation, pscan);
     378                 :         151 : }
     379                 :             : 
     380                 :             : /* ----------------------------------------------------------------
     381                 :             :  *              ExecSeqScanReInitializeDSM
     382                 :             :  *
     383                 :             :  *              Reset shared state before beginning a fresh scan.
     384                 :             :  * ----------------------------------------------------------------
     385                 :             :  */
     386                 :             : void
     387                 :          38 : ExecSeqScanReInitializeDSM(SeqScanState *node,
     388                 :             :                                                    ParallelContext *pcxt)
     389                 :             : {
     390                 :          38 :         ParallelTableScanDesc pscan;
     391                 :             : 
     392                 :          38 :         pscan = node->ss.ss_currentScanDesc->rs_parallel;
     393                 :          38 :         table_parallelscan_reinitialize(node->ss.ss_currentRelation, pscan);
     394                 :          38 : }
     395                 :             : 
     396                 :             : /* ----------------------------------------------------------------
     397                 :             :  *              ExecSeqScanInitializeWorker
     398                 :             :  *
     399                 :             :  *              Copy relevant information from TOC into planstate.
     400                 :             :  * ----------------------------------------------------------------
     401                 :             :  */
     402                 :             : void
     403                 :         452 : ExecSeqScanInitializeWorker(SeqScanState *node,
     404                 :             :                                                         ParallelWorkerContext *pwcxt)
     405                 :             : {
     406                 :         452 :         ParallelTableScanDesc pscan;
     407                 :             : 
     408                 :         452 :         pscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
     409                 :         452 :         node->ss.ss_currentScanDesc =
     410                 :         452 :                 table_beginscan_parallel(node->ss.ss_currentRelation, pscan);
     411                 :         452 : }
        

Generated by: LCOV version 2.3.2-1