LCOV - code coverage report
Current view: top level - src/include/executor - execScan.h (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 96.1 % 51 49
Test Date: 2026-02-28 14:14:49 Functions: 100.0 % 2 2
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  * execScan.h
       3              :  *      Inline-able support functions for Scan nodes
       4              :  *
       5              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       6              :  * Portions Copyright (c) 1994, Regents of the University of California
       7              :  *
       8              :  * IDENTIFICATION
       9              :  *      src/include/executor/execScan.h
      10              :  *-------------------------------------------------------------------------
      11              :  */
      12              : 
      13              : #ifndef EXECSCAN_H
      14              : #define EXECSCAN_H
      15              : 
      16              : #include "miscadmin.h"
      17              : #include "executor/executor.h"
      18              : #include "nodes/execnodes.h"
      19              : 
      20              : /*
      21              :  * ExecScanFetch -- check interrupts & fetch next potential tuple
      22              :  *
      23              :  * This routine substitutes a test tuple if inside an EvalPlanQual recheck.
      24              :  * Otherwise, it simply executes the access method's next-tuple routine.
      25              :  *
      26              :  * The pg_attribute_always_inline attribute allows the compiler to inline
      27              :  * this function into its caller. When EPQState is NULL, the EvalPlanQual
      28              :  * logic is completely eliminated at compile time, avoiding unnecessary
      29              :  * run-time checks and code for cases where EPQ is not required.
      30              :  */
      31              : static pg_attribute_always_inline TupleTableSlot *
      32     62247531 : ExecScanFetch(ScanState *node,
      33              :               EPQState *epqstate,
      34              :               ExecScanAccessMtd accessMtd,
      35              :               ExecScanRecheckMtd recheckMtd)
      36              : {
      37     62247531 :     CHECK_FOR_INTERRUPTS();
      38              : 
      39     62247531 :     if (epqstate != NULL)
      40              :     {
      41              :         /*
      42              :          * We are inside an EvalPlanQual recheck.  Return the test tuple if
      43              :          * one is available, after rechecking any access-method-specific
      44              :          * conditions.
      45              :          */
      46          375 :         Index       scanrelid = ((Scan *) node->ps.plan)->scanrelid;
      47              : 
      48          375 :         if (scanrelid == 0)
      49              :         {
      50              :             /*
      51              :              * This is a ForeignScan or CustomScan which has pushed down a
      52              :              * join to the remote side.  If it is a descendant node in the EPQ
      53              :              * recheck plan tree, run the recheck method function.  Otherwise,
      54              :              * run the access method function below.
      55              :              */
      56            3 :             if (bms_is_member(epqstate->epqParam, node->ps.plan->extParam))
      57              :             {
      58              :                 /*
      59              :                  * The recheck method is responsible not only for rechecking
      60              :                  * the scan/join quals but also for storing the correct tuple
      61              :                  * in the slot.
      62              :                  */
      63              : 
      64            2 :                 TupleTableSlot *slot = node->ss_ScanTupleSlot;
      65              : 
      66            2 :                 if (!(*recheckMtd) (node, slot))
      67            1 :                     ExecClearTuple(slot);   /* would not be returned by scan */
      68            2 :                 return slot;
      69              :             }
      70              :         }
      71          372 :         else if (epqstate->relsubs_done[scanrelid - 1])
      72              :         {
      73              :             /*
      74              :              * Return empty slot, as either there is no EPQ tuple for this rel
      75              :              * or we already returned it.
      76              :              */
      77              : 
      78          163 :             TupleTableSlot *slot = node->ss_ScanTupleSlot;
      79              : 
      80          163 :             return ExecClearTuple(slot);
      81              :         }
      82          209 :         else if (epqstate->relsubs_slot[scanrelid - 1] != NULL)
      83              :         {
      84              :             /*
      85              :              * Return replacement tuple provided by the EPQ caller.
      86              :              */
      87              : 
      88          182 :             TupleTableSlot *slot = epqstate->relsubs_slot[scanrelid - 1];
      89              : 
      90              :             Assert(epqstate->relsubs_rowmark[scanrelid - 1] == NULL);
      91              : 
      92              :             /* Mark to remember that we shouldn't return it again */
      93          182 :             epqstate->relsubs_done[scanrelid - 1] = true;
      94              : 
      95              :             /* Return empty slot if we haven't got a test tuple */
      96          182 :             if (TupIsNull(slot))
      97            3 :                 return NULL;
      98              : 
      99              :             /* Check if it meets the access-method conditions */
     100          179 :             if (!(*recheckMtd) (node, slot))
     101            6 :                 return ExecClearTuple(slot);    /* would not be returned by
     102              :                                                  * scan */
     103          173 :             return slot;
     104              :         }
     105           27 :         else if (epqstate->relsubs_rowmark[scanrelid - 1] != NULL)
     106              :         {
     107              :             /*
     108              :              * Fetch and return replacement tuple using a non-locking rowmark.
     109              :              */
     110              : 
     111           22 :             TupleTableSlot *slot = node->ss_ScanTupleSlot;
     112              : 
     113              :             /* Mark to remember that we shouldn't return more */
     114           22 :             epqstate->relsubs_done[scanrelid - 1] = true;
     115              : 
     116           22 :             if (!EvalPlanQualFetchRowMark(epqstate, scanrelid, slot))
     117            0 :                 return NULL;
     118              : 
     119              :             /* Return empty slot if we haven't got a test tuple */
     120           22 :             if (TupIsNull(slot))
     121            0 :                 return NULL;
     122              : 
     123              :             /* Check if it meets the access-method conditions */
     124           22 :             if (!(*recheckMtd) (node, slot))
     125            1 :                 return ExecClearTuple(slot);    /* would not be returned by
     126              :                                                  * scan */
     127           21 :             return slot;
     128              :         }
     129              :     }
     130              : 
     131              :     /*
     132              :      * Run the node-type-specific access method function to get the next tuple
     133              :      */
     134     62247162 :     return (*accessMtd) (node);
     135              : }
     136              : 
     137              : /* ----------------------------------------------------------------
     138              :  * ExecScanExtended
     139              :  *      Scans the relation using the specified 'access method' and returns the
     140              :  *      next tuple.  Optionally checks the tuple against 'qual' and applies
     141              :  *      'projInfo' if provided.
     142              :  *
     143              :  * The 'recheck method' validates an arbitrary tuple of the relation against
     144              :  * conditions enforced by the access method.
     145              :  *
     146              :  * This function is an alternative to ExecScan, used when callers may omit
     147              :  * 'qual' or 'projInfo'. The pg_attribute_always_inline attribute allows the
     148              :  * compiler to eliminate non-relevant branches at compile time, avoiding
     149              :  * run-time checks in those cases.
     150              :  *
     151              :  * Conditions:
     152              :  *  -- The AMI "cursor" is positioned at the previously returned tuple.
     153              :  *
     154              :  * Initial States:
     155              :  *  -- The relation is opened for scanning, with the "cursor"
     156              :  *  positioned before the first qualifying tuple.
     157              :  * ----------------------------------------------------------------
     158              :  */
     159              : static pg_attribute_always_inline TupleTableSlot *
     160     42834399 : ExecScanExtended(ScanState *node,
     161              :                  ExecScanAccessMtd accessMtd,   /* function returning a tuple */
     162              :                  ExecScanRecheckMtd recheckMtd,
     163              :                  EPQState *epqstate,
     164              :                  ExprState *qual,
     165              :                  ProjectionInfo *projInfo)
     166              : {
     167     42834399 :     ExprContext *econtext = node->ps.ps_ExprContext;
     168              : 
     169              :     /* interrupt checks are in ExecScanFetch */
     170              : 
     171              :     /*
     172              :      * If we have neither a qual to check nor a projection to do, just skip
     173              :      * all the overhead and return the raw scan tuple.
     174              :      */
     175     42834399 :     if (!qual && !projInfo)
     176              :     {
     177     13137152 :         ResetExprContext(econtext);
     178     13137152 :         return ExecScanFetch(node, epqstate, accessMtd, recheckMtd);
     179              :     }
     180              : 
     181              :     /*
     182              :      * Reset per-tuple memory context to free any expression evaluation
     183              :      * storage allocated in the previous tuple cycle.
     184              :      */
     185     29697247 :     ResetExprContext(econtext);
     186              : 
     187              :     /*
     188              :      * get a tuple from the access method.  Loop until we obtain a tuple that
     189              :      * passes the qualification.
     190              :      */
     191              :     for (;;)
     192     19413132 :     {
     193              :         TupleTableSlot *slot;
     194              : 
     195     49110379 :         slot = ExecScanFetch(node, epqstate, accessMtd, recheckMtd);
     196              : 
     197              :         /*
     198              :          * if the slot returned by the accessMtd contains NULL, then it means
     199              :          * there is nothing more to scan so we just return an empty slot,
     200              :          * being careful to use the projection result slot so it has correct
     201              :          * tupleDesc.
     202              :          */
     203     49110107 :         if (TupIsNull(slot))
     204              :         {
     205      1258031 :             if (projInfo)
     206      1171529 :                 return ExecClearTuple(projInfo->pi_state.resultslot);
     207              :             else
     208        86502 :                 return slot;
     209              :         }
     210              : 
     211              :         /*
     212              :          * place the current tuple into the expr context
     213              :          */
     214     47852076 :         econtext->ecxt_scantuple = slot;
     215              : 
     216              :         /*
     217              :          * check that the current tuple satisfies the qual-clause
     218              :          *
     219              :          * check for non-null qual here to avoid a function call to ExecQual()
     220              :          * when the qual is null ... saves only a few cycles, but they add up
     221              :          * ...
     222              :          */
     223     47852076 :         if (qual == NULL || ExecQual(qual, econtext))
     224              :         {
     225              :             /*
     226              :              * Found a satisfactory scan tuple.
     227              :              */
     228     28438927 :             if (projInfo)
     229              :             {
     230              :                 /*
     231              :                  * Form a projection tuple, store it in the result tuple slot
     232              :                  * and return it.
     233              :                  */
     234     24774850 :                 return ExecProject(projInfo);
     235              :             }
     236              :             else
     237              :             {
     238              :                 /*
     239              :                  * Here, we aren't projecting, so just return scan tuple.
     240              :                  */
     241      3664077 :                 return slot;
     242              :             }
     243              :         }
     244              :         else
     245     19413132 :             InstrCountFiltered1(node, 1);
     246              : 
     247              :         /*
     248              :          * Tuple fails qual, so free per-tuple memory and try again.
     249              :          */
     250     19413132 :         ResetExprContext(econtext);
     251              :     }
     252              : }
     253              : 
     254              : #endif                          /* EXECSCAN_H */
        

Generated by: LCOV version 2.0-1