postgresql/src/backend/executor/nodeNamedtuplestorescan.c

202 lines
5.5 KiB
C

/*-------------------------------------------------------------------------
*
* nodeNamedtuplestorescan.c
* routines to handle NamedTuplestoreScan nodes.
*
* Portions Copyright (c) 1996-2023, 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);
}