Files
openGauss-server/src/gausskernel/runtime/executor/nodeBitmapOr.cpp

233 lines
7.4 KiB
C++

/* -------------------------------------------------------------------------
*
* nodeBitmapOr.cpp
* routines to handle BitmapOr nodes.
*
* Portions Copyright (c) 2020 Huawei Technologies Co.,Ltd.
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* src/gausskernel/runtime/executor/nodeBitmapOr.cpp
*
* -------------------------------------------------------------------------
*
* 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 "knl/knl_variable.h"
#include "executor/exec/execdebug.h"
#include "executor/node/nodeBitmapOr.h"
#include "miscadmin.h"
/* ----------------------------------------------------------------
* 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 = NULL;
Plan* initNode = NULL;
/* 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->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.
*/
/*
* 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++;
}
return bitmaporstate;
}
/* ----------------------------------------------------------------
* MultiExecBitmapOr
* ----------------------------------------------------------------
*/
Node* MultiExecBitmapOr(BitmapOrState* node)
{
PlanState** bitmapplans;
int nplans;
int i;
TIDBitmap* result = NULL;
bool isUstore = ((BitmapOr*)node->ps.plan)->is_ustore;
/* 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];
subnode->hbktScanSlot.currSlot = node->ps.hbktScanSlot.currSlot;
TIDBitmap* subresult = NULL;
/*
* 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)) {
/* first subplan */
if (result == NULL) {
/* XXX should we use less than u_sess->attr.attr_memory.work_mem for this? */
long maxbytes = u_sess->attr.attr_memory.work_mem * 1024L;
result = tbm_create(maxbytes,
RelationIsGlobalIndex(((BitmapIndexScanState *)subnode)->biss_RelationDesc),
RelationIsCrossBucketIndex(((BitmapIndexScanState *)subnode)->biss_RelationDesc),
isUstore);
}
((BitmapIndexScanState*)subnode)->biss_result = result;
subresult = (TIDBitmap*)MultiExecProcNode(subnode);
if (subresult != result) {
ereport(ERROR,
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
errmsg("unrecognized result from BitmapIndexScan subplan when execute BitmapOr")));
}
} else {
/* standard implementation */
subresult = (TIDBitmap*)MultiExecProcNode(subnode);
if (subresult == NULL || !IsA(subresult, TIDBitmap)) {
ereport(ERROR,
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
errmsg("unrecognized result from non-BitmapIndexScan subplan when execute BitmapOr")));
}
if (result == NULL) {
result = subresult; /* first subplan */
} else {
TBMHandler tbm_handler = tbm_get_handler(result);
if (tbm_is_global(result) != tbm_is_global(subresult)) {
ereport(ERROR,
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
errmsg(
"do not support bitmap index scan for global index and local index simultaneously.")));
}
tbm_handler._union(result, subresult);
tbm_free(subresult);
}
}
}
/* We could return an empty result set here? */
if (result == NULL) {
ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("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);
}
}