text: /*-------------------------------------------------------------------------
   *
   * nodeBitmapIndexscan.c
   *	  Routines to support bitmapped index scans of relations
   *
   * Portions Copyright (c) 1996-2016, 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;
  }
  