]> granicus.if.org Git - postgresql/blobdiff - src/backend/executor/nodeBitmapIndexscan.c
Make some small planner API cleanups.
[postgresql] / src / backend / executor / nodeBitmapIndexscan.c
index ecb5a63013cc65c6a6912e4a648245198b4f6b00..bd837d3cd8e13c5a146461e6553afc02697faf21 100644 (file)
@@ -3,12 +3,12 @@
  * nodeBitmapIndexscan.c
  *       Routines to support bitmapped index scans of relations
  *
- * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/nodeBitmapIndexscan.c,v 1.8 2005/05/05 03:37:23 tgl Exp $
+ *       src/backend/executor/nodeBitmapIndexscan.c
  *
  *-------------------------------------------------------------------------
  */
  * INTERFACE ROUTINES
  *             MultiExecBitmapIndexScan        scans a relation using index.
  *             ExecInitBitmapIndexScan         creates and initializes state info.
- *             ExecBitmapIndexReScan           prepares to rescan the plan.
+ *             ExecReScanBitmapIndexScan       prepares to rescan the plan.
  *             ExecEndBitmapIndexScan          releases all storage.
  */
 #include "postgres.h"
 
 #include "access/genam.h"
 #include "executor/execdebug.h"
-#include "executor/instrument.h"
 #include "executor/nodeBitmapIndexscan.h"
 #include "executor/nodeIndexscan.h"
 #include "miscadmin.h"
+#include "utils/memutils.h"
 
 
+/* ----------------------------------------------------------------
+ *             ExecBitmapIndexScan
+ *
+ *             stub for pro forma compliance
+ * ----------------------------------------------------------------
+ */
+static TupleTableSlot *
+ExecBitmapIndexScan(PlanState *pstate)
+{
+       elog(ERROR, "BitmapIndexScan node does not support ExecProcNode call convention");
+       return NULL;
+}
+
 /* ----------------------------------------------------------------
  *             MultiExecBitmapIndexScan(node)
  * ----------------------------------------------------------------
 Node *
 MultiExecBitmapIndexScan(BitmapIndexScanState *node)
 {
-#define MAX_TIDS       1024
        TIDBitmap  *tbm;
        IndexScanDesc scandesc;
-       ItemPointerData tids[MAX_TIDS];
-       int32           ntids;
        double          nTuples = 0;
+       bool            doscan;
 
        /* must provide our own instrumentation support */
        if (node->ss.ps.instrument)
@@ -53,104 +64,108 @@ MultiExecBitmapIndexScan(BitmapIndexScanState *node)
        scandesc = node->biss_ScanDesc;
 
        /*
-        * If we have runtime keys and they've not already been set up, do it
-        * now.
+        * If we have runtime keys and they've not already been set up, do it now.
+        * Array keys are also treated as runtime keys; note that if ExecReScan
+        * returns with biss_RuntimeKeysReady still false, then there is an empty
+        * array key so we should do nothing.
         */
-       if (node->biss_RuntimeKeyInfo && !node->biss_RuntimeKeysReady)
-               ExecReScan((PlanState *) node, NULL);
+       if (!node->biss_RuntimeKeysReady &&
+               (node->biss_NumRuntimeKeys != 0 || node->biss_NumArrayKeys != 0))
+       {
+               ExecReScan((PlanState *) node);
+               doscan = node->biss_RuntimeKeysReady;
+       }
+       else
+               doscan = true;
 
        /*
         * Prepare the result bitmap.  Normally we just create a new one to pass
-        * back; however, our parent node is allowed to store a pre-made one
-        * into node->biss_result, in which case we just OR our tuple IDs into
-        * the existing bitmap.  (This saves needing explicit UNION steps.)
+        * back; however, our parent node is allowed to store a pre-made one into
+        * node->biss_result, in which case we just OR our tuple IDs into the
+        * existing bitmap.  (This saves needing explicit UNION steps.)
         */
        if (node->biss_result)
        {
                tbm = node->biss_result;
-               node->biss_result = NULL;               /* reset for next time */
+               node->biss_result = NULL;       /* reset for next time */
        }
        else
        {
                /* XXX should we use less than work_mem for this? */
-               tbm = tbm_create(work_mem * 1024L);
+               tbm = tbm_create(work_mem * 1024L,
+                                                ((BitmapIndexScan *) node->ss.ps.plan)->isshared ?
+                                                node->ss.ps.state->es_query_dsa : NULL);
        }
 
        /*
         * Get TIDs from index and insert into bitmap
         */
