LCOV - code coverage report
Current view: top level - src/backend/executor - nodeBitmapIndexscan.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 75 79 94.9 %
Date: 2017-09-29 15:12:54 Functions: 4 5 80.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * nodeBitmapIndexscan.c
       4             :  *    Routines to support bitmapped index scans of relations
       5             :  *
       6             :  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/executor/nodeBitmapIndexscan.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : /*
      16             :  * INTERFACE ROUTINES
      17             :  *      MultiExecBitmapIndexScan    scans a relation using index.
      18             :  *      ExecInitBitmapIndexScan     creates and initializes state info.
      19             :  *      ExecReScanBitmapIndexScan   prepares to rescan the plan.
      20             :  *      ExecEndBitmapIndexScan      releases all storage.
      21             :  */
      22             : #include "postgres.h"
      23             : 
      24             : #include "executor/execdebug.h"
      25             : #include "executor/nodeBitmapIndexscan.h"
      26             : #include "executor/nodeIndexscan.h"
      27             : #include "miscadmin.h"
      28             : #include "utils/memutils.h"
      29             : 
      30             : 
      31             : /* ----------------------------------------------------------------
      32             :  *      ExecBitmapIndexScan
      33             :  *
      34             :  *      stub for pro forma compliance
      35             :  * ----------------------------------------------------------------
      36             :  */
      37             : static TupleTableSlot *
      38           0 : ExecBitmapIndexScan(PlanState *pstate)
      39             : {
      40           0 :     elog(ERROR, "BitmapIndexScan node does not support ExecProcNode call convention");
      41             :     return NULL;
      42             : }
      43             : 
      44             : /* ----------------------------------------------------------------
      45             :  *      MultiExecBitmapIndexScan(node)
      46             :  * ----------------------------------------------------------------
      47             :  */
      48             : Node *
      49        1113 : MultiExecBitmapIndexScan(BitmapIndexScanState *node)
      50             : {
      51             :     TIDBitmap  *tbm;
      52             :     IndexScanDesc scandesc;
      53        1113 :     double      nTuples = 0;
      54             :     bool        doscan;
      55             : 
      56             :     /* must provide our own instrumentation support */
      57        1113 :     if (node->ss.ps.instrument)
      58           0 :         InstrStartNode(node->ss.ps.instrument);
      59             : 
      60             :     /*
      61             :      * extract necessary information from index scan node
      62             :      */
      63        1113 :     scandesc = node->biss_ScanDesc;
      64             : 
      65             :     /*
      66             :      * If we have runtime keys and they've not already been set up, do it now.
      67             :      * Array keys are also treated as runtime keys; note that if ExecReScan
      68             :      * returns with biss_RuntimeKeysReady still false, then there is an empty
      69             :      * array key so we should do nothing.
      70             :      */
      71        2093 :     if (!node->biss_RuntimeKeysReady &&
      72        1907 :         (node->biss_NumRuntimeKeys != 0 || node->biss_NumArrayKeys != 0))
      73             :     {
      74          55 :         ExecReScan((PlanState *) node);
      75          55 :         doscan = node->biss_RuntimeKeysReady;
      76             :     }
      77             :     else
      78        1058 :         doscan = true;
      79             : 
      80             :     /*
      81             :      * Prepare the result bitmap.  Normally we just create a new one to pass
      82             :      * back; however, our parent node is allowed to store a pre-made one into
      83             :      * node->biss_result, in which case we just OR our tuple IDs into the
      84             :      * existing bitmap.  (This saves needing explicit UNION steps.)
      85             :      */
      86        1113 :     if (node->biss_result)
      87             :     {
      88          17 :         tbm = node->biss_result;
      89          17 :         node->biss_result = NULL;    /* reset for next time */
      90             :     }
      91             :     else
      92             :     {
      93             :         /* XXX should we use less than work_mem for this? */
      94        1107 :         tbm = tbm_create(work_mem * 1024L,
      95        1096 :                          ((BitmapIndexScan *) node->ss.ps.plan)->isshared ?
      96          11 :                          node->ss.ps.state->es_query_dsa : NULL);
      97             :     }
      98             : 
      99             :     /*
     100             :      * Get TIDs from index and insert into bitmap
     101             :      */
     102        3341 :     while (doscan)
     103             :     {
     104        1115 :         nTuples += (double) index_getbitmap(scandesc, tbm);
     105             : 
     106        1115 :         CHECK_FOR_INTERRUPTS();
     107             : 
     108        1115 :         doscan = ExecIndexAdvanceArrayKeys(node->biss_ArrayKeys,
     109             :                                            node->biss_NumArrayKeys);
     110        1115 :         if (doscan)             /* reset index scan */
     111           2 :             index_rescan(node->biss_ScanDesc,
     112             :                          node->biss_ScanKeys, node->biss_NumScanKeys,
     113             :                          NULL, 0);
     114             :     }
     115             : 
     116             :     /* must provide our own instrumentation support */
     117        1113 :     if (node->ss.ps.instrument)
     118           0 :         InstrStopNode(node->ss.ps.instrument, nTuples);
     119             : 
     120        1113 :     return (Node *) tbm;
     121             : }
     122             : 
     123             : /* ----------------------------------------------------------------
     124             :  *      ExecReScanBitmapIndexScan(node)
     125             :  *
     126             :  *      Recalculates the values of any scan keys whose value depends on
     127             :  *      information known at runtime, then rescans the indexed relation.
     128             :  * ----------------------------------------------------------------
     129             :  */
     130             : void
     131         188 : ExecReScanBitmapIndexScan(BitmapIndexScanState *node)
     132             : {
     133         188 :     ExprContext *econtext = node->biss_RuntimeContext;
     134             : 
     135             :     /*
     136             :      * Reset the runtime-key context so we don't leak memory as each outer
     137             :      * tuple is scanned.  Note this assumes that we will recalculate *all*
     138             :      * runtime keys on each call.
     139             :      */
     140         188 :     if (econtext)
     141         160 :         ResetExprContext(econtext);
     142             : 
     143             :     /*
     144             :      * If we are doing runtime key calculations (ie, any of the index key
     145             :      * values weren't simple Consts), compute the new key values.
     146             :      *
     147             :      * Array keys are also treated as runtime keys; note that if we return
     148             :      * with biss_RuntimeKeysReady still false, then there is an empty array
     149             :      * key so no index scan is needed.
     150             :      */
     151         188 :     if (node->biss_NumRuntimeKeys != 0)
     152         158 :         ExecIndexEvalRuntimeKeys(econtext,
     153             :                                  node->biss_RuntimeKeys,
     154             :                                  node->biss_NumRuntimeKeys);
     155         188 :     if (node->biss_NumArrayKeys != 0)
     156           2 :         node->biss_RuntimeKeysReady =
     157           2 :             ExecIndexEvalArrayKeys(econtext,
     158             :                                    node->biss_ArrayKeys,
     159             :                                    node->biss_NumArrayKeys);
     160             :     else
     161         186 :         node->biss_RuntimeKeysReady = true;
     162             : 
     163             :     /* reset index scan */
     164         188 :     if (node->biss_RuntimeKeysReady)
     165         188 :         index_rescan(node->biss_ScanDesc,
     166             :                      node->biss_ScanKeys, node->biss_NumScanKeys,
     167             :                      NULL, 0);
     168         188 : }
     169             : 
     170             : /* ----------------------------------------------------------------
     171             :  *      ExecEndBitmapIndexScan
     172             :  * ----------------------------------------------------------------
     173             :  */
     174             : void
     175        1653 : ExecEndBitmapIndexScan(BitmapIndexScanState *node)
     176             : {
     177             :     Relation    indexRelationDesc;
     178             :     IndexScanDesc indexScanDesc;
     179             : 
     180             :     /*
     181             :      * extract information from the node
     182             :      */
     183        1653 :     indexRelationDesc = node->biss_RelationDesc;
     184        1653 :     indexScanDesc = node->biss_ScanDesc;
     185             : 
     186             :     /*
     187             :      * Free the exprcontext ... now dead code, see ExecFreeExprContext
     188             :      */
     189             : #ifdef NOT_USED
     190             :     if (node->biss_RuntimeContext)
     191             :         FreeExprContext(node->biss_RuntimeContext, true);
     192             : #endif
     193             : 
     194             :     /*
     195             :      * close the index relation (no-op if we didn't open it)
     196             :      */
     197        1653 :     if (indexScanDesc)
     198        1326 :         index_endscan(indexScanDesc);
     199        1653 :     if (indexRelationDesc)
     200        1326 :         index_close(indexRelationDesc, NoLock);
     201        1653 : }
     202             : 
     203             : /* ----------------------------------------------------------------
     204             :  *      ExecInitBitmapIndexScan
     205             :  *
     206             :  *      Initializes the index scan's state information.
     207             :  * ----------------------------------------------------------------
     208             :  */
     209             : BitmapIndexScanState *
     210        1657 : ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags)
     211             : {
     212             :     BitmapIndexScanState *indexstate;
     213             :     bool        relistarget;
     214             : 
     215             :     /* check for unsupported flags */
     216        1657 :     Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
     217             : 
     218             :     /*
     219             :      * create state structure
     220             :      */
     221        1657 :     indexstate = makeNode(BitmapIndexScanState);
     222        1657 :     indexstate->ss.ps.plan = (Plan *) node;
     223        1657 :     indexstate->ss.ps.state = estate;
     224        1657 :     indexstate->ss.ps.ExecProcNode = ExecBitmapIndexScan;
     225             : 
     226             :     /* normally we don't make the result bitmap till runtime */
     227        1657 :     indexstate->biss_result = NULL;
     228             : 
     229             :     /*
     230             :      * Miscellaneous initialization
     231             :      *
     232             :      * We do not need a standard exprcontext for this node, though we may
     233             :      * decide below to create a runtime-key exprcontext
     234             :      */
     235             : 
     236             :     /*
     237             :      * initialize child expressions
     238             :      *
     239             :      * We don't need to initialize targetlist or qual since neither are used.
     240             :      *
     241             :      * Note: we don't initialize all of the indexqual expression, only the
     242             :      * sub-parts corresponding to runtime keys (see below).
     243             :      */
     244             : 
     245             :     /*
     246             :      * We do not open or lock the base relation here.  We assume that an
     247             :      * ancestor BitmapHeapScan node is holding AccessShareLock (or better) on
     248             :      * the heap relation throughout the execution of the plan tree.
     249             :      */
     250             : 
     251        1657 :     indexstate->ss.ss_currentRelation = NULL;
     252        1657 :     indexstate->ss.ss_currentScanDesc = NULL;
     253             : 
     254             :     /*
     255             :      * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
     256             :      * here.  This allows an index-advisor plugin to EXPLAIN a plan containing
     257             :      * references to nonexistent indexes.
     258             :      */
     259        1657 :     if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
     260         327 :         return indexstate;
     261             : 
     262             :     /*
     263             :      * Open the index relation.
     264             :      *
     265             :      * If the parent table is one of the target relations of the query, then
     266             :      * InitPlan already opened and write-locked the index, so we can avoid
     267             :      * taking another lock here.  Otherwise we need a normal reader's lock.
     268             :      */
     269        1330 :     relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid);
     270        1330 :     indexstate->biss_RelationDesc = index_open(node->indexid,
     271             :                                                relistarget ? NoLock : AccessShareLock);
     272             : 
     273             :     /*
     274             :      * Initialize index-specific scan state
     275             :      */
     276        1330 :     indexstate->biss_RuntimeKeysReady = false;
     277        1330 :     indexstate->biss_RuntimeKeys = NULL;
     278        1330 :     indexstate->biss_NumRuntimeKeys = 0;
     279             : 
     280             :     /*
     281             :      * build the index scan keys from the index qualification
     282             :      */
     283        1330 :     ExecIndexBuildScanKeys((PlanState *) indexstate,
     284             :                            indexstate->biss_RelationDesc,
     285             :                            node->indexqual,
     286             :                            false,
     287             :                            &indexstate->biss_ScanKeys,
     288             :                            &indexstate->biss_NumScanKeys,
     289             :                            &indexstate->biss_RuntimeKeys,
     290             :                            &indexstate->biss_NumRuntimeKeys,
     291             :                            &indexstate->biss_ArrayKeys,
     292             :                            &indexstate->biss_NumArrayKeys);
     293             : 
     294             :     /*
     295             :      * If we have runtime keys or array keys, we need an ExprContext to
     296             :      * evaluate them. We could just create a "standard" plan node exprcontext,
     297             :      * but to keep the code looking similar to nodeIndexscan.c, it seems
     298             :      * better to stick with the approach of using a separate ExprContext.
     299             :      */
     300        2582 :     if (indexstate->biss_NumRuntimeKeys != 0 ||
     301        1252 :         indexstate->biss_NumArrayKeys != 0)
     302          80 :     {
     303          80 :         ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
     304             : 
     305          80 :         ExecAssignExprContext(estate, &indexstate->ss.ps);
     306          80 :         indexstate->biss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
     307          80 :         indexstate->ss.ps.ps_ExprContext = stdecontext;
     308             :     }
     309             :     else
     310             :     {
     311        1250 :         indexstate->biss_RuntimeContext = NULL;
     312             :     }
     313             : 
     314             :     /*
     315             :      * Initialize scan descriptor.
     316             :      */
     317        1330 :     indexstate->biss_ScanDesc =
     318        1330 :         index_beginscan_bitmap(indexstate->biss_RelationDesc,
     319             :                                estate->es_snapshot,
     320             :                                indexstate->biss_NumScanKeys);
     321             : 
     322             :     /*
     323             :      * If no run-time keys to calculate, go ahead and pass the scankeys to the
     324             :      * index AM.
     325             :      */
     326        2582 :     if (indexstate->biss_NumRuntimeKeys == 0 &&
     327        1252 :         indexstate->biss_NumArrayKeys == 0)
     328        1250 :         index_rescan(indexstate->biss_ScanDesc,
     329             :                      indexstate->biss_ScanKeys, indexstate->biss_NumScanKeys,
     330             :                      NULL, 0);
     331             : 
     332             :     /*
     333             :      * all done.
     334             :      */
     335        1330 :     return indexstate;
     336             : }

Generated by: LCOV version 1.11