mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			224 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			224 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*-------------------------------------------------------------------------
 | 
						|
 *
 | 
						|
 * nodeWorktablescan.c
 | 
						|
 *	  routines to handle WorkTableScan nodes.
 | 
						|
 *
 | 
						|
 * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
 | 
						|
 * Portions Copyright (c) 1994, Regents of the University of California
 | 
						|
 *
 | 
						|
 *
 | 
						|
 * IDENTIFICATION
 | 
						|
 *	  src/backend/executor/nodeWorktablescan.c
 | 
						|
 *
 | 
						|
 *-------------------------------------------------------------------------
 | 
						|
 */
 | 
						|
 | 
						|
#include "postgres.h"
 | 
						|
 | 
						|
#include "executor/execdebug.h"
 | 
						|
#include "executor/nodeWorktablescan.h"
 | 
						|
 | 
						|
static TupleTableSlot *WorkTableScanNext(WorkTableScanState *node);
 | 
						|
 | 
						|
/* ----------------------------------------------------------------
 | 
						|
 *		WorkTableScanNext
 | 
						|
 *
 | 
						|
 *		This is a workhorse for ExecWorkTableScan
 | 
						|
 * ----------------------------------------------------------------
 | 
						|
 */
 | 
						|
static TupleTableSlot *
 | 
						|
