Skip to content
Snippets Groups Projects
Select Git revision
  • benchmark-tools
  • postgres-lambda
  • master default
  • REL9_4_25
  • REL9_5_20
  • REL9_6_16
  • REL_10_11
  • REL_11_6
  • REL_12_1
  • REL_12_0
  • REL_12_RC1
  • REL_12_BETA4
  • REL9_4_24
  • REL9_5_19
  • REL9_6_15
  • REL_10_10
  • REL_11_5
  • REL_12_BETA3
  • REL9_4_23
  • REL9_5_18
  • REL9_6_14
  • REL_10_9
  • REL_11_4
23 results

nodeResult.c

Blame
  • nodeResult.c 7.71 KiB
    /*-------------------------------------------------------------------------
     *
     * nodeResult.c
     *	  support for constant nodes needing special code.
     *
     * DESCRIPTION
     *
     *		Result nodes are used in queries where no relations are scanned.
     *		Examples of such queries are:
     *
     *				select 1 * 2
     *
     *				insert into emp values ('mike', 15000)
     *
     *		(Remember that in an INSERT or UPDATE, we need a plan tree that
     *		generates the new rows.)
     *
     *		Result nodes are also used to optimise queries with constant
     *		qualifications (ie, quals that do not depend on the scanned data),
     *		such as:
     *
     *				select * from emp where 2 > 1
     *
     *		In this case, the plan generated is
     *
     *						Result	(with 2 > 1 qual)
     *						/
     *				   SeqScan (emp.*)
     *
     *		At runtime, the Result node evaluates the constant qual once,
     *		which is shown by EXPLAIN as a One-Time Filter.  If it's
     *		false, we can return an empty result set without running the
     *		controlled plan at all.  If it's true, we run the controlled
     *		plan normally and pass back the results.
     *
     *
     * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
     * Portions Copyright (c) 1994, Regents of the University of California
     *
     * IDENTIFICATION
     *	  src/backend/executor/nodeResult.c
     *
     *-------------------------------------------------------------------------
     */
    
    #include "postgres.h"
    
    #include "executor/executor.h"
    #include "executor/nodeResult.h"
    #include "utils/memutils.h"
    
    
    /* ----------------------------------------------------------------
     *		ExecResult(node)
     *
     *		returns the tuples from the outer plan which satisfy the
     *		qualification clause.  Since result nodes with right
     *		subtrees are never planned, we ignore the right subtree
     *		entirely (for now).. -cim 10/7/89
     *
     *		The qualification containing only constant clauses are
     *		checked first before any processing is done. It always returns
     *		'nil' if the constant qualification is not satisfied.
     * ----------------------------------------------------------------
     */
    TupleTableSlot *
    ExecResult(ResultState *node)
    {
    	TupleTableSlot *outerTupleSlot;
    	TupleTableSlot *resultSlot;
    	PlanState  *outerPlan;
    	ExprContext *econtext;
    	ExprDoneCond isDone;
    
    	econtext = node->ps.ps_ExprContext;
    
    	/*
    	 * check constant qualifications like (2 > 1), if not already done
    	 */
    	if (node->rs_checkqual)
    	{
    		bool		qualResult = ExecQual((List *) node->resconstantqual,
    										  econtext,
    										  false);
    
    		node->rs_checkqual = false;
    		if (!qualResult)
    		{
    			node->rs_done = true;
    			return NULL;
    		}
    	}
    
    	/*
    	 * Check to see if we're still projecting out tuples from a previous scan
    	 * tuple (because there is a function-returning-set in the projection
    	 * expressions).  If so, try to project another one.
    	 */
    	if (node->ps.ps_TupFromTlist)
    	{
    		resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
    		if (isDone == ExprMultipleResult)
    			return resultSlot;
    		/* Done with that source tuple... */
    		node->ps.ps_TupFromTlist = false;
    	}
    
    	/*
    	 * Reset per-tuple memory context to free any expression evaluation
    	 * storage allocated in the previous tuple cycle.  Note this can't happen
    	 * until we're done projecting out tuples from a scan tuple.
    	 */
    	ResetExprContext(econtext);
    
    	/*
    	 * if rs_done is true then it means that we were asked to return a
    	 * constant tuple and we already did the last time ExecResult() was
    	 * called, OR that we failed the constant qual check. Either way, now we
    	 * are through.
    	 */
    	while (!node->rs_done)
    	{
    		outerPlan = outerPlanState(node);
    
    		if (outerPlan != NULL)
    		{
    			/*
    			 * retrieve tuples from the outer plan until there are no more.
    			 */
    			outerTupleSlot = ExecProcNode(outerPlan);
    
    			if (TupIsNull(outerTupleSlot))
    				return NULL;
    
    			/*
    			 * prepare to compute projection expressions, which will expect to
    			 * access the input tuples as varno OUTER.
    			 */
    			econtext->ecxt_outertuple = outerTupleSlot;
    		}
    		else
    		{
    			/*
    			 * if we don't have an outer plan, then we are just generating the
    			 * results from a constant target list.  Do it only once.
    			 */
    			node->rs_done = true;
    		}
    
    		/*
    		 * form the result tuple using ExecProject(), and return it --- unless
    		 * the projection produces an empty set, in which case we must loop
    		 * back to see if there are more outerPlan tuples.
    		 */
    		resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
    
    		if (isDone != ExprEndResult)
    		{
    			node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
    			return resultSlot;
    		}
    	}
    
    	return NULL;
    }
    
    /* ----------------------------------------------------------------
     *		ExecResultMarkPos
     * ----------------------------------------------------------------
     */
    void
    ExecResultMarkPos(ResultState *node)
    {
    	PlanState  *outerPlan = outerPlanState(node);
    
    	if (outerPlan != NULL)
    		ExecMarkPos(outerPlan);
    	else
    		elog(DEBUG2, "Result nodes do not support mark/restore");
    }
    
    /* ----------------------------------------------------------------
     *		ExecResultRestrPos
     * ----------------------------------------------------------------
     */
    void
    ExecResultRestrPos(ResultState *node)
    {
    	PlanState  *outerPlan = outerPlanState(node);
    
    	if (outerPlan != NULL)
    		ExecRestrPos(outerPlan);
    	else
    		elog(ERROR, "Result nodes do not support mark/restore");
    }
    
    /* ----------------------------------------------------------------
     *		ExecInitResult
     *
     *		Creates the run-time state information for the result node
     *		produced by the planner and initializes outer relations
     *		(child nodes).
     * ----------------------------------------------------------------
     */
    ResultState *
    ExecInitResult(Result *node, EState *estate, int eflags)
    {
    	ResultState *resstate;
    
    	/* check for unsupported flags */
    	Assert(!(eflags & (EXEC_FLAG_MARK | EXEC_FLAG_BACKWARD)) ||
    		   outerPlan(node) != NULL);
    
    	/*
    	 * create state structure
    	 */
    	resstate = makeNode(ResultState);
    	resstate->ps.plan = (Plan *) node;
    	resstate->ps.state = estate;
    
    	resstate->rs_done = false;
    	resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
    
    	/*
    	 * Miscellaneous initialization
    	 *
    	 * create expression context for node
    	 */
    	ExecAssignExprContext(estate, &resstate->ps);
    
    	resstate->ps.ps_TupFromTlist = false;
    
    	/*
    	 * tuple table initialization
    	 */
    	ExecInitResultTupleSlot(estate, &resstate->ps);
    
    	/*
    	 * initialize child expressions
    	 */
    	resstate->ps.targetlist = (List *)
    		ExecInitExpr((Expr *) node->plan.targetlist,
    					 (PlanState *) resstate);
    	resstate->ps.qual = (List *)
    		ExecInitExpr((Expr *) node->plan.qual,
    					 (PlanState *) resstate);
    	resstate->resconstantqual = ExecInitExpr((Expr *) node->resconstantqual,
    											 (PlanState *) resstate);
    
    	/*
    	 * initialize child nodes
    	 */
    	outerPlanState(resstate) = ExecInitNode(outerPlan(node), estate, eflags);
    
    	/*
    	 * we don't use inner plan
    	 */
    	Assert(innerPlan(node) == NULL);
    
    	/*
    	 * initialize tuple type and projection info
    	 */
    	ExecAssignResultTypeFromTL(&resstate->ps);
    	ExecAssignProjectionInfo(&resstate->ps, NULL);
    
    	return resstate;
    }
    
    /* ----------------------------------------------------------------
     *		ExecEndResult
     *
     *		frees up storage allocated through C routines
     * ----------------------------------------------------------------
     */
    void
    ExecEndResult(ResultState *node)
    {
    	/*
    	 * Free the exprcontext
    	 */
    	ExecFreeExprContext(&node->ps);
    
    	/*
    	 * clean out the tuple table
    	 */
    	ExecClearTuple(node->ps.ps_ResultTupleSlot);
    
    	/*
    	 * shut down subplans
    	 */
    	ExecEndNode(outerPlanState(node));
    }
    
    void
    ExecReScanResult(ResultState *node)
    {
    	node->rs_done = false;
    	node->ps.ps_TupFromTlist = false;
    	node->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
    
    	/*
    	 * If chgParam of subnode is not null then plan will be re-scanned by
    	 * first ExecProcNode.
    	 */
    	if (node->ps.lefttree &&
    		node->ps.lefttree->chgParam == NULL)
    		ExecReScan(node->ps.lefttree);
    }