aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/Makefile6
-rw-r--r--src/backend/executor/execAmi.c23
-rw-r--r--src/backend/executor/execProcnode.c72
-rw-r--r--src/backend/executor/nodeBitmapAnd.c208
-rw-r--r--src/backend/executor/nodeBitmapHeapscan.c499
-rw-r--r--src/backend/executor/nodeBitmapIndexscan.c519
-rw-r--r--src/backend/executor/nodeBitmapOr.c209
7 files changed, 1532 insertions, 4 deletions
diff --git a/src/backend/executor/Makefile b/src/backend/executor/Makefile
index 7c0bc25352c..e9caf7d8373 100644
--- a/src/backend/executor/Makefile
+++ b/src/backend/executor/Makefile
@@ -4,7 +4,7 @@
# Makefile for executor
#
# IDENTIFICATION
-# $PostgreSQL: pgsql/src/backend/executor/Makefile,v 1.22 2003/11/29 19:51:48 pgsql Exp $
+# $PostgreSQL: pgsql/src/backend/executor/Makefile,v 1.23 2005/04/19 22:35:11 tgl Exp $
#
#-------------------------------------------------------------------------
@@ -14,7 +14,9 @@ include $(top_builddir)/src/Makefile.global
OBJS = execAmi.o execGrouping.o execJunk.o execMain.o \
execProcnode.o execQual.o execScan.o execTuples.o \
- execUtils.o functions.o instrument.o nodeAppend.o nodeAgg.o nodeHash.o \
+ execUtils.o functions.o instrument.o nodeAppend.o nodeAgg.o \
+ nodeBitmapAnd.o nodeBitmapOr.o \
+ nodeBitmapHeapscan.o nodeBitmapIndexscan.o nodeHash.o \
nodeHashjoin.o nodeIndexscan.o nodeMaterial.o nodeMergejoin.o \
nodeNestloop.o nodeFunctionscan.o nodeResult.o nodeSeqscan.o \
nodeSetOp.o nodeSort.o nodeUnique.o nodeLimit.o nodeGroup.o \
diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c
index 008768c3942..ddcd37ae286 100644
--- a/src/backend/executor/execAmi.c
+++ b/src/backend/executor/execAmi.c
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/executor/execAmi.c,v 1.82 2004/12/31 21:59:45 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execAmi.c,v 1.83 2005/04/19 22:35:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,6 +19,10 @@
#include "executor/instrument.h"
#include "executor/nodeAgg.h"
#include "executor/nodeAppend.h"
+#include "executor/nodeBitmapAnd.h"
+#include "executor/nodeBitmapHeapscan.h"
+#include "executor/nodeBitmapIndexscan.h"
+#include "executor/nodeBitmapOr.h"
#include "executor/nodeFunctionscan.h"
#include "executor/nodeGroup.h"
#include "executor/nodeGroup.h"
@@ -107,6 +111,14 @@ ExecReScan(PlanState *node, ExprContext *exprCtxt)
ExecReScanAppend((AppendState *) node, exprCtxt);
break;
+ case T_BitmapAndState:
+ ExecReScanBitmapAnd((BitmapAndState *) node, exprCtxt);
+ break;
+
+ case T_BitmapOrState:
+ ExecReScanBitmapOr((BitmapOrState *) node, exprCtxt);
+ break;
+
case T_SeqScanState:
ExecSeqReScan((SeqScanState *) node, exprCtxt);
break;
@@ -115,6 +127,14 @@ ExecReScan(PlanState *node, ExprContext *exprCtxt)
ExecIndexReScan((IndexScanState *) node, exprCtxt);
break;
+ case T_BitmapIndexScanState:
+ ExecBitmapIndexReScan((BitmapIndexScanState *) node, exprCtxt);
+ break;
+
+ case T_BitmapHeapScanState:
+ ExecBitmapHeapReScan((BitmapHeapScanState *) node, exprCtxt);
+ break;
+
case T_TidScanState:
ExecTidReScan((TidScanState *) node, exprCtxt);
break;
@@ -380,6 +400,7 @@ ExecMayReturnRawTuples(PlanState *node)
/* Table scan nodes */
case T_SeqScanState:
case T_IndexScanState:
+ case T_BitmapHeapScanState:
case T_TidScanState:
case T_SubqueryScanState:
case T_FunctionScanState:
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index 555668e7799..28f67a2562f 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -12,7 +12,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execProcnode.c,v 1.49 2005/04/16 20:07:35 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execProcnode.c,v 1.50 2005/04/19 22:35:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -81,6 +81,10 @@
#include "executor/instrument.h"
#include "executor/nodeAgg.h"
#include "executor/nodeAppend.h"
+#include "executor/nodeBitmapAnd.h"
+#include "executor/nodeBitmapHeapscan.h"
+#include "executor/nodeBitmapIndexscan.h"
+#include "executor/nodeBitmapOr.h"
#include "executor/nodeFunctionscan.h"
#include "executor/nodeGroup.h"
#include "executor/nodeHash.h"
@@ -140,6 +144,14 @@ ExecInitNode(Plan *node, EState *estate)
result = (PlanState *) ExecInitAppend((Append *) node, estate);
break;
+ case T_BitmapAnd:
+ result = (PlanState *) ExecInitBitmapAnd((BitmapAnd *) node, estate);
+ break;
+
+ case T_BitmapOr:
+ result = (PlanState *) ExecInitBitmapOr((BitmapOr *) node, estate);
+ break;
+
/*
* scan nodes
*/
@@ -151,6 +163,14 @@ ExecInitNode(Plan *node, EState *estate)
result = (PlanState *) ExecInitIndexScan((IndexScan *) node, estate);
break;
+ case T_BitmapIndexScan:
+ result = (PlanState *) ExecInitBitmapIndexScan((BitmapIndexScan *) node, estate);
+ break;
+
+ case T_BitmapHeapScan:
+ result = (PlanState *) ExecInitBitmapHeapScan((BitmapHeapScan *) node, estate);
+ break;
+
case T_TidScan:
result = (PlanState *) ExecInitTidScan((TidScan *) node, estate);
break;
@@ -290,6 +310,10 @@ ExecProcNode(PlanState *node)
result = ExecAppend((AppendState *) node);
break;
+ /* BitmapAndState does not yield tuples */
+
+ /* BitmapOrState does not yield tuples */
+
/*
* scan nodes
*/
@@ -301,6 +325,12 @@ ExecProcNode(PlanState *node)
result = ExecIndexScan((IndexScanState *) node);
break;
+ /* BitmapIndexScanState does not yield tuples */
+
+ case T_BitmapHeapScanState:
+ result = ExecBitmapHeapScan((BitmapHeapScanState *) node);
+ break;
+
case T_TidScanState:
result = ExecTidScan((TidScanState *) node);
break;
@@ -409,6 +439,18 @@ MultiExecProcNode(PlanState *node)
result = MultiExecHash((HashState *) node);
break;
+ case T_BitmapIndexScanState:
+ result = MultiExecBitmapIndexScan((BitmapIndexScanState *) node);
+ break;
+
+ case T_BitmapAndState:
+ result = MultiExecBitmapAnd((BitmapAndState *) node);
+ break;
+
+ case T_BitmapOrState:
+ result = MultiExecBitmapOr((BitmapOrState *) node);
+ break;
+
default:
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
result = NULL;
@@ -442,6 +484,12 @@ ExecCountSlotsNode(Plan *node)
case T_Append:
return ExecCountSlotsAppend((Append *) node);
+ case T_BitmapAnd:
+ return ExecCountSlotsBitmapAnd((BitmapAnd *) node);
+
+ case T_BitmapOr:
+ return ExecCountSlotsBitmapOr((BitmapOr *) node);
+
/*
* scan nodes
*/
@@ -451,6 +499,12 @@ ExecCountSlotsNode(Plan *node)
case T_IndexScan:
return ExecCountSlotsIndexScan((IndexScan *) node);
+ case T_BitmapIndexScan:
+ return ExecCountSlotsBitmapIndexScan((BitmapIndexScan *) node);
+
+ case T_BitmapHeapScan:
+ return ExecCountSlotsBitmapHeapScan((BitmapHeapScan *) node);
+
case T_TidScan:
return ExecCountSlotsTidScan((TidScan *) node);
@@ -554,6 +608,14 @@ ExecEndNode(PlanState *node)
ExecEndAppend((AppendState *) node);
break;
+ case T_BitmapAndState:
+ ExecEndBitmapAnd((BitmapAndState *) node);
+ break;
+
+ case T_BitmapOrState:
+ ExecEndBitmapOr((BitmapOrState *) node);
+ break;
+
/*
* scan nodes
*/
@@ -565,6 +627,14 @@ ExecEndNode(PlanState *node)
ExecEndIndexScan((IndexScanState *) node);
break;
+ case T_BitmapIndexScanState:
+ ExecEndBitmapIndexScan((BitmapIndexScanState *) node);
+ break;
+
+ case T_BitmapHeapScanState:
+ ExecEndBitmapHeapScan((BitmapHeapScanState *) node);
+ break;
+
case T_TidScanState:
ExecEndTidScan((TidScanState *) node);
break;
diff --git a/src/backend/executor/nodeBitmapAnd.c b/src/backend/executor/nodeBitmapAnd.c
new file mode 100644
index 00000000000..4af1624012b
--- /dev/null
+++ b/src/backend/executor/nodeBitmapAnd.c
@@ -0,0 +1,208 @@
+/*-------------------------------------------------------------------------
+ *
+ * nodeBitmapAnd.c
+ * routines to handle BitmapAnd nodes.
+ *
+ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $PostgreSQL: pgsql/src/backend/executor/nodeBitmapAnd.c,v 1.1 2005/04/19 22:35:12 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+/* INTERFACE ROUTINES
+ * ExecInitBitmapAnd - initialize the BitmapAnd node
+ * MultiExecBitmapAnd - retrieve the result bitmap from the node
+ * ExecEndBitmapAnd - shut down the BitmapAnd node
+ * ExecReScanBitmapAnd - rescan the BitmapAnd node
+ *
+ * NOTES
+ * BitmapAnd nodes don't make use of their left and right
+ * subtrees, rather they maintain a list of subplans,
+ * much like Append nodes. The logic is much simpler than
+ * Append, however, since we needn't cope with forward/backward
+ * execution.
+ */
+
+#include "postgres.h"
+
+#include "executor/execdebug.h"
+#include "executor/instrument.h"
+#include "executor/nodeBitmapAnd.h"
+
+
+/* ----------------------------------------------------------------
+ * ExecInitBitmapAnd
+ *
+ * Begin all of the subscans of the BitmapAnd node.
+ * ----------------------------------------------------------------
+ */
+BitmapAndState *
+ExecInitBitmapAnd(BitmapAnd *node, EState *estate)
+{
+ BitmapAndState *bitmapandstate = makeNode(BitmapAndState);
+ PlanState **bitmapplanstates;
+ int nplans;
+ int i;
+ Plan *initNode;
+
+ CXT1_printf("ExecInitBitmapAnd: context is %d\n", CurrentMemoryContext);
+
+ /*
+ * Set up empty vector of subplan states
+ */
+ nplans = list_length(node->bitmapplans);
+
+ bitmapplanstates = (PlanState **) palloc0(nplans * sizeof(PlanState *));
+
+ /*
+ * create new BitmapAndState for our BitmapAnd node
+ */
+ bitmapandstate->ps.plan = (Plan *) node;
+ bitmapandstate->ps.state = estate;
+ bitmapandstate->bitmapplans = bitmapplanstates;
+ bitmapandstate->nplans = nplans;
+
+ /*
+ * Miscellaneous initialization
+ *
+ * BitmapAnd plans don't have expression contexts because they never call
+ * ExecQual or ExecProject. They don't need any tuple slots either.
+ */
+
+#define BITMAPAND_NSLOTS 0
+
+ /*
+ * call ExecInitNode on each of the plans to be executed and save the
+ * results into the array "bitmapplanstates".
+ */
+ for (i = 0; i < nplans; i++)
+ {
+ initNode = (Plan *) list_nth(node->bitmapplans, i);
+ bitmapplanstates[i] = ExecInitNode(initNode, estate);
+ }
+
+ return bitmapandstate;
+}
+
+int
+ExecCountSlotsBitmapAnd(BitmapAnd *node)
+{
+ ListCell *plan;
+ int nSlots = 0;
+
+ foreach(plan, node->bitmapplans)
+ nSlots += ExecCountSlotsNode((Plan *) lfirst(plan));
+ return nSlots + BITMAPAND_NSLOTS;
+}
+
+/* ----------------------------------------------------------------
+ * MultiExecBitmapAnd
+ * ----------------------------------------------------------------
+ */
+Node *
+MultiExecBitmapAnd(BitmapAndState *node)
+{
+ PlanState **bitmapplans;
+ int nplans;
+ int i;
+ TIDBitmap *result = NULL;
+
+ /* must provide our own instrumentation support */
+ if (node->ps.instrument)
+ InstrStartNode(node->ps.instrument);
+
+ /*
+ * get information from the node
+ */
+ bitmapplans = node->bitmapplans;
+ nplans = node->nplans;
+
+ /*
+ * Scan all the subplans and AND their result bitmaps
+ */
+ for (i = 0; i < nplans; i++)
+ {
+ PlanState *subnode = bitmapplans[i];
+ TIDBitmap *subresult;
+
+ subresult = (TIDBitmap *) MultiExecProcNode(subnode);
+
+ if (!subresult || !IsA(subresult, TIDBitmap))
+ elog(ERROR, "unrecognized result from subplan");
+
+ if (result == NULL)
+ result = subresult; /* first subplan */
+ else
+ {
+ tbm_intersect(result, subresult);
+ tbm_free(subresult);
+ }
+ }
+
+ if (result == NULL)
+ elog(ERROR, "BitmapAnd doesn't support zero inputs");
+
+ /* must provide our own instrumentation support */
+ if (node->ps.instrument)
+ InstrStopNodeMulti(node->ps.instrument, 0 /* XXX */);
+
+ return (Node *) result;
+}
+
+/* ----------------------------------------------------------------
+ * ExecEndBitmapAnd
+ *
+ * Shuts down the subscans of the BitmapAnd node.
+ *
+ * Returns nothing of interest.
+ * ----------------------------------------------------------------
+ */
+void
+ExecEndBitmapAnd(BitmapAndState *node)
+{
+ PlanState **bitmapplans;
+ int nplans;
+ int i;
+
+ /*
+ * get information from the node
+ */
+ bitmapplans = node->bitmapplans;
+ nplans = node->nplans;
+
+ /*
+ * shut down each of the subscans (that we've initialized)
+ */
+ for (i = 0; i < nplans; i++)
+ {
+ if (bitmapplans[i])
+ ExecEndNode(bitmapplans[i]);
+ }
+}
+
+void
+ExecReScanBitmapAnd(BitmapAndState *node, ExprContext *exprCtxt)
+{
+ int i;
+
+ for (i = 0; i < node->nplans; i++)
+ {
+ PlanState *subnode = node->bitmapplans[i];
+
+ /*
+ * ExecReScan doesn't know about my subplans, so I have to do
+ * changed-parameter signaling myself.
+ */
+ if (node->ps.chgParam != NULL)
+ UpdateChangedParamSet(subnode, node->ps.chgParam);
+
+ /*
+ * Always rescan the inputs immediately, to ensure we can pass down
+ * any outer tuple that might be used in index quals.
+ */
+ ExecReScan(subnode, exprCtxt);
+ }
+}
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
new file mode 100644
index 00000000000..141e29dd293
--- /dev/null
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -0,0 +1,499 @@
+/*-------------------------------------------------------------------------
+ *
+ * nodeBitmapHeapscan.c
+ * Routines to support bitmapped scans of relations
+ *
+ * NOTE: it is critical that this plan type only be used with MVCC-compliant
+ * snapshots (ie, regular snapshots, not SnapshotNow or one of the other
+ * special snapshots). The reason is that since index and heap scans are
+ * decoupled, there can be no assurance that the index tuple prompting a
+ * visit to a particular heap TID still exists when the visit is made.
+ * Therefore the tuple might not exist anymore either (which is OK because
+ * heap_fetch will cope) --- but worse, the tuple slot could have been
+ * re-used for a newer tuple. With an MVCC snapshot the newer tuple is
+ * certain to fail the time qual and so it will not be mistakenly returned.
+ * With SnapshotNow we might return a tuple that doesn't meet the required
+ * index qual conditions.
+ *
+ *
+ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $PostgreSQL: pgsql/src/backend/executor/nodeBitmapHeapscan.c,v 1.1 2005/04/19 22:35:12 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+/*
+ * INTERFACE ROUTINES
+ * ExecBitmapHeapScan scans a relation using bitmap info
+ * ExecBitmapHeapNext workhorse for above
+ * ExecInitBitmapHeapScan creates and initializes state info.
+ * ExecBitmapHeapReScan prepares to rescan the plan.
+ * ExecEndBitmapHeapScan releases all storage.
+ */
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "executor/execdebug.h"
+#include "executor/nodeBitmapHeapscan.h"
+#include "parser/parsetree.h"
+
+
+static TupleTableSlot *BitmapHeapNext(BitmapHeapScanState *node);
+
+
+/* ----------------------------------------------------------------
+ * BitmapHeapNext
+ *
+ * Retrieve next tuple from the BitmapHeapScan node's currentRelation
+ * ----------------------------------------------------------------
+ */
+static TupleTableSlot *
+BitmapHeapNext(BitmapHeapScanState *node)
+{
+ EState *estate;
+ ExprContext *econtext;
+ HeapScanDesc scandesc;
+ Index scanrelid;
+ TIDBitmap *tbm;
+ TBMIterateResult *tbmres;
+ OffsetNumber targoffset;
+ TupleTableSlot *slot;
+
+ /*
+ * extract necessary information from index scan node
+ */
+ estate = node->ss.ps.state;
+ econtext = node->ss.ps.ps_ExprContext;
+ slot = node->ss.ss_ScanTupleSlot;
+ scandesc = node->ss.ss_currentScanDesc;
+ scanrelid = ((BitmapHeapScan *) node->ss.ps.plan)->scan.scanrelid;
+ tbm = node->tbm;
+ tbmres = node->tbmres;
+
+ /*
+ * Clear any reference to the previously returned tuple. The idea
+ * here is to not have the tuple slot be the last holder of a pin on
+ * that tuple's buffer; if it is, we'll need a separate visit to the
+ * bufmgr to release the buffer. By clearing here, we get to have the
+ * release done by ReleaseAndReadBuffer, below.
+ */
+ ExecClearTuple(slot);
+
+ /*
+ * Check if we are evaluating PlanQual for tuple of this relation.
+ * Additional checking is not good, but no other way for now. We could
+ * introduce new nodes for this case and handle IndexScan --> NewNode
+ * switching in Init/ReScan plan...
+ */
+ if (estate->es_evTuple != NULL &&
+ estate->es_evTuple[scanrelid - 1] != NULL)
+ {
+ if (estate->es_evTupleNull[scanrelid - 1])
+ return slot; /* return empty slot */
+
+ ExecStoreTuple(estate->es_evTuple[scanrelid - 1],
+ slot, InvalidBuffer, false);
+
+ /* Does the tuple meet the original qual conditions? */
+ econtext->ecxt_scantuple = slot;
+
+ ResetExprContext(econtext);
+
+ if (!ExecQual(node->bitmapqualorig, econtext, false))
+ ExecClearTuple(slot); /* would not be returned by scan */
+
+ /* Flag for the next call that no more tuples */
+ estate->es_evTupleNull[scanrelid - 1] = true;
+
+ return slot;
+ }
+
+ /*
+ * If we haven't yet performed the underlying index scan, do it,
+ * and prepare the bitmap to be iterated over.
+ */
+ if (tbm == NULL)
+ {
+ tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node));
+
+ if (!tbm || !IsA(tbm, TIDBitmap))
+ elog(ERROR, "unrecognized result from subplan");
+
+ node->tbm = tbm;
+ node->tbmres = tbmres = NULL;
+
+ tbm_begin_iterate(tbm);
+ }
+
+ for (;;)
+ {
+ /*
+ * Get next page of results if needed
+ */
+ if (tbmres == NULL)
+ {
+ node->tbmres = tbmres = tbm_iterate(tbm);
+ if (tbmres == NULL)
+ {
+ /* no more entries in the bitmap */
+ break;
+ }
+
+ /*
+ * Ignore any claimed entries past what we think is the end of
+ * the relation. (This is probably not necessary given that we
+ * got AccessShareLock before performing any of the indexscans,
+ * but let's be safe.)
+ */
+ if (tbmres->blockno >= scandesc->rs_nblocks)
+ {
+ node->tbmres = tbmres = NULL;
+ continue;
+ }
+
+ /*
+ * Acquire pin on the current heap page. We'll hold the pin
+ * until done looking at the page. We trade in any pin we
+ * held before.
+ */
+ scandesc->rs_cbuf = ReleaseAndReadBuffer(scandesc->rs_cbuf,
+ scandesc->rs_rd,
+ tbmres->blockno);
+
+ /*
+ * Determine how many entries we need to look at on this page.
+ * If the bitmap is lossy then we need to look at each physical
+ * item pointer; otherwise we just look through the offsets
+ * listed in tbmres.
+ */
+ if (tbmres->ntuples >= 0)
+ {
+ /* non-lossy case */
+ node->minslot = 0;
+ node->maxslot = tbmres->ntuples - 1;
+ }
+ else
+ {
+ /* lossy case */
+ Page dp;
+
+ LockBuffer(scandesc->rs_cbuf, BUFFER_LOCK_SHARE);
+ dp = (Page) BufferGetPage(scandesc->rs_cbuf);
+
+ node->minslot = FirstOffsetNumber;
+ node->maxslot = PageGetMaxOffsetNumber(dp);
+
+ LockBuffer(scandesc->rs_cbuf, BUFFER_LOCK_UNLOCK);
+ }
+
+ /*
+ * Set curslot to first slot to examine
+ */
+ node->curslot = node->minslot;
+ }
+ else
+ {
+ /*
+ * Continuing in previously obtained page; advance curslot
+ */
+ node->curslot++;
+ }
+
+ /*
+ * Out of range? If so, nothing more to look at on this page
+ */
+ if (node->curslot < node->minslot || node->curslot > node->maxslot)
+ {
+ node->tbmres = tbmres = NULL;
+ continue;
+ }
+
+ /*
+ * Okay to try to fetch the tuple
+ */
+ if (tbmres->ntuples >= 0)
+ {
+ /* non-lossy case */
+ targoffset = tbmres->offsets[node->curslot];
+ }
+ else
+ {
+ /* lossy case */
+ targoffset = (OffsetNumber) node->curslot;
+ }
+
+ ItemPointerSet(&scandesc->rs_ctup.t_self, tbmres->blockno, targoffset);
+
+ /*
+ * Fetch the heap tuple and see if it matches the snapshot.
+ * We use heap_release_fetch to avoid useless bufmgr traffic.
+ */
+ if (heap_release_fetch(scandesc->rs_rd,
+ scandesc->rs_snapshot,
+ &scandesc->rs_ctup,
+ &scandesc->rs_cbuf,
+ true,
+ &scandesc->rs_pgstat_info))
+ {
+ /*
+ * Set up the result slot to point to this tuple.
+ * Note that the slot acquires a pin on the buffer.
+ */
+ ExecStoreTuple(&scandesc->rs_ctup,
+ slot,
+ scandesc->rs_cbuf,
+ false);
+
+ /*
+ * If we are using lossy info, we have to recheck the qual
+ * conditions at every tuple.
+ */
+ if (tbmres->ntuples < 0)
+ {
+ econtext->ecxt_scantuple = slot;
+ ResetExprContext(econtext);
+
+ if (!ExecQual(node->bitmapqualorig, econtext, false))
+ {
+ /* Fails recheck, so drop it and loop back for another */
+ ExecClearTuple(slot);
+ continue;
+ }
+ }
+
+ /* OK to return this tuple */
+ return slot;
+ }
+
+ /*
+ * Failed the snap, so loop back and try again.
+ */
+ }
+
+ /*
+ * if we get here it means we are at the end of the scan..
+ */
+ return ExecClearTuple(slot);
+}
+
+/* ----------------------------------------------------------------
+ * ExecBitmapHeapScan(node)
+ * ----------------------------------------------------------------
+ */
+TupleTableSlot *
+ExecBitmapHeapScan(BitmapHeapScanState *node)
+{
+ /*
+ * use BitmapHeapNext as access method
+ */
+ return ExecScan(&node->ss, (ExecScanAccessMtd) BitmapHeapNext);
+}
+
+/* ----------------------------------------------------------------
+ * ExecBitmapHeapReScan(node)
+ * ----------------------------------------------------------------
+ */
+void
+ExecBitmapHeapReScan(BitmapHeapScanState *node, ExprContext *exprCtxt)
+{
+ EState *estate;
+ Index scanrelid;
+
+ estate = node->ss.ps.state;
+ scanrelid = ((BitmapHeapScan *) node->ss.ps.plan)->scan.scanrelid;
+
+ /*
+ * If we are being passed an outer tuple, link it into the "regular"
+ * per-tuple econtext for possible qual eval.
+ */
+ if (exprCtxt != NULL)
+ {
+ ExprContext *stdecontext;
+
+ stdecontext = node->ss.ps.ps_ExprContext;
+ stdecontext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
+ }
+
+ /* If this is re-scanning of PlanQual ... */
+ if (estate->es_evTuple != NULL &&
+ estate->es_evTuple[scanrelid - 1] != NULL)
+ {
+ estate->es_evTupleNull[scanrelid - 1] = false;
+ }
+
+ /* rescan to release any page pin */
+ heap_rescan(node->ss.ss_currentScanDesc, NULL);
+
+ if (node->tbm)
+ tbm_free(node->tbm);
+ node->tbm = NULL;
+ node->tbmres = NULL;
+
+ /*
+ * Always rescan the input immediately, to ensure we can pass down
+ * any outer tuple that might be used in index quals.
+ */
+ ExecReScan(outerPlanState(node), exprCtxt);
+}
+
+/* ----------------------------------------------------------------
+ * ExecEndBitmapHeapScan
+ * ----------------------------------------------------------------
+ */
+void
+ExecEndBitmapHeapScan(BitmapHeapScanState *node)
+{
+ Relation relation;
+ HeapScanDesc scanDesc;
+
+ /*
+ * extract information from the node
+ */
+ relation = node->ss.ss_currentRelation;
+ scanDesc = node->ss.ss_currentScanDesc;
+
+ /*
+ * Free the exprcontext
+ */
+ ExecFreeExprContext(&node->ss.ps);
+
+ /*
+ * clear out tuple table slots
+ */
+ ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
+ ExecClearTuple(node->ss.ss_ScanTupleSlot);
+
+ /*
+ * close down subplans
+ */
+ ExecEndNode(outerPlanState(node));
+
+ /*
+ * release bitmap if any
+ */
+ if (node->tbm)
+ tbm_free(node->tbm);
+
+ /*
+ * close heap scan
+ */
+ heap_endscan(scanDesc);
+
+ /*
+ * close the heap relation.
+ *
+ * Currently, we do not release the AccessShareLock acquired by
+ * ExecInitBitmapHeapScan. This lock should be held till end of
+ * transaction. (There is a faction that considers this too much
+ * locking, however.)
+ */
+ heap_close(relation, NoLock);
+}
+
+/* ----------------------------------------------------------------
+ * ExecInitBitmapHeapScan
+ *
+ * Initializes the scan's state information.
+ * ----------------------------------------------------------------
+ */
+BitmapHeapScanState *
+ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate)
+{
+ BitmapHeapScanState *scanstate;
+ RangeTblEntry *rtentry;
+ Index relid;
+ Oid reloid;
+ Relation currentRelation;
+
+ /*
+ * create state structure
+ */
+ scanstate = makeNode(BitmapHeapScanState);
+ scanstate->ss.ps.plan = (Plan *) node;
+ scanstate->ss.ps.state = estate;
+
+ scanstate->tbm = NULL;
+ scanstate->tbmres = NULL;
+
+ /*
+ * Miscellaneous initialization
+ *
+ * create expression context for node
+ */
+ ExecAssignExprContext(estate, &scanstate->ss.ps);
+
+ /*
+ * initialize child expressions
+ */
+ scanstate->ss.ps.targetlist = (List *)
+ ExecInitExpr((Expr *) node->scan.plan.targetlist,
+ (PlanState *) scanstate);
+ scanstate->ss.ps.qual = (List *)
+ ExecInitExpr((Expr *) node->scan.plan.qual,
+ (PlanState *) scanstate);
+ scanstate->bitmapqualorig = (List *)
+ ExecInitExpr((Expr *) node->bitmapqualorig,
+ (PlanState *) scanstate);
+
+ /*
+ * initialize child nodes
+ */
+ outerPlanState(scanstate) = ExecInitNode(outerPlan(node), estate);
+
+#define BITMAPHEAPSCAN_NSLOTS 2
+
+ /*
+ * tuple table initialization
+ */
+ ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
+ ExecInitScanTupleSlot(estate, &scanstate->ss);
+
+ CXT1_printf("ExecInitBitmapHeapScan: context is %d\n", CurrentMemoryContext);
+
+ /*
+ * open the base relation and acquire AccessShareLock on it.
+ */
+ relid = node->scan.scanrelid;
+ rtentry = rt_fetch(relid, estate->es_range_table);
+ reloid = rtentry->relid;
+
+ currentRelation = heap_open(reloid, AccessShareLock);
+
+ scanstate->ss.ss_currentRelation = currentRelation;
+
+ /*
+ * Even though we aren't going to do a conventional seqscan, it is
+ * useful to create a HeapScanDesc --- this checks the relation size
+ * and sets up statistical infrastructure for us.
+ */
+ scanstate->ss.ss_currentScanDesc = heap_beginscan(currentRelation,
+ estate->es_snapshot,
+ 0,
+ NULL);
+
+ /*
+ * get the scan type from the relation descriptor.
+ */
+ ExecAssignScanType(&scanstate->ss, RelationGetDescr(currentRelation), false);
+
+ /*
+ * Initialize result tuple type and projection info.
+ */
+ ExecAssignResultTypeFromTL(&scanstate->ss.ps);
+ ExecAssignScanProjectionInfo(&scanstate->ss);
+
+ /*
+ * all done.
+ */
+ return scanstate;
+}
+
+int
+ExecCountSlotsBitmapHeapScan(BitmapHeapScan *node)
+{
+ return ExecCountSlotsNode(outerPlan((Plan *) node)) +
+ ExecCountSlotsNode(innerPlan((Plan *) node)) + BITMAPHEAPSCAN_NSLOTS;
+}
diff --git a/src/backend/executor/nodeBitmapIndexscan.c b/src/backend/executor/nodeBitmapIndexscan.c
new file mode 100644
index 00000000000..3ed03eb7cb8
--- /dev/null
+++ b/src/backend/executor/nodeBitmapIndexscan.c
@@ -0,0 +1,519 @@
+/*-------------------------------------------------------------------------
+ *
+ * nodeBitmapIndexscan.c
+ * Routines to support bitmapped index scans of relations
+ *
+ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $PostgreSQL: pgsql/src/backend/executor/nodeBitmapIndexscan.c,v 1.1 2005/04/19 22:35:12 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+/*
+ * INTERFACE ROUTINES
+ * MultiExecBitmapIndexScan scans a relation using index.
+ * ExecInitBitmapIndexScan creates and initializes state info.
+ * ExecBitmapIndexReScan prepares to rescan the plan.
+ * ExecEndBitmapIndexScan releases all storage.
+ */
+#include "postgres.h"
+
+#include "access/genam.h"
+#include "access/heapam.h"
+#include "executor/execdebug.h"
+#include "executor/instrument.h"
+#include "executor/nodeBitmapIndexscan.h"
+#include "miscadmin.h"
+#include "nodes/nodeFuncs.h"
+#include "optimizer/clauses.h"
+#include "parser/parsetree.h"
+
+
+/* ----------------------------------------------------------------
+ * MultiExecBitmapIndexScan(node)
+ * ----------------------------------------------------------------
+ */
+Node *
+MultiExecBitmapIndexScan(BitmapIndexScanState *node)
+{
+#define MAX_TIDS 1024
+ TIDBitmap *tbm;
+ IndexScanDesc scandesc;
+ ItemPointerData tids[MAX_TIDS];
+ int32 ntids;
+ double nTuples = 0;
+
+ /* must provide our own instrumentation support */
+ if (node->ss.ps.instrument)
+ InstrStartNode(node->ss.ps.instrument);
+
+ /*
+ * If we have runtime keys and they've not already been set up, do it
+ * now.
+ */
+ if (node->biss_RuntimeKeyInfo && !node->biss_RuntimeKeysReady)
+ ExecReScan((PlanState *) node, NULL);
+
+ /*
+ * extract necessary information from index scan node
+ */
+ scandesc = node->biss_ScanDesc;
+
+ /*
+ * Prepare result bitmap
+ */
+ tbm = tbm_create(work_mem * 1024L);
+
+ /*
+ * Get TIDs from index and insert into bitmap
+ */
+ for (;;)
+ {
+ bool more = index_getmulti(scandesc, tids, MAX_TIDS, &ntids);
+
+ if (ntids > 0)
+ {
+ tbm_add_tuples(tbm, tids, ntids);
+ nTuples += ntids;
+ }
+
+ if (!more)
+ break;
+
+ CHECK_FOR_INTERRUPTS();
+ }
+
+ /* must provide our own instrumentation support */
+ if (node->ss.ps.instrument)
+ InstrStopNodeMulti(node->ss.ps.instrument, nTuples);
+
+ return (Node *) tbm;
+}
+
+/* ----------------------------------------------------------------
+ * ExecBitmapIndexReScan(node)
+ *
+ * Recalculates the value of the scan keys whose value depends on
+ * information known at runtime and rescans the indexed relation.
+ * Updating the scan key was formerly done separately in
+ * ExecUpdateIndexScanKeys. Integrating it into ReScan makes
+ * rescans of indices and relations/general streams more uniform.
+ *
+ * ----------------------------------------------------------------
+ */
+void
+ExecBitmapIndexReScan(BitmapIndexScanState *node, ExprContext *exprCtxt)
+{
+ ExprContext *econtext;
+ ExprState **runtimeKeyInfo;
+ Index scanrelid;
+
+ econtext = node->biss_RuntimeContext; /* context for runtime
+ * keys */
+ runtimeKeyInfo = node->biss_RuntimeKeyInfo;
+ scanrelid = ((BitmapIndexScan *) node->ss.ps.plan)->scan.scanrelid;
+
+ if (econtext)
+ {
+ /*
+ * If we are being passed an outer tuple, save it for runtime key
+ * calc. We also need to link it into the "regular" per-tuple
+ * econtext.
+ */
+ if (exprCtxt != NULL)
+ {
+ ExprContext *stdecontext;
+
+ econtext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
+ stdecontext = node->ss.ps.ps_ExprContext;
+ stdecontext->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 (runtimeKeyInfo)
+ {
+ int n_keys;
+ ScanKey scan_keys;
+ ExprState **run_keys;
+ int j;
+
+ n_keys = node->biss_NumScanKeys;
+ scan_keys = node->biss_ScanKeys;
+ run_keys = runtimeKeyInfo;
+
+ for (j = 0; j < n_keys; j++)
+ {
+ /*
+ * If we have a run-time key, then extract the run-time
+ * expression and evaluate it with respect to the current
+ * outer tuple. We then stick the result into the scan
+ * key.
+ *
+ * Note: the result of the eval could be a pass-by-ref value
+ * that's stored in the outer scan's tuple, not in
+ * econtext->ecxt_per_tuple_memory. We assume that the
+ * outer tuple will stay put throughout our scan. If this
+ * is wrong, we could copy the result into our context
+ * explicitly, but I think that's not necessary...
+ */
+ if (run_keys[j] != NULL)
+ {
+ Datum scanvalue;
+ bool isNull;
+
+ scanvalue = ExecEvalExprSwitchContext(run_keys[j],
+ econtext,
+ &isNull,
+ NULL);
+ scan_keys[j].sk_argument = scanvalue;
+ if (isNull)
+ scan_keys[j].sk_flags |= SK_ISNULL;
+ else
+ scan_keys[j].sk_flags &= ~SK_ISNULL;
+ }
+ }
+
+ node->biss_RuntimeKeysReady = true;
+ }
+
+ index_rescan(node->biss_ScanDesc, node->biss_ScanKeys);
+}
+
+/* ----------------------------------------------------------------
+ * ExecEndBitmapIndexScan
+ * ----------------------------------------------------------------
+ */
+void
+ExecEndBitmapIndexScan(BitmapIndexScanState *node)
+{
+ Relation relation;
+
+ /*
+ * extract information from the node
+ */
+ relation = node->ss.ss_currentRelation;
+
+ /*
+ * Free the exprcontext(s)
+ */
+ ExecFreeExprContext(&node->ss.ps);
+ if (node->biss_RuntimeContext)
+ FreeExprContext(node->biss_RuntimeContext);
+
+ /*
+ * close the index relation
+ */
+ if (node->biss_ScanDesc != NULL)
+ index_endscan(node->biss_ScanDesc);
+
+ if (node->biss_RelationDesc != NULL)
+ index_close(node->biss_RelationDesc);
+
+ /*
+ * close the heap relation.
+ *
+ * Currently, we do not release the AccessShareLock acquired by
+ * ExecInitBitmapIndexScan. This lock should be held till end of
+ * transaction. (There is a faction that considers this too much
+ * locking, however.)
+ */
+ heap_close(relation, NoLock);
+}
+
+/* ----------------------------------------------------------------
+ * ExecInitBitmapIndexScan
+ *
+ * Initializes the index scan's state information, creates
+ * scan keys, and opens the base and index relations.
+ *
+ * Note: index scans have 2 sets of state information because
+ * we have to keep track of the base relation and the
+ * index relations.
+ *
+ * old comments
+ * Creates the run-time state information for the node and
+ * sets the relation id to contain relevant descriptors.
+ *
+ * Parameters:
+ * node: BitmapIndexNode node produced by the planner.
+ * estate: the execution state initialized in InitPlan.
+ * ----------------------------------------------------------------
+ */
+BitmapIndexScanState *
+ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate)
+{
+ BitmapIndexScanState *indexstate;
+ ExprState **runtimeKeyInfo;
+ bool have_runtime_keys;
+ RangeTblEntry *rtentry;
+ Index relid;
+ Oid reloid;
+ Relation currentRelation;
+
+ /*
+ * create state structure
+ */
+ indexstate = makeNode(BitmapIndexScanState);
+ indexstate->ss.ps.plan = (Plan *) node;
+ indexstate->ss.ps.state = estate;
+
+ /*
+ * Miscellaneous initialization
+ *
+ * create expression context for node
+ */
+ ExecAssignExprContext(estate, &indexstate->ss.ps);
+
+ /*
+ * initialize child expressions
+ *
+ * We don't need to initialize targetlist or qual since neither are used.
+ *
+ * Note: we don't initialize all of the indxqual expression, only the
+ * sub-parts corresponding to runtime keys (see below).
+ */
+
+#define BITMAPINDEXSCAN_NSLOTS 0
+
+ /*
+ * Initialize index-specific scan state
+ */
+ indexstate->biss_ScanKeys = NULL;
+ indexstate->biss_NumScanKeys = 0;
+ indexstate->biss_RuntimeKeyInfo = NULL;
+ indexstate->biss_RuntimeContext = NULL;
+ indexstate->biss_RuntimeKeysReady = false;
+ indexstate->biss_RelationDesc = NULL;
+ indexstate->biss_ScanDesc = NULL;
+
+ CXT1_printf("ExecInitBitmapIndexScan: context is %d\n", CurrentMemoryContext);
+
+ /*
+ * initialize space for runtime key info (may not be needed)
+ */
+ have_runtime_keys = false;
+
+ /*
+ * build the index scan keys from the index qualification
+ */
+ {
+ List *quals;
+ List *strategies;
+ List *subtypes;
+ ListCell *qual_cell;
+ ListCell *strategy_cell;
+ ListCell *subtype_cell;
+ int n_keys;
+ ScanKey scan_keys;
+ ExprState **run_keys;
+ int j;
+
+ quals = node->indxqual;
+ strategies = node->indxstrategy;
+ subtypes = node->indxsubtype;
+ n_keys = list_length(quals);
+ scan_keys = (n_keys <= 0) ? NULL :
+ (ScanKey) palloc(n_keys * sizeof(ScanKeyData));
+ run_keys = (n_keys <= 0) ? NULL :
+ (ExprState **) palloc(n_keys * sizeof(ExprState *));
+
+ /*
+ * for each opclause in the given qual, convert each qual's
+ * opclause into a single scan key
+ */
+ qual_cell = list_head(quals);
+ strategy_cell = list_head(strategies);
+ subtype_cell = list_head(subtypes);
+ for (j = 0; j < n_keys; j++)
+ {
+ OpExpr *clause; /* one clause of index qual */
+ Expr *leftop; /* expr on lhs of operator */
+ Expr *rightop; /* expr on rhs ... */
+ int flags = 0;
+ AttrNumber varattno; /* att number used in scan */
+ StrategyNumber strategy; /* op's strategy number */
+ Oid subtype; /* op's strategy subtype */
+ RegProcedure opfuncid; /* operator proc id used in scan */
+ Datum scanvalue; /* value used in scan (if const) */
+
+ /*
+ * extract clause information from the qualification
+ */
+ clause = (OpExpr *) lfirst(qual_cell);
+ qual_cell = lnext(qual_cell);
+ strategy = lfirst_int(strategy_cell);
+ strategy_cell = lnext(strategy_cell);
+ subtype = lfirst_oid(subtype_cell);
+ subtype_cell = lnext(subtype_cell);
+
+ if (!IsA(clause, OpExpr))
+ elog(ERROR, "indxqual is not an OpExpr");
+
+ opfuncid = clause->opfuncid;
+
+ /*
+ * Here we figure out the contents of the index qual. The
+ * usual case is (var op const) which means we form a scan key
+ * for the attribute listed in the var node and use the value
+ * of the const as comparison data.
+ *
+ * If we don't have a const node, it means our scan key is a
+ * function of information obtained during the execution of
+ * the plan, in which case we need to recalculate the index
+ * scan key at run time. Hence, we set have_runtime_keys to
+ * true and place the appropriate subexpression in run_keys.
+ * The corresponding scan key values are recomputed at run
+ * time.
+ */
+ run_keys[j] = NULL;
+
+ /*
+ * determine information in leftop
+ */
+ leftop = (Expr *) get_leftop((Expr *) clause);
+
+ if (leftop && IsA(leftop, RelabelType))
+ leftop = ((RelabelType *) leftop)->arg;
+
+ Assert(leftop != NULL);
+
+ if (!(IsA(leftop, Var) &&
+ var_is_rel((Var *) leftop)))
+ elog(ERROR, "indxqual doesn't have key on left side");
+
+ varattno = ((Var *) leftop)->varattno;
+
+ /*
+ * now determine information in rightop
+ */
+ rightop = (Expr *) get_rightop((Expr *) clause);
+
+ if (rightop && IsA(rightop, RelabelType))
+ rightop = ((RelabelType *) rightop)->arg;
+
+ Assert(rightop != NULL);
+
+ if (IsA(rightop, Const))
+ {
+ /*
+ * if the rightop is a const node then it means it
+ * identifies the value to place in our scan key.
+ */
+ scanvalue = ((Const *) rightop)->constvalue;
+ if (((Const *) rightop)->constisnull)
+ flags |= SK_ISNULL;
+ }
+ else
+ {
+ /*
+ * otherwise, the rightop contains an expression evaluable
+ * at runtime to figure out the value to place in our scan
+ * key.
+ */
+ have_runtime_keys = true;
+ run_keys[j] = ExecInitExpr(rightop, (PlanState *) indexstate);
+ scanvalue = (Datum) 0;
+ }
+
+ /*
+ * initialize the scan key's fields appropriately
+ */
+ ScanKeyEntryInitialize(&scan_keys[j],
+ flags,
+ varattno, /* attribute number to
+ * scan */
+ strategy, /* op's strategy */
+ subtype, /* strategy subtype */
+ opfuncid, /* reg proc to use */
+ scanvalue); /* constant */
+ }
+
+ /*
+ * store the key information into the node.
+ */
+ indexstate->biss_NumScanKeys = n_keys;
+ indexstate->biss_ScanKeys = scan_keys;
+ runtimeKeyInfo = run_keys;
+ }
+
+
+ /*
+ * If all of our keys have the form (var op const), then we have no
+ * runtime keys so we store NULL in the runtime key info. Otherwise
+ * runtime key info contains an array of pointers (one for each index)
+ * to arrays of flags (one for each key) which indicate that the qual
+ * needs to be evaluated at runtime. -cim 10/24/89
+ *
+ * If we do have runtime keys, we need an ExprContext to evaluate them;
+ * the node's standard context won't do because we want to reset that
+ * context for every tuple. So, build another context just like the
+ * other one... -tgl 7/11/00
+ */
+ if (have_runtime_keys)
+ {
+ ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
+
+ ExecAssignExprContext(estate, &indexstate->ss.ps);
+ indexstate->biss_RuntimeKeyInfo = runtimeKeyInfo;
+ indexstate->biss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
+ indexstate->ss.ps.ps_ExprContext = stdecontext;
+ }
+ else
+ {
+ indexstate->biss_RuntimeKeyInfo = NULL;
+ indexstate->biss_RuntimeContext = NULL;
+ /* Get rid of the speculatively-allocated flag array, too */
+ pfree(runtimeKeyInfo);
+ }
+
+ /*
+ * open the base relation and acquire AccessShareLock on it.
+ */
+ relid = node->scan.scanrelid;
+ rtentry = rt_fetch(relid, estate->es_range_table);
+ reloid = rtentry->relid;
+
+ currentRelation = heap_open(reloid, AccessShareLock);
+
+ indexstate->ss.ss_currentRelation = currentRelation;
+ indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
+
+ /*
+ * 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. (We rely on having AccessShareLock
+ * on the parent table to ensure the index won't go away!)
+ */
+ indexstate->biss_RelationDesc = index_open(node->indxid);
+ indexstate->biss_ScanDesc =
+ index_beginscan_multi(indexstate->biss_RelationDesc,
+ estate->es_snapshot,
+ indexstate->biss_NumScanKeys,
+ indexstate->biss_ScanKeys);
+
+ /*
+ * all done.
+ */
+ return indexstate;
+}
+
+int
+ExecCountSlotsBitmapIndexScan(BitmapIndexScan *node)
+{
+ return ExecCountSlotsNode(outerPlan((Plan *) node)) +
+ ExecCountSlotsNode(innerPlan((Plan *) node)) + BITMAPINDEXSCAN_NSLOTS;
+}
diff --git a/src/backend/executor/nodeBitmapOr.c b/src/backend/executor/nodeBitmapOr.c
new file mode 100644
index 00000000000..f4ef17223c8
--- /dev/null
+++ b/src/backend/executor/nodeBitmapOr.c
@@ -0,0 +1,209 @@
+/*-------------------------------------------------------------------------
+ *
+ * nodeBitmapOr.c
+ * routines to handle BitmapOr nodes.
+ *
+ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $PostgreSQL: pgsql/src/backend/executor/nodeBitmapOr.c,v 1.1 2005/04/19 22:35:12 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+/* INTERFACE ROUTINES
+ * ExecInitBitmapOr - initialize the BitmapOr node
+ * MultiExecBitmapOr - retrieve the result bitmap from the node
+ * ExecEndBitmapOr - shut down the BitmapOr node
+ * ExecReScanBitmapOr - rescan the BitmapOr node
+ *
+ * NOTES
+ * BitmapOr nodes don't make use of their left and right
+ * subtrees, rather they maintain a list of subplans,
+ * much like Append nodes. The logic is much simpler than
+ * Append, however, since we needn't cope with forward/backward
+ * execution.
+ */
+
+#include "postgres.h"
+
+#include "executor/execdebug.h"
+#include "executor/instrument.h"
+#include "executor/nodeBitmapOr.h"
+
+
+/* ----------------------------------------------------------------
+ * ExecInitBitmapOr
+ *
+ * Begin all of the subscans of the BitmapOr node.
+ * ----------------------------------------------------------------
+ */
+BitmapOrState *
+ExecInitBitmapOr(BitmapOr *node, EState *estate)
+{
+ BitmapOrState *bitmaporstate = makeNode(BitmapOrState);
+ PlanState **bitmapplanstates;
+ int nplans;
+ int i;
+ Plan *initNode;
+
+ CXT1_printf("ExecInitBitmapOr: context is %d\n", CurrentMemoryContext);
+
+ /*
+ * Set up empty vector of subplan states
+ */
+ nplans = list_length(node->bitmapplans);
+
+ bitmapplanstates = (PlanState **) palloc0(nplans * sizeof(PlanState *));
+
+ /*
+ * create new BitmapOrState for our BitmapOr node
+ */
+ bitmaporstate->ps.plan = (Plan *) node;
+ bitmaporstate->ps.state = estate;
+ bitmaporstate->bitmapplans = bitmapplanstates;
+ bitmaporstate->nplans = nplans;
+
+ /*
+ * Miscellaneous initialization
+ *
+ * BitmapOr plans don't have expression contexts because they never call
+ * ExecQual or ExecProject. They don't need any tuple slots either.
+ */
+
+#define BITMAPOR_NSLOTS 0
+
+ /*
+ * call ExecInitNode on each of the plans to be executed and save the
+ * results into the array "bitmapplanstates".
+ */
+ for (i = 0; i < nplans; i++)
+ {
+ initNode = (Plan *) list_nth(node->bitmapplans, i);
+ bitmapplanstates[i] = ExecInitNode(initNode, estate);
+ }
+
+ return bitmaporstate;
+}
+
+int
+ExecCountSlotsBitmapOr(BitmapOr *node)
+{
+ ListCell *plan;
+ int nSlots = 0;
+
+ foreach(plan, node->bitmapplans)
+ nSlots += ExecCountSlotsNode((Plan *) lfirst(plan));
+ return nSlots + BITMAPOR_NSLOTS;
+}
+
+/* ----------------------------------------------------------------
+ * MultiExecBitmapOr
+ * ----------------------------------------------------------------
+ */
+Node *
+MultiExecBitmapOr(BitmapOrState *node)
+{
+ PlanState **bitmapplans;
+ int nplans;
+ int i;
+ TIDBitmap *result = NULL;
+
+ /* must provide our own instrumentation support */
+ if (node->ps.instrument)
+ InstrStartNode(node->ps.instrument);
+
+ /*
+ * get information from the node
+ */
+ bitmapplans = node->bitmapplans;
+ nplans = node->nplans;
+
+ /*
+ * Scan all the subplans and OR their result bitmaps
+ */
+ for (i = 0; i < nplans; i++)
+ {
+ PlanState *subnode = bitmapplans[i];
+ TIDBitmap *subresult;
+
+ subresult = (TIDBitmap *) MultiExecProcNode(subnode);
+
+ if (!subresult || !IsA(subresult, TIDBitmap))
+ elog(ERROR, "unrecognized result from subplan");
+
+ if (result == NULL)
+ result = subresult; /* first subplan */
+ else
+ {
+ tbm_union(result, subresult);
+ tbm_free(subresult);
+ }
+ }
+
+ /* We could return an empty result set here? */
+ if (result == NULL)
+ elog(ERROR, "BitmapOr doesn't support zero inputs");
+
+ /* must provide our own instrumentation support */
+ if (node->ps.instrument)
+ InstrStopNodeMulti(node->ps.instrument, 0 /* XXX */);
+
+ return (Node *) result;
+}
+
+/* ----------------------------------------------------------------
+ * ExecEndBitmapOr
+ *
+ * Shuts down the subscans of the BitmapOr node.
+ *
+ * Returns nothing of interest.
+ * ----------------------------------------------------------------
+ */
+void
+ExecEndBitmapOr(BitmapOrState *node)
+{
+ PlanState **bitmapplans;
+ int nplans;
+ int i;
+
+ /*
+ * get information from the node
+ */
+ bitmapplans = node->bitmapplans;
+ nplans = node->nplans;
+
+ /*
+ * shut down each of the subscans (that we've initialized)
+ */
+ for (i = 0; i < nplans; i++)
+ {
+ if (bitmapplans[i])
+ ExecEndNode(bitmapplans[i]);
+ }
+}
+
+void
+ExecReScanBitmapOr(BitmapOrState *node, ExprContext *exprCtxt)
+{
+ int i;
+
+ for (i = 0; i < node->nplans; i++)
+ {
+ PlanState *subnode = node->bitmapplans[i];
+
+ /*
+ * ExecReScan doesn't know about my subplans, so I have to do
+ * changed-parameter signaling myself.
+ */
+ if (node->ps.chgParam != NULL)
+ UpdateChangedParamSet(subnode, node->ps.chgParam);
+
+ /*
+ * Always rescan the inputs immediately, to ensure we can pass down
+ * any outer tuple that might be used in index quals.
+ */
+ ExecReScan(subnode, exprCtxt);
+ }
+}