Files
openGauss-server/src/gausskernel/runtime/executor/execAmi.cpp
dengxuyue c7b25efcff New features (and bug fixes)
1. alter large sequence
    2. subpartition
    2.1 split subpartition
    2.2 truncate subpartition
    3. 支持load
    4. 支持start-with/connect-by
    5. ...
2021-12-29 21:33:28 +08:00

646 lines
19 KiB
C++
Executable File

/* -------------------------------------------------------------------------
*
* execAmi.cpp
* miscellaneous executor access method routines
*
* 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
* Portions Copyright (c) 2021, openGauss Contributors
*
* IDENTIFICATION
* src/gausskernel/runtime/executor/execAmi.cpp
*
* -------------------------------------------------------------------------
*/
#include "postgres.h"
#include "knl/knl_variable.h"
#include "executor/exec/execdebug.h"
#include "executor/node/nodeAgg.h"
#include "executor/node/nodeAppend.h"
#include "executor/node/nodeBitmapAnd.h"
#include "executor/node/nodeBitmapHeapscan.h"
#include "executor/node/nodeBitmapIndexscan.h"
#include "executor/node/nodeBitmapOr.h"
#include "executor/node/nodeCtescan.h"
#include "executor/node/nodeExtensible.h"
#include "executor/node/nodeForeignscan.h"
#include "executor/node/nodeFunctionscan.h"
#include "executor/node/nodeGroup.h"
#include "executor/node/nodeGroup.h"
#include "executor/node/nodeHash.h"
#include "executor/node/nodeHashjoin.h"
#include "executor/node/nodeIndexonlyscan.h"
#include "executor/node/nodeIndexscan.h"
#include "executor/node/nodeLimit.h"
#include "executor/node/nodeLockRows.h"
#include "executor/node/nodeMaterial.h"
#include "executor/node/nodeMergeAppend.h"
#include "executor/node/nodeMergejoin.h"
#include "executor/node/nodeModifyTable.h"
#include "executor/node/nodeNestloop.h"
#include "executor/node/nodePartIterator.h"
#include "executor/node/nodeRecursiveunion.h"
#include "executor/node/nodeResult.h"
#include "executor/node/nodeSeqscan.h"
#include "executor/node/nodeSetOp.h"
#include "executor/node/nodeSort.h"
#include "executor/node/nodeSubplan.h"
#include "executor/node/nodeSubqueryscan.h"
#include "executor/node/nodeTidscan.h"
#include "executor/node/nodeUnique.h"
#include "executor/node/nodeValuesscan.h"
#include "executor/node/nodeWindowAgg.h"
#include "executor/node/nodeWorktablescan.h"
#include "nodes/nodeFuncs.h"
#include "vecexecutor/vecnodes.h"
#include "vecexecutor/vecnodevectorow.h"
#include "utils/rel.h"
#include "utils/rel_gs.h"
#include "utils/syscache.h"
#ifdef PGXC
#include "pgxc/execRemote.h"
#endif
static bool target_list_supports_backward_scan(List* targetlist);
static bool index_supports_backward_scan(Oid indexid);
/*
* ExecReScan
* Reset a plan node so that its output can be re-scanned.
*
* Note that if the plan node has parameters that have changed value,
* the output might be different from last time.
*/
void ExecReScanByType(PlanState* node)
{
/* If collecting timing stats, update them */
/*
* If we have changed parameters, propagate that info.
*
* Note: ExecReScanSetParamPlan() can add bits to node->chgParam,
* corresponding to the output param(s) that the InitPlan will update.
* Since we make only one pass over the list, that means that an InitPlan
* can depend on the output param(s) of a sibling InitPlan only if that
* sibling appears earlier in the list. This is workable for now given
* the limited ways in which one InitPlan could depend on another, but
* eventually we might need to work harder (or else make the planner
* enlarge the extParam/allParam sets to include the params of depended-on
* InitPlans).
*/
/* Well. Now set chgParam for left/right trees. */
/* Shut down any SRFs in the plan node's targetlist */
/* If need stub execution, stop rescan here */
/* And do node-type-specific processing */
switch (nodeTag(node)) {
case T_ResultState:
ExecReScanResult((ResultState*)node);
break;
case T_ModifyTableState:
case T_DistInsertSelectState:
ExecReScanModifyTable((ModifyTableState*)node);
break;
case T_AppendState:
ExecReScanAppend((AppendState*)node);
break;
case T_MergeAppendState:
ExecReScanMergeAppend((MergeAppendState*)node);
break;
case T_RecursiveUnionState:
ExecReScanRecursiveUnion((RecursiveUnionState*)node);
break;
case T_StartWithOpState:
ExecReScanStartWithOp((StartWithOpState *)node);
break;
case T_BitmapAndState:
ExecReScanBitmapAnd((BitmapAndState*)node);
break;
case T_BitmapOrState:
ExecReScanBitmapOr((BitmapOrState*)node);
break;
case T_SeqScanState:
ExecReScanSeqScan((SeqScanState*)node);
break;
case T_IndexScanState:
ExecReScanIndexScan((IndexScanState*)node);
break;
case T_IndexOnlyScanState:
ExecReScanIndexOnlyScan((IndexOnlyScanState*)node);
break;
case T_BitmapIndexScanState:
ExecReScanBitmapIndexScan((BitmapIndexScanState*)node);
break;
case T_BitmapHeapScanState:
ExecReScanBitmapHeapScan((BitmapHeapScanState*)node);
break;
case T_TidScanState:
ExecReScanTidScan((TidScanState*)node);
break;
case T_SubqueryScanState:
ExecReScanSubqueryScan((SubqueryScanState*)node);
break;
case T_FunctionScanState:
ExecReScanFunctionScan((FunctionScanState*)node);
break;
case T_ValuesScanState:
ExecReScanValuesScan((ValuesScanState*)node);
break;
case T_CteScanState:
ExecReScanCteScan((CteScanState*)node);
break;
case T_WorkTableScanState:
ExecReScanWorkTableScan((WorkTableScanState*)node);
break;
case T_ForeignScanState:
ExecReScanForeignScan((ForeignScanState*)node);
break;
case T_ExtensiblePlanState:
ExecReScanExtensiblePlan((ExtensiblePlanState*)node);
break;
/*
* partition iterator node
*/
case T_PartIteratorState:
ExecReScanPartIterator((PartIteratorState*)node);
break;
#ifdef PGXC
case T_RemoteQueryState:
ExecRemoteQueryReScan((RemoteQueryState*)node, node->ps_ExprContext);
break;
#endif
case T_NestLoopState:
ExecReScanNestLoop((NestLoopState*)node);
break;
case T_MergeJoinState:
ExecReScanMergeJoin((MergeJoinState*)node);
break;
case T_HashJoinState:
ExecReScanHashJoin((HashJoinState*)node);
break;
case T_MaterialState:
ExecReScanMaterial((MaterialState*)node);
break;
case T_SortState:
ExecReScanSort((SortState*)node);
break;
case T_GroupState:
ExecReScanGroup((GroupState*)node);
break;
case T_AggState:
ExecReScanAgg((AggState*)node);
break;
case T_WindowAggState:
ExecReScanWindowAgg((WindowAggState*)node);
break;
case T_UniqueState:
ExecReScanUnique((UniqueState*)node);
break;
case T_HashState:
ExecReScanHash((HashState*)node);
break;
case T_SetOpState:
ExecReScanSetOp((SetOpState*)node);
break;
case T_LockRowsState:
ExecReScanLockRows((LockRowsState*)node);
break;
case T_LimitState:
ExecReScanLimit((LimitState*)node);
break;
case T_VecToRowState:
ExecReScanVecToRow((VecToRowState*)node);
break;
default:
ereport(ERROR,
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
errmsg("unrecognized node type: %d when rescan", (int)nodeTag(node))));
break;
}
}
/*
* ExecReScan
* Reset a plan node so that its output can be re-scanned.
*
* Note that if the plan node has parameters that have changed value,
* the output might be different from last time.
*/
void ExecReScan(PlanState* node)
{
/* If collecting timing stats, update them */
if (node->instrument) {
InstrEndLoop(node->instrument);
}
/* reset the rownum */
if (!node->do_not_reset_rownum) {
node->ps_rownum = 0;
}
/*
* If we have changed parameters, propagate that info.
*
* Note: ExecReScanSetParamPlan() can add bits to node->chgParam,
* corresponding to the output param(s) that the InitPlan will update.
* Since we make only one pass over the list, that means that an InitPlan
* can depend on the output param(s) of a sibling InitPlan only if that
* sibling appears earlier in the list. This is workable for now given
* the limited ways in which one InitPlan could depend on another, but
* eventually we might need to work harder (or else make the planner
* enlarge the extParam/allParam sets to include the params of depended-on
* InitPlans).
*/
if (node->chgParam != NULL) {
ListCell* l = NULL;
foreach (l, node->initPlan) {
SubPlanState* sstate = (SubPlanState*)lfirst(l);
PlanState* splan = sstate->planstate;
if (splan->plan->extParam != NULL) {
/* don't care about child local Params */
UpdateChangedParamSet(splan, node->chgParam);
}
if (splan->chgParam != NULL) {
ExecReScanSetParamPlan(sstate, node);
}
}
foreach (l, node->subPlan) {
SubPlanState* sstate = (SubPlanState*)lfirst(l);
PlanState* splan = sstate->planstate;
if (splan->plan->extParam != NULL) {
UpdateChangedParamSet(splan, node->chgParam);
}
}
/* Well. Now set chgParam for left/right trees. */
if (node->lefttree != NULL) {
UpdateChangedParamSet(node->lefttree, node->chgParam);
}
if (node->righttree != NULL) {
UpdateChangedParamSet(node->righttree, node->chgParam);
}
}
/* Shut down any SRFs in the plan node's targetlist */
if (node->ps_ExprContext) {
ReScanExprContext(node->ps_ExprContext);
}
/* If need stub execution, stop rescan here */
if (!planstate_need_stub(node)) {
if (IS_PGXC_DATANODE && EXEC_IN_RECURSIVE_MODE(node->plan) && IsA(node, StreamState)) {
return;
}
ExecReScanByType(node);
}
if (node->chgParam != NULL) {
bms_free_ext(node->chgParam);
node->chgParam = NULL;
}
}
/*
* ExecMarkPos
*
* Marks the current scan position.
*/
void ExecMarkPos(PlanState* node)
{
switch (nodeTag(node)) {
case T_SeqScanState:
ExecSeqMarkPos((SeqScanState*)node);
break;
case T_IndexScanState:
ExecIndexMarkPos((IndexScanState*)node);
break;
case T_IndexOnlyScanState:
ExecIndexOnlyMarkPos((IndexOnlyScanState*)node);
break;
case T_TidScanState:
ExecTidMarkPos((TidScanState*)node);
break;
case T_ValuesScanState:
ExecValuesMarkPos((ValuesScanState*)node);
break;
case T_MaterialState:
ExecMaterialMarkPos((MaterialState*)node);
break;
case T_SortState:
ExecSortMarkPos((SortState*)node);
break;
case T_ResultState:
ExecResultMarkPos((ResultState*)node);
break;
default:
/* don't make hard error unless caller asks to restore... */
elog(DEBUG2, "unrecognized node type: %d", (int)nodeTag(node));
break;
}
}
/*
* ExecRestrPos
*
* restores the scan position previously saved with ExecMarkPos()
*
* NOTE: the semantics of this are that the first ExecProcNode following
* the restore operation will yield the same tuple as the first one following
* the mark operation. It is unspecified what happens to the plan node's
* result TupleTableSlot. (In most cases the result slot is unchanged by
* a restore, but the node may choose to clear it or to load it with the
* restored-to tuple.) Hence the caller should discard any previously
* returned TupleTableSlot after doing a restore.
*/
void ExecRestrPos(PlanState* node)
{
switch (nodeTag(node)) {
case T_SeqScanState:
ExecSeqRestrPos((SeqScanState*)node);
break;
case T_IndexScanState:
ExecIndexRestrPos((IndexScanState*)node);
break;
case T_IndexOnlyScanState:
ExecIndexOnlyRestrPos((IndexOnlyScanState*)node);
break;
case T_TidScanState:
ExecTidRestrPos((TidScanState*)node);
break;
case T_ValuesScanState:
ExecValuesRestrPos((ValuesScanState*)node);
break;
case T_MaterialState:
ExecMaterialRestrPos((MaterialState*)node);
break;
case T_SortState:
ExecSortRestrPos((SortState*)node);
break;
case T_ResultState:
ExecResultRestrPos((ResultState*)node);
break;
default:
ereport(ERROR,
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
errmsg("unrecognized node type: %d when restore scan position", (int)nodeTag(node))));
break;
}
}
/*
* ExecSupportsMarkRestore - does a plan type support mark/restore?
*
* XXX Ideally, all plan node types would support mark/restore, and this
* wouldn't be needed. For now, this had better match the routines above.
* But note the test is on Plan nodetype, not PlanState nodetype.
*
* (However, since the only present use of mark/restore is in mergejoin,
* there is no need to support mark/restore in any plan type that is not
* capable of generating ordered output. So the seqscan, tidscan,
* and valuesscan support is actually useless code at present.)
*/
bool ExecSupportsMarkRestore(Path *pathnode)
{
switch (pathnode->pathtype) {
case T_SeqScan:
case T_IndexScan:
case T_IndexOnlyScan:
case T_TidScan:
case T_ValuesScan:
case T_Material:
case T_Sort:
return true;
case T_BaseResult:
/*
* T_BaseResult only supports mark/restore if it has a child plan that
* does, so we do not have enough information to give a really
* correct answer. However, for current uses it's enough to
* always say "false", because this routine is not asked about
* gating Result plans, only base-case Results.
*/
return false;
case T_ExtensiblePlan:
return castNode(ExtensiblePath, pathnode)->flags & EXTENSIBLEPATH_SUPPORT_MARK_RESTORE;
default:
break;
}
return false;
}
/*
* ExecSupportsBackwardScan - does a plan type support backwards scanning?
*
* Ideally, all plan types would support backwards scan, but that seems
* unlikely to happen soon. In some cases, a plan node passes the backwards
* scan down to its children, and so supports backwards scan only if its
* children do. Therefore, this routine must be passed a complete plan tree.
*/
bool ExecSupportsBackwardScan(Plan* node)
{
if (node == NULL)
return false;
switch (nodeTag(node)) {
case T_BaseResult:
if (outerPlan(node) != NULL) {
return ExecSupportsBackwardScan(outerPlan(node)) && target_list_supports_backward_scan(node->targetlist);
} else {
return false;
}
case T_Append: {
ListCell* l = NULL;
foreach (l, ((Append*)node)->appendplans) {
if (!ExecSupportsBackwardScan((Plan*)lfirst(l))) {
return false;
}
}
/* need not check tlist because Append doesn't evaluate it */
return true;
}
case T_SeqScan:
/* Tablesample scan cann't support backward scan. */
if (((SeqScan*)node)->tablesample) {
return false;
}
/* fall through */
case T_TidScan:
case T_FunctionScan:
case T_ValuesScan:
case T_CteScan:
return target_list_supports_backward_scan(node->targetlist);
case T_IndexScan:
return index_supports_backward_scan(((IndexScan*)node)->indexid) &&
target_list_supports_backward_scan(node->targetlist);
case T_IndexOnlyScan:
return index_supports_backward_scan(((IndexOnlyScan*)node)->indexid) &&
target_list_supports_backward_scan(node->targetlist);
case T_SubqueryScan:
return ExecSupportsBackwardScan(((SubqueryScan*)node)->subplan) &&
target_list_supports_backward_scan(node->targetlist);
case T_ExtensiblePlan:
return ((ExtensiblePlan *)node)->flags & EXTENSIBLEPATH_SUPPORT_BACKWARD_SCAN;
case T_Material:
case T_Sort:
/* these don't evaluate tlist */
return true;
case T_LockRows:
case T_Limit:
/* these don't evaluate tlist */
return ExecSupportsBackwardScan(outerPlan(node));
default:
return false;
}
}
/*
* If the tlist contains set-returning functions, we can't support backward
* scan, because the TupFromTlist code is direction-ignorant.
*/
static bool target_list_supports_backward_scan(List* targetlist)
{
if (expression_returns_set((Node*)targetlist)) {
return false;
}
return true;
}
/*
* An IndexScan or IndexOnlyScan node supports backward scan only if the
* index's AM does.
*/
static bool index_supports_backward_scan(Oid indexid)
{
bool result = false;
HeapTuple ht_idxrel;
HeapTuple ht_am;
Form_pg_class idxrelrec;
Form_pg_am amrec;
/* Fetch the pg_class tuple of the index relation */
ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexid));
if (!HeapTupleIsValid(ht_idxrel)) {
ereport(ERROR,
(errcode(ERRCODE_CACHE_LOOKUP_FAILED),
errmsg("cache lookup failed for relation %u when check backward scan for Index.", indexid)));
}
idxrelrec = (Form_pg_class)GETSTRUCT(ht_idxrel);
/* Fetch the pg_am tuple of the index' access method */
ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(idxrelrec->relam));
if (!HeapTupleIsValid(ht_am)) {
ereport(ERROR,
(errcode(ERRCODE_CACHE_LOOKUP_FAILED),
errmsg("cache lookup failed for access method %u when test backward scan for Index %s",
idxrelrec->relam,
NameStr(idxrelrec->relname))));
}
amrec = (Form_pg_am)GETSTRUCT(ht_am);
result = amrec->amcanbackward;
ReleaseSysCache(ht_idxrel);
ReleaseSysCache(ht_am);
return result;
}
/*
* ExecMaterializesOutput - does a plan type materialize its output?
*
* Returns true if the plan node type is one that automatically materializes
* its output (typically by keeping it in a tuplestore). For such plans,
* a rescan without any parameter change will have zero startup cost and
* very low per-tuple cost.
*/
bool ExecMaterializesOutput(NodeTag plantype)
{
switch (plantype) {
case T_Material:
case T_FunctionScan:
case T_CteScan:
case T_WorkTableScan:
case T_Sort:
return true;
default:
break;
}
return false;
}