first commit for openGauss server
This commit is contained in:
273
src/gausskernel/runtime/executor/nodeAppend.cpp
Executable file
273
src/gausskernel/runtime/executor/nodeAppend.cpp
Executable file
@ -0,0 +1,273 @@
|
||||
/* -------------------------------------------------------------------------
|
||||
*
|
||||
* nodeAppend.cpp
|
||||
* routines to handle append 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/nodeAppend.cpp
|
||||
*
|
||||
* -------------------------------------------------------------------------
|
||||
* INTERFACE ROUTINES
|
||||
* ExecInitAppend - initialize the append node
|
||||
* ExecAppend - retrieve the next tuple from the node
|
||||
* ExecEndAppend - shut down the append node
|
||||
* ExecReScanAppend - rescan the append node
|
||||
*
|
||||
* NOTES
|
||||
* Each append node contains a list of one or more subplans which
|
||||
* must be iteratively processed (forwards or backwards).
|
||||
* Tuples are retrieved by executing the 'whichplan'th subplan
|
||||
* until the subplan stops returning tuples, at which point that
|
||||
* plan is shut down and the next started up.
|
||||
*
|
||||
* Append nodes don't make use of their left and right
|
||||
* subtrees, rather they maintain a list of subplans so
|
||||
* a typical append node looks like this in the plan tree:
|
||||
*
|
||||
* ...
|
||||
* /
|
||||
* Append -------+------+------+--- nil
|
||||
* / \ | | |
|
||||
* nil nil ... ... ...
|
||||
* subplans
|
||||
*
|
||||
* Append nodes are currently used for unions, and to support
|
||||
* inheritance queries, where several relations need to be scanned.
|
||||
* For example, in our standard person/student/employee/student-emp
|
||||
* example, where student and employee inherit from person
|
||||
* and student-emp inherits from student and employee, the
|
||||
* query:
|
||||
*
|
||||
* select name from person
|
||||
*
|
||||
* generates the plan:
|
||||
*
|
||||
* |
|
||||
* Append -------+-------+--------+--------+
|
||||
* / \ | | | |
|
||||
* nil nil Scan Scan Scan Scan
|
||||
* | | | |
|
||||
* person employee student student-emp
|
||||
*/
|
||||
#include "postgres.h"
|
||||
#include "knl/knl_variable.h"
|
||||
|
||||
#include "executor/execdebug.h"
|
||||
#include "executor/nodeAppend.h"
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* exec_append_initialize_next
|
||||
*
|
||||
* Sets up the append state node for the "next" scan.
|
||||
*
|
||||
* Returns t iff there is a "next" scan to process.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
bool exec_append_initialize_next(AppendState* appendstate)
|
||||
{
|
||||
int whichplan;
|
||||
|
||||
/*
|
||||
* get information from the append node
|
||||
*/
|
||||
whichplan = appendstate->as_whichplan;
|
||||
|
||||
if (whichplan < 0) {
|
||||
/*
|
||||
* if scanning in reverse, we start at the last scan in the list and
|
||||
* then proceed back to the first.. in any case we inform ExecAppend
|
||||
* that we are at the end of the line by returning FALSE
|
||||
*/
|
||||
appendstate->as_whichplan = 0;
|
||||
return FALSE;
|
||||
} else if (whichplan >= appendstate->as_nplans) {
|
||||
/*
|
||||
* as above, end the scan if we go beyond the last scan in our list..
|
||||
*/
|
||||
appendstate->as_whichplan = appendstate->as_nplans - 1;
|
||||
return FALSE;
|
||||
} else {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* ExecInitAppend
|
||||
*
|
||||
* Begin all of the subscans of the append node.
|
||||
*
|
||||
* (This is potentially wasteful, since the entire result of the
|
||||
* append node may not be scanned, but this way all of the
|
||||
* structures get allocated in the executor's top level memory
|
||||
* block instead of that of the call to ExecAppend.)
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
AppendState* ExecInitAppend(Append* node, EState* estate, int eflags)
|
||||
{
|
||||
AppendState* appendstate = makeNode(AppendState);
|
||||
PlanState** appendplanstates;
|
||||
int nplans;
|
||||
int i;
|
||||
ListCell* lc = NULL;
|
||||
|
||||
/* check for unsupported flags */
|
||||
Assert(!(eflags & EXEC_FLAG_MARK));
|
||||
|
||||
/*
|
||||
* Set up empty vector of subplan states
|
||||
*/
|
||||
nplans = list_length(node->appendplans);
|
||||
|
||||
appendplanstates = (PlanState**)palloc0(nplans * sizeof(PlanState*));
|
||||
|
||||
/*
|
||||
* create new AppendState for our append node
|
||||
*/
|
||||
appendstate->ps.plan = (Plan*)node;
|
||||
appendstate->ps.state = estate;
|
||||
appendstate->appendplans = appendplanstates;
|
||||
appendstate->as_nplans = nplans;
|
||||
|
||||
/*
|
||||
* Miscellaneous initialization
|
||||
*
|
||||
* Append plans don't have expression contexts because they never call
|
||||
* ExecQual or ExecProject.
|
||||
*/
|
||||
/*
|
||||
* append nodes still have Result slots, which hold pointers to tuples, so
|
||||
* we have to initialize them.
|
||||
*/
|
||||
ExecInitResultTupleSlot(estate, &appendstate->ps);
|
||||
|
||||
/*
|
||||
* call ExecInitNode on each of the plans to be executed and save the
|
||||
* results into the array "appendplans".
|
||||
*/
|
||||
i = 0;
|
||||
foreach (lc, node->appendplans) {
|
||||
Plan* initNode = (Plan*)lfirst(lc);
|
||||
|
||||
appendplanstates[i] = ExecInitNode(initNode, estate, eflags);
|
||||
i++;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize output tuple type
|
||||
*/
|
||||
ExecAssignResultTypeFromTL(&appendstate->ps);
|
||||
appendstate->ps.ps_ProjInfo = NULL;
|
||||
|
||||
/*
|
||||
* initialize to scan first subplan
|
||||
*/
|
||||
appendstate->as_whichplan = 0;
|
||||
(void)exec_append_initialize_next(appendstate);
|
||||
return appendstate;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* ExecAppend
|
||||
*
|
||||
* Handles iteration over multiple subplans.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
TupleTableSlot* ExecAppend(AppendState* node)
|
||||
{
|
||||
for (;;) {
|
||||
PlanState* subnode = NULL;
|
||||
TupleTableSlot* result = NULL;
|
||||
|
||||
/*
|
||||
* figure out which subplan we are currently processing
|
||||
*/
|
||||
subnode = node->appendplans[node->as_whichplan];
|
||||
|
||||
/*
|
||||
* get a tuple from the subplan
|
||||
*/
|
||||
result = ExecProcNode(subnode);
|
||||
if (!TupIsNull(result)) {
|
||||
/*
|
||||
* If the subplan gave us something then return it as-is. We do
|
||||
* NOT make use of the result slot that was set up in
|
||||
* ExecInitAppend; there's no need for it.
|
||||
*/
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Early free each of subplans after finishing execution */
|
||||
ExecEarlyFree(subnode);
|
||||
|
||||
/*
|
||||
* Go on to the "next" subplan in the appropriate direction. If no
|
||||
* more subplans, return the empty slot set up for us by
|
||||
* ExecInitAppend.
|
||||
*/
|
||||
if (ScanDirectionIsForward(node->ps.state->es_direction))
|
||||
node->as_whichplan++;
|
||||
else
|
||||
node->as_whichplan--;
|
||||
if (!exec_append_initialize_next(node))
|
||||
return ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
||||
|
||||
/* Else loop back and try to get a tuple from the new subplan */
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* ExecEndAppend
|
||||
*
|
||||
* Shuts down the subscans of the append node.
|
||||
*
|
||||
* Returns nothing of interest.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void ExecEndAppend(AppendState* node)
|
||||
{
|
||||
PlanState** appendplans;
|
||||
int nplans;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* get information from the node
|
||||
*/
|
||||
appendplans = node->appendplans;
|
||||
nplans = node->as_nplans;
|
||||
|
||||
/*
|
||||
* shut down each of the subscans
|
||||
*/
|
||||
for (i = 0; i < nplans; i++)
|
||||
ExecEndNode(appendplans[i]);
|
||||
}
|
||||
|
||||
void ExecReScanAppend(AppendState* node)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < node->as_nplans; i++) {
|
||||
PlanState* subnode = node->appendplans[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);
|
||||
}
|
||||
node->as_whichplan = 0;
|
||||
(void)exec_append_initialize_next(node);
|
||||
}
|
||||
Reference in New Issue
Block a user