#include "postgres.h"#include "executor/execdebug.h"#include "executor/nodeCtescan.h"#include "miscadmin.h"
Go to the source code of this file.
Functions | |
| static TupleTableSlot * | CteScanNext (CteScanState *node) |
| static bool | CteScanRecheck (CteScanState *node, TupleTableSlot *slot) |
| TupleTableSlot * | ExecCteScan (CteScanState *node) |
| CteScanState * | ExecInitCteScan (CteScan *node, EState *estate, int eflags) |
| void | ExecEndCteScan (CteScanState *node) |
| void | ExecReScanCteScan (CteScanState *node) |
| static TupleTableSlot * CteScanNext | ( | CteScanState * | node | ) | [static] |
Definition at line 31 of file nodeCtescan.c.
References CteScanState::cte_table, CteScanState::cteplanstate, CteScanState::eof_cte, EState::es_direction, ExecClearTuple(), ExecCopySlot(), ExecProcNode(), CteScanState::leader, ScanState::ps, CteScanState::readptr, ScanDirectionIsForward, CteScanState::ss, ScanState::ss_ScanTupleSlot, PlanState::state, TupIsNull, tuplestore_advance(), tuplestore_ateof(), tuplestore_gettupleslot(), tuplestore_puttupleslot(), and tuplestore_select_read_pointer().
Referenced by ExecCteScan().
{
EState *estate;
ScanDirection dir;
bool forward;
Tuplestorestate *tuplestorestate;
bool eof_tuplestore;
TupleTableSlot *slot;
/*
* get state info from node
*/
estate = node->ss.ps.state;
dir = estate->es_direction;
forward = ScanDirectionIsForward(dir);
tuplestorestate = node->leader->cte_table;
tuplestore_select_read_pointer(tuplestorestate, node->readptr);
slot = node->ss.ss_ScanTupleSlot;
/*
* If we are not at the end of the tuplestore, or are going backwards, try
* to fetch a tuple from tuplestore.
*/
eof_tuplestore = tuplestore_ateof(tuplestorestate);
if (!forward && eof_tuplestore)
{
if (!node->leader->eof_cte)
{
/*
* When reversing direction at tuplestore EOF, the first
* gettupleslot call will fetch the last-added tuple; but we want
* to return the one before that, if possible. So do an extra
* fetch.
*/
if (!tuplestore_advance(tuplestorestate, forward))
return NULL; /* the tuplestore must be empty */
}
eof_tuplestore = false;
}
/*
* If we can fetch another tuple from the tuplestore, return it.
*
* Note: we have to use copy=true in the tuplestore_gettupleslot call,
* because we are sharing the tuplestore with other nodes that might write
* into the tuplestore before we get called again.
*/
if (!eof_tuplestore)
{
if (tuplestore_gettupleslot(tuplestorestate, forward, true, slot))
return slot;
if (forward)
eof_tuplestore = true;
}
/*
* If necessary, try to fetch another row from the CTE query.
*
* Note: the eof_cte state variable exists to short-circuit further calls
* of the CTE plan. It's not optional, unfortunately, because some plan
* node types are not robust about being called again when they've already
* returned NULL.
*/
if (eof_tuplestore && !node->leader->eof_cte)
{
TupleTableSlot *cteslot;
/*
* We can only get here with forward==true, so no need to worry about
* which direction the subplan will go.
*/
cteslot = ExecProcNode(node->cteplanstate);
if (TupIsNull(cteslot))
{
node->leader->eof_cte = true;
return NULL;
}
/*
* Append a copy of the returned tuple to tuplestore. NOTE: because
* our read pointer is certainly in EOF state, its read position will
* move forward over the added tuple. This is what we want. Also,
* any other readers will *not* move past the new tuple, which is what
* they want.
*/
tuplestore_puttupleslot(tuplestorestate, cteslot);
/*
* We MUST copy the CTE query's output tuple into our own slot. This
* is because other CteScan nodes might advance the CTE query before
* we are called again, and our output tuple must stay stable over
* that.
*/
return ExecCopySlot(slot, cteslot);
}
/*
* Nothing left ...
*/
return ExecClearTuple(slot);
}
| static bool CteScanRecheck | ( | CteScanState * | node, | |
| TupleTableSlot * | slot | |||
| ) | [static] |
Definition at line 138 of file nodeCtescan.c.
Referenced by ExecCteScan().
{
/* nothing to check */
return true;
}
| TupleTableSlot* ExecCteScan | ( | CteScanState * | node | ) |
Definition at line 153 of file nodeCtescan.c.
References CteScanNext(), CteScanRecheck(), ExecScan(), and CteScanState::ss.
Referenced by ExecProcNode().
{
return ExecScan(&node->ss,
(ExecScanAccessMtd) CteScanNext,
(ExecScanRecheckMtd) CteScanRecheck);
}
| void ExecEndCteScan | ( | CteScanState * | node | ) |
Definition at line 280 of file nodeCtescan.c.
References CteScanState::cte_table, ExecClearTuple(), ExecFreeExprContext(), CteScanState::leader, ScanState::ps, PlanState::ps_ResultTupleSlot, CteScanState::ss, ScanState::ss_ScanTupleSlot, and tuplestore_end().
Referenced by ExecEndNode().
{
/*
* Free exprcontext
*/
ExecFreeExprContext(&node->ss.ps);
/*
* clean out the tuple table
*/
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
/*
* If I am the leader, free the tuplestore.
*/
if (node->leader == node)
{
tuplestore_end(node->cte_table);
node->cte_table = NULL;
}
}
| CteScanState* ExecInitCteScan | ( | CteScan * | node, | |
| EState * | estate, | |||
| int | eflags | |||
| ) |
Definition at line 166 of file nodeCtescan.c.
References Assert, CteScanState::cte_table, CteScan::cteParam, CteScan::ctePlanId, CteScanState::cteplanstate, DatumGetPointer, CteScanState::eflags, CteScanState::eof_cte, EState::es_param_exec_vals, EState::es_subplanstates, EXEC_FLAG_MARK, ExecAssignExprContext(), ExecAssignResultTypeFromTL(), ExecAssignScanProjectionInfo(), ExecAssignScanType(), ExecGetResultType(), ExecInitExpr(), ExecInitResultTupleSlot(), ExecInitScanTupleSlot(), ParamExecData::execPlan, innerPlan, IsA, ParamExecData::isnull, CteScanState::leader, list_nth(), makeNode, NULL, outerPlan, Scan::plan, PlanState::plan, PointerGetDatum, ScanState::ps, PlanState::ps_TupFromTlist, Plan::qual, PlanState::qual, CteScanState::readptr, CteScan::scan, CteScanState::ss, PlanState::state, Plan::targetlist, PlanState::targetlist, tuplestore_alloc_read_pointer(), tuplestore_begin_heap(), tuplestore_set_eflags(), ParamExecData::value, and work_mem.
Referenced by ExecInitNode().
{
CteScanState *scanstate;
ParamExecData *prmdata;
/* check for unsupported flags */
Assert(!(eflags & EXEC_FLAG_MARK));
/*
* For the moment we have to force the tuplestore to allow REWIND, because
* we might be asked to rescan the CTE even though upper levels didn't
* tell us to be prepared to do it efficiently. Annoying, since this
* prevents truncation of the tuplestore. XXX FIXME
*/
eflags |= EXEC_FLAG_REWIND;
/*
* CteScan should not have any children.
*/
Assert(outerPlan(node) == NULL);
Assert(innerPlan(node) == NULL);
/*
* create new CteScanState for node
*/
scanstate = makeNode(CteScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
scanstate->eflags = eflags;
scanstate->cte_table = NULL;
scanstate->eof_cte = false;
/*
* Find the already-initialized plan for the CTE query.
*/
scanstate->cteplanstate = (PlanState *) list_nth(estate->es_subplanstates,
node->ctePlanId - 1);
/*
* The Param slot associated with the CTE query is used to hold a pointer
* to the CteState of the first CteScan node that initializes for this
* CTE. This node will be the one that holds the shared state for all the
* CTEs, particularly the shared tuplestore.
*/
prmdata = &(estate->es_param_exec_vals[node->cteParam]);
Assert(prmdata->execPlan == NULL);
Assert(!prmdata->isnull);
scanstate->leader = (CteScanState *) DatumGetPointer(prmdata->value);
if (scanstate->leader == NULL)
{
/* I am the leader */
prmdata->value = PointerGetDatum(scanstate);
scanstate->leader = scanstate;
scanstate->cte_table = tuplestore_begin_heap(true, false, work_mem);
tuplestore_set_eflags(scanstate->cte_table, scanstate->eflags);
scanstate->readptr = 0;
}
else
{
/* Not the leader */
Assert(IsA(scanstate->leader, CteScanState));
scanstate->readptr =
tuplestore_alloc_read_pointer(scanstate->leader->cte_table,
scanstate->eflags);
}
/*
* Miscellaneous initialization
*
* create expression context for node
*/
ExecAssignExprContext(estate, &scanstate->ss.ps);
/*
* initialize child expressions
*/
scanstate->ss.ps.targetlist = (List *)
ExecInitExpr((Expr *) node->scan.plan.targetlist,
(PlanState *) scanstate);
scanstate->ss.ps.qual = (List *)
ExecInitExpr((Expr *) node->scan.plan.qual,
(PlanState *) scanstate);
/*
* tuple table initialization
*/
ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
ExecInitScanTupleSlot(estate, &scanstate->ss);
/*
* The scan tuple type (ie, the rowtype we expect to find in the work
* table) is the same as the result rowtype of the CTE query.
*/
ExecAssignScanType(&scanstate->ss,
ExecGetResultType(scanstate->cteplanstate));
/*
* Initialize result tuple type and projection info.
*/
ExecAssignResultTypeFromTL(&scanstate->ss.ps);
ExecAssignScanProjectionInfo(&scanstate->ss);
scanstate->ss.ps.ps_TupFromTlist = false;
return scanstate;
}
| void ExecReScanCteScan | ( | CteScanState * | node | ) |
Definition at line 310 of file nodeCtescan.c.
References PlanState::chgParam, CteScanState::cte_table, CteScanState::cteplanstate, CteScanState::eof_cte, ExecClearTuple(), ExecScanReScan(), CteScanState::leader, NULL, ScanState::ps, PlanState::ps_ResultTupleSlot, CteScanState::readptr, CteScanState::ss, tuplestore_clear(), tuplestore_rescan(), and tuplestore_select_read_pointer().
Referenced by ExecReScan().
{
Tuplestorestate *tuplestorestate = node->leader->cte_table;
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecScanReScan(&node->ss);
/*
* Clear the tuplestore if a new scan of the underlying CTE is required.
* This implicitly resets all the tuplestore's read pointers. Note that
* multiple CTE nodes might redundantly clear the tuplestore; that's OK,
* and not unduly expensive. We'll stop taking this path as soon as
* somebody has attempted to read something from the underlying CTE
* (thereby causing its chgParam to be cleared).
*/
if (node->leader->cteplanstate->chgParam != NULL)
{
tuplestore_clear(tuplestorestate);
node->leader->eof_cte = false;
}
else
{
/*
* Else, just rewind my own pointer. Either the underlying CTE
* doesn't need a rescan (and we can re-read what's in the tuplestore
* now), or somebody else already took care of it.
*/
tuplestore_select_read_pointer(tuplestorestate, node->readptr);
tuplestore_rescan(tuplestorestate);
}
}
1.7.1