Header And Logo

PostgreSQL
| The world's most advanced open source database.

execScan.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * execScan.c
00004  *    This code provides support for generalized relation scans. ExecScan
00005  *    is passed a node and a pointer to a function to "do the right thing"
00006  *    and return a tuple from the relation. ExecScan then does the tedious
00007  *    stuff - checking the qualification and projecting the tuple
00008  *    appropriately.
00009  *
00010  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00011  * Portions Copyright (c) 1994, Regents of the University of California
00012  *
00013  *
00014  * IDENTIFICATION
00015  *    src/backend/executor/execScan.c
00016  *
00017  *-------------------------------------------------------------------------
00018  */
00019 #include "postgres.h"
00020 
00021 #include "executor/executor.h"
00022 #include "miscadmin.h"
00023 #include "utils/memutils.h"
00024 
00025 
00026 static bool tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc);
00027 
00028 
00029 /*
00030  * ExecScanFetch -- fetch next potential tuple
00031  *
00032  * This routine is concerned with substituting a test tuple if we are
00033  * inside an EvalPlanQual recheck.  If we aren't, just execute
00034  * the access method's next-tuple routine.
00035  */
00036 static inline TupleTableSlot *
00037 ExecScanFetch(ScanState *node,
00038               ExecScanAccessMtd accessMtd,
00039               ExecScanRecheckMtd recheckMtd)
00040 {
00041     EState     *estate = node->ps.state;
00042 
00043     if (estate->es_epqTuple != NULL)
00044     {
00045         /*
00046          * We are inside an EvalPlanQual recheck.  Return the test tuple if
00047          * one is available, after rechecking any access-method-specific
00048          * conditions.
00049          */
00050         Index       scanrelid = ((Scan *) node->ps.plan)->scanrelid;
00051 
00052         Assert(scanrelid > 0);
00053         if (estate->es_epqTupleSet[scanrelid - 1])
00054         {
00055             TupleTableSlot *slot = node->ss_ScanTupleSlot;
00056 
00057             /* Return empty slot if we already returned a tuple */
00058             if (estate->es_epqScanDone[scanrelid - 1])
00059                 return ExecClearTuple(slot);
00060             /* Else mark to remember that we shouldn't return more */
00061             estate->es_epqScanDone[scanrelid - 1] = true;
00062 
00063             /* Return empty slot if we haven't got a test tuple */
00064             if (estate->es_epqTuple[scanrelid - 1] == NULL)
00065                 return ExecClearTuple(slot);
00066 
00067             /* Store test tuple in the plan node's scan slot */
00068             ExecStoreTuple(estate->es_epqTuple[scanrelid - 1],
00069                            slot, InvalidBuffer, false);
00070 
00071             /* Check if it meets the access-method conditions */
00072             if (!(*recheckMtd) (node, slot))
00073                 ExecClearTuple(slot);   /* would not be returned by scan */
00074 
00075             return slot;
00076         }
00077     }
00078 
00079     /*
00080      * Run the node-type-specific access method function to get the next tuple
00081      */
00082     return (*accessMtd) (node);
00083 }
00084 
00085 /* ----------------------------------------------------------------
00086  *      ExecScan
00087  *
00088  *      Scans the relation using the 'access method' indicated and
00089  *      returns the next qualifying tuple in the direction specified
00090  *      in the global variable ExecDirection.
00091  *      The access method returns the next tuple and execScan() is
00092  *      responsible for checking the tuple returned against the qual-clause.
00093  *
00094  *      A 'recheck method' must also be provided that can check an
00095  *      arbitrary tuple of the relation against any qual conditions
00096  *      that are implemented internal to the access method.
00097  *
00098  *      Conditions:
00099  *        -- the "cursor" maintained by the AMI is positioned at the tuple
00100  *           returned previously.
00101  *
00102  *      Initial States:
00103  *        -- the relation indicated is opened for scanning so that the
00104  *           "cursor" is positioned before the first qualifying tuple.
00105  * ----------------------------------------------------------------
00106  */
00107 TupleTableSlot *
00108 ExecScan(ScanState *node,
00109          ExecScanAccessMtd accessMtd,   /* function returning a tuple */
00110          ExecScanRecheckMtd recheckMtd)
00111 {
00112     ExprContext *econtext;
00113     List       *qual;
00114     ProjectionInfo *projInfo;
00115     ExprDoneCond isDone;
00116     TupleTableSlot *resultSlot;
00117 
00118     /*
00119      * Fetch data from node
00120      */
00121     qual = node->ps.qual;
00122     projInfo = node->ps.ps_ProjInfo;
00123     econtext = node->ps.ps_ExprContext;
00124 
00125     /*
00126      * If we have neither a qual to check nor a projection to do, just skip
00127      * all the overhead and return the raw scan tuple.
00128      */
00129     if (!qual && !projInfo)
00130     {
00131         ResetExprContext(econtext);
00132         return ExecScanFetch(node, accessMtd, recheckMtd);
00133     }
00134 
00135     /*
00136      * Check to see if we're still projecting out tuples from a previous scan
00137      * tuple (because there is a function-returning-set in the projection
00138      * expressions).  If so, try to project another one.
00139      */
00140     if (node->ps.ps_TupFromTlist)
00141     {
00142         Assert(projInfo);       /* can't get here if not projecting */
00143         resultSlot = ExecProject(projInfo, &isDone);
00144         if (isDone == ExprMultipleResult)
00145             return resultSlot;
00146         /* Done with that source tuple... */
00147         node->ps.ps_TupFromTlist = false;
00148     }
00149 
00150     /*
00151      * Reset per-tuple memory context to free any expression evaluation
00152      * storage allocated in the previous tuple cycle.  Note this can't happen
00153      * until we're done projecting out tuples from a scan tuple.
00154      */
00155     ResetExprContext(econtext);
00156 
00157     /*
00158      * get a tuple from the access method.  Loop until we obtain a tuple that
00159      * passes the qualification.
00160      */
00161     for (;;)
00162     {
00163         TupleTableSlot *slot;
00164 
00165         CHECK_FOR_INTERRUPTS();
00166 
00167         slot = ExecScanFetch(node, accessMtd, recheckMtd);
00168 
00169         /*
00170          * if the slot returned by the accessMtd contains NULL, then it means
00171          * there is nothing more to scan so we just return an empty slot,
00172          * being careful to use the projection result slot so it has correct
00173          * tupleDesc.
00174          */
00175         if (TupIsNull(slot))
00176         {
00177             if (projInfo)
00178                 return ExecClearTuple(projInfo->pi_slot);
00179             else
00180                 return slot;
00181         }
00182 
00183         /*
00184          * place the current tuple into the expr context
00185          */
00186         econtext->ecxt_scantuple = slot;
00187 
00188         /*
00189          * check that the current tuple satisfies the qual-clause
00190          *
00191          * check for non-nil qual here to avoid a function call to ExecQual()
00192          * when the qual is nil ... saves only a few cycles, but they add up
00193          * ...
00194          */
00195         if (!qual || ExecQual(qual, econtext, false))
00196         {
00197             /*
00198              * Found a satisfactory scan tuple.
00199              */
00200             if (projInfo)
00201             {
00202                 /*
00203                  * Form a projection tuple, store it in the result tuple slot
00204                  * and return it --- unless we find we can project no tuples
00205                  * from this scan tuple, in which case continue scan.
00206                  */
00207                 resultSlot = ExecProject(projInfo, &isDone);
00208                 if (isDone != ExprEndResult)
00209                 {
00210                     node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
00211                     return resultSlot;
00212                 }
00213             }
00214             else
00215             {
00216                 /*
00217                  * Here, we aren't projecting, so just return scan tuple.
00218                  */
00219                 return slot;
00220             }
00221         }
00222         else
00223             InstrCountFiltered1(node, 1);
00224 
00225         /*
00226          * Tuple fails qual, so free per-tuple memory and try again.
00227          */
00228         ResetExprContext(econtext);
00229     }
00230 }
00231 
00232 /*
00233  * ExecAssignScanProjectionInfo
00234  *      Set up projection info for a scan node, if necessary.
00235  *
00236  * We can avoid a projection step if the requested tlist exactly matches
00237  * the underlying tuple type.  If so, we just set ps_ProjInfo to NULL.
00238  * Note that this case occurs not only for simple "SELECT * FROM ...", but
00239  * also in most cases where there are joins or other processing nodes above
00240  * the scan node, because the planner will preferentially generate a matching
00241  * tlist.
00242  *
00243  * ExecAssignScanType must have been called already.
00244  */
00245 void
00246 ExecAssignScanProjectionInfo(ScanState *node)
00247 {
00248     Scan       *scan = (Scan *) node->ps.plan;
00249     Index       varno;
00250 
00251     /* Vars in an index-only scan's tlist should be INDEX_VAR */
00252     if (IsA(scan, IndexOnlyScan))
00253         varno = INDEX_VAR;
00254     else
00255         varno = scan->scanrelid;
00256 
00257     if (tlist_matches_tupdesc(&node->ps,
00258                               scan->plan.targetlist,
00259                               varno,
00260                               node->ss_ScanTupleSlot->tts_tupleDescriptor))
00261         node->ps.ps_ProjInfo = NULL;
00262     else
00263         ExecAssignProjectionInfo(&node->ps,
00264                                  node->ss_ScanTupleSlot->tts_tupleDescriptor);
00265 }
00266 
00267 static bool
00268 tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc)
00269 {
00270     int         numattrs = tupdesc->natts;
00271     int         attrno;
00272     bool        hasoid;
00273     ListCell   *tlist_item = list_head(tlist);
00274 
00275     /* Check the tlist attributes */
00276     for (attrno = 1; attrno <= numattrs; attrno++)
00277     {
00278         Form_pg_attribute att_tup = tupdesc->attrs[attrno - 1];
00279         Var        *var;
00280 
00281         if (tlist_item == NULL)
00282             return false;       /* tlist too short */
00283         var = (Var *) ((TargetEntry *) lfirst(tlist_item))->expr;
00284         if (!var || !IsA(var, Var))
00285             return false;       /* tlist item not a Var */
00286         /* if these Asserts fail, planner messed up */
00287         Assert(var->varno == varno);
00288         Assert(var->varlevelsup == 0);
00289         if (var->varattno != attrno)
00290             return false;       /* out of order */
00291         if (att_tup->attisdropped)
00292             return false;       /* table contains dropped columns */
00293 
00294         /*
00295          * Note: usually the Var's type should match the tupdesc exactly, but
00296          * in situations involving unions of columns that have different
00297          * typmods, the Var may have come from above the union and hence have
00298          * typmod -1.  This is a legitimate situation since the Var still
00299          * describes the column, just not as exactly as the tupdesc does. We
00300          * could change the planner to prevent it, but it'd then insert
00301          * projection steps just to convert from specific typmod to typmod -1,
00302          * which is pretty silly.
00303          */
00304         if (var->vartype != att_tup->atttypid ||
00305             (var->vartypmod != att_tup->atttypmod &&
00306              var->vartypmod != -1))
00307             return false;       /* type mismatch */
00308 
00309         tlist_item = lnext(tlist_item);
00310     }
00311 
00312     if (tlist_item)
00313         return false;           /* tlist too long */
00314 
00315     /*
00316      * If the plan context requires a particular hasoid setting, then that has
00317      * to match, too.
00318      */
00319     if (ExecContextForcesOids(ps, &hasoid) &&
00320         hasoid != tupdesc->tdhasoid)
00321         return false;
00322 
00323     return true;
00324 }
00325 
00326 /*
00327  * ExecScanReScan
00328  *
00329  * This must be called within the ReScan function of any plan node type
00330  * that uses ExecScan().
00331  */
00332 void
00333 ExecScanReScan(ScanState *node)
00334 {
00335     EState     *estate = node->ps.state;
00336 
00337     /* Stop projecting any tuples from SRFs in the targetlist */
00338     node->ps.ps_TupFromTlist = false;
00339 
00340     /* Rescan EvalPlanQual tuple if we're inside an EvalPlanQual recheck */
00341     if (estate->es_epqScanDone != NULL)
00342     {
00343         Index       scanrelid = ((Scan *) node->ps.plan)->scanrelid;
00344 
00345         Assert(scanrelid > 0);
00346 
00347         estate->es_epqScanDone[scanrelid - 1] = false;
00348     }
00349 }