LCOV - code coverage report
Current view: top level - src/backend/executor - execScan.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 68 98 69.4 %
Date: 2017-09-29 15:12:54 Functions: 6 6 100.0 %
Legend: Lines: hit not hit

          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-2017, 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             : static bool tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc);
      27             : 
      28             : 
      29             : /*
      30             :  * ExecScanFetch -- fetch next potential tuple
      31             :  *
      32             :  * This routine is concerned with substituting a test tuple if we are
      33             :  * inside an EvalPlanQual recheck.  If we aren't, just execute
      34             :  * the access method's next-tuple routine.
      35             :  */
      36             : static inline TupleTableSlot *
      37     4253392 : ExecScanFetch(ScanState *node,
      38             :               ExecScanAccessMtd accessMtd,
      39             :               ExecScanRecheckMtd recheckMtd)
      40             : {
      41     4253392 :     EState     *estate = node->ps.state;
      42             : 
      43     4253392 :     if (estate->es_epqTuple != NULL)
      44             :     {
      45             :         /*
      46             :          * We are inside an EvalPlanQual recheck.  Return the test tuple if
      47             :          * one is available, after rechecking any access-method-specific
      48             :          * conditions.
      49             :          */
      50           0 :         Index       scanrelid = ((Scan *) node->ps.plan)->scanrelid;
      51             : 
      52           0 :         if (scanrelid == 0)
      53             :         {
      54           0 :             TupleTableSlot *slot = node->ss_ScanTupleSlot;
      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           0 :             if (!(*recheckMtd) (node, slot))
      63           0 :                 ExecClearTuple(slot);   /* would not be returned by scan */
      64           0 :             return slot;
      65             :         }
      66           0 :         else if (estate->es_epqTupleSet[scanrelid - 1])
      67             :         {
      68           0 :             TupleTableSlot *slot = node->ss_ScanTupleSlot;
      69             : 
      70             :             /* Return empty slot if we already returned a tuple */
      71           0 :             if (estate->es_epqScanDone[scanrelid - 1])
      72           0 :                 return ExecClearTuple(slot);
      73             :             /* Else mark to remember that we shouldn't return more */
      74           0 :             estate->es_epqScanDone[scanrelid - 1] = true;
      75             : 
      76             :             /* Return empty slot if we haven't got a test tuple */
      77           0 :             if (estate->es_epqTuple[scanrelid - 1] == NULL)
      78           0 :                 return ExecClearTuple(slot);
      79             : 
      80             :             /* Store test tuple in the plan node's scan slot */
      81           0 :             ExecStoreTuple(estate->es_epqTuple[scanrelid - 1],
      82             :                            slot, InvalidBuffer, false);
      83             : 
      84             :             /* Check if it meets the access-method conditions */
      85           0 :             if (!(*recheckMtd) (node, slot))
      86           0 :                 ExecClearTuple(slot);   /* would not be returned by scan */
      87             : 
      88           0 :             return slot;
      89             :         }
      90             :     }
      91             : 
      92             :     /*
      93             :      * Run the node-type-specific access method function to get the next tuple
      94             :      */
      95     4253392 :     return (*accessMtd) (node);
      96             : }
      97             : 
      98             : /* ----------------------------------------------------------------
      99             :  *      ExecScan
     100             :  *
     101             :  *      Scans the relation using the 'access method' indicated and
     102             :  *      returns the next qualifying tuple in the direction specified
     103             :  *      in the global variable ExecDirection.
     104             :  *      The access method returns the next tuple and ExecScan() is
     105             :  *      responsible for checking the tuple returned against the qual-clause.
     106             :  *
     107             :  *      A 'recheck method' must also be provided that can check an
     108             :  *      arbitrary tuple of the relation against any qual conditions
     109             :  *      that are implemented internal to the access method.
     110             :  *
     111             :  *      Conditions:
     112             :  *        -- the "cursor" maintained by the AMI is positioned at the tuple
     113             :  *           returned previously.
     114             :  *
     115             :  *      Initial States:
     116             :  *        -- the relation indicated is opened for scanning so that the
     117             :  *           "cursor" is positioned before the first qualifying tuple.
     118             :  * ----------------------------------------------------------------
     119             :  */
     120             : TupleTableSlot *
     121     3359598 : ExecScan(ScanState *node,
     122             :          ExecScanAccessMtd accessMtd,   /* function returning a tuple */
     123             :          ExecScanRecheckMtd recheckMtd)
     124             : {
     125             :     ExprContext *econtext;
     126             :     ExprState  *qual;
     127             :     ProjectionInfo *projInfo;
     128             : 
     129             :     /*
     130             :      * Fetch data from node
     131             :      */
     132     3359598 :     qual = node->ps.qual;
     133     3359598 :     projInfo = node->ps.ps_ProjInfo;
     134     3359598 :     econtext = node->ps.ps_ExprContext;
     135             : 
     136             :     /*
     137             :      * If we have neither a qual to check nor a projection to do, just skip
     138             :      * all the overhead and return the raw scan tuple.
     139             :      */
     140     3359598 :     if (!qual && !projInfo)
     141             :     {
     142     1321977 :         ResetExprContext(econtext);
     143     1321977 :         return ExecScanFetch(node, accessMtd, recheckMtd);
     144             :     }
     145             : 
     146             :     /*
     147             :      * Reset per-tuple memory context to free any expression evaluation
     148             :      * storage allocated in the previous tuple cycle.
     149             :      */
     150     2037621 :     ResetExprContext(econtext);
     151             : 
     152             :     /*
     153             :      * get a tuple from the access method.  Loop until we obtain a tuple that
     154             :      * passes the qualification.
     155             :      */
     156             :     for (;;)
     157             :     {
     158             :         TupleTableSlot *slot;
     159             : 
     160     2931415 :         CHECK_FOR_INTERRUPTS();
     161             : 
     162     2931415 :         slot = ExecScanFetch(node, accessMtd, recheckMtd);
     163             : 
     164             :         /*
     165             :          * if the slot returned by the accessMtd contains NULL, then it means
     166             :          * there is nothing more to scan so we just return an empty slot,
     167             :          * being careful to use the projection result slot so it has correct
     168             :          * tupleDesc.
     169             :          */
     170     2931352 :         if (TupIsNull(slot))
     171             :         {
     172       36106 :             if (projInfo)
     173       32319 :                 return ExecClearTuple(projInfo->pi_state.resultslot);
     174             :             else
     175        3787 :                 return slot;
     176             :         }
     177             : 
     178             :         /*
     179             :          * place the current tuple into the expr context
     180             :          */
     181     2895246 :         econtext->ecxt_scantuple = slot;
     182             : 
     183             :         /*
     184             :          * check that the current tuple satisfies the qual-clause
     185             :          *
     186             :          * check for non-null qual here to avoid a function call to ExecQual()
     187             :          * when the qual is null ... saves only a few cycles, but they add up
     188             :          * ...
     189             :          */
     190     2895246 :         if (qual == NULL || ExecQual(qual, econtext))
     191             :         {
     192             :             /*
     193             :              * Found a satisfactory scan tuple.
     194             :              */
     195     2001451 :             if (projInfo)
     196             :             {
     197             :                 /*
     198             :                  * Form a projection tuple, store it in the result tuple slot
     199             :                  * and return it.
     200             :                  */
     201     1801550 :                 return ExecProject(projInfo);
     202             :             }
     203             :             else
     204             :             {
     205             :                 /*
     206             :                  * Here, we aren't projecting, so just return scan tuple.
     207             :                  */
     208      199901 :                 return slot;
     209             :             }
     210             :         }
     211             :         else
     212      893794 :             InstrCountFiltered1(node, 1);
     213             : 
     214             :         /*
     215             :          * Tuple fails qual, so free per-tuple memory and try again.
     216             :          */
     217      893794 :         ResetExprContext(econtext);
     218      893794 :     }
     219             : }
     220             : 
     221             : /*
     222             :  * ExecAssignScanProjectionInfo
     223             :  *      Set up projection info for a scan node, if necessary.
     224             :  *
     225             :  * We can avoid a projection step if the requested tlist exactly matches
     226             :  * the underlying tuple type.  If so, we just set ps_ProjInfo to NULL.
     227             :  * Note that this case occurs not only for simple "SELECT * FROM ...", but
     228             :  * also in most cases where there are joins or other processing nodes above
     229             :  * the scan node, because the planner will preferentially generate a matching
     230             :  * tlist.
     231             :  *
     232             :  * ExecAssignScanType must have been called already.
     233             :  */
     234             : void
     235       20896 : ExecAssignScanProjectionInfo(ScanState *node)
     236             : {
     237       20896 :     Scan       *scan = (Scan *) node->ps.plan;
     238             : 
     239       20896 :     ExecAssignScanProjectionInfoWithVarno(node, scan->scanrelid);
     240       20896 : }
     241             : 
     242             : /*
     243             :  * ExecAssignScanProjectionInfoWithVarno
     244             :  *      As above, but caller can specify varno expected in Vars in the tlist.
     245             :  */
     246             : void
     247       21681 : ExecAssignScanProjectionInfoWithVarno(ScanState *node, Index varno)
     248             : {
     249       21681 :     Scan       *scan = (Scan *) node->ps.plan;
     250             : 
     251       21681 :     if (tlist_matches_tupdesc(&node->ps,
     252             :                               scan->plan.targetlist,
     253             :                               varno,
     254       21681 :                               node->ss_ScanTupleSlot->tts_tupleDescriptor))
     255        8412 :         node->ps.ps_ProjInfo = NULL;
     256             :     else
     257       13269 :         ExecAssignProjectionInfo(&node->ps,
     258       13269 :                                  node->ss_ScanTupleSlot->tts_tupleDescriptor);
     259       21681 : }
     260             : 
     261             : static bool
     262       21681 : tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc)
     263             : {
     264       21681 :     int         numattrs = tupdesc->natts;
     265             :     int         attrno;
     266             :     bool        hasoid;
     267       21681 :     ListCell   *tlist_item = list_head(tlist);
     268             : 
     269             :     /* Check the tlist attributes */
     270       70329 :     for (attrno = 1; attrno <= numattrs; attrno++)
     271             :     {
     272       61447 :         Form_pg_attribute att_tup = TupleDescAttr(tupdesc, attrno - 1);
     273             :         Var        *var;
     274             : 
     275       61447 :         if (tlist_item == NULL)
     276        1639 :             return false;       /* tlist too short */
     277       59808 :         var = (Var *) ((TargetEntry *) lfirst(tlist_item))->expr;
     278       59808 :         if (!var || !IsA(var, Var))
     279        2816 :             return false;       /* tlist item not a Var */
     280             :         /* if these Asserts fail, planner messed up */
     281       56992 :         Assert(var->varno == varno);
     282       56992 :         Assert(var->varlevelsup == 0);
     283       56992 :         if (var->varattno != attrno)
     284        8343 :             return false;       /* out of order */
     285       48649 :         if (att_tup->attisdropped)
     286           0 :             return false;       /* table contains dropped columns */
     287             : 
     288             :         /*
     289             :          * Note: usually the Var's type should match the tupdesc exactly, but
     290             :          * in situations involving unions of columns that have different
     291             :          * typmods, the Var may have come from above the union and hence have
     292             :          * typmod -1.  This is a legitimate situation since the Var still
     293             :          * describes the column, just not as exactly as the tupdesc does. We
     294             :          * could change the planner to prevent it, but it'd then insert
     295             :          * projection steps just to convert from specific typmod to typmod -1,
     296             :          * which is pretty silly.
     297             :          */
     298       97297 :         if (var->vartype != att_tup->atttypid ||
     299       48649 :             (var->vartypmod != att_tup->atttypmod &&
     300           1 :              var->vartypmod != -1))
     301           1 :             return false;       /* type mismatch */
     302             : 
     303       48648 :         tlist_item = lnext(tlist_item);
     304             :     }
     305             : 
     306        8882 :     if (tlist_item)
     307         461 :         return false;           /* tlist too long */
     308             : 
     309             :     /*
     310             :      * If the plan context requires a particular hasoid setting, then that has
     311             :      * to match, too.
     312             :      */
     313        8794 :     if (ExecContextForcesOids(ps, &hasoid) &&
     314         373 :         hasoid != tupdesc->tdhasoid)
     315           9 :         return false;
     316             : 
     317        8412 :     return true;
     318             : }
     319             : 
     320             : /*
     321             :  * ExecScanReScan
     322             :  *
     323             :  * This must be called within the ReScan function of any plan node type
     324             :  * that uses ExecScan().
     325             :  */
     326             : void
     327       54488 : ExecScanReScan(ScanState *node)
     328             : {
     329       54488 :     EState     *estate = node->ps.state;
     330             : 
     331             :     /* Rescan EvalPlanQual tuple if we're inside an EvalPlanQual recheck */
     332       54488 :     if (estate->es_epqScanDone != NULL)
     333             :     {
     334           0 :         Index       scanrelid = ((Scan *) node->ps.plan)->scanrelid;
     335             : 
     336           0 :         if (scanrelid > 0)
     337           0 :             estate->es_epqScanDone[scanrelid - 1] = false;
     338             :         else
     339             :         {
     340             :             Bitmapset  *relids;
     341           0 :             int         rtindex = -1;
     342             : 
     343             :             /*
     344             :              * If an FDW or custom scan provider has replaced the join with a
     345             :              * scan, there are multiple RTIs; reset the epqScanDone flag for
     346             :              * all of them.
     347             :              */
     348           0 :             if (IsA(node->ps.plan, ForeignScan))
     349           0 :                 relids = ((ForeignScan *) node->ps.plan)->fs_relids;
     350           0 :             else if (IsA(node->ps.plan, CustomScan))
     351           0 :                 relids = ((CustomScan *) node->ps.plan)->custom_relids;
     352             :             else
     353           0 :                 elog(ERROR, "unexpected scan node: %d",
     354             :                      (int) nodeTag(node->ps.plan));
     355             : 
     356           0 :             while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
     357             :             {
     358           0 :                 Assert(rtindex > 0);
     359           0 :                 estate->es_epqScanDone[rtindex - 1] = false;
     360             :             }
     361             :         }
     362             :     }
     363       54488 : }

Generated by: LCOV version 1.11