-       for (;;)
+       while (doscan)
        {
-               bool    more = index_getmulti(scandesc, tids, MAX_TIDS, &ntids);
-
-               if (ntids > 0)
-               {
-                       tbm_add_tuples(tbm, tids, ntids);
-                       nTuples += ntids;
-               }
-
-               if (!more)
-                       break;
+               nTuples += (double) index_getbitmap(scandesc, tbm);
 
                CHECK_FOR_INTERRUPTS();
+
+               doscan = ExecIndexAdvanceArrayKeys(node->biss_ArrayKeys,
+                                                                                  node->biss_NumArrayKeys);
+               if (doscan)                             /* reset index scan */
+                       index_rescan(node->biss_ScanDesc,
+                                                node->biss_ScanKeys, node->biss_NumScanKeys,
+                                                NULL, 0);
        }
 
        /* must provide our own instrumentation support */
        if (node->ss.ps.instrument)
-               InstrStopNodeMulti(node->ss.ps.instrument, nTuples);
+               InstrStopNode(node->ss.ps.instrument, nTuples);
 
        return (Node *) tbm;
 }
 
 /* ----------------------------------------------------------------
- *             ExecBitmapIndexReScan(node)
+ *             ExecReScanBitmapIndexScan(node)
  *
- *             Recalculates the value of the scan keys whose value depends on
- *             information known at runtime and rescans the indexed relation.
+ *             Recalculates the values of any scan keys whose value depends on
+ *             information known at runtime, then rescans the indexed relation.
  * ----------------------------------------------------------------
  */
 void
-ExecBitmapIndexReScan(BitmapIndexScanState *node, ExprContext *exprCtxt)
+ExecReScanBitmapIndexScan(BitmapIndexScanState *node)
 {
-       ExprContext *econtext;
-       ExprState **runtimeKeyInfo;
-
-       econtext = node->biss_RuntimeContext;           /* context for runtime
-                                                                                                * keys */
-       runtimeKeyInfo = node->biss_RuntimeKeyInfo;
+       ExprContext *econtext = node->biss_RuntimeContext;
 
+       /*
+        * Reset the runtime-key context so we don't leak memory as each outer
+        * tuple is scanned.  Note this assumes that we will recalculate *all*
+        * runtime keys on each call.
+        */
        if (econtext)
-       {
-               /*
-                * If we are being passed an outer tuple, save it for runtime key
-                * calc.
-                */
-               if (exprCtxt != NULL)
-                       econtext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
-
-               /*
-                * Reset the runtime-key context so we don't leak memory as each
-                * outer tuple is scanned.      Note this assumes that we will
-                * recalculate *all* runtime keys on each call.
-                */
                ResetExprContext(econtext);
-       }
 
        /*
-        * If we are doing runtime key calculations (ie, the index keys depend
-        * on data from an outer scan), compute the new key values
+        * If we are doing runtime key calculations (ie, any of the index key
+        * values weren't simple Consts), compute the new key values.
+        *
+        * Array keys are also treated as runtime keys; note that if we return
+        * with biss_RuntimeKeysReady still false, then there is an empty array
+        * key so no index scan is needed.
         */
-       if (runtimeKeyInfo)
-       {
+       if (node->biss_NumRuntimeKeys != 0)
                ExecIndexEvalRuntimeKeys(econtext,
-                                                                runtimeKeyInfo,
-                                                                node->biss_ScanKeys,
-                                                                node->biss_NumScanKeys);
+                                                                node->biss_RuntimeKeys,
+                                                                node->biss_NumRuntimeKeys);
+       if (node->biss_NumArrayKeys != 0)
+               node->biss_RuntimeKeysReady =
+                       ExecIndexEvalArrayKeys(econtext,
+                                                                  node->biss_ArrayKeys,
+                                                                  node->biss_NumArrayKeys);
+       else
                node->biss_RuntimeKeysReady = true;
-       }
 
        /* reset index scan */
