Create executor and planner-backend support for decoupled heap and index

scans, using in-memory tuple ID bitmaps as the intermediary.  The planner
frontend (path creation and cost estimation) is not there yet, so none
of this code can be executed.  I have tested it using some hacked planner
code that is far too ugly to see the light of day, however.  Committing
now so that the bulk of the infrastructure changes go in before the tree
drifts under me.
This commit is contained in:
Tom Lane 2005-04-19 22:35:18 +00:00
parent 04ce41ca62
commit 4a8c5d0375
30 changed files with 2783 additions and 76 deletions

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994-5, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.132 2005/04/16 20:07:35 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.133 2005/04/19 22:35:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -423,6 +423,12 @@ explain_outNode(StringInfo str,
case T_Append:
pname = "Append";
break;
case T_BitmapAnd:
pname = "BitmapAnd";
break;
case T_BitmapOr:
pname = "BitmapOr";
break;
case T_NestLoop:
switch (((NestLoop *) plan)->join.jointype)
{
@ -498,6 +504,12 @@ explain_outNode(StringInfo str,
case T_IndexScan:
pname = "Index Scan";
break;
case T_BitmapIndexScan:
pname = "Bitmap Index Scan";
break;
case T_BitmapHeapScan:
pname = "Bitmap Heap Scan";
break;
case T_TidScan:
pname = "Tid Scan";
break;
@ -586,6 +598,7 @@ explain_outNode(StringInfo str,
}
/* FALL THRU */
case T_SeqScan:
case T_BitmapHeapScan:
case T_TidScan:
if (((Scan *) plan)->scanrelid > 0)
{
@ -606,6 +619,10 @@ explain_outNode(StringInfo str,
quote_identifier(rte->eref->aliasname));
}
break;
case T_BitmapIndexScan:
appendStringInfo(str, " on %s",
quote_identifier(get_rel_name(((BitmapIndexScan *) plan)->indxid)));
break;
case T_SubqueryScan:
if (((Scan *) plan)->scanrelid > 0)
{
@ -696,6 +713,21 @@ explain_outNode(StringInfo str,
outer_plan,
str, indent, es);
break;
case T_BitmapIndexScan:
show_scan_qual(((BitmapIndexScan *) plan)->indxqualorig, false,
"Index Cond",
((Scan *) plan)->scanrelid,
outer_plan,
str, indent, es);
break;
case T_BitmapHeapScan:
/* XXX do we want to show this in production? */
show_scan_qual(((BitmapHeapScan *) plan)->bitmapqualorig, false,
"Recheck Cond",
((Scan *) plan)->scanrelid,
outer_plan,
str, indent, es);
/* FALL THRU */
case T_SeqScan:
case T_TidScan:
case T_SubqueryScan:
@ -857,6 +889,54 @@ explain_outNode(StringInfo str,
}
}
if (IsA(plan, BitmapAnd))
{
BitmapAnd *bitmapandplan = (BitmapAnd *) plan;
BitmapAndState *bitmapandstate = (BitmapAndState *) planstate;
ListCell *lst;
int j;
j = 0;
foreach(lst, bitmapandplan->bitmapplans)
{
Plan *subnode = (Plan *) lfirst(lst);
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
explain_outNode(str, subnode,
bitmapandstate->bitmapplans[j],
NULL,
indent + 3, es);
j++;
}
}
if (IsA(plan, BitmapOr))
{
BitmapOr *bitmaporplan = (BitmapOr *) plan;
BitmapOrState *bitmaporstate = (BitmapOrState *) planstate;
ListCell *lst;
int j;
j = 0;
foreach(lst, bitmaporplan->bitmapplans)
{
Plan *subnode = (Plan *) lfirst(lst);
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
explain_outNode(str, subnode,
bitmaporstate->bitmapplans[j],
NULL,
indent + 3, es);
j++;
}
}
if (IsA(plan, SubqueryScan))
{
SubqueryScan *subqueryscan = (SubqueryScan *) plan;

View File

@ -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 \

View File

@ -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:

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.301 2005/04/07 01:51:38 neilc Exp $
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.302 2005/04/19 22:35:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -148,6 +148,48 @@ _copyAppend(Append *from)
return newnode;
}
/*
* _copyBitmapAnd
*/
static BitmapAnd *
_copyBitmapAnd(BitmapAnd *from)
{
BitmapAnd *newnode = makeNode(BitmapAnd);
/*
* copy node superclass fields
*/
CopyPlanFields((Plan *) from, (Plan *) newnode);
/*
* copy remainder of node
*/
COPY_NODE_FIELD(bitmapplans);
return newnode;
}
/*
* _copyBitmapOr
*/
static BitmapOr *
_copyBitmapOr(BitmapOr *from)
{
BitmapOr *newnode = makeNode(BitmapOr);
/*
* copy node superclass fields
*/
CopyPlanFields((Plan *) from, (Plan *) newnode);
/*
* copy remainder of node
*/
COPY_NODE_FIELD(bitmapplans);
return newnode;
}
/*
* CopyScanFields
@ -222,6 +264,52 @@ _copyIndexScan(IndexScan *from)
return newnode;
}
/*
* _copyBitmapIndexScan
*/
static BitmapIndexScan *
_copyBitmapIndexScan(BitmapIndexScan *from)
{
BitmapIndexScan *newnode = makeNode(BitmapIndexScan);
/*
* copy node superclass fields
*/
CopyScanFields((Scan *) from, (Scan *) newnode);
/*
* copy remainder of node
*/
COPY_SCALAR_FIELD(indxid);
COPY_NODE_FIELD(indxqual);
COPY_NODE_FIELD(indxqualorig);
COPY_NODE_FIELD(indxstrategy);
COPY_NODE_FIELD(indxsubtype);
return newnode;
}
/*
* _copyBitmapHeapScan
*/
static BitmapHeapScan *
_copyBitmapHeapScan(BitmapHeapScan *from)
{
BitmapHeapScan *newnode = makeNode(BitmapHeapScan);
/*
* copy node superclass fields
*/
CopyScanFields((Scan *) from, (Scan *) newnode);
/*
* copy remainder of node
*/
COPY_NODE_FIELD(bitmapqualorig);
return newnode;
}
/*
* _copyTidScan
*/
@ -2598,6 +2686,12 @@ copyObject(void *from)
case T_Append:
retval = _copyAppend(from);
break;
case T_BitmapAnd:
retval = _copyBitmapAnd(from);
break;
case T_BitmapOr:
retval = _copyBitmapOr(from);
break;
case T_Scan:
retval = _copyScan(from);
break;
@ -2607,6 +2701,12 @@ copyObject(void *from)
case T_IndexScan:
retval = _copyIndexScan(from);
break;
case T_BitmapIndexScan:
retval = _copyBitmapIndexScan(from);
break;
case T_BitmapHeapScan:
retval = _copyBitmapHeapScan(from);
break;
case T_TidScan:
retval = _copyTidScan(from);
break;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.246 2005/04/06 16:34:05 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.247 2005/04/19 22:35:14 tgl Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
@ -308,6 +308,26 @@ _outAppend(StringInfo str, Append *node)
WRITE_BOOL_FIELD(isTarget);
}
static void
_outBitmapAnd(StringInfo str, BitmapAnd *node)
{
WRITE_NODE_TYPE("BITMAPAND");
_outPlanInfo(str, (Plan *) node);
WRITE_NODE_FIELD(bitmapplans);
}
static void
_outBitmapOr(StringInfo str, BitmapOr *node)
{
WRITE_NODE_TYPE("BITMAPOR");
_outPlanInfo(str, (Plan *) node);
WRITE_NODE_FIELD(bitmapplans);
}
static void
_outScan(StringInfo str, Scan *node)
{
@ -340,6 +360,30 @@ _outIndexScan(StringInfo str, IndexScan *node)
WRITE_ENUM_FIELD(indxorderdir, ScanDirection);
}
static void
_outBitmapIndexScan(StringInfo str, BitmapIndexScan *node)
{
WRITE_NODE_TYPE("BITMAPINDEXSCAN");
_outScanInfo(str, (Scan *) node);
WRITE_OID_FIELD(indxid);
WRITE_NODE_FIELD(indxqual);
WRITE_NODE_FIELD(indxqualorig);
WRITE_NODE_FIELD(indxstrategy);
WRITE_NODE_FIELD(indxsubtype);
}
static void
_outBitmapHeapScan(StringInfo str, BitmapHeapScan *node)
{
WRITE_NODE_TYPE("BITMAPHEAPSCAN");
_outScanInfo(str, (Scan *) node);
WRITE_NODE_FIELD(bitmapqualorig);
}
static void
_outTidScan(StringInfo str, TidScan *node)
{
@ -968,9 +1012,6 @@ _outPath(StringInfo str, Path *node)
_outPathInfo(str, (Path *) node);
}
/*
* IndexPath is a subclass of Path.
*/
static void
_outIndexPath(StringInfo str, IndexPath *node)
{
@ -986,6 +1027,18 @@ _outIndexPath(StringInfo str, IndexPath *node)
WRITE_FLOAT_FIELD(rows, "%.0f");
}
static void
_outBitmapHeapPath(StringInfo str, BitmapHeapPath *node)
{
WRITE_NODE_TYPE("BITMAPHEAPPATH");
_outPathInfo(str, (Path *) node);
WRITE_NODE_FIELD(bitmapqual);
WRITE_BOOL_FIELD(isjoininner);
WRITE_FLOAT_FIELD(rows, "%.0f");
}
static void
_outTidPath(StringInfo str, TidPath *node)
{
@ -1620,6 +1673,12 @@ _outNode(StringInfo str, void *obj)
case T_Append:
_outAppend(str, obj);
break;
case T_BitmapAnd:
_outBitmapAnd(str, obj);
break;
case T_BitmapOr:
_outBitmapOr(str, obj);
break;
case T_Scan:
_outScan(str, obj);
break;
@ -1629,6 +1688,12 @@ _outNode(StringInfo str, void *obj)
case T_IndexScan:
_outIndexScan(str, obj);
break;
case T_BitmapIndexScan:
_outBitmapIndexScan(str, obj);
break;
case T_BitmapHeapScan:
_outBitmapHeapScan(str, obj);
break;
case T_TidScan:
_outTidScan(str, obj);
break;
@ -1783,6 +1848,9 @@ _outNode(StringInfo str, void *obj)
case T_IndexPath:
_outIndexPath(str, obj);
break;
case T_BitmapHeapPath:
_outBitmapHeapPath(str, obj);
break;
case T_TidPath:
_outTidPath(str, obj);
break;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/print.c,v 1.74 2005/04/06 16:34:05 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/print.c,v 1.75 2005/04/19 22:35:15 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@ -493,12 +493,20 @@ plannode_type(Plan *p)
return "RESULT";
case T_Append:
return "APPEND";
case T_BitmapAnd:
return "BITMAPAND";
case T_BitmapOr:
return "BITMAPOR";
case T_Scan:
return "SCAN";
case T_SeqScan:
return "SEQSCAN";
case T_IndexScan:
return "INDEXSCAN";
case T_BitmapIndexScan:
return "BITMAPINDEXSCAN";
case T_BitmapHeapScan:
return "BITMAPHEAPSCAN";
case T_TidScan:
return "TIDSCAN";
case T_SubqueryScan:
@ -551,7 +559,8 @@ print_plan_recursive(Plan *p, Query *parsetree, int indentLevel, char *label)
p->startup_cost, p->total_cost,
p->plan_rows, p->plan_width);
if (IsA(p, Scan) ||
IsA(p, SeqScan))
IsA(p, SeqScan) ||
IsA(p, BitmapHeapScan))
{
RangeTblEntry *rte;
@ -584,27 +593,48 @@ print_plan_recursive(Plan *p, Query *parsetree, int indentLevel, char *label)
if (IsA(p, Append))
{
ListCell *l;
int whichplan = 0;
Append *appendplan = (Append *) p;
foreach(l, appendplan->appendplans)
{
Plan *subnode = (Plan *) lfirst(l);
/*
* I don't think we need to fiddle with the range table here,
* bjm
*/
print_plan_recursive(subnode, parsetree, indentLevel + 3, "a: ");
}
}
whichplan++;
if (IsA(p, BitmapAnd))
{
ListCell *l;
BitmapAnd *bitmapandplan = (BitmapAnd *) p;
foreach(l, bitmapandplan->bitmapplans)
{
Plan *subnode = (Plan *) lfirst(l);
print_plan_recursive(subnode, parsetree, indentLevel + 3, "a: ");
}
}
if (IsA(p, BitmapOr))
{
ListCell *l;
BitmapOr *bitmaporplan = (BitmapOr *) p;
foreach(l, bitmaporplan->bitmapplans)
{
Plan *subnode = (Plan *) lfirst(l);
print_plan_recursive(subnode, parsetree, indentLevel + 3, "a: ");
}
}
}
/* print_plan
prints just the plan node types */
/*
* print_plan
*
* prints just the plan node types
*/
void
print_plan(Plan *p, Query *parsetree)
{

View File

@ -23,7 +23,7 @@
* Copyright (c) 2003-2005, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/tidbitmap.c,v 1.1 2005/04/17 22:24:02 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/tidbitmap.c,v 1.2 2005/04/19 22:35:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -160,7 +160,7 @@ tbm_create(long maxbytes)
hash_ctl.hash = tag_hash;
hash_ctl.hcxt = CurrentMemoryContext;
tbm->pagetable = hash_create("TIDBitmap",
nbuckets,
128, /* start small and extend */
&hash_ctl,
HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.125 2005/04/06 16:34:05 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.126 2005/04/19 22:35:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -898,6 +898,9 @@ print_path(Query *root, Path *path, int indent)
case T_IndexPath:
ptype = "IdxScan";
break;
case T_BitmapHeapPath:
ptype = "BitmapHeapScan";
break;
case T_TidPath:
ptype = "TidScan";
break;

View File

@ -49,7 +49,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.141 2005/04/04 01:43:12 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.142 2005/04/19 22:35:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -400,6 +400,36 @@ cost_index(Path *path, Query *root,
path->total_cost = startup_cost + run_cost;
}
/*
* cost_bitmap_scan
* Determines and returns the cost of scanning a relation using a bitmap
* index-then-heap plan.
*
* 'root' is the query root
* 'baserel' is the relation to be scanned
* 'bitmapqual' is an AND/OR tree of IndexPaths for the component scans
* 'is_injoin' is T if we are considering using the scan as the inside
* of a nestloop join (hence, some of the quals are join clauses)
*/
void
cost_bitmap_scan(Path *path, Query *root, RelOptInfo *baserel,
Node *bitmapqual, bool is_injoin)
{
Cost startup_cost = 0;
Cost run_cost = 0;
/* Should only be applied to base relations */
Assert(IsA(baserel, RelOptInfo));
Assert(baserel->relid > 0);
Assert(baserel->rtekind == RTE_RELATION);
/* XXX lots to do here */
run_cost += 10;
path->startup_cost = startup_cost;
path->total_cost = startup_cost + run_cost;
}
/*
* cost_tidscan
* Determines and returns the cost of scanning a relation using TIDs.
@ -760,6 +790,8 @@ cost_nestloop(NestPath *path, Query *root)
*/
if (IsA(inner_path, IndexPath))
inner_path_rows = ((IndexPath *) inner_path)->rows;
else if (IsA(inner_path, BitmapHeapPath))
inner_path_rows = ((BitmapHeapPath *) inner_path)->rows;
if (!enable_nestloop)
startup_cost += disable_cost;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.92 2005/01/23 02:21:26 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.93 2005/04/19 22:35:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -391,6 +391,7 @@ match_unsorted_outer(Query *root,
* waste of time.)
*/
if (!(IsA(inner_cheapest_total, IndexPath) ||
IsA(inner_cheapest_total, BitmapHeapPath) ||
IsA(inner_cheapest_total, TidPath)))
matpath = (Path *)
create_material_path(innerrel, inner_cheapest_total);

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.179 2005/04/12 05:11:28 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.180 2005/04/19 22:35:16 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -48,6 +48,12 @@ static SeqScan *create_seqscan_plan(Query *root, Path *best_path,
List *tlist, List *scan_clauses);
static IndexScan *create_indexscan_plan(Query *root, IndexPath *best_path,
List *tlist, List *scan_clauses);
static BitmapHeapScan *create_bitmap_scan_plan(Query *root,
BitmapHeapPath *best_path,
List *tlist, List *scan_clauses);
static Plan *create_bitmap_subplan(Query *root, Node *bitmapqual);
static List *create_bitmap_qual(Node *bitmapqual);
static List *create_bitmap_indxqual(Node *bitmapqual);
static TidScan *create_tidscan_plan(Query *root, TidPath *best_path,
List *tlist, List *scan_clauses);
static SubqueryScan *create_subqueryscan_plan(Query *root, Path *best_path,
@ -80,10 +86,22 @@ static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
List *indxid, List *indxqual, List *indxqualorig,
List *indxstrategy, List *indxsubtype, List *indxlossy,
ScanDirection indexscandir);
static BitmapIndexScan *make_bitmap_indexscan(Index scanrelid, Oid indxid,
List *indxqual,
List *indxqualorig,
List *indxstrategy,
List *indxsubtype);
static BitmapHeapScan *make_bitmap_heapscan(List *qptlist,
List *qpqual,
Plan *lefttree,
List *bitmapqualorig,
Index scanrelid);
static TidScan *make_tidscan(List *qptlist, List *qpqual, Index scanrelid,
List *tideval);
static FunctionScan *make_functionscan(List *qptlist, List *qpqual,
Index scanrelid);
static BitmapAnd *make_bitmap_and(List *bitmapplans);
static BitmapOr *make_bitmap_or(List *bitmapplans);
static NestLoop *make_nestloop(List *tlist,
List *joinclauses, List *otherclauses,
Plan *lefttree, Plan *righttree,
@ -127,8 +145,9 @@ create_plan(Query *root, Path *best_path)
switch (best_path->pathtype)
{
case T_IndexScan:
case T_SeqScan:
case T_IndexScan:
case T_BitmapHeapScan:
case T_TidScan:
case T_SubqueryScan:
case T_FunctionScan:
@ -220,6 +239,13 @@ create_scan_plan(Query *root, Path *best_path)
scan_clauses);
break;
case T_BitmapHeapScan:
plan = (Scan *) create_bitmap_scan_plan(root,
(BitmapHeapPath *) best_path,
tlist,
scan_clauses);
break;
case T_TidScan:
plan = (Scan *) create_tidscan_plan(root,
(TidPath *) best_path,
@ -328,8 +354,9 @@ disuse_physical_tlist(Plan *plan, Path *path)
/* Only need to undo it for path types handled by create_scan_plan() */
switch (path->pathtype)
{
case T_IndexScan:
case T_SeqScan:
case T_IndexScan:
case T_BitmapHeapScan:
case T_TidScan:
case T_SubqueryScan:
case T_FunctionScan:
@ -671,7 +698,7 @@ create_seqscan_plan(Query *root, Path *best_path,
/*
* create_indexscan_plan
* Returns a indexscan plan for the base relation scanned by 'best_path'
* Returns an indexscan plan for the base relation scanned by 'best_path'
* with restriction clauses 'scan_clauses' and targetlist 'tlist'.
*
* The indexquals list of the path contains a sublist of implicitly-ANDed
@ -705,6 +732,37 @@ create_indexscan_plan(Query *root,
Assert(baserelid > 0);
Assert(best_path->path.parent->rtekind == RTE_RELATION);
/* Build list of index OIDs */
indexids = NIL;
foreach(l, best_path->indexinfo)
{
IndexOptInfo *index = (IndexOptInfo *) lfirst(l);
indexids = lappend_oid(indexids, index->indexoid);
}
/*
* Build "stripped" indexquals structure (no RestrictInfos) to pass to
* executor as indxqualorig
*/
stripped_indxquals = NIL;
foreach(l, indxquals)
{
List *andlist = (List *) lfirst(l);
stripped_indxquals = lappend(stripped_indxquals,
get_actual_clauses(andlist));
}
/*
* The executor needs a copy with the indexkey on the left of each
* clause and with index attr numbers substituted for table ones. This
* pass also gets strategy info and looks for "lossy" operators.
*/
fix_indxqual_references(indxquals, best_path,
&fixed_indxquals,
&indxstrategy, &indxsubtype, &indxlossy);
/*
* If this is a innerjoin scan, the indexclauses will contain join
* clauses that are not present in scan_clauses (since the passed-in
@ -729,31 +787,6 @@ create_indexscan_plan(Query *root,
/* Reduce RestrictInfo list to bare expressions */
scan_clauses = get_actual_clauses(scan_clauses);
/* Sort clauses into best execution order */
scan_clauses = order_qual_clauses(root, scan_clauses);
/* Build list of index OIDs */
indexids = NIL;
foreach(l, best_path->indexinfo)
{
IndexOptInfo *index = (IndexOptInfo *) lfirst(l);
indexids = lappend_oid(indexids, index->indexoid);
}
/*
* Build "stripped" indexquals structure (no RestrictInfos) to pass to
* executor as indxqualorig
*/
stripped_indxquals = NIL;
foreach(l, indxquals)
{
List *andlist = (List *) lfirst(l);
stripped_indxquals = lappend(stripped_indxquals,
get_actual_clauses(andlist));
}
/*
* The qpqual list must contain all restrictions not automatically
* handled by the index. All the predicates in the indexquals will be
@ -784,14 +817,8 @@ create_indexscan_plan(Query *root,
qpqual = list_difference(scan_clauses, linitial(stripped_indxquals));
}
/*
* The executor needs a copy with the indexkey on the left of each
* clause and with index attr numbers substituted for table ones. This
* pass also gets strategy info and looks for "lossy" operators.
*/
fix_indxqual_references(indxquals, best_path,
&fixed_indxquals,
&indxstrategy, &indxsubtype, &indxlossy);
/* Sort clauses into best execution order */
qpqual = order_qual_clauses(root, qpqual);
/* Finally ready to build the plan node */
scan_plan = make_indexscan(tlist,
@ -812,6 +839,339 @@ create_indexscan_plan(Query *root,
return scan_plan;
}
/*
* create_bitmap_scan_plan
* Returns a bitmap scan plan for the base relation scanned by 'best_path'
* with restriction clauses 'scan_clauses' and targetlist 'tlist'.
*/
static BitmapHeapScan *
create_bitmap_scan_plan(Query *root,
BitmapHeapPath *best_path,
List *tlist,
List *scan_clauses)
{
Index baserelid = best_path->path.parent->relid;
Plan *bitmapqualplan;
List *bitmapqualorig;
List *indexquals;
List *qpqual;
BitmapHeapScan *scan_plan;
/* it should be a base rel... */
Assert(baserelid > 0);
Assert(best_path->path.parent->rtekind == RTE_RELATION);
/* Process the bitmapqual tree into a Plan tree */
bitmapqualplan = create_bitmap_subplan(root, best_path->bitmapqual);
/* Process the bitmapqual tree into an expression tree, too */
bitmapqualorig = create_bitmap_qual(best_path->bitmapqual);
/* Also extract the true index conditions */
indexquals = create_bitmap_indxqual(best_path->bitmapqual);
/*
* If this is a innerjoin scan, the indexclauses will contain join
* clauses that are not present in scan_clauses (since the passed-in
* value is just the rel's baserestrictinfo list). We must add these
* clauses to scan_clauses to ensure they get checked. In most cases
* we will remove the join clauses again below, but if a join clause
* contains a special operator, we need to make sure it gets into the
* scan_clauses.
*/
if (best_path->isjoininner)
{
/*
* Pointer comparison should be enough to determine RestrictInfo
* matches.
*/
scan_clauses = list_union_ptr(scan_clauses, bitmapqualorig);
}
/* Reduce RestrictInfo list to bare expressions */
scan_clauses = get_actual_clauses(scan_clauses);
/*
* The qpqual list must contain all restrictions not automatically
* handled by the index. All the predicates in the indexquals will be
* checked (either by the index itself, or by nodeBitmapHeapscan.c),
* but if there are any "special" or lossy operators involved then they
* must be added to qpqual. The upshot is that qpquals must contain
* scan_clauses minus whatever appears in indexquals.
*
* NOTE: when there are OR clauses in indexquals, the simple equality
* check used by list_difference will only detect matches in case of
* chance equality of the OR subclause ordering. This is probably all
* right for now because that order will match what's in scan_clauses
* ... but perhaps we need more smarts here.
*/
qpqual = list_difference(scan_clauses, indexquals);
/* Sort clauses into best execution order */
qpqual = order_qual_clauses(root, qpqual);
/* Finally ready to build the plan node */
scan_plan = make_bitmap_heapscan(tlist,
qpqual,
bitmapqualplan,
bitmapqualorig,
baserelid);
copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
/* use the indexscan-specific rows estimate, not the parent rel's */
scan_plan->scan.plan.plan_rows = best_path->rows;
return scan_plan;
}
/*
* Given a bitmapqual tree, generate the Plan tree that implements it
*/
static Plan *
create_bitmap_subplan(Query *root, Node *bitmapqual)
{
Plan *plan;
Plan *subplan;
if (bitmapqual == NULL)
return NULL; /* probably can't happen */
if (IsA(bitmapqual, List))
{
/* this case is to handle the List arguments of AND/OR */
List *newlist = NIL;
ListCell *l;
foreach(l, (List *) bitmapqual)
{
subplan = create_bitmap_subplan(root, lfirst(l));
newlist = lappend(newlist, subplan);
}
plan = (Plan *) newlist;
}
else if (and_clause(bitmapqual))
{
subplan = create_bitmap_subplan(root,
(Node *) ((BoolExpr *) bitmapqual)->args);
plan = (Plan *) make_bitmap_and((List *) subplan);
}
else if (or_clause(bitmapqual))
{
subplan = create_bitmap_subplan(root,
(Node *) ((BoolExpr *) bitmapqual)->args);
plan = (Plan *) make_bitmap_or((List *) subplan);
}
else if (IsA(bitmapqual, IndexPath))
{
IndexPath *ipath = (IndexPath *) bitmapqual;
IndexScan *iscan;
BitmapIndexScan *bscan;
/* Use the regular indexscan plan build machinery... */
iscan = create_indexscan_plan(root, ipath, NIL, NIL);
Assert(list_length(iscan->indxid) == 1);
/* then convert to a bitmap indexscan */
bscan = make_bitmap_indexscan(iscan->scan.scanrelid,
linitial_oid(iscan->indxid),
linitial(iscan->indxqual),
linitial(iscan->indxqualorig),
linitial(iscan->indxstrategy),
linitial(iscan->indxsubtype));
/* XXX this cost is wrong: */
copy_path_costsize(&bscan->scan.plan, &ipath->path);
/* use the indexscan-specific rows estimate, not the parent rel's */
bscan->scan.plan.plan_rows = ipath->rows;
plan = (Plan *) bscan;
}
else
{
elog(ERROR, "unrecognized node type: %d", nodeTag(bitmapqual));
plan = NULL; /* keep compiler quiet */
}
return plan;
}
/*
* Given a bitmapqual tree, generate the equivalent ordinary expression tree
* (which we need for the bitmapqualorig field of the BitmapHeapScan plan).
* The result is expressed as an implicit-AND list.
*/
static List *
create_bitmap_qual(Node *bitmapqual)
{
List *result;
List *sublist;
if (and_clause(bitmapqual))
{
ListCell *l;
result = NIL;
foreach(l, ((BoolExpr *) bitmapqual)->args)
{
sublist = create_bitmap_qual(lfirst(l));
result = list_concat(result, sublist);
}
}
else if (or_clause(bitmapqual))
{
List *newlist = NIL;
ListCell *l;
foreach(l, ((BoolExpr *) bitmapqual)->args)
{
sublist = create_bitmap_qual(lfirst(l));
if (sublist == NIL)
{
/* constant TRUE input yields constant TRUE OR result */
return NIL;
}
newlist = lappend(newlist, make_ands_explicit(sublist));
}
result = list_make1(make_orclause(newlist));
}
else if (IsA(bitmapqual, IndexPath))
{
IndexPath *ipath = (IndexPath *) bitmapqual;
Assert(list_length(ipath->indexclauses) == 1);
result = get_actual_clauses(linitial(ipath->indexclauses));
}
else
{
elog(ERROR, "unrecognized node type: %d", nodeTag(bitmapqual));
result = NIL; /* keep compiler quiet */
}
return result;
}
/*
* Same as above, except extract the indxqual conditions (which are different
* if there are special index operators or lossy operators involved).
*
* The result essentially represents the conditions the indexscan guarantees
* to enforce, which may be weaker than the original qual expressions.
*/
static List *
create_bitmap_indxqual(Node *bitmapqual)
{
List *result;
List *sublist;
ListCell *l;
if (and_clause(bitmapqual))
{
result = NIL;
foreach(l, ((BoolExpr *) bitmapqual)->args)
{
sublist = create_bitmap_indxqual(lfirst(l));
result = list_concat(result, sublist);
}
}
else if (or_clause(bitmapqual))
{
List *newlist = NIL;
foreach(l, ((BoolExpr *) bitmapqual)->args)
{
sublist = create_bitmap_indxqual(lfirst(l));
if (sublist == NIL)
{
/* constant TRUE input yields constant TRUE OR result */
return NIL;
}
newlist = lappend(newlist, make_ands_explicit(sublist));
}
result = list_make1(make_orclause(newlist));
}
else if (IsA(bitmapqual, IndexPath))
{
IndexPath *ipath = (IndexPath *) bitmapqual;
IndexOptInfo *index;
Assert(list_length(ipath->indexinfo) == 1);
index = linitial(ipath->indexinfo);
/*
* We have to remove "lossy" index operators from the result, since
* the index isn't guaranteeing they are enforced. (This will lead
* to the operators being rechecked as qpquals of the BitmapHeapScan
* node.)
*
* XXX look at restructuring to share code better with
* fix_indxqual_references()
*/
result = NIL;
Assert(list_length(ipath->indexquals) == 1);
foreach(l, (List *) linitial(ipath->indexquals))
{
RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
OpExpr *clause;
Oid opno;
Node *indexkey;
Oid opclass;
int stratno;
Oid stratsubtype;
bool recheck;
Assert(IsA(rinfo, RestrictInfo));
clause = (OpExpr *) rinfo->clause;
if (!IsA(clause, OpExpr) || list_length(clause->args) != 2)
elog(ERROR, "indexqual clause is not binary opclause");
opno = clause->opno;
/*
* Check to see if the indexkey is on the right; if so, commute
* the operator. The indexkey should be the side that refers to
* (only) the base relation.
*/
if (!bms_equal(rinfo->left_relids, index->rel->relids))
{
opno = get_commutator(opno);
if (!OidIsValid(opno))
elog(ERROR, "could not find commutator for operator %u",
clause->opno);
indexkey = lsecond(clause->args);
}
else
indexkey = linitial(clause->args);
/*
* Identify the index attribute and get the index opclass.
* We use fix_indxqual_operand() which does a little more
* than we really need, but it will do.
*/
(void) fix_indxqual_operand(indexkey,
index,
&opclass);
/*
* Look up the (possibly commuted) operator in the operator class
* to get its strategy numbers and the recheck indicator. This
* also double-checks that we found an operator matching the
* index.
*/
get_op_opclass_properties(opno, opclass,
&stratno, &stratsubtype, &recheck);
/*
* Finally, we can include the clause in the result if it's
* not a lossy operator.
*/
if (!recheck)
result = lappend(result, clause);
}
}
else
{
elog(ERROR, "unrecognized node type: %d", nodeTag(bitmapqual));
result = NIL; /* keep compiler quiet */
}
return result;
}
/*
* create_tidscan_plan
* Returns a tidscan plan for the base relation scanned by 'best_path'
@ -1550,6 +1910,53 @@ make_indexscan(List *qptlist,
return node;
}
static BitmapIndexScan *
make_bitmap_indexscan(Index scanrelid,
Oid indxid,
List *indxqual,
List *indxqualorig,
List *indxstrategy,
List *indxsubtype)
{
BitmapIndexScan *node = makeNode(BitmapIndexScan);
Plan *plan = &node->scan.plan;
/* cost should be inserted by caller */
plan->targetlist = NIL; /* not used */
plan->qual = NIL; /* not used */
plan->lefttree = NULL;
plan->righttree = NULL;
node->scan.scanrelid = scanrelid;
node->indxid = indxid;
node->indxqual = indxqual;
node->indxqualorig = indxqualorig;
node->indxstrategy = indxstrategy;
node->indxsubtype = indxsubtype;
return node;
}
static BitmapHeapScan *
make_bitmap_heapscan(List *qptlist,
List *qpqual,
Plan *lefttree,
List *bitmapqualorig,
Index scanrelid)
{
BitmapHeapScan *node = makeNode(BitmapHeapScan);
Plan *plan = &node->scan.plan;
/* cost should be inserted by caller */
plan->targetlist = qptlist;
plan->qual = qpqual;
plan->lefttree = lefttree;
plan->righttree = NULL;
node->scan.scanrelid = scanrelid;
node->bitmapqualorig = bitmapqualorig;
return node;
}
static TidScan *
make_tidscan(List *qptlist,
List *qpqual,
@ -1653,6 +2060,82 @@ make_append(List *appendplans, bool isTarget, List *tlist)
return node;
}
static BitmapAnd *
make_bitmap_and(List *bitmapplans)
{
BitmapAnd *node = makeNode(BitmapAnd);
Plan *plan = &node->plan;
ListCell *subnode;
/*
* Compute cost as sum of subplan costs, plus 10x cpu_operator_cost
* (a pretty arbitrary amount, agreed) for each tbm_intersect needed.
*/
plan->startup_cost = 0;
plan->total_cost = 0;
plan->plan_rows = 0;
plan->plan_width = 0; /* meaningless */
foreach(subnode, bitmapplans)
{
Plan *subplan = (Plan *) lfirst(subnode);
if (subnode == list_head(bitmapplans)) /* first node? */
{
plan->startup_cost = subplan->startup_cost;
plan->plan_rows = subplan->plan_rows;
}
else
plan->plan_rows = Min(plan->plan_rows, subplan->plan_rows);
plan->total_cost += subplan->total_cost;
}
plan->targetlist = NIL;
plan->qual = NIL;
plan->lefttree = NULL;
plan->righttree = NULL;
node->bitmapplans = bitmapplans;
return node;
}
static BitmapOr *
make_bitmap_or(List *bitmapplans)
{
BitmapOr *node = makeNode(BitmapOr);
Plan *plan = &node->plan;
ListCell *subnode;
/*
* Compute cost as sum of subplan costs, plus 10x cpu_operator_cost
* (a pretty arbitrary amount, agreed) for each tbm_union needed.
* We assume that tbm_union can be optimized away for BitmapIndexScan
* subplans.
*/
plan->startup_cost = 0;
plan->total_cost = 0;
plan->plan_rows = 0;
plan->plan_width = 0; /* meaningless */
foreach(subnode, bitmapplans)
{
Plan *subplan = (Plan *) lfirst(subnode);
if (subnode == list_head(bitmapplans)) /* first node? */
plan->startup_cost = subplan->startup_cost;
else if (!IsA(subplan, BitmapIndexScan))
plan->total_cost += cpu_operator_cost * 10;
plan->total_cost += subplan->total_cost;
plan->plan_rows += subplan->plan_rows; /* ignore overlap */
}
plan->targetlist = NIL;
plan->qual = NIL;
plan->lefttree = NULL;
plan->righttree = NULL;
node->bitmapplans = bitmapplans;
return node;
}
static NestLoop *
make_nestloop(List *tlist,
List *joinclauses,

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.106 2005/04/06 16:34:05 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.107 2005/04/19 22:35:16 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -107,6 +107,21 @@ set_plan_references(Plan *plan, List *rtable)
fix_expr_references(plan,
(Node *) ((IndexScan *) plan)->indxqualorig);
break;
case T_BitmapIndexScan:
/* no need to fix targetlist and qual */
Assert(plan->targetlist == NIL);
Assert(plan->qual == NIL);
fix_expr_references(plan,
(Node *) ((BitmapIndexScan *) plan)->indxqual);
fix_expr_references(plan,
(Node *) ((BitmapIndexScan *) plan)->indxqualorig);
break;
case T_BitmapHeapScan:
fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual);
fix_expr_references(plan,
(Node *) ((BitmapHeapScan *) plan)->bitmapqualorig);
break;
case T_TidScan:
fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual);
@ -225,6 +240,16 @@ set_plan_references(Plan *plan, List *rtable)
foreach(l, ((Append *) plan)->appendplans)
set_plan_references((Plan *) lfirst(l), rtable);
break;
case T_BitmapAnd:
/* BitmapAnd works like Append */
foreach(l, ((BitmapAnd *) plan)->bitmapplans)
set_plan_references((Plan *) lfirst(l), rtable);
break;
case T_BitmapOr:
/* BitmapOr works like Append */
foreach(l, ((BitmapOr *) plan)->bitmapplans)
set_plan_references((Plan *) lfirst(l), rtable);
break;
default:
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(plan));

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.96 2005/04/11 23:06:55 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.97 2005/04/19 22:35:16 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1037,6 +1037,20 @@ finalize_plan(Plan *plan, List *rtable,
*/
break;
case T_BitmapIndexScan:
finalize_primnode((Node *) ((BitmapIndexScan *) plan)->indxqual,
&context);
/*
* we need not look at indxqualorig, since it will have the
* same param references as indxqual.
*/
break;
case T_BitmapHeapScan:
finalize_primnode((Node *) ((BitmapHeapScan *) plan)->bitmapqualorig,
&context);
break;
case T_TidScan:
finalize_primnode((Node *) ((TidScan *) plan)->tideval,
&context);
@ -1082,6 +1096,38 @@ finalize_plan(Plan *plan, List *rtable,
}
break;
case T_BitmapAnd:
{
ListCell *l;
foreach(l, ((BitmapAnd *) plan)->bitmapplans)
{
context.paramids =
bms_add_members(context.paramids,
finalize_plan((Plan *) lfirst(l),
rtable,
outer_params,
valid_params));
}
}
break;
case T_BitmapOr:
{
ListCell *l;
foreach(l, ((BitmapOr *) plan)->bitmapplans)
{
context.paramids =
bms_add_members(context.paramids,
finalize_plan((Plan *) lfirst(l),
rtable,
outer_params,
valid_params));
}
}
break;
case T_NestLoop:
finalize_primnode((Node *) ((Join *) plan)->joinqual,
&context);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.115 2005/04/06 16:34:06 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.116 2005/04/19 22:35:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -471,6 +471,39 @@ create_index_path(Query *root,
return pathnode;
}
/*
* create_bitmap_heap_path
* Creates a path node for a bitmap scan.
*
* 'bitmapqual' is an AND/OR tree of IndexPath nodes.
*/
BitmapHeapPath *
create_bitmap_heap_path(Query *root,
RelOptInfo *rel,
Node *bitmapqual)
{
BitmapHeapPath *pathnode = makeNode(BitmapHeapPath);
pathnode->path.pathtype = T_BitmapHeapScan;
pathnode->path.parent = rel;
pathnode->path.pathkeys = NIL; /* always unordered */
pathnode->bitmapqual = bitmapqual;
/* It's not an innerjoin path. */
pathnode->isjoininner = false;
/*
* The number of rows is the same as the parent rel's estimate, since
* this isn't a join inner indexscan.
*/
pathnode->rows = rel->rows;
cost_bitmap_scan(&pathnode->path, root, rel, bitmapqual, false);
return pathnode;
}
/*
* create_tidscan_path
* Creates a path corresponding to a tid_direct scan, returning the

View File

@ -0,0 +1,25 @@
/*-------------------------------------------------------------------------
*
* nodeBitmapAnd.h
*
*
*
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/executor/nodeBitmapAnd.h,v 1.1 2005/04/19 22:35:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef NODEBITMAPAND_H
#define NODEBITMAPAND_H
#include "nodes/execnodes.h"
extern int ExecCountSlotsBitmapAnd(BitmapAnd *node);
extern BitmapAndState *ExecInitBitmapAnd(BitmapAnd *node, EState *estate);
extern Node *MultiExecBitmapAnd(BitmapAndState *node);
extern void ExecEndBitmapAnd(BitmapAndState *node);
extern void ExecReScanBitmapAnd(BitmapAndState *node, ExprContext *exprCtxt);
#endif /* NODEBITMAPAND_H */

View File

@ -0,0 +1,25 @@
/*-------------------------------------------------------------------------
*
* nodeBitmapHeapscan.h
*
*
*
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/executor/nodeBitmapHeapscan.h,v 1.1 2005/04/19 22:35:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef NODEBITMAPHEAPSCAN_H
#define NODEBITMAPHEAPSCAN_H
#include "nodes/execnodes.h"
extern int ExecCountSlotsBitmapHeapScan(BitmapHeapScan *node);
extern BitmapHeapScanState *ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate);
extern TupleTableSlot *ExecBitmapHeapScan(BitmapHeapScanState *node);
extern void ExecEndBitmapHeapScan(BitmapHeapScanState *node);
extern void ExecBitmapHeapReScan(BitmapHeapScanState *node, ExprContext *exprCtxt);
#endif /* NODEBITMAPHEAPSCAN_H */

View File

@ -0,0 +1,25 @@
/*-------------------------------------------------------------------------
*
* nodeBitmapIndexscan.h
*
*
*
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/executor/nodeBitmapIndexscan.h,v 1.1 2005/04/19 22:35:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef NODEBITMAPINDEXSCAN_H
#define NODEBITMAPINDEXSCAN_H
#include "nodes/execnodes.h"
extern int ExecCountSlotsBitmapIndexScan(BitmapIndexScan *node);
extern BitmapIndexScanState *ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate);
extern Node *MultiExecBitmapIndexScan(BitmapIndexScanState *node);
extern void ExecEndBitmapIndexScan(BitmapIndexScanState *node);
extern void ExecBitmapIndexReScan(BitmapIndexScanState *node, ExprContext *exprCtxt);
#endif /* NODEBITMAPINDEXSCAN_H */

View File

@ -0,0 +1,25 @@
/*-------------------------------------------------------------------------
*
* nodeBitmapOr.h
*
*
*
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/executor/nodeBitmapOr.h,v 1.1 2005/04/19 22:35:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef NODEBITMAPOR_H
#define NODEBITMAPOR_H
#include "nodes/execnodes.h"
extern int ExecCountSlotsBitmapOr(BitmapOr *node);
extern BitmapOrState *ExecInitBitmapOr(BitmapOr *node, EState *estate);
extern Node *MultiExecBitmapOr(BitmapOrState *node);
extern void ExecEndBitmapOr(BitmapOrState *node);
extern void ExecReScanBitmapOr(BitmapOrState *node, ExprContext *exprCtxt);
#endif /* NODEBITMAPOR_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/executor/nodeIndexscan.h,v 1.21 2004/12/31 22:03:29 pgsql Exp $
* $PostgreSQL: pgsql/src/include/executor/nodeIndexscan.h,v 1.22 2005/04/19 22:35:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -24,6 +24,4 @@ extern void ExecIndexMarkPos(IndexScanState *node);
extern void ExecIndexRestrPos(IndexScanState *node);
extern void ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt);
extern void ExecUpdateIndexScanKeys(IndexScanState *node, ExprContext *econtext);
#endif /* NODEINDEXSCAN_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.125 2005/03/25 21:58:00 tgl Exp $
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.126 2005/04/19 22:35:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -20,6 +20,7 @@
#include "nodes/bitmapset.h"
#include "nodes/params.h"
#include "nodes/plannodes.h"
#include "nodes/tidbitmap.h"
#include "utils/hsearch.h"
#include "utils/tuplestore.h"
@ -803,6 +804,28 @@ typedef struct AppendState
int as_lastplan;
} AppendState;
/* ----------------
* BitmapAndState information
* ----------------
*/
typedef struct BitmapAndState
{
PlanState ps; /* its first field is NodeTag */
PlanState **bitmapplans; /* array of PlanStates for my inputs */
int nplans; /* number of input plans */
} BitmapAndState;
/* ----------------
* BitmapOrState information
* ----------------
*/
typedef struct BitmapOrState
{
PlanState ps; /* its first field is NodeTag */
PlanState **bitmapplans; /* array of PlanStates for my inputs */
int nplans; /* number of input plans */
} BitmapOrState;
/* ----------------------------------------------------------------
* Scan State Information
* ----------------------------------------------------------------
@ -875,6 +898,53 @@ typedef struct IndexScanState
long iss_MaxHash;
} IndexScanState;
/* ----------------
* BitmapIndexScanState information
*
* ScanKeys Skey structures to scan index rel
* NumScanKeys number of Skey structs
* RuntimeKeyInfo array of exprstates for Skeys
* that will be evaluated at runtime
* RuntimeContext expr context for evaling runtime Skeys
* RuntimeKeysReady true if runtime Skeys have been computed
* RelationDesc relation descriptor
* ScanDesc scan descriptor
* ----------------
*/
typedef struct BitmapIndexScanState
{
ScanState ss; /* its first field is NodeTag */
ScanKey biss_ScanKeys;
int biss_NumScanKeys;
ExprState **biss_RuntimeKeyInfo;
ExprContext *biss_RuntimeContext;
bool biss_RuntimeKeysReady;
Relation biss_RelationDesc;
IndexScanDesc biss_ScanDesc;
} BitmapIndexScanState;
/* ----------------
* BitmapHeapScanState information
*
* bitmapqualorig execution state for bitmapqualorig expressions
* tbm bitmap obtained from child index scan(s)
* tbmres current-page data
* curslot current tbmres index or tuple offset on page
* minslot lowest tbmres index or tuple offset to try
* maxslot highest tbmres index or tuple offset to try
* ----------------
*/
typedef struct BitmapHeapScanState
{
ScanState ss; /* its first field is NodeTag */
List *bitmapqualorig;
TIDBitmap *tbm;
TBMIterateResult *tbmres;
int curslot;
int minslot;
int maxslot;
} BitmapHeapScanState;
/* ----------------
* TidScanState information
*

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.166 2005/04/17 22:24:02 tgl Exp $
* $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.167 2005/04/19 22:35:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -44,9 +44,13 @@ typedef enum NodeTag
T_Plan = 100,
T_Result,
T_Append,
T_BitmapAnd,
T_BitmapOr,
T_Scan,
T_SeqScan,
T_IndexScan,
T_BitmapIndexScan,
T_BitmapHeapScan,
T_TidScan,
T_SubqueryScan,
T_FunctionScan,
@ -71,9 +75,13 @@ typedef enum NodeTag
T_PlanState = 200,
T_ResultState,
T_AppendState,
T_BitmapAndState,
T_BitmapOrState,
T_ScanState,
T_SeqScanState,
T_IndexScanState,
T_BitmapIndexScanState,
T_BitmapHeapScanState,
T_TidScanState,
T_SubqueryScanState,
T_FunctionScanState,
@ -161,6 +169,7 @@ typedef enum NodeTag
T_IndexOptInfo,
T_Path,
T_IndexPath,
T_BitmapHeapPath,
T_NestPath,
T_MergePath,
T_HashPath,

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.77 2004/12/31 22:03:34 pgsql Exp $
* $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.78 2005/04/19 22:35:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -134,6 +134,34 @@ typedef struct Append
bool isTarget;
} Append;
/* ----------------
* BitmapAnd node -
* Generate the intersection of the results of sub-plans.
*
* The subplans must be of types that yield tuple bitmaps. The targetlist
* and qual fields of the plan are unused and are always NIL.
* ----------------
*/
typedef struct BitmapAnd
{
Plan plan;
List *bitmapplans;
} BitmapAnd;
/* ----------------
* BitmapOr node -
* Generate the union of the results of sub-plans.
*
* The subplans must be of types that yield tuple bitmaps. The targetlist
* and qual fields of the plan are unused and are always NIL.
* ----------------
*/
typedef struct BitmapOr
{
Plan plan;
List *bitmapplans;
} BitmapOr;
/*
* ==========
* Scan nodes
@ -156,6 +184,8 @@ typedef Scan SeqScan;
*
* Note: this can actually represent N indexscans, all on the same table
* but potentially using different indexes, put together with OR semantics.
* (XXX that extension should probably go away, because bitmapindexscan will
* largely eliminate the need for it.)
* ----------------
*/
typedef struct IndexScan
@ -171,7 +201,46 @@ typedef struct IndexScan
} IndexScan;
/* ----------------
* tid scan node
* bitmap index scan node
*
* BitmapIndexScan delivers a bitmap of potential tuple locations;
* it does not access the heap itself. The bitmap is used by an
* ancestor BitmapHeapScan node, possibly after passing through
* intermediate BitmapAnd and/or BitmapOr nodes to combine it with
* the results of other BitmapIndexScans.
*
* In a BitmapIndexScan plan node, the targetlist and qual fields are
* not used and are always NIL. The indxqualorig field is useless at
* run time too, but is saved for the benefit of EXPLAIN.
* ----------------
*/
typedef struct BitmapIndexScan
{
Scan scan;
Oid indxid; /* OID of index to scan */
List *indxqual; /* list of index quals */
List *indxqualorig; /* list of original forms of index quals */
List *indxstrategy; /* list of strategy numbers */
List *indxsubtype; /* list of strategy subtypes */
} BitmapIndexScan;
/* ----------------
* bitmap sequential scan node
*
* This needs a copy of the qual conditions being used by the input index
* scans because there are various cases where we need to recheck the quals;
* for example, when the bitmap is lossy about the specific rows on a page
* that meet the index condition.
* ----------------
*/
typedef struct BitmapHeapScan
{
Scan scan;
List *bitmapqualorig; /* index quals, in standard expr form */
} BitmapHeapScan;
/* ----------------
* tid scan node
* ----------------
*/
typedef struct TidScan

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.104 2005/03/27 06:29:45 tgl Exp $
* $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.105 2005/04/19 22:35:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -342,6 +342,9 @@ typedef struct Path
* tuples matched during any scan. (The executor is smart enough not to return
* the same tuple more than once, even if it is matched in multiple scans.)
*
* XXX bitmap index scans will probably obviate the need for plain OR
* indexscans, allowing a lot of this to be simplified.
*
* 'indexinfo' is a list of IndexOptInfo nodes, one per scan to be performed.
*
* 'indexclauses' is a list of index qualifications, also one per scan.
@ -389,6 +392,30 @@ typedef struct IndexPath
double rows; /* estimated number of result tuples */
} IndexPath;
/*
* BitmapHeapPath represents one or more indexscans that generate TID bitmaps
* instead of directly accessing the heap, followed by AND/OR combinations
* to produce a single bitmap, followed by a heap scan that uses the bitmap.
* Note that the output is always considered unordered, since it will come
* out in physical heap order no matter what the underlying indexes did.
*
* The individual indexscans are represented by IndexPath nodes, and any
* logic on top of them is represented by regular AND and OR expressions.
* Notice that we can use the same IndexPath node both to represent an
* ordered index scan, and as the child of a BitmapHeapPath that represents
* scanning the same index in an unordered way.
*
* BitmapHeapPaths can be nestloop inner indexscans. The isjoininner and
* rows fields serve the same purpose as for plain IndexPaths.
*/
typedef struct BitmapHeapPath
{
Path path;
Node *bitmapqual; /* the IndexPath/AND/OR tree */
bool isjoininner; /* T if it's a nestloop inner scan */
double rows; /* estimated number of result tuples */
} BitmapHeapPath;
/*
* TidPath represents a scan by TID
*

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/optimizer/cost.h,v 1.63 2005/03/27 06:29:49 tgl Exp $
* $PostgreSQL: pgsql/src/include/optimizer/cost.h,v 1.64 2005/04/19 22:35:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -53,6 +53,8 @@ extern double clamp_row_est(double nrows);
extern void cost_seqscan(Path *path, Query *root, RelOptInfo *baserel);
extern void cost_index(Path *path, Query *root, IndexOptInfo *index,
List *indexQuals, bool is_injoin);
extern void cost_bitmap_scan(Path *path, Query *root, RelOptInfo *baserel,
Node *bitmapqual, bool is_injoin);
extern void cost_tidscan(Path *path, Query *root,
RelOptInfo *baserel, List *tideval);
extern void cost_subqueryscan(Path *path, RelOptInfo *baserel);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/optimizer/pathnode.h,v 1.57 2005/03/27 06:29:49 tgl Exp $
* $PostgreSQL: pgsql/src/include/optimizer/pathnode.h,v 1.58 2005/04/19 22:35:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -33,6 +33,9 @@ extern IndexPath *create_index_path(Query *root,
List *restriction_clauses,
List *pathkeys,
ScanDirection indexscandir);
extern BitmapHeapPath *create_bitmap_heap_path(Query *root,
RelOptInfo *rel,
Node *bitmapqual);
extern TidPath *create_tidscan_path(Query *root, RelOptInfo *rel,
List *tideval);
extern AppendPath *create_append_path(RelOptInfo *rel, List *subpaths);