LCOV - code coverage report
Current view: top level - src/backend/executor - nodeBitmapIndexscan.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17beta1 Lines: 80 82 97.6 %
Date: 2024-06-17 23:11:01 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-2024, 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/executor.h"
      26             : #include "executor/nodeBitmapIndexscan.h"
      27             : #include "executor/nodeIndexscan.h"
      28             : #include "miscadmin.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       19560 : MultiExecBitmapIndexScan(BitmapIndexScanState *node)
      50             : {
      51             :     TIDBitmap  *tbm;
      52             :     IndexScanDesc scandesc;
      53       19560 :     double      nTuples = 0;
      54             :     bool        doscan;
      55             : 
      56             :     /* must provide our own instrumentation support */
      57       19560 :     if (node->ss.ps.instrument)
      58         492 :         InstrStartNode(node->ss.ps.instrument);
      59             : 
      60             :     /*
      61             :      * extract necessary information from index scan node
      62             :      */
      63       19560 :     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       19560 :     if (!node->biss_RuntimeKeysReady &&
      72       12932 :         (node->biss_NumRuntimeKeys != 0 || node->biss_NumArrayKeys != 0))
      73             :     {
      74         566 :         ExecReScan((PlanState *) node);
      75         566 :         doscan = node->biss_RuntimeKeysReady;
      76             :     }
      77             :     else
      78       18994 :         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       19560 :     if (node->biss_result)
      87             :     {
      88         502 :         tbm = node->biss_result;
      89         502 :         node->biss_result = NULL;    /* reset for next time */
      90             :     }
      91             :     else
      92             :     {
      93             :         /* XXX should we use less than work_mem for this? */
      94       19058 :         tbm = tbm_create(work_mem * 1024L,
      95       19058 :                          ((BitmapIndexScan *) node->ss.ps.plan)->isshared ?
      96          72 :                          node->ss.ps.state->es_query_dsa : NULL);
      97             :     }
      98             : 
      99             :     /*
     100             :      * Get TIDs from index and insert into bitmap
     101             :      */
     102       39146 :     while (doscan)
     103             :     {
     104       19586 :         nTuples += (double) index_getbitmap(scandesc, tbm);
     105             : 
     106       19586 :         CHECK_FOR_INTERRUPTS();
     107             : 
     108       19586 :         doscan = ExecIndexAdvanceArrayKeys(node->biss_ArrayKeys,
     109             :                                            node->biss_NumArrayKeys);
     110       19586 :         if (doscan)             /* reset index scan */
     111          26 :             index_rescan(node->biss_ScanDesc,
     112          26 :                          node->biss_ScanKeys, node->biss_NumScanKeys,
     113             :                          NULL, 0);
     114             :     }
     115             : 
     116             :     /* must provide our own instrumentation support */
     117       19560 :     if (node->ss.ps.instrument)
     118         492 :         InstrStopNode(node->ss.ps.instrument, nTuples);
     119             : 
     120       19560 :     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        7194 : ExecReScanBitmapIndexScan(BitmapIndexScanState *node)
     132             : {
     133        7194 :     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        7194 :     if (econtext)
     141        6920 :         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        7194 :     if (node->biss_NumRuntimeKeys != 0)
     152        6894 :         ExecIndexEvalRuntimeKeys(econtext,
     153             :                                  node->biss_RuntimeKeys,
     154             :                                  node->biss_NumRuntimeKeys);
     155        7194 :     if (node->biss_NumArrayKeys != 0)
     156          26 :         node->biss_RuntimeKeysReady =
     157          26 :             ExecIndexEvalArrayKeys(econtext,
     158             :                                    node->biss_ArrayKeys,
     159             :                                    node->biss_NumArrayKeys);
     160             :     else
     161        7168 :         node->biss_RuntimeKeysReady = true;
     162             : 
     163             :     /* reset index scan */
     164        7194 :     if (node->biss_RuntimeKeysReady)
     165        7194 :         index_rescan(node->biss_ScanDesc,
     166        7194 :                      node->biss_ScanKeys, node->biss_NumScanKeys,
     167             :                      NULL, 0);
     168        7194 : }
     169             : 
     170             : /* ----------------------------------------------------------------
     171             :  *      ExecEndBitmapIndexScan
     172             :  * ----------------------------------------------------------------
     173             :  */
     174             : void
     175       20596 : ExecEndBitmapIndexScan(BitmapIndexScanState *node)
     176             : {
     177             :     Relation    indexRelationDesc;
     178             :     IndexScanDesc indexScanDesc;
     179             : 
     180             :     /*
     181             :      * extract information from the node
     182             :      */
     183       20596 :     indexRelationDesc = node->biss_RelationDesc;
     184       20596 :     indexScanDesc = node->biss_ScanDesc;
     185             : 
     186             :     /*
     187             :      * close the index relation (no-op if we didn't open it)
     188             :      */
     189       20596 :     if (indexScanDesc)
     190       17140 :         index_endscan(indexScanDesc);
     191       20596 :     if (indexRelationDesc)
     192       17140 :         index_close(indexRelationDesc, NoLock);
     193       20596 : }
     194             : 
     195             : /* ----------------------------------------------------------------
     196             :  *      ExecInitBitmapIndexScan
     197             :  *
     198             :  *      Initializes the index scan's state information.
     199             :  * ----------------------------------------------------------------
     200             :  */
     201             : BitmapIndexScanState *
     202       20662 : ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags)
     203             : {
     204             :     BitmapIndexScanState *indexstate;
     205             :     LOCKMODE    lockmode;
     206             : 
     207             :     /* check for unsupported flags */
     208             :     Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
     209             : 
     210             :     /*
     211             :      * create state structure
     212             :      */
     213       20662 :     indexstate = makeNode(BitmapIndexScanState);
     214       20662 :     indexstate->ss.ps.plan = (Plan *) node;
     215       20662 :     indexstate->ss.ps.state = estate;
     216       20662 :     indexstate->ss.ps.ExecProcNode = ExecBitmapIndexScan;
     217             : 
     218             :     /* normally we don't make the result bitmap till runtime */
     219       20662 :     indexstate->biss_result = NULL;
     220             : 
     221             :     /*
     222             :      * We do not open or lock the base relation here.  We assume that an
     223             :      * ancestor BitmapHeapScan node is holding AccessShareLock (or better) on
     224             :      * the heap relation throughout the execution of the plan tree.
     225             :      */
     226             : 
     227       20662 :     indexstate->ss.ss_currentRelation = NULL;
     228       20662 :     indexstate->ss.ss_currentScanDesc = NULL;
     229             : 
     230             :     /*
     231             :      * Miscellaneous initialization
     232             :      *
     233             :      * We do not need a standard exprcontext for this node, though we may
     234             :      * decide below to create a runtime-key exprcontext
     235             :      */
     236             : 
     237             :     /*
     238             :      * initialize child expressions
     239             :      *
     240             :      * We don't need to initialize targetlist or qual since neither are used.
     241             :      *
     242             :      * Note: we don't initialize all of the indexqual expression, only the
     243             :      * sub-parts corresponding to runtime keys (see below).
     244             :      */
     245             : 
     246             :     /*
     247             :      * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
     248             :      * here.  This allows an index-advisor plugin to EXPLAIN a plan containing
     249             :      * references to nonexistent indexes.
     250             :      */
     251       20662 :     if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
     252        3456 :         return indexstate;
     253             : 
     254             :     /* Open the index relation. */
     255       17206 :     lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode;
     256       17206 :     indexstate->biss_RelationDesc = index_open(node->indexid, lockmode);
     257             : 
     258             :     /*
     259             :      * Initialize index-specific scan state
     260             :      */
     261       17206 :     indexstate->biss_RuntimeKeysReady = false;
     262       17206 :     indexstate->biss_RuntimeKeys = NULL;
     263       17206 :     indexstate->biss_NumRuntimeKeys = 0;
     264             : 
     265             :     /*
     266             :      * build the index scan keys from the index qualification
     267             :      */
     268       17206 :     ExecIndexBuildScanKeys((PlanState *) indexstate,
     269             :                            indexstate->biss_RelationDesc,
     270             :                            node->indexqual,
     271             :                            false,
     272       17206 :                            &indexstate->biss_ScanKeys,
     273             :                            &indexstate->biss_NumScanKeys,
     274             :                            &indexstate->biss_RuntimeKeys,
     275             :                            &indexstate->biss_NumRuntimeKeys,
     276             :                            &indexstate->biss_ArrayKeys,
     277             :                            &indexstate->biss_NumArrayKeys);
     278             : 
     279             :     /*
     280             :      * If we have runtime keys or array keys, we need an ExprContext to
     281             :      * evaluate them. We could just create a "standard" plan node exprcontext,
     282             :      * but to keep the code looking similar to nodeIndexscan.c, it seems
     283             :      * better to stick with the approach of using a separate ExprContext.
     284             :      */
     285       17206 :     if (indexstate->biss_NumRuntimeKeys != 0 ||
     286       13330 :         indexstate->biss_NumArrayKeys != 0)
     287        3902 :     {
     288        3902 :         ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
     289             : 
     290        3902 :         ExecAssignExprContext(estate, &indexstate->ss.ps);
     291        3902 :         indexstate->biss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
     292        3902 :         indexstate->ss.ps.ps_ExprContext = stdecontext;
     293             :     }
     294             :     else
     295             :     {
     296       13304 :         indexstate->biss_RuntimeContext = NULL;
     297             :     }
     298             : 
     299             :     /*
     300             :      * Initialize scan descriptor.
     301             :      */
     302       17206 :     indexstate->biss_ScanDesc =
     303       17206 :         index_beginscan_bitmap(indexstate->biss_RelationDesc,
     304             :                                estate->es_snapshot,
     305             :                                indexstate->biss_NumScanKeys);
     306             : 
     307             :     /*
     308             :      * If no run-time keys to calculate, go ahead and pass the scankeys to the
     309             :      * index AM.
     310             :      */
     311       17206 :     if (indexstate->biss_NumRuntimeKeys == 0 &&
     312       13330 :         indexstate->biss_NumArrayKeys == 0)
     313       13304 :         index_rescan(indexstate->biss_ScanDesc,
     314       13304 :                      indexstate->biss_ScanKeys, indexstate->biss_NumScanKeys,
     315             :                      NULL, 0);
     316             : 
     317             :     /*
     318             :      * all done.
     319             :      */
     320       17206 :     return indexstate;
     321             : }

Generated by: LCOV version 1.14