309 lines
9.4 KiB
C++
309 lines
9.4 KiB
C++
/* -------------------------------------------------------------------------
|
|
*
|
|
* nodeValuesscan.cpp
|
|
* Support routines for scanning Values lists
|
|
* ("VALUES (...), (...), ..." in rangetable).
|
|
*
|
|
* 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/nodeValuesscan.cpp
|
|
*
|
|
* -------------------------------------------------------------------------
|
|
*
|
|
* INTERFACE ROUTINES
|
|
* ExecValuesScan scans a values list.
|
|
* ExecValuesNext retrieve next tuple in sequential order.
|
|
* ExecInitValuesScan creates and initializes a valuesscan node.
|
|
* ExecEndValuesScan releases any storage allocated.
|
|
* ExecReScanValuesScan rescans the values list
|
|
*/
|
|
#include "postgres.h"
|
|
#include "knl/knl_variable.h"
|
|
|
|
#include "executor/executor.h"
|
|
#include "executor/nodeValuesscan.h"
|
|
#include "parser/parsetree.h"
|
|
|
|
static TupleTableSlot* ValuesNext(ValuesScanState* node);
|
|
|
|
/* ----------------------------------------------------------------
|
|
* Scan Support
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
/* ----------------------------------------------------------------
|
|
* ValuesNext
|
|
*
|
|
* This is a workhorse for ExecValuesScan
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
static TupleTableSlot* ValuesNext(ValuesScanState* node)
|
|
{
|
|
List* expr_list = NIL;
|
|
|
|
/*
|
|
* get information from the estate and scan state
|
|
*/
|
|
EState* estate = node->ss.ps.state;
|
|
ScanDirection direction = estate->es_direction;
|
|
TupleTableSlot* slot = node->ss.ss_ScanTupleSlot;
|
|
ExprContext* econtext = node->rowcontext;
|
|
|
|
/*
|
|
* Get the next tuple. Return NULL if no more tuples.
|
|
*/
|
|
if (ScanDirectionIsForward(direction)) {
|
|
if (node->curr_idx < node->array_len)
|
|
node->curr_idx++;
|
|
if (node->curr_idx < node->array_len)
|
|
expr_list = node->exprlists[node->curr_idx];
|
|
else
|
|
expr_list = NIL;
|
|
} else {
|
|
if (node->curr_idx >= 0)
|
|
node->curr_idx--;
|
|
if (node->curr_idx >= 0)
|
|
expr_list = node->exprlists[node->curr_idx];
|
|
else
|
|
expr_list = NIL;
|
|
}
|
|
|
|
/*
|
|
* Always clear the result slot; this is appropriate if we are at the end
|
|
* of the data, and if we're not, we still need it as the first step of
|
|
* the store-virtual-tuple protocol. It seems wise to clear the slot
|
|
* before we reset the context it might have pointers into.
|
|
*/
|
|
(void)ExecClearTuple(slot);
|
|
|
|
if (expr_list != NULL) {
|
|
MemoryContext old_context;
|
|
List* expr_state_list = NIL;
|
|
Datum* values = NULL;
|
|
bool* is_null = NULL;
|
|
ListCell* lc = NULL;
|
|
int resind;
|
|
|
|
/*
|
|
* Get rid of any prior cycle's leftovers. We use ReScanExprContext
|
|
* not just ResetExprContext because we want any registered shutdown
|
|
* callbacks to be called.
|
|
*/
|
|
ReScanExprContext(econtext);
|
|
|
|
/*
|
|
* Build the expression eval state in the econtext's per-tuple memory.
|
|
* This is a tad unusual, but we want to delete the eval state again
|
|
* when we move to the next row, to avoid growth of memory
|
|
* requirements over a long values list.
|
|
*/
|
|
old_context = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
|
|
|
|
/*
|
|
* Pass NULL, not my plan node, because we don't want anything in this
|
|
* transient state linking into permanent state. The only possibility
|
|
* is a SubPlan, and there shouldn't be any (any subselects in the
|
|
* VALUES list should be InitPlans).
|
|
*/
|
|
expr_state_list = (List*)ExecInitExpr((Expr*)expr_list, NULL);
|
|
|
|
/* parser should have checked all sublists are the same length */
|
|
Assert(list_length(expr_state_list) == slot->tts_tupleDescriptor->natts);
|
|
|
|
/*
|
|
* Compute the expressions and build a virtual result tuple. We
|
|
* already did ExecClearTuple(slot).
|
|
*/
|
|
values = slot->tts_values;
|
|
is_null = slot->tts_isnull;
|
|
|
|
resind = 0;
|
|
foreach (lc, expr_state_list) {
|
|
ExprState* exprState = (ExprState*)lfirst(lc);
|
|
|
|
values[resind] = ExecEvalExpr(exprState, econtext, &is_null[resind], NULL);
|
|
resind++;
|
|
}
|
|
|
|
MemoryContextSwitchTo(old_context);
|
|
|
|
/*
|
|
* And return the virtual tuple.
|
|
*/
|
|
ExecStoreVirtualTuple(slot);
|
|
}
|
|
|
|
return slot;
|
|
}
|
|
|
|
/*
|
|
* ValuesRecheck -- access method routine to recheck a tuple in EvalPlanQual
|
|
*/
|
|
static bool ValuesRecheck(ValuesScanState* node, TupleTableSlot* slot)
|
|
{
|
|
/* nothing to check */
|
|
return true;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------
|
|
* ExecValuesScan(node)
|
|
*
|
|
* Scans the values lists sequentially and returns the next qualifying
|
|
* tuple.
|
|
* We call the ExecScan() routine and pass it the appropriate
|
|
* access method functions.
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
TupleTableSlot* ExecValuesScan(ValuesScanState* node)
|
|
{
|
|
return ExecScan(&node->ss, (ExecScanAccessMtd)ValuesNext, (ExecScanRecheckMtd)ValuesRecheck);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------
|
|
* ExecInitValuesScan
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
ValuesScanState* ExecInitValuesScan(ValuesScan* node, EState* estate, int eflags)
|
|
{
|
|
RangeTblEntry* rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
|
|
TupleDesc tupdesc = NULL;
|
|
ListCell* vtl = NULL;
|
|
int i;
|
|
|
|
/*
|
|
* ValuesScan should not have any children.
|
|
*/
|
|
Assert(outerPlan(node) == NULL);
|
|
Assert(innerPlan(node) == NULL);
|
|
|
|
/*
|
|
* create new ScanState for node
|
|
*/
|
|
ValuesScanState* scan_state = makeNode(ValuesScanState);
|
|
|
|
scan_state->ss.ps.plan = (Plan*)node;
|
|
scan_state->ss.ps.state = estate;
|
|
|
|
/*
|
|
* Miscellaneous initialization
|
|
*/
|
|
PlanState* plan_state = &scan_state->ss.ps;
|
|
|
|
/*
|
|
* Create expression contexts. We need two, one for per-sublist
|
|
* processing and one for execScan.c to use for quals and projections. We
|
|
* cheat a little by using ExecAssignExprContext() to build both.
|
|
*/
|
|
ExecAssignExprContext(estate, plan_state);
|
|
scan_state->rowcontext = plan_state->ps_ExprContext;
|
|
ExecAssignExprContext(estate, plan_state);
|
|
|
|
/*
|
|
* tuple table initialization
|
|
*/
|
|
ExecInitResultTupleSlot(estate, &scan_state->ss.ps);
|
|
ExecInitScanTupleSlot(estate, &scan_state->ss);
|
|
|
|
/*
|
|
* initialize child expressions
|
|
*/
|
|
scan_state->ss.ps.targetlist = (List*)ExecInitExpr((Expr*)node->scan.plan.targetlist, (PlanState*)scan_state);
|
|
scan_state->ss.ps.qual = (List*)ExecInitExpr((Expr*)node->scan.plan.qual, (PlanState*)scan_state);
|
|
|
|
/*
|
|
* get info about values list
|
|
* value lists scan, no relation is involved, default tableAm type is set to HEAP.
|
|
*/
|
|
tupdesc = ExecTypeFromExprList((List*)linitial(node->values_lists), rte->eref->colnames, TAM_HEAP);
|
|
|
|
ExecAssignScanType(&scan_state->ss, tupdesc);
|
|
|
|
/*
|
|
* Other node-specific setup
|
|
*/
|
|
scan_state->marked_idx = -1;
|
|
scan_state->curr_idx = -1;
|
|
scan_state->array_len = list_length(node->values_lists);
|
|
|
|
/* convert list of sublists into array of sublists for easy addressing */
|
|
scan_state->exprlists = (List**)palloc(scan_state->array_len * sizeof(List*));
|
|
i = 0;
|
|
foreach (vtl, node->values_lists) {
|
|
scan_state->exprlists[i++] = (List*)lfirst(vtl);
|
|
}
|
|
|
|
scan_state->ss.ps.ps_TupFromTlist = false;
|
|
|
|
/*
|
|
* Initialize result tuple type and projection info.
|
|
* value lists result tuple is set to default tableAm type HEAP.
|
|
*/
|
|
ExecAssignResultTypeFromTL(&scan_state->ss.ps, TAM_HEAP);
|
|
|
|
ExecAssignScanProjectionInfo(&scan_state->ss);
|
|
|
|
return scan_state;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------
|
|
* ExecEndValuesScan
|
|
*
|
|
* frees any storage allocated through C routines.
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
void ExecEndValuesScan(ValuesScanState* node)
|
|
{
|
|
/*
|
|
* Free both exprcontexts
|
|
*/
|
|
ExecFreeExprContext(&node->ss.ps);
|
|
node->ss.ps.ps_ExprContext = node->rowcontext;
|
|
ExecFreeExprContext(&node->ss.ps);
|
|
|
|
/*
|
|
* clean out the tuple table
|
|
*/
|
|
(void)ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
|
|
(void)ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------
|
|
* ExecValuesMarkPos
|
|
*
|
|
* Marks scan position.
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
void ExecValuesMarkPos(ValuesScanState* node)
|
|
{
|
|
node->marked_idx = node->curr_idx;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------
|
|
* ExecValuesRestrPos
|
|
*
|
|
* Restores scan position.
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
void ExecValuesRestrPos(ValuesScanState* node)
|
|
{
|
|
node->curr_idx = node->marked_idx;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------
|
|
* ExecReScanValuesScan
|
|
*
|
|
* Rescans the relation.
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
void ExecReScanValuesScan(ValuesScanState* node)
|
|
{
|
|
(void)ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
|
|
|
|
ExecScanReScan(&node->ss);
|
|
|
|
node->curr_idx = -1;
|
|
}
|