/*------------------------------------------------------------------------- * * nodeNamedtuplestorescan.c * routines to handle NamedTuplestoreScan nodes. * * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * src/backend/executor/nodeNamedtuplestorescan.c * *------------------------------------------------------------------------- */ #include "postgres.h" #include "executor/execdebug.h" #include "executor/nodeNamedtuplestorescan.h" #include "miscadmin.h" #include "utils/queryenvironment.h" static TupleTableSlot *NamedTuplestoreScanNext(NamedTuplestoreScanState *node); /* ---------------------------------------------------------------- * NamedTuplestoreScanNext * * This is a workhorse for ExecNamedTuplestoreScan * ---------------------------------------------------------------- */ static TupleTableSlot * NamedTuplestoreScanNext(NamedTuplestoreScanState *node) { TupleTableSlot *slot; /* We intentionally do not support backward scan. */ Assert(ScanDirectionIsForward(node->ss.ps.state->es_direction)); /* * Get the next tuple from tuplestore. Return NULL if no more tuples. */ slot = node->ss.ss_ScanTupleSlot; tuplestore_select_read_pointer(node->relation, node->readptr); (void) tuplestore_gettupleslot(node->relation, true, false, slot); return slot; } /* * NamedTuplestoreScanRecheck -- access method routine to recheck a tuple in * EvalPlanQual */ static bool NamedTuplestoreScanRecheck(NamedTuplestoreScanState *node, TupleTableSlot *slot) { /* nothing to check */ return true; } /* ---------------------------------------------------------------- * ExecNamedTuplestoreScan(node) * * Scans the CTE sequentially and returns the next qualifying tuple. * We call the ExecScan() routine and pass it the appropriate * access method functions. * ---------------------------------------------------------------- */ static TupleTableSlot * ExecNamedTuplestoreScan(PlanState *pstate) { NamedTuplestoreScanState *node = castNode(NamedTuplestoreScanState, pstate); return ExecScan(&node->ss, (ExecScanAccessMtd) NamedTuplestoreScanNext, (ExecScanRecheckMtd) NamedTuplestoreScanRecheck); } /* ---------------------------------------------------------------- * ExecInitNamedTuplestoreScan * ---------------------------------------------------------------- */ NamedTuplestoreScanState * ExecInitNamedTuplestoreScan(NamedTuplestoreScan *node, EState *estate, int eflags) { NamedTuplestoreScanState *scanstate; EphemeralNamedRelation enr; /* check for unsupported flags */ Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); /* * NamedTuplestoreScan should not have any children. */ Assert(outerPlan(node) == NULL); Assert(innerPlan(node) == NULL); /* * create new NamedTuplestoreScanState for node */ scanstate = makeNode(NamedTuplestoreScanState); scanstate->ss.ps.plan = (Plan *) node; scanstate->ss.ps.state = estate; scanstate->ss.ps.ExecProcNode = ExecNamedTuplestoreScan; enr = get_ENR(estate->es_queryEnv, node->enrname); if (!enr) elog(ERROR, "executor could not find named tuplestore \"%s\"", node->enrname); Assert(enr->reldata); scanstate->relation = (Tuplestorestate *) enr->reldata; scanstate->tupdesc = ENRMetadataGetTupDesc(&(enr->md)); scanstate->readptr = tuplestore_alloc_read_pointer(scanstate->relation, EXEC_FLAG_REWIND); /* * The new read pointer copies its position from read pointer 0, which * could be anywhere, so explicitly rewind it. */ tuplestore_select_read_pointer(scanstate->relation, scanstate->readptr); tuplestore_rescan(scanstate->relation); /* * XXX: Should we add a function to free that read pointer when done? * * This was attempted, but it did not improve performance or memory usage * in any tested cases. */ /* * Miscellaneous initialization * * create expression context for node */ ExecAssignExprContext(estate, &scanstate->ss.ps); /* * The scan tuple type is specified for the tuplestore. */ ExecInitScanTupleSlot(estate, &scanstate->ss, scanstate->tupdesc, &TTSOpsMinimalTuple); /* * Initialize result type and projection. */ ExecInitResultTypeTL(&scanstate->ss.ps); ExecAssignScanProjectionInfo(&scanstate->ss); /* * initialize child expressions */ scanstate->ss.ps.qual = ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate); return scanstate; } /* ---------------------------------------------------------------- * ExecEndNamedTuplestoreScan * * frees any storage allocated through C routines. * ---------------------------------------------------------------- */ void ExecEndNamedTuplestoreScan(NamedTuplestoreScanState *node) { /* * Free exprcontext */ ExecFreeExprContext(&node->ss.ps); /* * clean out the tuple table */ if (node->ss.ps.ps_ResultTupleSlot) ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecClearTuple(node->ss.ss_ScanTupleSlot); } /* ---------------------------------------------------------------- * ExecReScanNamedTuplestoreScan * * Rescans the relation. * ---------------------------------------------------------------- */ void ExecReScanNamedTuplestoreScan(NamedTuplestoreScanState *node) { Tuplestorestate *tuplestorestate = node->relation; if (node->ss.ps.ps_ResultTupleSlot) ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecScanReScan(&node->ss); /* * Rewind my own pointer. */ tuplestore_select_read_pointer(tuplestorestate, node->readptr); tuplestore_rescan(tuplestorestate); }