mirror of
https://github.com/postgres/postgres.git
synced 2025-04-24 10:47:04 +03:00
321 lines
9.1 KiB
C
321 lines
9.1 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* nodeBitmapIndexscan.c
|
|
* Routines to support bitmapped index scans of relations
|
|
*
|
|
* Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
*
|
|
* IDENTIFICATION
|
|
* src/backend/executor/nodeBitmapIndexscan.c
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
/*
|
|
* INTERFACE ROUTINES
|
|
* MultiExecBitmapIndexScan scans a relation using index.
|
|
* ExecInitBitmapIndexScan creates and initializes state info.
|
|
* ExecReScanBitmapIndexScan prepares to rescan the plan.
|
|
* ExecEndBitmapIndexScan releases all storage.
|
|
*/
|
|
#include "postgres.h"
|
|
|
|
#include "executor/execdebug.h"
|
|
#include "executor/nodeBitmapIndexscan.h"
|
|
#include "executor/nodeIndexscan.h"
|
|
#include "miscadmin.h"
|
|
#include "utils/memutils.h"
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
* MultiExecBitmapIndexScan(node)
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
Node *
|
|
MultiExecBitmapIndexScan(BitmapIndexScanState *node)
|
|
{
|
|
TIDBitmap *tbm;
|
|
IndexScanDesc scandesc;
|
|
double nTuples = 0;
|
|
bool doscan;
|
|
|
|
/* must provide our own instrumentation support */
|
|
if (node->ss.ps.instrument)
|
|
InstrStartNode(node->ss.ps.instrument);
|
|
|
|
/*
|
|
* extract necessary information from index scan node
|
|
*/
|
|
scandesc = node->biss_ScanDesc;
|
|
|
|
/*
|
|
* 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_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.)
|
|
*/
|
|
if (node->biss_result)
|
|
{
|
|
tbm = node->biss_result;
|
|
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);
|
|
}
|
|
|
|
/*
|
|
* Get TIDs from index and insert into bitmap
|
|
*/
|
|
while (doscan)
|
|
{
|
|
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)
|
|
InstrStopNode(node->ss.ps.instrument, nTuples);
|
|
|
|
return (Node *) tbm;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------
|
|
* ExecReScanBitmapIndexScan(node)
|
|
*
|
|
* Recalculates the values of any scan keys whose value depends on
|
|
* information known at runtime, then rescans the indexed relation.
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
void
|
|
ExecReScanBitmapIndexScan(BitmapIndexScanState *node)
|
|
{
|
|
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)
|
|
ResetExprContext(econtext);
|
|
|
|
/*
|
|
* 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 (node->biss_NumRuntimeKeys != 0)
|
|
ExecIndexEvalRuntimeKeys(econtext,
|
|
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 */
|
|
if (node->biss_RuntimeKeysReady)
|
|
index_rescan(node->biss_ScanDesc,
|
|
node->biss_ScanKeys, node->biss_NumScanKeys,
|
|
NULL, 0);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------
|
|
* ExecEndBitmapIndexScan
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
void
|
|
ExecEndBitmapIndexScan(BitmapIndexScanState *node)
|
|
{
|
|
Relation indexRelationDesc;
|
|
IndexScanDesc indexScanDesc;
|
|
|
|
/*
|
|
* extract information from the node
|
|
*/
|
|
indexRelationDesc = node->biss_RelationDesc;
|
|
indexScanDesc = node->biss_ScanDesc;
|
|
|
|
/*
|
|
* Free the exprcontext ... now dead code, see ExecFreeExprContext
|
|
*/
|
|
#ifdef NOT_USED
|
|
if (node->biss_RuntimeContext)
|
|
FreeExprContext(node->biss_RuntimeContext, true);
|
|
#endif
|
|
|
|
/*
|
|
* close the index relation (no-op if we didn't open it)
|
|
*/
|
|
if (indexScanDesc)
|
|
index_endscan(indexScanDesc);
|
|
if (indexRelationDesc)
|
|
index_close(indexRelationDesc, NoLock);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------
|
|
* ExecInitBitmapIndexScan
|
|
*
|
|
* Initializes the index scan's state information.
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
BitmapIndexScanState *
|
|
ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags)
|
|
{
|
|
BitmapIndexScanState *indexstate;
|
|
bool relistarget;
|
|
|
|
/* check for unsupported flags */
|
|
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
|
|
|
|
/*
|
|
* create state structure
|
|
*/
|
|
indexstate = makeNode(BitmapIndexScanState);
|
|
indexstate->ss.ps.plan = (Plan *) node;
|
|
indexstate->ss.ps.state = estate;
|
|
|
|
/* normally we don't make the result bitmap till runtime */
|
|
indexstate->biss_result = NULL;
|
|
|
|
/*
|
|
* Miscellaneous initialization
|
|
*
|
|
* We do not need a standard exprcontext for this node, though we may
|
|
* decide below to create a runtime-key exprcontext
|
|
*/
|
|
|
|
/*
|
|
* initialize child expressions
|
|
*
|
|
* We don't need to initialize targetlist or qual since neither are used.
|
|
*
|
|
* Note: we don't initialize all of the indexqual expression, only the
|
|
* sub-parts corresponding to runtime keys (see below).
|
|
*/
|
|
|
|
/*
|
|
* 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;
|
|
|
|
/*
|
|
* 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;
|
|
indexstate->biss_RuntimeKeys = NULL;
|
|
indexstate->biss_NumRuntimeKeys = 0;
|
|
|
|
/*
|
|
* build the index scan keys from the index qualification
|
|
*/
|
|
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 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 (indexstate->biss_NumRuntimeKeys != 0 ||
|
|
indexstate->biss_NumArrayKeys != 0)
|
|
{
|
|
ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
|
|
|
|
ExecAssignExprContext(estate, &indexstate->ss.ps);
|
|
indexstate->biss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
|
|
indexstate->ss.ps.ps_ExprContext = stdecontext;
|
|
}
|
|
else
|
|
{
|
|
indexstate->biss_RuntimeContext = NULL;
|
|
}
|
|
|
|
/*
|
|
* Initialize scan descriptor.
|
|
*/
|
|
indexstate->biss_ScanDesc =
|
|
index_beginscan_bitmap(indexstate->biss_RelationDesc,
|
|
estate->es_snapshot,
|
|
indexstate->biss_NumScanKeys);
|
|
|
|
/*
|
|
* If no run-time keys to calculate, go ahead and pass the scankeys to the
|
|
* index AM.
|
|
*/
|
|
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;
|
|
}
|