
got an empty bitmap after any step; the remaining subplans can no longer affect the result. Per a suggestion from Ilia Kantor.
222 lines
5.4 KiB
C
222 lines
5.4 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* 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.3 2005/08/28 22:47:20 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;
|
|
ListCell *l;
|
|
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".
|
|
*/
|
|
i = 0;
|
|
foreach(l, node->bitmapplans)
|
|
{
|
|
initNode = (Plan *) lfirst(l);
|
|
bitmapplanstates[i] = ExecInitNode(initNode, estate);
|
|
i++;
|
|
}
|
|
|
|
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 at any stage we have a completely empty bitmap, we can fall
|
|
* out without evaluating the remaining subplans, since ANDing them
|
|
* can no longer change the result. (Note: the fact that indxpath.c
|
|
* orders the subplans by selectivity should make this case more
|
|
* likely to occur.)
|
|
*/
|
|
if (tbm_is_empty(result))
|
|
break;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|