diff options
Diffstat (limited to 'src/backend/executor/nodeBitmapOr.c')
-rw-r--r-- | src/backend/executor/nodeBitmapOr.c | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/src/backend/executor/nodeBitmapOr.c b/src/backend/executor/nodeBitmapOr.c new file mode 100644 index 0000000..4a8c01d --- /dev/null +++ b/src/backend/executor/nodeBitmapOr.c @@ -0,0 +1,241 @@ +/*------------------------------------------------------------------------- + * + * nodeBitmapOr.c + * routines to handle BitmapOr nodes. + * + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/executor/nodeBitmapOr.c + * + *------------------------------------------------------------------------- + */ +/* 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/nodeBitmapOr.h" +#include "miscadmin.h" + + +/* ---------------------------------------------------------------- + * ExecBitmapOr + * + * stub for pro forma compliance + * ---------------------------------------------------------------- + */ +static TupleTableSlot * +ExecBitmapOr(PlanState *pstate) +{ + elog(ERROR, "BitmapOr node does not support ExecProcNode call convention"); + return NULL; +} + +/* ---------------------------------------------------------------- + * ExecInitBitmapOr + * + * Begin all of the subscans of the BitmapOr node. + * ---------------------------------------------------------------- + */ +BitmapOrState * +ExecInitBitmapOr(BitmapOr *node, EState *estate, int eflags) +{ + BitmapOrState *bitmaporstate = makeNode(BitmapOrState); + PlanState **bitmapplanstates; + int nplans; + int i; + ListCell *l; + Plan *initNode; + + /* check for unsupported flags */ + Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); + + /* + * 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->ps.ExecProcNode = ExecBitmapOr; + bitmaporstate->bitmapplans = bitmapplanstates; + bitmaporstate->nplans = nplans; + + /* + * 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, eflags); + i++; + } + + /* + * Miscellaneous initialization + * + * BitmapOr plans don't have expression contexts because they never call + * ExecQual or ExecProject. They don't need any tuple slots either. + */ + + return bitmaporstate; +} + +/* ---------------------------------------------------------------- + * 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; + + /* + * We can special-case BitmapIndexScan children to avoid an explicit + * tbm_union step for each child: just pass down the current result + * bitmap and let the child OR directly into it. + */ + if (IsA(subnode, BitmapIndexScanState)) + { + if (result == NULL) /* first subplan */ + { + /* XXX should we use less than work_mem for this? */ + result = tbm_create(work_mem * 1024L, + ((BitmapOr *) node->ps.plan)->isshared ? + node->ps.state->es_query_dsa : NULL); + } + + ((BitmapIndexScanState *) subnode)->biss_result = result; + + subresult = (TIDBitmap *) MultiExecProcNode(subnode); + + if (subresult != result) + elog(ERROR, "unrecognized result from subplan"); + } + else + { + /* standard implementation */ + 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) + InstrStopNode(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) +{ + 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); + + /* + * If chgParam of subnode is not null then plan will be re-scanned by + * first ExecProcNode. + */ + if (subnode->chgParam == NULL) + ExecReScan(subnode); + } +} |