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

Generated by: LCOV version 2.0-1