Header And Logo

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

nodeBitmapIndexscan.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * nodeBitmapIndexscan.c
00004  *    Routines to support bitmapped index scans of relations
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/executor/nodeBitmapIndexscan.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 /*
00016  * INTERFACE ROUTINES
00017  *      MultiExecBitmapIndexScan    scans a relation using index.
00018  *      ExecInitBitmapIndexScan     creates and initializes state info.
00019  *      ExecReScanBitmapIndexScan   prepares to rescan the plan.
00020  *      ExecEndBitmapIndexScan      releases all storage.
00021  */
00022 #include "postgres.h"
00023 
00024 #include "executor/execdebug.h"
00025 #include "executor/nodeBitmapIndexscan.h"
00026 #include "executor/nodeIndexscan.h"
00027 #include "miscadmin.h"
00028 #include "utils/memutils.h"
00029 
00030 
00031 /* ----------------------------------------------------------------
00032  *      MultiExecBitmapIndexScan(node)
00033  * ----------------------------------------------------------------
00034  */
00035 Node *
00036 MultiExecBitmapIndexScan(BitmapIndexScanState *node)
00037 {
00038     TIDBitmap  *tbm;
00039     IndexScanDesc scandesc;
00040     double      nTuples = 0;
00041     bool        doscan;
00042 
00043     /* must provide our own instrumentation support */
00044     if (node->ss.ps.instrument)
00045         InstrStartNode(node->ss.ps.instrument);
00046 
00047     /*
00048      * extract necessary information from index scan node
00049      */
00050     scandesc = node->biss_ScanDesc;
00051 
00052     /*
00053      * If we have runtime keys and they've not already been set up, do it now.
00054      * Array keys are also treated as runtime keys; note that if ExecReScan
00055      * returns with biss_RuntimeKeysReady still false, then there is an empty
00056      * array key so we should do nothing.
00057      */
00058     if (!node->biss_RuntimeKeysReady &&
00059         (node->biss_NumRuntimeKeys != 0 || node->biss_NumArrayKeys != 0))
00060     {
00061         ExecReScan((PlanState *) node);
00062         doscan = node->biss_RuntimeKeysReady;
00063     }
00064     else
00065         doscan = true;
00066 
00067     /*
00068      * Prepare the result bitmap.  Normally we just create a new one to pass
00069      * back; however, our parent node is allowed to store a pre-made one into
00070      * node->biss_result, in which case we just OR our tuple IDs into the
00071      * existing bitmap.  (This saves needing explicit UNION steps.)
00072      */
00073     if (node->biss_result)
00074     {
00075         tbm = node->biss_result;
00076         node->biss_result = NULL;       /* reset for next time */
00077     }
00078     else
00079     {
00080         /* XXX should we use less than work_mem for this? */
00081         tbm = tbm_create(work_mem * 1024L);
00082     }
00083 
00084     /*
00085      * Get TIDs from index and insert into bitmap
00086      */
00087     while (doscan)
00088     {
00089         nTuples += (double) index_getbitmap(scandesc, tbm);
00090 
00091         CHECK_FOR_INTERRUPTS();
00092 
00093         doscan = ExecIndexAdvanceArrayKeys(node->biss_ArrayKeys,
00094                                            node->biss_NumArrayKeys);
00095         if (doscan)             /* reset index scan */
00096             index_rescan(node->biss_ScanDesc,
00097                          node->biss_ScanKeys, node->biss_NumScanKeys,
00098                          NULL, 0);
00099     }
00100 
00101     /* must provide our own instrumentation support */
00102     if (node->ss.ps.instrument)
00103         InstrStopNode(node->ss.ps.instrument, nTuples);
00104 
00105     return (Node *) tbm;
00106 }
00107 
00108 /* ----------------------------------------------------------------
00109  *      ExecReScanBitmapIndexScan(node)
00110  *
00111  *      Recalculates the values of any scan keys whose value depends on
00112  *      information known at runtime, then rescans the indexed relation.
00113  * ----------------------------------------------------------------
00114  */
00115 void
00116 ExecReScanBitmapIndexScan(BitmapIndexScanState *node)
00117 {
00118     ExprContext *econtext = node->biss_RuntimeContext;
00119 
00120     /*
00121      * Reset the runtime-key context so we don't leak memory as each outer
00122      * tuple is scanned.  Note this assumes that we will recalculate *all*
00123      * runtime keys on each call.
00124      */
00125     if (econtext)
00126         ResetExprContext(econtext);
00127 
00128     /*
00129      * If we are doing runtime key calculations (ie, any of the index key
00130      * values weren't simple Consts), compute the new key values.
00131      *
00132      * Array keys are also treated as runtime keys; note that if we return
00133      * with biss_RuntimeKeysReady still false, then there is an empty array
00134      * key so no index scan is needed.
00135      */
00136     if (node->biss_NumRuntimeKeys != 0)
00137         ExecIndexEvalRuntimeKeys(econtext,
00138                                  node->biss_RuntimeKeys,
00139                                  node->biss_NumRuntimeKeys);
00140     if (node->biss_NumArrayKeys != 0)
00141         node->biss_RuntimeKeysReady =
00142             ExecIndexEvalArrayKeys(econtext,
00143                                    node->biss_ArrayKeys,
00144                                    node->biss_NumArrayKeys);
00145     else
00146         node->biss_RuntimeKeysReady = true;
00147 
00148     /* reset index scan */
00149     if (node->biss_RuntimeKeysReady)
00150         index_rescan(node->biss_ScanDesc,
00151                      node->biss_ScanKeys, node->biss_NumScanKeys,
00152                      NULL, 0);
00153 }
00154 
00155 /* ----------------------------------------------------------------
00156  *      ExecEndBitmapIndexScan
00157  * ----------------------------------------------------------------
00158  */
00159 void
00160 ExecEndBitmapIndexScan(BitmapIndexScanState *node)
00161 {
00162     Relation    indexRelationDesc;
00163     IndexScanDesc indexScanDesc;
00164 
00165     /*
00166      * extract information from the node
00167      */
00168     indexRelationDesc = node->biss_RelationDesc;
00169     indexScanDesc = node->biss_ScanDesc;
00170 
00171     /*
00172      * Free the exprcontext ... now dead code, see ExecFreeExprContext
00173      */
00174 #ifdef NOT_USED
00175     if (node->biss_RuntimeContext)
00176         FreeExprContext(node->biss_RuntimeContext, true);
00177 #endif
00178 
00179     /*
00180      * close the index relation (no-op if we didn't open it)
00181      */
00182     if (indexScanDesc)
00183         index_endscan(indexScanDesc);
00184     if (indexRelationDesc)
00185         index_close(indexRelationDesc, NoLock);
00186 }
00187 
00188 /* ----------------------------------------------------------------
00189  *      ExecInitBitmapIndexScan
00190  *
00191  *      Initializes the index scan's state information.
00192  * ----------------------------------------------------------------
00193  */
00194 BitmapIndexScanState *
00195 ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags)
00196 {
00197     BitmapIndexScanState *indexstate;
00198     bool        relistarget;
00199 
00200     /* check for unsupported flags */
00201     Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
00202 
00203     /*
00204      * create state structure
00205      */
00206     indexstate = makeNode(BitmapIndexScanState);
00207     indexstate->ss.ps.plan = (Plan *) node;
00208     indexstate->ss.ps.state = estate;
00209 
00210     /* normally we don't make the result bitmap till runtime */
00211     indexstate->biss_result = NULL;
00212 
00213     /*
00214      * Miscellaneous initialization
00215      *
00216      * We do not need a standard exprcontext for this node, though we may
00217      * decide below to create a runtime-key exprcontext
00218      */
00219 
00220     /*
00221      * initialize child expressions
00222      *
00223      * We don't need to initialize targetlist or qual since neither are used.
00224      *
00225      * Note: we don't initialize all of the indexqual expression, only the
00226      * sub-parts corresponding to runtime keys (see below).
00227      */
00228 
00229     /*
00230      * We do not open or lock the base relation here.  We assume that an
00231      * ancestor BitmapHeapScan node is holding AccessShareLock (or better) on
00232      * the heap relation throughout the execution of the plan tree.
00233      */
00234 
00235     indexstate->ss.ss_currentRelation = NULL;
00236     indexstate->ss.ss_currentScanDesc = NULL;
00237 
00238     /*
00239      * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
00240      * here.  This allows an index-advisor plugin to EXPLAIN a plan containing
00241      * references to nonexistent indexes.
00242      */
00243     if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
00244         return indexstate;
00245 
00246     /*
00247      * Open the index relation.
00248      *
00249      * If the parent table is one of the target relations of the query, then
00250      * InitPlan already opened and write-locked the index, so we can avoid
00251      * taking another lock here.  Otherwise we need a normal reader's lock.
00252      */
00253     relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid);
00254     indexstate->biss_RelationDesc = index_open(node->indexid,
00255                                      relistarget ? NoLock : AccessShareLock);
00256 
00257     /*
00258      * Initialize index-specific scan state
00259      */
00260     indexstate->biss_RuntimeKeysReady = false;
00261     indexstate->biss_RuntimeKeys = NULL;
00262     indexstate->biss_NumRuntimeKeys = 0;
00263 
00264     /*
00265      * build the index scan keys from the index qualification
00266      */
00267     ExecIndexBuildScanKeys((PlanState *) indexstate,
00268                            indexstate->biss_RelationDesc,
00269                            node->indexqual,
00270                            false,
00271                            &indexstate->biss_ScanKeys,
00272                            &indexstate->biss_NumScanKeys,
00273                            &indexstate->biss_RuntimeKeys,
00274                            &indexstate->biss_NumRuntimeKeys,
00275                            &indexstate->biss_ArrayKeys,
00276                            &indexstate->biss_NumArrayKeys);
00277 
00278     /*
00279      * If we have runtime keys or array keys, we need an ExprContext to
00280      * evaluate them. We could just create a "standard" plan node exprcontext,
00281      * but to keep the code looking similar to nodeIndexscan.c, it seems
00282      * better to stick with the approach of using a separate ExprContext.
00283      */
00284     if (indexstate->biss_NumRuntimeKeys != 0 ||
00285         indexstate->biss_NumArrayKeys != 0)
00286     {
00287         ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
00288 
00289         ExecAssignExprContext(estate, &indexstate->ss.ps);
00290         indexstate->biss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
00291         indexstate->ss.ps.ps_ExprContext = stdecontext;
00292     }
00293     else
00294     {
00295         indexstate->biss_RuntimeContext = NULL;
00296     }
00297 
00298     /*
00299      * Initialize scan descriptor.
00300      */
00301     indexstate->biss_ScanDesc =
00302         index_beginscan_bitmap(indexstate->biss_RelationDesc,
00303                                estate->es_snapshot,
00304                                indexstate->biss_NumScanKeys);
00305 
00306     /*
00307      * If no run-time keys to calculate, go ahead and pass the scankeys to the
00308      * index AM.
00309      */
00310     if (indexstate->biss_NumRuntimeKeys == 0 &&
00311         indexstate->biss_NumArrayKeys == 0)
00312         index_rescan(indexstate->biss_ScanDesc,
00313                      indexstate->biss_ScanKeys, indexstate->biss_NumScanKeys,
00314                      NULL, 0);
00315 
00316     /*
00317      * all done.
00318      */
00319     return indexstate;
00320 }