-       index_rescan(node->biss_ScanDesc, node->biss_ScanKeys);
+       if (node->biss_RuntimeKeysReady)
+               index_rescan(node->biss_ScanDesc,
+                                        node->biss_ScanKeys, node->biss_NumScanKeys,
+                                        NULL, 0);
 }
 
 /* ----------------------------------------------------------------
@@ -174,14 +189,16 @@ ExecEndBitmapIndexScan(BitmapIndexScanState *node)
         */
 #ifdef NOT_USED
        if (node->biss_RuntimeContext)
-               FreeExprContext(node->biss_RuntimeContext);
+               FreeExprContext(node->biss_RuntimeContext, true);
 #endif
 
        /*
-        * close the index relation
+        * close the index relation (no-op if we didn't open it)
         */
-       index_endscan(indexScanDesc);
-       index_close(indexRelationDesc);
+       if (indexScanDesc)
+               index_endscan(indexScanDesc);
+       if (indexRelationDesc)
+               index_close(indexRelationDesc, NoLock);
 }
 
 /* ----------------------------------------------------------------
@@ -191,13 +208,13 @@ ExecEndBitmapIndexScan(BitmapIndexScanState *node)
  * ----------------------------------------------------------------
  */
 BitmapIndexScanState *
-ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate)
+ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags)
 {
        BitmapIndexScanState *indexstate;
-       ScanKey         scanKeys;
-       int                     numScanKeys;
-       ExprState **runtimeKeyInfo;
-       bool            have_runtime_keys;
+       bool            relistarget;
+
+       /* check for unsupported flags */
+       Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
 
        /*
         * create state structure
@@ -205,10 +222,20 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate)
        indexstate = makeNode(BitmapIndexScanState);
        indexstate->ss.ps.plan = (Plan *) node;
        indexstate->ss.ps.state = estate;
+       indexstate->ss.ps.ExecProcNode = ExecBitmapIndexScan;
 
        /* normally we don't make the result bitmap till runtime */
        indexstate->biss_result = NULL;
 
+       /*
+        * We do not open or lock the base relation here.  We assume that an
+        * ancestor BitmapHeapScan node is holding AccessShareLock (or better) on
+        * the heap relation throughout the execution of the plan tree.
+        */
+
+       indexstate->ss.ss_currentRelation = NULL;
+       indexstate->ss.ss_currentScanDesc = NULL;
+
        /*
         * Miscellaneous initialization
         *
@@ -225,38 +252,54 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate)
         * sub-parts corresponding to runtime keys (see below).
         */
 
-#define BITMAPINDEXSCAN_NSLOTS 0
+       /*
+        * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
+        * here.  This allows an index-advisor plugin to EXPLAIN a plan containing
+        * references to nonexistent indexes.
+        */
+       if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
+               return indexstate;
+
+       /*
+        * Open the index relation.
+        *
+        * If the parent table is one of the target relations of the query, then
+        * InitPlan already opened and write-locked the index, so we can avoid
+        * taking another lock here.  Otherwise we need a normal reader's lock.
+        */
+       relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid);
+       indexstate->biss_RelationDesc = index_open(node->indexid,
+                                                                                          relistarget ? NoLock : AccessShareLock);
 
        /*
         * Initialize index-specific scan state
         */
        indexstate->biss_RuntimeKeysReady = false;