WorkTableScanNext(WorkTableScanState *node)
 | 
						|
{
 | 
						|
	TupleTableSlot *slot;
 | 
						|
	Tuplestorestate *tuplestorestate;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * get information from the estate and scan state
 | 
						|
	 *
 | 
						|
	 * Note: we intentionally do not support backward scan.  Although it would
 | 
						|
	 * take only a couple more lines here, it would force nodeRecursiveunion.c
 | 
						|
	 * to create the tuplestore with backward scan enabled, which has a
 | 
						|
	 * performance cost.  In practice backward scan is never useful for a
 | 
						|
	 * worktable plan node, since it cannot appear high enough in the plan
 | 
						|
	 * tree of a scrollable cursor to be exposed to a backward-scan
 | 
						|
	 * requirement.  So it's not worth expending effort to support it.
 | 
						|
	 *
 | 
						|
	 * Note: we are also assuming that this node is the only reader of the
 | 
						|
	 * worktable.  Therefore, we don't need a private read pointer for the
 | 
						|
	 * tuplestore, nor do we need to tell tuplestore_gettupleslot to copy.
 | 
						|
	 */
 | 
						|
	Assert(ScanDirectionIsForward(node->ss.ps.state->es_direction));
 | 
						|
 | 
						|
	tuplestorestate = node->rustate->working_table;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Get the next tuple from tuplestore. Return NULL if no more tuples.
 | 
						|
	 */
 | 
						|
	slot = node->ss.ss_ScanTupleSlot;
 | 
						|
	(void) tuplestore_gettupleslot(tuplestorestate, true, false, slot);
 | 
						|
	return slot;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * WorkTableScanRecheck -- access method routine to recheck a tuple in EvalPlanQual
 | 
						|
 */
 | 
						|
static bool
 | 
						|
WorkTableScanRecheck(WorkTableScanState *node, TupleTableSlot *slot)
 | 
						|
{
 | 
						|
	/* nothing to check */
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
/* ----------------------------------------------------------------
 | 
						|
 *		ExecWorkTableScan(node)
 | 
						|
 *
 | 
						|
 *		Scans the worktable sequentially and returns the next qualifying tuple.
 | 
						|
 *		We call the ExecScan() routine and pass it the appropriate
 | 
						|
 *		access method functions.
 | 
						|
 * ----------------------------------------------------------------
 | 
						|
 */
 | 
						|
static TupleTableSlot *
 | 
						|
ExecWorkTableScan(PlanState *pstate)
 | 
						|
{
 | 
						|
	WorkTableScanState *node = castNode(WorkTableScanState, pstate);
 | 
						|
 | 
						|
	/*
 | 
						|
	 * On the first call, find the ancestor RecursiveUnion's state via the
 | 
						|
	 * Param slot reserved for it.  (We can't do this during node init because
 | 
						|
	 * there are corner cases where we'll get the init call before the
 | 
						|
	 * RecursiveUnion does.)
 | 
						|
	 */
 | 
						|
	if (node->rustate == NULL)
 | 
						|
	{
 | 
						|
		WorkTableScan *plan = (WorkTableScan *) node->ss.ps.plan;
 | 
						|
		EState	   *estate = node->ss.ps.state;
 | 
						|
		ParamExecData *param;
 | 
						|
 | 
						|
		param = &(estate->es_param_exec_vals[plan->wtParam]);
 | 
						|
		Assert(param->execPlan == NULL);
 | 
						|
		Assert(!param->isnull);
 | 
						|
		node->rustate = castNode(RecursiveUnionState, DatumGetPointer(param->value));
 | 
						|
		Assert(node->rustate);
 | 
						|
 | 
						|
		/*
 | 
						|
		 * The scan tuple type (ie, the rowtype we expect to find in the work
 | 
						|
		 * table) is the same as the result rowtype of the ancestor
 | 
						|
		 * RecursiveUnion node.  Note this depends on the assumption that
 | 
						|
		 * RecursiveUnion doesn't allow projection.
 | 
						|
		 */
 | 
						|
		ExecAssignScanType(&node->ss,
 | 
						|
						   ExecGetResultType(&node->rustate->ps));
 | 
						|
 | 
						|
		/*
 | 
						|
		 * Now we can initialize the projection info.  This must be completed
 | 
						|
		 * before we can call ExecScan().
 | 
						|
		 */
 | 
						|
		ExecAssignScanProjectionInfo(&node->ss);
 | 
						|
	}
 | 
						|
 | 
						|
	return ExecScan(&node->ss,
 | 
						|
					(ExecScanAccessMtd) WorkTableScanNext,
 | 
						|
					(ExecScanRecheckMtd) WorkTableScanRecheck);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* ----------------------------------------------------------------
 | 
						|
 *		ExecInitWorkTableScan
 | 
						|
 * ----------------------------------------------------------------
 | 
						|
 */
 | 
						|
WorkTableScanState *
 | 
						|
ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags)
 | 
						|
{
 | 
						|
	WorkTableScanState *scanstate;
 | 
						|
 | 
						|
	/* check for unsupported flags */
 | 
						|
	Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
 | 
						|
 | 
						|
	/*
 | 
						|
	 * WorkTableScan should not have any children.
 | 
						|
	 */
 | 
						|
	Assert(outerPlan(node) == NULL);
 | 
						|
	Assert(innerPlan(node) == NULL);
 | 
						|
 | 
						|
	/*
 | 
						|
	 * create new WorkTableScanState for node
 | 
						|
	 */
 | 
						|
	scanstate = makeNode(WorkTableScanState);
 | 
						|
	scanstate->ss.ps.plan = (Plan *) node;
 | 
						|
	scanstate->ss.ps.state = estate;
 | 
						|
	scanstate->ss.ps.ExecProcNode = ExecWorkTableScan;
 | 
						|
	scanstate->rustate = NULL;	/* we'll set this later */
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Miscellaneous initialization
 | 
						|
	 *
 | 
						|
	 * create expression context for node
 | 
						|
	 */
 | 
						|
	ExecAssignExprContext(estate, &scanstate->ss.ps);
 | 
						|
 | 
						|
	/*
 | 
						|
	 * tuple table initialization
 | 
						|
	 */
 | 
						|
	ExecInitResultTypeTL(&scanstate->ss.ps);
 | 
						|
 | 
						|
	/* signal that return type is not yet known */
 | 
						|
	scanstate->ss.ps.resultopsset = true;
 | 
						|
	scanstate->ss.ps.resultopsfixed = false;
 | 
						|
 | 
						|
	ExecInitScanTupleSlot(estate, &scanstate->ss, NULL, &TTSOpsMinimalTuple);
 | 
						|
 | 
						|
	/*
 | 
						|
	 * initialize child expressions
 | 
						|
	 */
 | 
						|
	scanstate->ss.ps.qual =
 | 
						|
		ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Do not yet initialize projection info, see ExecWorkTableScan() for
 | 
						|
	 * details.
 | 
						|
	 */
 | 
						|
 | 
						|
	return scanstate;
 | 
						|
}
 | 
						|
 | 
						|
/* ----------------------------------------------------------------
 | 
						|
 *		ExecEndWorkTableScan
 | 
						|
 *
 | 
						|
 *		frees any storage allocated through C routines.
 | 
						|
 * ----------------------------------------------------------------
 | 
						|
 */
 | 
						|
void
 | 
						|
ExecEndWorkTableScan(WorkTableScanState *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);
 | 
						|
}
 | 
						|
 | 
						|
/* ----------------------------------------------------------------
 | 
						|
 *		ExecReScanWorkTableScan
 | 
						|
 *
 | 
						|
 *		Rescans the relation.
 | 
						|
 * ----------------------------------------------------------------
 | 
						|
 */
 | 
						|
void
 | 
						|
ExecReScanWorkTableScan(WorkTableScanState *node)
 | 
						|
{
 | 
						|
	if (node->ss.ps.ps_ResultTupleSlot)
 | 
						|
		ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
 | 
						|
 | 
						|
	ExecScanReScan(&node->ss);
 | 
						|
 | 
						|
	/* No need (or way) to rescan if ExecWorkTableScan not called yet */
 | 
						|
	if (node->rustate)
 | 
						|
		tuplestore_rescan(node->rustate->working_table);
 | 
						|
}
 |