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

Generated by: LCOV version 1.14