188 lines
6.4 KiB
C++
Executable File
188 lines
6.4 KiB
C++
Executable File
/*
|
|
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
|
|
*
|
|
* openGauss is licensed under Mulan PSL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
* You may obtain a copy of Mulan PSL v2 at:
|
|
*
|
|
* http://license.coscl.org.cn/MulanPSL2
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
* See the Mulan PSL v2 for more details.
|
|
* ---------------------------------------------------------------------------------------
|
|
*
|
|
* nodeExtensible.cpp
|
|
* ExtensiblePlan is an extended plan node which supports various customize operations.
|
|
* Normally we built our ExtensiblePlan on the upper level of the original plan.
|
|
* To implement the ExtensiblePlan, we should first implement BeginExtensiblePlan() method,
|
|
* ExecExtensiblePlan() method, EndExtensiblePlan() method ReScanExtensiblePlan() method.
|
|
*
|
|
* IDENTIFICATION
|
|
* src/gausskernel/runtime/executor/nodeExtensible.cpp
|
|
*
|
|
* ---------------------------------------------------------------------------------------
|
|
*/
|
|
#include "postgres.h"
|
|
#include "knl/knl_variable.h"
|
|
|
|
#include "executor/executor.h"
|
|
#include "executor/nodeExtensible.h"
|
|
#include "nodes/execnodes.h"
|
|
#include "nodes/plannodes.h"
|
|
#include "parser/parsetree.h"
|
|
#include "utils/hsearch.h"
|
|
#include "utils/memutils.h"
|
|
#include "utils/rel.h"
|
|
|
|
const int EXTNODENAME_MAX_LEN = 64;
|
|
static HTAB* g_extensible_plan_methods = NULL;
|
|
const int HASHTABLE_LENGTH = 100;
|
|
|
|
typedef struct {
|
|
char extnodename[EXTNODENAME_MAX_LEN];
|
|
void* extnodemethods;
|
|
} ExtensibleNodeEntry;
|
|
|
|
ExtensiblePlanState* ExecInitExtensiblePlan(ExtensiblePlan* eplan, EState* estate, int eflags)
|
|
{
|
|
ExtensiblePlanState* extensionPlanState;
|
|
Relation scan_rel = NULL;
|
|
Index scanrelid = eplan->scan.scanrelid;
|
|
Index tlistvarno;
|
|
|
|
/*
|
|
* Allocate the ExtensiblePlanState object. We let the extensible scan provider
|
|
* do the palloc, in case it wants to make a larger object that embeds
|
|
* ExtensiblePlanState as the first field. It must set the node tag and the
|
|
* methods field correctly at this time. Other standard fields should be
|
|
* set to zero.
|
|
*/
|
|
extensionPlanState = (ExtensiblePlanState*)eplan->methods->CreateExtensiblePlanState(eplan);
|
|
|
|
/* ensure flags is filled correctly */
|
|
extensionPlanState->flags = eplan->flags;
|
|
|
|
/* fill up fields of ScanState */
|
|
extensionPlanState->ss.ps.plan = &eplan->scan.plan;
|
|
extensionPlanState->ss.ps.state = estate;
|
|
|
|
/* create expression context for node */
|
|
ExecAssignExprContext(estate, &extensionPlanState->ss.ps);
|
|
|
|
extensionPlanState->ss.ps.ps_TupFromTlist = false;
|
|
|
|
/* initialize child expressions */
|
|
extensionPlanState->ss.ps.targetlist =
|
|
(List*)ExecInitExpr((Expr*)eplan->scan.plan.targetlist, (PlanState*)extensionPlanState);
|
|
extensionPlanState->ss.ps.qual = (List*)ExecInitExpr((Expr*)eplan->scan.plan.qual, (PlanState*)extensionPlanState);
|
|
|
|
/* tuple table initialization */
|
|
ExecInitScanTupleSlot(estate, &extensionPlanState->ss);
|
|
ExecInitResultTupleSlot(estate, &extensionPlanState->ss.ps);
|
|
|
|
/*
|
|
* open the base relation, if any, and acquire an appropriate lock on it
|
|
*/
|
|
if (scanrelid > 0) {
|
|
scan_rel = ExecOpenScanRelation(estate, scanrelid);
|
|
extensionPlanState->ss.ss_currentRelation = scan_rel;
|
|
}
|
|
|
|
/*
|
|
* Determine the scan tuple type. If the extensible scan provider provided a
|
|
* targetlist describing the scan tuples, use that; else use base
|
|
* relation's rowtype.
|
|
*/
|
|
if (eplan->extensible_plan_tlist != NIL || scan_rel == NULL) {
|
|
TupleDesc scan_tupdesc;
|
|
|
|
scan_tupdesc = ExecTypeFromTL(eplan->extensible_plan_tlist, false);
|
|
ExecAssignScanType(&extensionPlanState->ss, scan_tupdesc);
|
|
/* Node's targetlist will contain Vars with varno = INDEX_VAR */
|
|
tlistvarno = INDEX_VAR;
|
|
} else {
|
|
ExecAssignScanType(&extensionPlanState->ss, RelationGetDescr(scan_rel));
|
|
/* Node's targetlist will contain Vars with varno = scanrelid */
|
|
tlistvarno = scanrelid;
|
|
}
|
|
|
|
/*
|
|
* Initialize result tuple type and projection info.
|
|
*/
|
|
ExecAssignResultTypeFromTL(&extensionPlanState->ss.ps);
|
|
ExecAssignScanProjectionInfoWithVarno(&extensionPlanState->ss, tlistvarno);
|
|
|
|
/*
|
|
* The callback of extensible-scan provider applies the final initialization
|
|
* of the extensible-scan-state node according to its logic.
|
|
*/
|
|
extensionPlanState->methods->BeginExtensiblePlan(extensionPlanState, estate, eflags);
|
|
|
|
return extensionPlanState;
|
|
}
|
|
|
|
TupleTableSlot* ExecExtensiblePlan(ExtensiblePlanState* node)
|
|
{
|
|
Assert(node->methods->ExecExtensiblePlan != NULL);
|
|
return node->methods->ExecExtensiblePlan(node);
|
|
}
|
|
|
|
void ExecEndExtensiblePlan(ExtensiblePlanState* node)
|
|
{
|
|
Assert(node->methods->EndExtensiblePlan != NULL);
|
|
node->methods->EndExtensiblePlan(node);
|
|
|
|
/* Free the exprcontext */
|
|
ExecFreeExprContext(&node->ss.ps);
|
|
|
|
/* Clean out the tuple table */
|
|
(void)ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
|
|
(void)ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
|
|
|
/* Close the heap relation */
|
|
if (node->ss.ss_currentRelation) {
|
|
ExecCloseScanRelation(node->ss.ss_currentRelation);
|
|
}
|
|
}
|
|
|
|
void ExecReScanExtensiblePlan(ExtensiblePlanState* node)
|
|
{
|
|
Assert(node->methods->ReScanExtensiblePlan != NULL);
|
|
node->methods->ReScanExtensiblePlan(node);
|
|
}
|
|
|
|
/*
|
|
* An internal routine to get an ExtensibleNodeEntry by the given identifier
|
|
*/
|
|
static void* GetExtensibleNodeEntry(HTAB* htable, const char* extnodename, bool missing_ok)
|
|
{
|
|
ExtensibleNodeEntry* entry = NULL;
|
|
|
|
if (htable != NULL) {
|
|
entry = (ExtensibleNodeEntry*)hash_search(htable, extnodename, HASH_FIND, NULL);
|
|
}
|
|
if (entry != NULL) {
|
|
if (missing_ok) {
|
|
return NULL;
|
|
}
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
errmsg("ExtensibleNodeMethods \"%s\" was not registered", extnodename)));
|
|
}
|
|
if (entry != NULL) {
|
|
return entry->extnodemethods;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Get the methods for a given name of ExtensiblePlanMethods
|
|
*/
|
|
ExtensiblePlanMethods* GetExtensiblePlanMethods(const char* ExtensibleName, bool missing_ok)
|
|
{
|
|
return (ExtensiblePlanMethods*)GetExtensibleNodeEntry(g_extensible_plan_methods, ExtensibleName, missing_ok);
|
|
}
|