-
-       CXT1_printf("ExecInitBitmapIndexScan: context is %d\n", CurrentMemoryContext);
+       indexstate->biss_RuntimeKeys = NULL;
+       indexstate->biss_NumRuntimeKeys = 0;
 
        /*
         * build the index scan keys from the index qualification
         */
-       have_runtime_keys =
-               ExecIndexBuildScanKeys((PlanState *) indexstate,
-                                                          node->indexqual,
-                                                          node->indexstrategy,
-                                                          node->indexsubtype,
-                                                          &runtimeKeyInfo,
-                                                          &scanKeys,
-                                                          &numScanKeys);
-
-       indexstate->biss_RuntimeKeyInfo = runtimeKeyInfo;
-       indexstate->biss_ScanKeys = scanKeys;
-       indexstate->biss_NumScanKeys = numScanKeys;
+       ExecIndexBuildScanKeys((PlanState *) indexstate,
+                                                  indexstate->biss_RelationDesc,
+                                                  node->indexqual,
+                                                  false,
+                                                  &indexstate->biss_ScanKeys,
+                                                  &indexstate->biss_NumScanKeys,
+                                                  &indexstate->biss_RuntimeKeys,
+                                                  &indexstate->biss_NumRuntimeKeys,
+                                                  &indexstate->biss_ArrayKeys,
+                                                  &indexstate->biss_NumArrayKeys);
 
        /*
-        * If we have runtime keys, we need an ExprContext to evaluate them.
-        * We could just create a "standard" plan node exprcontext, but to
-        * keep the code looking similar to nodeIndexscan.c, it seems better
-        * to stick with the approach of using a separate ExprContext.
+        * If we have runtime keys or array keys, we need an ExprContext to
+        * evaluate them. We could just create a "standard" plan node exprcontext,
+        * but to keep the code looking similar to nodeIndexscan.c, it seems
+        * better to stick with the approach of using a separate ExprContext.
         */
-       if (have_runtime_keys)
+       if (indexstate->biss_NumRuntimeKeys != 0 ||
+               indexstate->biss_NumArrayKeys != 0)
        {
                ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
 
@@ -270,35 +313,25 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate)
        }
 
        /*
-        * We do not open or lock the base relation here.  We assume that an
-        * ancestor BitmapHeapScan node is holding AccessShareLock on the
-        * heap relation throughout the execution of the plan tree.
+        * Initialize scan descriptor.
         */
-
-       indexstate->ss.ss_currentRelation = NULL;
-       indexstate->ss.ss_currentScanDesc = NULL;
+       indexstate->biss_ScanDesc =
+               index_beginscan_bitmap(indexstate->biss_RelationDesc,
+                                                          estate->es_snapshot,
+                                                          indexstate->biss_NumScanKeys);
 
        /*
-        * open the index relation and initialize relation and scan
-        * descriptors.  Note we acquire no locks here; the index machinery
-        * does its own locks and unlocks.
+        * If no run-time keys to calculate, go ahead and pass the scankeys to the
+        * index AM.
         */
-       indexstate->biss_RelationDesc = index_open(node->indexid);
-       indexstate->biss_ScanDesc =
-               index_beginscan_multi(indexstate->biss_RelationDesc,
-                                                         estate->es_snapshot,
-                                                         numScanKeys,
-                                                         scanKeys);
+       if (indexstate->biss_NumRuntimeKeys == 0 &&
+               indexstate->biss_NumArrayKeys == 0)
+               index_rescan(indexstate->biss_ScanDesc,
+                                        indexstate->biss_ScanKeys, indexstate->biss_NumScanKeys,
+                                        NULL, 0);
 
        /*
         * all done.
         */
        return indexstate;
 }
-
-int
-ExecCountSlotsBitmapIndexScan(BitmapIndexScan *node)
-{
-       return ExecCountSlotsNode(outerPlan((Plan *) node)) +
-               ExecCountSlotsNode(innerPlan((Plan *) node)) + BITMAPINDEXSCAN_NSLOTS;
-}