LCOV - differential code coverage report
Current view: top level - src/backend/executor - execScan.c (source / functions) Coverage Total Hit UNC UBC GNC CBC DUB
Current: Differential Code Coverage HEAD vs 15 Lines: 80.5 % 82 66 1 15 66 1
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 5 5 1 4
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * execScan.c
       4                 :  *    This code provides support for generalized relation scans. ExecScan
       5                 :  *    is passed a node and a pointer to a function to "do the right thing"
       6                 :  *    and return a tuple from the relation. ExecScan then does the tedious
       7                 :  *    stuff - checking the qualification and projecting the tuple
       8                 :  *    appropriately.
       9                 :  *
      10                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
      11                 :  * Portions Copyright (c) 1994, Regents of the University of California
      12                 :  *
      13                 :  *
      14                 :  * IDENTIFICATION
      15                 :  *    src/backend/executor/execScan.c
      16                 :  *
      17                 :  *-------------------------------------------------------------------------
      18                 :  */
      19                 : #include "postgres.h"
      20                 : 
      21                 : #include "executor/executor.h"
      22                 : #include "miscadmin.h"
      23                 : #include "utils/memutils.h"
      24                 : 
      25                 : 
      26                 : 
      27                 : /*
      28                 :  * ExecScanFetch -- check interrupts & fetch next potential tuple
      29                 :  *
      30                 :  * This routine is concerned with substituting a test tuple if we are
      31                 :  * inside an EvalPlanQual recheck.  If we aren't, just execute
      32                 :  * the access method's next-tuple routine.
      33                 :  */
      34                 : static inline TupleTableSlot *
      35 CBC    53701537 : ExecScanFetch(ScanState *node,
      36                 :               ExecScanAccessMtd accessMtd,
      37                 :               ExecScanRecheckMtd recheckMtd)
      38                 : {
      39        53701537 :     EState     *estate = node->ps.state;
      40                 : 
      41        53701537 :     CHECK_FOR_INTERRUPTS();
      42                 : 
      43        53701537 :     if (estate->es_epq_active != NULL)
      44                 :     {
      45             221 :         EPQState   *epqstate = estate->es_epq_active;
      46                 : 
      47                 :         /*
      48                 :          * We are inside an EvalPlanQual recheck.  Return the test tuple if
      49                 :          * one is available, after rechecking any access-method-specific
      50                 :          * conditions.
      51                 :          */
      52             221 :         Index       scanrelid = ((Scan *) node->ps.plan)->scanrelid;
      53                 : 
      54             221 :         if (scanrelid == 0)
      55                 :         {
      56                 :             /*
      57                 :              * This is a ForeignScan or CustomScan which has pushed down a
      58                 :              * join to the remote side.  The recheck method is responsible not
      59                 :              * only for rechecking the scan/join quals but also for storing
      60                 :              * the correct tuple in the slot.
      61                 :              */
      62                 : 
      63 UBC           0 :             TupleTableSlot *slot = node->ss_ScanTupleSlot;
      64                 : 
      65               0 :             if (!(*recheckMtd) (node, slot))
      66               0 :                 ExecClearTuple(slot);   /* would not be returned by scan */
      67               0 :             return slot;
      68                 :         }
      69 CBC         221 :         else if (epqstate->relsubs_done[scanrelid - 1])
      70                 :         {
      71                 :             /*
      72                 :              * Return empty slot, as we already performed an EPQ substitution
      73                 :              * for this relation.
      74                 :              */
      75                 : 
      76              16 :             TupleTableSlot *slot = node->ss_ScanTupleSlot;
      77                 : 
      78                 :             /* Return empty slot, as we already returned a tuple */
      79              16 :             return ExecClearTuple(slot);
      80                 :         }
      81             205 :         else if (epqstate->relsubs_slot[scanrelid - 1] != NULL)
      82                 :         {
      83                 :             /*
      84                 :              * Return replacement tuple provided by the EPQ caller.
      85                 :              */
      86                 : 
      87             129 :             TupleTableSlot *slot = epqstate->relsubs_slot[scanrelid - 1];
      88                 : 
      89             129 :             Assert(epqstate->relsubs_rowmark[scanrelid - 1] == NULL);
      90                 : 
      91                 :             /* Mark to remember that we shouldn't return more */
      92             129 :             epqstate->relsubs_done[scanrelid - 1] = true;
      93                 : 
      94                 :             /* Return empty slot if we haven't got a test tuple */
      95             129 :             if (TupIsNull(slot))
      96              15 :                 return NULL;
      97                 : 
      98                 :             /* Check if it meets the access-method conditions */
      99             114 :             if (!(*recheckMtd) (node, slot))
     100               5 :                 return ExecClearTuple(slot);    /* would not be returned by
     101                 :                                                  * scan */
     102             109 :             return slot;
     103                 :         }
     104              76 :         else if (epqstate->relsubs_rowmark[scanrelid - 1] != NULL)
     105                 :         {
     106                 :             /*
     107                 :              * Fetch and return replacement tuple using a non-locking rowmark.
     108                 :              */
     109                 : 
     110               7 :             TupleTableSlot *slot = node->ss_ScanTupleSlot;
     111                 : 
     112                 :             /* Mark to remember that we shouldn't return more */
     113               7 :             epqstate->relsubs_done[scanrelid - 1] = true;
     114                 : 
     115               7 :             if (!EvalPlanQualFetchRowMark(epqstate, scanrelid, slot))
     116 UBC           0 :                 return NULL;
     117                 : 
     118                 :             /* Return empty slot if we haven't got a test tuple */
     119 CBC           7 :             if (TupIsNull(slot))
     120 UBC           0 :                 return NULL;
     121                 : 
     122                 :             /* Check if it meets the access-method conditions */
     123 CBC           7 :             if (!(*recheckMtd) (node, slot))
     124 UBC           0 :                 return ExecClearTuple(slot);    /* would not be returned by
     125                 :                                                  * scan */
     126 CBC           7 :             return slot;
     127                 :         }
     128                 :     }
     129                 : 
     130                 :     /*
     131                 :      * Run the node-type-specific access method function to get the next tuple
     132                 :      */
     133        53701385 :     return (*accessMtd) (node);
     134                 : }
     135                 : 
     136                 : /* ----------------------------------------------------------------
     137                 :  *      ExecScan
     138                 :  *
     139                 :  *      Scans the relation using the 'access method' indicated and
     140                 :  *      returns the next qualifying tuple.
     141                 :  *      The access method returns the next tuple and ExecScan() is
     142                 :  *      responsible for checking the tuple returned against the qual-clause.
     143                 :  *
     144                 :  *      A 'recheck method' must also be provided that can check an
     145                 :  *      arbitrary tuple of the relation against any qual conditions
     146                 :  *      that are implemented internal to the access method.
     147                 :  *
     148                 :  *      Conditions:
     149                 :  *        -- the "cursor" maintained by the AMI is positioned at the tuple
     150                 :  *           returned previously.
     151                 :  *
     152                 :  *      Initial States:
     153                 :  *        -- the relation indicated is opened for scanning so that the
     154                 :  *           "cursor" is positioned before the first qualifying tuple.
     155                 :  * ----------------------------------------------------------------
     156                 :  */
     157                 : TupleTableSlot *
     158        39744821 : ExecScan(ScanState *node,
     159                 :          ExecScanAccessMtd accessMtd,   /* function returning a tuple */
     160                 :          ExecScanRecheckMtd recheckMtd)
     161                 : {
     162                 :     ExprContext *econtext;
     163                 :     ExprState  *qual;
     164                 :     ProjectionInfo *projInfo;
     165                 : 
     166                 :     /*
     167                 :      * Fetch data from node
     168                 :      */
     169        39744821 :     qual = node->ps.qual;
     170        39744821 :     projInfo = node->ps.ps_ProjInfo;
     171        39744821 :     econtext = node->ps.ps_ExprContext;
     172                 : 
     173                 :     /* interrupt checks are in ExecScanFetch */
     174                 : 
     175                 :     /*
     176                 :      * If we have neither a qual to check nor a projection to do, just skip
     177                 :      * all the overhead and return the raw scan tuple.
     178                 :      */
     179        39744821 :     if (!qual && !projInfo)
     180                 :     {
     181        13113234 :         ResetExprContext(econtext);
     182        13113234 :         return ExecScanFetch(node, accessMtd, recheckMtd);
     183                 :     }
     184                 : 
     185                 :     /*
     186                 :      * Reset per-tuple memory context to free any expression evaluation
     187                 :      * storage allocated in the previous tuple cycle.
     188                 :      */
     189        26631587 :     ResetExprContext(econtext);
     190                 : 
     191                 :     /*
     192                 :      * get a tuple from the access method.  Loop until we obtain a tuple that
     193                 :      * passes the qualification.
     194                 :      */
     195                 :     for (;;)
     196        13956716 :     {
     197                 :         TupleTableSlot *slot;
     198                 : 
     199        40588303 :         slot = ExecScanFetch(node, accessMtd, recheckMtd);
     200                 : 
     201                 :         /*
     202                 :          * if the slot returned by the accessMtd contains NULL, then it means
     203                 :          * there is nothing more to scan so we just return an empty slot,
     204                 :          * being careful to use the projection result slot so it has correct
     205                 :          * tupleDesc.
     206                 :          */
     207        40588062 :         if (TupIsNull(slot))
     208                 :         {
     209          630144 :             if (projInfo)
     210          582414 :                 return ExecClearTuple(projInfo->pi_state.resultslot);
     211                 :             else
     212           47730 :                 return slot;
     213                 :         }
     214                 : 
     215                 :         /*
     216                 :          * place the current tuple into the expr context
     217                 :          */
     218        39957918 :         econtext->ecxt_scantuple = slot;
     219                 : 
     220                 :         /*
     221                 :          * check that the current tuple satisfies the qual-clause
     222                 :          *
     223                 :          * check for non-null qual here to avoid a function call to ExecQual()
     224                 :          * when the qual is null ... saves only a few cycles, but they add up
     225                 :          * ...
     226                 :          */
     227        39957918 :         if (qual == NULL || ExecQual(qual, econtext))
     228                 :         {
     229                 :             /*
     230                 :              * Found a satisfactory scan tuple.
     231                 :              */
     232        26001174 :             if (projInfo)
     233                 :             {
     234                 :                 /*
     235                 :                  * Form a projection tuple, store it in the result tuple slot
     236                 :                  * and return it.
     237                 :                  */
     238        22877743 :                 return ExecProject(projInfo);
     239                 :             }
     240                 :             else
     241                 :             {
     242                 :                 /*
     243                 :                  * Here, we aren't projecting, so just return scan tuple.
     244                 :                  */
     245         3123431 :                 return slot;
     246                 :             }
     247                 :         }
     248                 :         else
     249        13956716 :             InstrCountFiltered1(node, 1);
     250                 : 
     251                 :         /*
     252                 :          * Tuple fails qual, so free per-tuple memory and try again.
     253                 :          */
     254        13956716 :         ResetExprContext(econtext);
     255                 :     }
     256                 : }
     257                 : 
     258                 : /*
     259                 :  * ExecAssignScanProjectionInfo
     260                 :  *      Set up projection info for a scan node, if necessary.
     261                 :  *
     262                 :  * We can avoid a projection step if the requested tlist exactly matches
     263                 :  * the underlying tuple type.  If so, we just set ps_ProjInfo to NULL.
     264                 :  * Note that this case occurs not only for simple "SELECT * FROM ...", but
     265                 :  * also in most cases where there are joins or other processing nodes above
     266                 :  * the scan node, because the planner will preferentially generate a matching
     267                 :  * tlist.
     268                 :  *
     269                 :  * The scan slot's descriptor must have been set already.
     270                 :  */
     271                 : void
     272          202242 : ExecAssignScanProjectionInfo(ScanState *node)
     273                 : {
     274          202242 :     Scan       *scan = (Scan *) node->ps.plan;
     275          202242 :     TupleDesc   tupdesc = node->ss_ScanTupleSlot->tts_tupleDescriptor;
     276                 : 
     277          202242 :     ExecConditionalAssignProjectionInfo(&node->ps, tupdesc, scan->scanrelid);
     278          202242 : }
     279                 : 
     280                 : /*
     281                 :  * ExecAssignScanProjectionInfoWithVarno
     282                 :  *      As above, but caller can specify varno expected in Vars in the tlist.
     283                 :  */
     284                 : void
     285            7478 : ExecAssignScanProjectionInfoWithVarno(ScanState *node, int varno)
     286                 : {
     287            7478 :     TupleDesc   tupdesc = node->ss_ScanTupleSlot->tts_tupleDescriptor;
     288                 : 
     289            7478 :     ExecConditionalAssignProjectionInfo(&node->ps, tupdesc, varno);
     290            7478 : }
     291                 : 
     292                 : /*
     293                 :  * ExecScanReScan
     294                 :  *
     295                 :  * This must be called within the ReScan function of any plan node type
     296                 :  * that uses ExecScan().
     297                 :  */
     298                 : void
     299          672543 : ExecScanReScan(ScanState *node)
     300                 : {
     301          672543 :     EState     *estate = node->ps.state;
     302                 : 
     303                 :     /*
     304                 :      * We must clear the scan tuple so that observers (e.g., execCurrent.c)
     305                 :      * can tell that this plan node is not positioned on a tuple.
     306                 :      */
     307          672543 :     ExecClearTuple(node->ss_ScanTupleSlot);
     308                 : 
     309                 :     /* Rescan EvalPlanQual tuple if we're inside an EvalPlanQual recheck */
     310          672543 :     if (estate->es_epq_active != NULL)
     311                 :     {
     312              69 :         EPQState   *epqstate = estate->es_epq_active;
     313              69 :         Index       scanrelid = ((Scan *) node->ps.plan)->scanrelid;
     314                 : 
     315              69 :         if (scanrelid > 0)
     316              69 :             epqstate->relsubs_done[scanrelid - 1] = false;
     317                 :         else
     318                 :         {
     319                 :             Bitmapset  *relids;
     320 UBC           0 :             int         rtindex = -1;
     321                 : 
     322                 :             /*
     323                 :              * If an FDW or custom scan provider has replaced the join with a
     324                 :              * scan, there are multiple RTIs; reset the epqScanDone flag for
     325                 :              * all of them.
     326                 :              */
     327               0 :             if (IsA(node->ps.plan, ForeignScan))
     328 UNC           0 :                 relids = ((ForeignScan *) node->ps.plan)->fs_base_relids;
     329 UBC           0 :             else if (IsA(node->ps.plan, CustomScan))
     330               0 :                 relids = ((CustomScan *) node->ps.plan)->custom_relids;
     331                 :             else
     332               0 :                 elog(ERROR, "unexpected scan node: %d",
     333                 :                      (int) nodeTag(node->ps.plan));
     334                 : 
     335               0 :             while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
     336                 :             {
     337               0 :                 Assert(rtindex > 0);
     338               0 :                 epqstate->relsubs_done[rtindex - 1] = false;
     339                 :             }
     340                 :         }
     341                 :     }
     342 CBC      672543 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a