#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); } }