Skip to content
Snippets Groups Projects
Select Git revision
  • benchmark-tools
  • postgres-lambda
  • master default
  • REL9_4_25
  • REL9_5_20
  • REL9_6_16
  • REL_10_11
  • REL_11_6
  • REL_12_1
  • REL_12_0
  • REL_12_RC1
  • REL_12_BETA4
  • REL9_4_24
  • REL9_5_19
  • REL9_6_15
  • REL_10_10
  • REL_11_5
  • REL_12_BETA3
  • REL9_4_23
  • REL9_5_18
  • REL9_6_14
  • REL_10_9
  • REL_11_4
23 results

nodeBitmapIndexscan.c

Blame
  • nodeBitmapIndexscan.c 9.10 KiB
    /*-------------------------------------------------------------------------
     *
     * nodeBitmapIndexscan.c
     *	  Routines to support bitmapped index scans of relations
     *
     * Portions Copyright (c) 1996-2012, 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;
    }