Remove obsoleted code relating to targetlist SRF evaluation.

Since 69f4b9c plain expression evaluation (and thus normal projection)
can't return sets of tuples anymore. Thus remove code dealing with
that possibility.

This will require adjustments in external code using
ExecEvalExpr()/ExecProject() - that should neither be hard nor very
common.

Author: Andres Freund and Tom Lane
Discussion: https://postgr.es/m/20160822214023.aaxz5l4igypowyri@alap3.anarazel.de
This commit is contained in:
Andres Freund 2017-01-19 14:12:38 -08:00
parent 8eace46d34
commit ea15e18677
44 changed files with 356 additions and 1212 deletions

View File

@ -3444,7 +3444,7 @@ process_query_params(ExprContext *econtext,
bool isNull; bool isNull;
/* Evaluate the parameter expression */ /* Evaluate the parameter expression */
expr_value = ExecEvalExpr(expr_state, econtext, &isNull, NULL); expr_value = ExecEvalExpr(expr_state, econtext, &isNull);
/* /*
* Get string representation of each parameter value by invoking * Get string representation of each parameter value by invoking

View File

@ -1805,8 +1805,7 @@ FormIndexDatum(IndexInfo *indexInfo,
elog(ERROR, "wrong number of index expressions"); elog(ERROR, "wrong number of index expressions");
iDatum = ExecEvalExprSwitchContext((ExprState *) lfirst(indexpr_item), iDatum = ExecEvalExprSwitchContext((ExprState *) lfirst(indexpr_item),
GetPerTupleExprContext(estate), GetPerTupleExprContext(estate),
&isNull, &isNull);
NULL);
indexpr_item = lnext(indexpr_item); indexpr_item = lnext(indexpr_item);
} }
values[i] = iDatum; values[i] = iDatum;

View File

@ -1358,7 +1358,7 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
test_exprstate = ExecInitExpr(test_expr, NULL); test_exprstate = ExecInitExpr(test_expr, NULL);
test_result = ExecEvalExprSwitchContext(test_exprstate, test_result = ExecEvalExprSwitchContext(test_exprstate,
GetPerTupleExprContext(estate), GetPerTupleExprContext(estate),
&isNull, NULL); &isNull);
MemoryContextSwitchTo(oldcxt); MemoryContextSwitchTo(oldcxt);
FreeExecutorState(estate); FreeExecutorState(estate);
@ -1630,8 +1630,7 @@ FormPartitionKeyDatum(PartitionDispatch pd,
elog(ERROR, "wrong number of partition key expressions"); elog(ERROR, "wrong number of partition key expressions");
datum = ExecEvalExprSwitchContext((ExprState *) lfirst(partexpr_item), datum = ExecEvalExprSwitchContext((ExprState *) lfirst(partexpr_item),
GetPerTupleExprContext(estate), GetPerTupleExprContext(estate),
&isNull, &isNull);
NULL);
partexpr_item = lnext(partexpr_item); partexpr_item = lnext(partexpr_item);
} }
values[i] = datum; values[i] = datum;

View File

@ -3394,7 +3394,7 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
Assert(CurrentMemoryContext == econtext->ecxt_per_tuple_memory); Assert(CurrentMemoryContext == econtext->ecxt_per_tuple_memory);
values[defmap[i]] = ExecEvalExpr(defexprs[i], econtext, values[defmap[i]] = ExecEvalExpr(defexprs[i], econtext,
&nulls[defmap[i]], NULL); &nulls[defmap[i]]);
} }
return true; return true;

View File

@ -413,8 +413,7 @@ EvaluateParams(PreparedStatement *pstmt, List *params,
prm->pflags = PARAM_FLAG_CONST; prm->pflags = PARAM_FLAG_CONST;
prm->value = ExecEvalExprSwitchContext(n, prm->value = ExecEvalExprSwitchContext(n,
GetPerTupleExprContext(estate), GetPerTupleExprContext(estate),
&prm->isnull, &prm->isnull);
NULL);
i++; i++;
} }

View File

@ -4460,8 +4460,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
values[ex->attnum - 1] = ExecEvalExpr(ex->exprstate, values[ex->attnum - 1] = ExecEvalExpr(ex->exprstate,
econtext, econtext,
&isnull[ex->attnum - 1], &isnull[ex->attnum - 1]);
NULL);
} }
/* /*

View File

@ -2735,7 +2735,7 @@ validateDomainConstraint(Oid domainoid, char *ccbin)
conResult = ExecEvalExprSwitchContext(exprstate, conResult = ExecEvalExprSwitchContext(exprstate,
econtext, econtext,
&isNull, NULL); &isNull);
if (!isNull && !DatumGetBool(conResult)) if (!isNull && !DatumGetBool(conResult))
{ {

View File

@ -59,7 +59,6 @@
#include "utils/syscache.h" #include "utils/syscache.h"
static bool TargetListSupportsBackwardScan(List *targetlist);
static bool IndexSupportsBackwardScan(Oid indexid); static bool IndexSupportsBackwardScan(Oid indexid);
@ -120,7 +119,7 @@ ExecReScan(PlanState *node)
UpdateChangedParamSet(node->righttree, node->chgParam); UpdateChangedParamSet(node->righttree, node->chgParam);
} }
/* Shut down any SRFs in the plan node's targetlist */ /* Call expression callbacks */
if (node->ps_ExprContext) if (node->ps_ExprContext)
ReScanExprContext(node->ps_ExprContext); ReScanExprContext(node->ps_ExprContext);
@ -460,8 +459,7 @@ ExecSupportsBackwardScan(Plan *node)
{ {
case T_Result: case T_Result:
if (outerPlan(node) != NULL) if (outerPlan(node) != NULL)
return ExecSupportsBackwardScan(outerPlan(node)) && return ExecSupportsBackwardScan(outerPlan(node));
TargetListSupportsBackwardScan(node->targetlist);
else else
return false; return false;
@ -478,13 +476,6 @@ ExecSupportsBackwardScan(Plan *node)
return true; return true;
} }
case T_SeqScan:
case T_TidScan:
case T_FunctionScan:
case T_ValuesScan:
case T_CteScan:
return TargetListSupportsBackwardScan(node->targetlist);
case T_SampleScan: case T_SampleScan:
/* Simplify life for tablesample methods by disallowing this */ /* Simplify life for tablesample methods by disallowing this */
return false; return false;
@ -493,35 +484,34 @@ ExecSupportsBackwardScan(Plan *node)
return false; return false;
case T_IndexScan: case T_IndexScan:
return IndexSupportsBackwardScan(((IndexScan *) node)->indexid) && return IndexSupportsBackwardScan(((IndexScan *) node)->indexid);
TargetListSupportsBackwardScan(node->targetlist);
case T_IndexOnlyScan: case T_IndexOnlyScan:
return IndexSupportsBackwardScan(((IndexOnlyScan *) node)->indexid) && return IndexSupportsBackwardScan(((IndexOnlyScan *) node)->indexid);
TargetListSupportsBackwardScan(node->targetlist);
case T_SubqueryScan: case T_SubqueryScan:
return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan) && return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan);
TargetListSupportsBackwardScan(node->targetlist);
case T_CustomScan: case T_CustomScan:
{ {
uint32 flags = ((CustomScan *) node)->flags; uint32 flags = ((CustomScan *) node)->flags;
if ((flags & CUSTOMPATH_SUPPORT_BACKWARD_SCAN) && if (flags & CUSTOMPATH_SUPPORT_BACKWARD_SCAN)
TargetListSupportsBackwardScan(node->targetlist))
return true; return true;
} }
return false; return false;
case T_SeqScan:
case T_TidScan:
case T_FunctionScan:
case T_ValuesScan:
case T_CteScan:
case T_Material: case T_Material:
case T_Sort: case T_Sort:
/* these don't evaluate tlist */
return true; return true;
case T_LockRows: case T_LockRows:
case T_Limit: case T_Limit:
/* these don't evaluate tlist */
return ExecSupportsBackwardScan(outerPlan(node)); return ExecSupportsBackwardScan(outerPlan(node));
default: default:
@ -529,18 +519,6 @@ ExecSupportsBackwardScan(Plan *node)
} }
} }
/*
* If the tlist contains set-returning functions, we can't support backward
* scan, because the TupFromTlist code is direction-ignorant.
*/
static bool
TargetListSupportsBackwardScan(List *targetlist)
{
if (expression_returns_set((Node *) targetlist))
return false;
return true;
}
/* /*
* An IndexScan or IndexOnlyScan node supports backward scan only if the * An IndexScan or IndexOnlyScan node supports backward scan only if the
* index's AM does. * index's AM does.

File diff suppressed because it is too large Load Diff

View File

@ -125,8 +125,6 @@ ExecScan(ScanState *node,
ExprContext *econtext; ExprContext *econtext;
List *qual; List *qual;
ProjectionInfo *projInfo; ProjectionInfo *projInfo;
ExprDoneCond isDone;
TupleTableSlot *resultSlot;
/* /*
* Fetch data from node * Fetch data from node
@ -145,25 +143,9 @@ ExecScan(ScanState *node,
return ExecScanFetch(node, accessMtd, recheckMtd); return ExecScanFetch(node, accessMtd, recheckMtd);
} }
/*
* 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)
{
Assert(projInfo); /* can't get here if not projecting */
resultSlot = ExecProject(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 * Reset per-tuple memory context to free any expression evaluation
* storage allocated in the previous tuple cycle. Note this can't happen * storage allocated in the previous tuple cycle.
* until we're done projecting out tuples from a scan tuple.
*/ */
ResetExprContext(econtext); ResetExprContext(econtext);
@ -214,15 +196,9 @@ ExecScan(ScanState *node,
{ {
/* /*
* Form a projection tuple, store it in the result tuple slot * Form a projection tuple, store it in the result tuple slot
* and return it --- unless we find we can project no tuples * and return it.
* from this scan tuple, in which case continue scan.
*/ */
resultSlot = ExecProject(projInfo, &isDone); return ExecProject(projInfo);
if (isDone != ExprEndResult)
{
node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
return resultSlot;
}
} }
else else
{ {
@ -352,9 +328,6 @@ ExecScanReScan(ScanState *node)
{ {
EState *estate = node->ps.state; EState *estate = node->ps.state;
/* Stop projecting any tuples from SRFs in the targetlist */
node->ps.ps_TupFromTlist = false;
/* Rescan EvalPlanQual tuple if we're inside an EvalPlanQual recheck */ /* Rescan EvalPlanQual tuple if we're inside an EvalPlanQual recheck */
if (estate->es_epqScanDone != NULL) if (estate->es_epqScanDone != NULL)
{ {

View File

@ -586,12 +586,6 @@ ExecBuildProjectionInfo(List *targetList,
projInfo->pi_numSimpleVars = numSimpleVars; projInfo->pi_numSimpleVars = numSimpleVars;
projInfo->pi_directMap = directMap; projInfo->pi_directMap = directMap;
if (exprlist == NIL)
projInfo->pi_itemIsDone = NULL; /* not needed */
else
projInfo->pi_itemIsDone = (ExprDoneCond *)
palloc(len * sizeof(ExprDoneCond));
return projInfo; return projInfo;
} }

View File

@ -854,7 +854,7 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup)
/* compute input for all aggregates */ /* compute input for all aggregates */
if (aggstate->evalproj) if (aggstate->evalproj)
aggstate->evalslot = ExecProject(aggstate->evalproj, NULL); aggstate->evalslot = ExecProject(aggstate->evalproj);
for (transno = 0; transno < numTrans; transno++) for (transno = 0; transno < numTrans; transno++)
{ {
@ -871,7 +871,7 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup)
bool isnull; bool isnull;
res = ExecEvalExprSwitchContext(filter, aggstate->tmpcontext, res = ExecEvalExprSwitchContext(filter, aggstate->tmpcontext,
&isnull, NULL); &isnull);
if (isnull || !DatumGetBool(res)) if (isnull || !DatumGetBool(res))
continue; continue;
} }
@ -970,7 +970,7 @@ combine_aggregates(AggState *aggstate, AggStatePerGroup pergroup)
Assert(aggstate->phase->numsets == 0); Assert(aggstate->phase->numsets == 0);
/* compute input for all aggregates */ /* compute input for all aggregates */
slot = ExecProject(aggstate->evalproj, NULL); slot = ExecProject(aggstate->evalproj);
for (transno = 0; transno < numTrans; transno++) for (transno = 0; transno < numTrans; transno++)
{ {
@ -1368,8 +1368,7 @@ finalize_aggregate(AggState *aggstate,
fcinfo.arg[i] = ExecEvalExpr(expr, fcinfo.arg[i] = ExecEvalExpr(expr,
aggstate->ss.ps.ps_ExprContext, aggstate->ss.ps.ps_ExprContext,
&fcinfo.argnull[i], &fcinfo.argnull[i]);
NULL);
anynull |= fcinfo.argnull[i]; anynull |= fcinfo.argnull[i];
i++; i++;
} }
@ -1630,7 +1629,7 @@ finalize_aggregates(AggState *aggstate,
/* /*
* Project the result of a group (whose aggs have already been calculated by * Project the result of a group (whose aggs have already been calculated by
* finalize_aggregates). Returns the result slot, or NULL if no row is * finalize_aggregates). Returns the result slot, or NULL if no row is
* projected (suppressed by qual or by an empty SRF). * projected (suppressed by qual).
*/ */
static TupleTableSlot * static TupleTableSlot *
project_aggregates(AggState *aggstate) project_aggregates(AggState *aggstate)
@ -1643,20 +1642,10 @@ project_aggregates(AggState *aggstate)
if (ExecQual(aggstate->ss.ps.qual, econtext, false)) if (ExecQual(aggstate->ss.ps.qual, econtext, false))
{ {
/* /*
* Form and return or store a projection tuple using the aggregate * Form and return projection tuple using the aggregate results and
* results and the representative input tuple. * the representative input tuple.
*/ */
ExprDoneCond isDone; return ExecProject(aggstate->ss.ps.ps_ProjInfo);
TupleTableSlot *result;
result = ExecProject(aggstate->ss.ps.ps_ProjInfo, &isDone);
if (isDone != ExprEndResult)
{
aggstate->ss.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
return result;
}
} }
else else
InstrCountFiltered1(aggstate, 1); InstrCountFiltered1(aggstate, 1);
@ -1911,27 +1900,6 @@ ExecAgg(AggState *node)
{ {
TupleTableSlot *result; TupleTableSlot *result;
/*
* Check to see if we're still projecting out tuples from a previous agg
* tuple (because there is a function-returning-set in the projection
* expressions). If so, try to project another one.
*/
if (node->ss.ps.ps_TupFromTlist)
{
ExprDoneCond isDone;
result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
if (isDone == ExprMultipleResult)
return result;
/* Done with that source tuple... */
node->ss.ps.ps_TupFromTlist = false;
}
/*
* (We must do the ps_TupFromTlist check first, because in some cases
* agg_done gets set before we emit the final aggregate tuple, and we have
* to finish running SRFs for it.)
*/
if (!node->agg_done) if (!node->agg_done)
{ {
/* Dispatch based on strategy */ /* Dispatch based on strategy */
@ -2571,8 +2539,6 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
ExecAssignResultTypeFromTL(&aggstate->ss.ps); ExecAssignResultTypeFromTL(&aggstate->ss.ps);
ExecAssignProjectionInfo(&aggstate->ss.ps, NULL); ExecAssignProjectionInfo(&aggstate->ss.ps, NULL);
aggstate->ss.ps.ps_TupFromTlist = false;
/* /*
* get the count of aggregates in targetlist and quals * get the count of aggregates in targetlist and quals
*/ */
@ -3575,8 +3541,6 @@ ExecReScanAgg(AggState *node)
node->agg_done = false; node->agg_done = false;
node->ss.ps.ps_TupFromTlist = false;
if (aggnode->aggstrategy == AGG_HASHED) if (aggnode->aggstrategy == AGG_HASHED)
{ {
/* /*

View File

@ -575,8 +575,6 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags)
*/ */
ExecAssignExprContext(estate, &scanstate->ss.ps); ExecAssignExprContext(estate, &scanstate->ss.ps);
scanstate->ss.ps.ps_TupFromTlist = false;
/* /*
* initialize child expressions * initialize child expressions
*/ */

View File

@ -269,8 +269,6 @@ ExecInitCteScan(CteScan *node, EState *estate, int eflags)
ExecAssignResultTypeFromTL(&scanstate->ss.ps); ExecAssignResultTypeFromTL(&scanstate->ss.ps);
ExecAssignScanProjectionInfo(&scanstate->ss); ExecAssignScanProjectionInfo(&scanstate->ss);
scanstate->ss.ps.ps_TupFromTlist = false;
return scanstate; return scanstate;
} }

View File

@ -48,8 +48,6 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
/* create expression context for node */ /* create expression context for node */
ExecAssignExprContext(estate, &css->ss.ps); ExecAssignExprContext(estate, &css->ss.ps);
css->ss.ps.ps_TupFromTlist = false;
/* initialize child expressions */ /* initialize child expressions */
css->ss.ps.targetlist = (List *) css->ss.ps.targetlist = (List *)
ExecInitExpr((Expr *) cscan->scan.plan.targetlist, ExecInitExpr((Expr *) cscan->scan.plan.targetlist,

View File

@ -152,8 +152,6 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
*/ */
ExecAssignExprContext(estate, &scanstate->ss.ps); ExecAssignExprContext(estate, &scanstate->ss.ps);
scanstate->ss.ps.ps_TupFromTlist = false;
/* /*
* initialize child expressions * initialize child expressions
*/ */

View File

@ -331,8 +331,6 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
*/ */
ExecAssignExprContext(estate, &scanstate->ss.ps); ExecAssignExprContext(estate, &scanstate->ss.ps);
scanstate->ss.ps.ps_TupFromTlist = false;
/* /*
* tuple table initialization * tuple table initialization
*/ */

View File

@ -100,8 +100,6 @@ ExecInitGather(Gather *node, EState *estate, int eflags)
outerNode = outerPlan(node); outerNode = outerPlan(node);
outerPlanState(gatherstate) = ExecInitNode(outerNode, estate, eflags); outerPlanState(gatherstate) = ExecInitNode(outerNode, estate, eflags);
gatherstate->ps.ps_TupFromTlist = false;
/* /*
* Initialize result tuple type and projection info. * Initialize result tuple type and projection info.
*/ */
@ -132,8 +130,6 @@ ExecGather(GatherState *node)
TupleTableSlot *fslot = node->funnel_slot; TupleTableSlot *fslot = node->funnel_slot;
int i; int i;
TupleTableSlot *slot; TupleTableSlot *slot;
TupleTableSlot *resultSlot;
ExprDoneCond isDone;
ExprContext *econtext; ExprContext *econtext;
/* /*
@ -199,26 +195,11 @@ ExecGather(GatherState *node)
node->initialized = true; node->initialized = true;
} }
/*
* 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 * Reset per-tuple memory context to free any expression evaluation
* storage allocated in the previous tuple cycle. Note we can't do this * storage allocated in the previous tuple cycle. This will also clear
* until we're done projecting. This will also clear any previous tuple * any previous tuple returned by a TupleQueueReader; to make sure we
* returned by a TupleQueueReader; to make sure we don't leave a dangling * don't leave a dangling pointer around, clear the working slot first.
* pointer around, clear the working slot first.
*/ */
ExecClearTuple(node->funnel_slot); ExecClearTuple(node->funnel_slot);
econtext = node->ps.ps_ExprContext; econtext = node->ps.ps_ExprContext;
@ -241,13 +222,8 @@ ExecGather(GatherState *node)
* back around for another tuple * back around for another tuple
*/ */
econtext->ecxt_outertuple = slot; econtext->ecxt_outertuple = slot;
resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
if (isDone != ExprEndResult) return ExecProject(node->ps.ps_ProjInfo);
{
node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
return resultSlot;
}
} }
return slot; return slot;

View File

@ -49,23 +49,6 @@ ExecGroup(GroupState *node)
numCols = ((Group *) node->ss.ps.plan)->numCols; numCols = ((Group *) node->ss.ps.plan)->numCols;
grpColIdx = ((Group *) node->ss.ps.plan)->grpColIdx; grpColIdx = ((Group *) node->ss.ps.plan)->grpColIdx;
/*
* Check to see if we're still projecting out tuples from a previous group
* tuple (because there is a function-returning-set in the projection
* expressions). If so, try to project another one.
*/
if (node->ss.ps.ps_TupFromTlist)
{
TupleTableSlot *result;
ExprDoneCond isDone;
result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
if (isDone == ExprMultipleResult)
return result;
/* Done with that source tuple... */
node->ss.ps.ps_TupFromTlist = false;
}
/* /*
* The ScanTupleSlot holds the (copied) first tuple of each group. * The ScanTupleSlot holds the (copied) first tuple of each group.
*/ */
@ -107,16 +90,7 @@ ExecGroup(GroupState *node)
/* /*
* Form and return a projection tuple using the first input tuple. * Form and return a projection tuple using the first input tuple.
*/ */
TupleTableSlot *result; return ExecProject(node->ss.ps.ps_ProjInfo);
ExprDoneCond isDone;
result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
if (isDone != ExprEndResult)
{
node->ss.ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
return result;
}
} }
else else
InstrCountFiltered1(node, 1); InstrCountFiltered1(node, 1);
@ -170,16 +144,7 @@ ExecGroup(GroupState *node)
/* /*
* Form and return a projection tuple using the first input tuple. * Form and return a projection tuple using the first input tuple.
*/ */
TupleTableSlot *result; return ExecProject(node->ss.ps.ps_ProjInfo);
ExprDoneCond isDone;
result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
if (isDone != ExprEndResult)
{
node->ss.ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
return result;
}
} }
else else
InstrCountFiltered1(node, 1); InstrCountFiltered1(node, 1);
@ -246,8 +211,6 @@ ExecInitGroup(Group *node, EState *estate, int eflags)
ExecAssignResultTypeFromTL(&grpstate->ss.ps); ExecAssignResultTypeFromTL(&grpstate->ss.ps);
ExecAssignProjectionInfo(&grpstate->ss.ps, NULL); ExecAssignProjectionInfo(&grpstate->ss.ps, NULL);
grpstate->ss.ps.ps_TupFromTlist = false;
/* /*
* Precompute fmgr lookup data for inner loop * Precompute fmgr lookup data for inner loop
*/ */
@ -283,7 +246,6 @@ ExecReScanGroup(GroupState *node)
PlanState *outerPlan = outerPlanState(node); PlanState *outerPlan = outerPlanState(node);
node->grp_done = FALSE; node->grp_done = FALSE;
node->ss.ps.ps_TupFromTlist = false;
/* must clear first tuple */ /* must clear first tuple */
ExecClearTuple(node->ss.ss_ScanTupleSlot); ExecClearTuple(node->ss.ss_ScanTupleSlot);

View File

@ -959,7 +959,7 @@ ExecHashGetHashValue(HashJoinTable hashtable,
/* /*
* Get the join attribute value of the tuple * Get the join attribute value of the tuple
*/ */
keyval = ExecEvalExpr(keyexpr, econtext, &isNull, NULL); keyval = ExecEvalExpr(keyexpr, econtext, &isNull);
/* /*
* If the attribute is NULL, and the join operator is strict, then * If the attribute is NULL, and the join operator is strict, then

View File

@ -66,7 +66,6 @@ ExecHashJoin(HashJoinState *node)
List *joinqual; List *joinqual;
List *otherqual; List *otherqual;
ExprContext *econtext; ExprContext *econtext;
ExprDoneCond isDone;
HashJoinTable hashtable; HashJoinTable hashtable;
TupleTableSlot *outerTupleSlot; TupleTableSlot *outerTupleSlot;
uint32 hashvalue; uint32 hashvalue;
@ -82,26 +81,9 @@ ExecHashJoin(HashJoinState *node)
hashtable = node->hj_HashTable; hashtable = node->hj_HashTable;
econtext = node->js.ps.ps_ExprContext; econtext = node->js.ps.ps_ExprContext;
/*
* Check to see if we're still projecting out tuples from a previous join
* tuple (because there is a function-returning-set in the projection
* expressions). If so, try to project another one.
*/
if (node->js.ps.ps_TupFromTlist)
{
TupleTableSlot *result;
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
if (isDone == ExprMultipleResult)
return result;
/* Done with that source tuple... */
node->js.ps.ps_TupFromTlist = false;
}
/* /*
* Reset per-tuple memory context to free any expression evaluation * Reset per-tuple memory context to free any expression evaluation
* storage allocated in the previous tuple cycle. Note this can't happen * storage allocated in the previous tuple cycle.
* until we're done projecting out tuples from a join tuple.
*/ */
ResetExprContext(econtext); ResetExprContext(econtext);
@ -314,18 +296,7 @@ ExecHashJoin(HashJoinState *node)
if (otherqual == NIL || if (otherqual == NIL ||
ExecQual(otherqual, econtext, false)) ExecQual(otherqual, econtext, false))
{ return ExecProject(node->js.ps.ps_ProjInfo);
TupleTableSlot *result;
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
if (isDone != ExprEndResult)
{
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
return result;
}
}
else else
InstrCountFiltered2(node, 1); InstrCountFiltered2(node, 1);
} }
@ -353,18 +324,7 @@ ExecHashJoin(HashJoinState *node)
if (otherqual == NIL || if (otherqual == NIL ||
ExecQual(otherqual, econtext, false)) ExecQual(otherqual, econtext, false))
{ return ExecProject(node->js.ps.ps_ProjInfo);
TupleTableSlot *result;
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
if (isDone != ExprEndResult)
{
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
return result;
}
}
else else
InstrCountFiltered2(node, 1); InstrCountFiltered2(node, 1);
} }
@ -392,18 +352,7 @@ ExecHashJoin(HashJoinState *node)
if (otherqual == NIL || if (otherqual == NIL ||
ExecQual(otherqual, econtext, false)) ExecQual(otherqual, econtext, false))
{ return ExecProject(node->js.ps.ps_ProjInfo);
TupleTableSlot *result;
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
if (isDone != ExprEndResult)
{
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
return result;
}
}
else else
InstrCountFiltered2(node, 1); InstrCountFiltered2(node, 1);
break; break;
@ -586,7 +535,6 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags)
/* child Hash node needs to evaluate inner hash keys, too */ /* child Hash node needs to evaluate inner hash keys, too */
((HashState *) innerPlanState(hjstate))->hashkeys = rclauses; ((HashState *) innerPlanState(hjstate))->hashkeys = rclauses;
hjstate->js.ps.ps_TupFromTlist = false;
hjstate->hj_JoinState = HJ_BUILD_HASHTABLE; hjstate->hj_JoinState = HJ_BUILD_HASHTABLE;
hjstate->hj_MatchedOuter = false; hjstate->hj_MatchedOuter = false;
hjstate->hj_OuterNotEmpty = false; hjstate->hj_OuterNotEmpty = false;
@ -1000,7 +948,6 @@ ExecReScanHashJoin(HashJoinState *node)
node->hj_CurSkewBucketNo = INVALID_SKEW_BUCKET_NO; node->hj_CurSkewBucketNo = INVALID_SKEW_BUCKET_NO;
node->hj_CurTuple = NULL; node->hj_CurTuple = NULL;
node->js.ps.ps_TupFromTlist = false;
node->hj_MatchedOuter = false; node->hj_MatchedOuter = false;
node->hj_FirstOuterTupleSlot = NULL; node->hj_FirstOuterTupleSlot = NULL;

View File

@ -412,8 +412,6 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
*/ */
ExecAssignExprContext(estate, &indexstate->ss.ps); ExecAssignExprContext(estate, &indexstate->ss.ps);
indexstate->ss.ps.ps_TupFromTlist = false;
/* /*
* initialize child expressions * initialize child expressions
* *

View File

@ -336,8 +336,7 @@ EvalOrderByExpressions(IndexScanState *node, ExprContext *econtext)
node->iss_OrderByValues[i] = ExecEvalExpr(orderby, node->iss_OrderByValues[i] = ExecEvalExpr(orderby,
econtext, econtext,
&node->iss_OrderByNulls[i], &node->iss_OrderByNulls[i]);
NULL);
i++; i++;
} }
@ -590,8 +589,7 @@ ExecIndexEvalRuntimeKeys(ExprContext *econtext,
*/ */
scanvalue = ExecEvalExpr(key_expr, scanvalue = ExecEvalExpr(key_expr,
econtext, econtext,
&isNull, &isNull);
NULL);
if (isNull) if (isNull)
{ {
scan_key->sk_argument = scanvalue; scan_key->sk_argument = scanvalue;
@ -648,8 +646,7 @@ ExecIndexEvalArrayKeys(ExprContext *econtext,
*/ */
arraydatum = ExecEvalExpr(array_expr, arraydatum = ExecEvalExpr(array_expr,
econtext, econtext,
&isNull, &isNull);
NULL);
if (isNull) if (isNull)
{ {
result = false; result = false;
@ -837,8 +834,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
*/ */
ExecAssignExprContext(estate, &indexstate->ss.ps); ExecAssignExprContext(estate, &indexstate->ss.ps);
indexstate->ss.ps.ps_TupFromTlist = false;
/* /*
* initialize child expressions * initialize child expressions
* *

View File

@ -239,8 +239,7 @@ recompute_limits(LimitState *node)
{ {
val = ExecEvalExprSwitchContext(node->limitOffset, val = ExecEvalExprSwitchContext(node->limitOffset,
econtext, econtext,
&isNull, &isNull);
NULL);
/* Interpret NULL offset as no offset */ /* Interpret NULL offset as no offset */
if (isNull) if (isNull)
node->offset = 0; node->offset = 0;
@ -263,8 +262,7 @@ recompute_limits(LimitState *node)
{ {
val = ExecEvalExprSwitchContext(node->limitCount, val = ExecEvalExprSwitchContext(node->limitCount,
econtext, econtext,
&isNull, &isNull);
NULL);
/* Interpret NULL count as no count (LIMIT ALL) */ /* Interpret NULL count as no count (LIMIT ALL) */
if (isNull) if (isNull)
{ {
@ -346,18 +344,11 @@ pass_down_bound(LimitState *node, PlanState *child_node)
else if (IsA(child_node, ResultState)) else if (IsA(child_node, ResultState))
{ {
/* /*
* An extra consideration here is that if the Result is projecting a
* targetlist that contains any SRFs, we can't assume that every input
* tuple generates an output tuple, so a Sort underneath might need to
* return more than N tuples to satisfy LIMIT N. So we cannot use
* bounded sort.
*
* If Result supported qual checking, we'd have to punt on seeing a * If Result supported qual checking, we'd have to punt on seeing a
* qual, too. Note that having a resconstantqual is not a * qual. Note that having a resconstantqual is not a showstopper: if
* showstopper: if that fails we're not getting any rows at all. * that fails we're not getting any rows at all.
*/ */
if (outerPlanState(child_node) && if (outerPlanState(child_node))
!expression_returns_set((Node *) child_node->plan->targetlist))
pass_down_bound(node, outerPlanState(child_node)); pass_down_bound(node, outerPlanState(child_node));
} }
} }

View File

@ -313,7 +313,7 @@ MJEvalOuterValues(MergeJoinState *mergestate)
MergeJoinClause clause = &mergestate->mj_Clauses[i]; MergeJoinClause clause = &mergestate->mj_Clauses[i];
clause->ldatum = ExecEvalExpr(clause->lexpr, econtext, clause->ldatum = ExecEvalExpr(clause->lexpr, econtext,
&clause->lisnull, NULL); &clause->lisnull);
if (clause->lisnull) if (clause->lisnull)
{ {
/* match is impossible; can we end the join early? */ /* match is impossible; can we end the join early? */
@ -360,7 +360,7 @@ MJEvalInnerValues(MergeJoinState *mergestate, TupleTableSlot *innerslot)
MergeJoinClause clause = &mergestate->mj_Clauses[i]; MergeJoinClause clause = &mergestate->mj_Clauses[i];
clause->rdatum = ExecEvalExpr(clause->rexpr, econtext, clause->rdatum = ExecEvalExpr(clause->rexpr, econtext,
&clause->risnull, NULL); &clause->risnull);
if (clause->risnull) if (clause->risnull)
{ {
/* match is impossible; can we end the join early? */ /* match is impossible; can we end the join early? */
@ -465,19 +465,9 @@ MJFillOuter(MergeJoinState *node)
* qualification succeeded. now form the desired projection tuple and * qualification succeeded. now form the desired projection tuple and
* return the slot containing it. * return the slot containing it.
*/ */
TupleTableSlot *result;
ExprDoneCond isDone;
MJ_printf("ExecMergeJoin: returning outer fill tuple\n"); MJ_printf("ExecMergeJoin: returning outer fill tuple\n");
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone); return ExecProject(node->js.ps.ps_ProjInfo);
if (isDone != ExprEndResult)
{
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
return result;
}
} }
else else
InstrCountFiltered2(node, 1); InstrCountFiltered2(node, 1);
@ -506,19 +496,9 @@ MJFillInner(MergeJoinState *node)
* qualification succeeded. now form the desired projection tuple and * qualification succeeded. now form the desired projection tuple and
* return the slot containing it. * return the slot containing it.
*/ */
TupleTableSlot *result;
ExprDoneCond isDone;
MJ_printf("ExecMergeJoin: returning inner fill tuple\n"); MJ_printf("ExecMergeJoin: returning inner fill tuple\n");
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone); return ExecProject(node->js.ps.ps_ProjInfo);
if (isDone != ExprEndResult)
{
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
return result;
}
} }
else else
InstrCountFiltered2(node, 1); InstrCountFiltered2(node, 1);
@ -641,27 +621,9 @@ ExecMergeJoin(MergeJoinState *node)
doFillOuter = node->mj_FillOuter; doFillOuter = node->mj_FillOuter;
doFillInner = node->mj_FillInner; doFillInner = node->mj_FillInner;
/*
* Check to see if we're still projecting out tuples from a previous join
* tuple (because there is a function-returning-set in the projection
* expressions). If so, try to project another one.
*/
if (node->js.ps.ps_TupFromTlist)
{
TupleTableSlot *result;
ExprDoneCond isDone;
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
if (isDone == ExprMultipleResult)
return result;
/* Done with that source tuple... */
node->js.ps.ps_TupFromTlist = false;
}
/* /*
* Reset per-tuple memory context to free any expression evaluation * Reset per-tuple memory context to free any expression evaluation
* storage allocated in the previous tuple cycle. Note this can't happen * storage allocated in the previous tuple cycle.
* until we're done projecting out tuples from a join tuple.
*/ */
ResetExprContext(econtext); ResetExprContext(econtext);
@ -856,20 +818,9 @@ ExecMergeJoin(MergeJoinState *node)
* qualification succeeded. now form the desired * qualification succeeded. now form the desired
* projection tuple and return the slot containing it. * projection tuple and return the slot containing it.
*/ */
TupleTableSlot *result;
ExprDoneCond isDone;
MJ_printf("ExecMergeJoin: returning tuple\n"); MJ_printf("ExecMergeJoin: returning tuple\n");
result = ExecProject(node->js.ps.ps_ProjInfo, return ExecProject(node->js.ps.ps_ProjInfo);
&isDone);
if (isDone != ExprEndResult)
{
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
return result;
}
} }
else else
InstrCountFiltered2(node, 1); InstrCountFiltered2(node, 1);
@ -1629,7 +1580,6 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
* initialize join state * initialize join state
*/ */
mergestate->mj_JoinState = EXEC_MJ_INITIALIZE_OUTER; mergestate->mj_JoinState = EXEC_MJ_INITIALIZE_OUTER;
mergestate->js.ps.ps_TupFromTlist = false;
mergestate->mj_MatchedOuter = false; mergestate->mj_MatchedOuter = false;
mergestate->mj_MatchedInner = false; mergestate->mj_MatchedInner = false;
mergestate->mj_OuterTupleSlot = NULL; mergestate->mj_OuterTupleSlot = NULL;
@ -1684,7 +1634,6 @@ ExecReScanMergeJoin(MergeJoinState *node)
ExecClearTuple(node->mj_MarkedTupleSlot); ExecClearTuple(node->mj_MarkedTupleSlot);
node->mj_JoinState = EXEC_MJ_INITIALIZE_OUTER; node->mj_JoinState = EXEC_MJ_INITIALIZE_OUTER;
node->js.ps.ps_TupFromTlist = false;
node->mj_MatchedOuter = false; node->mj_MatchedOuter = false;
node->mj_MatchedInner = false; node->mj_MatchedInner = false;
node->mj_OuterTupleSlot = NULL; node->mj_OuterTupleSlot = NULL;

View File

@ -175,7 +175,7 @@ ExecProcessReturning(ResultRelInfo *resultRelInfo,
econtext->ecxt_outertuple = planSlot; econtext->ecxt_outertuple = planSlot;
/* Compute the RETURNING expressions */ /* Compute the RETURNING expressions */
return ExecProject(projectReturning, NULL); return ExecProject(projectReturning);
} }
/* /*
@ -1300,7 +1300,7 @@ ExecOnConflictUpdate(ModifyTableState *mtstate,
} }
/* Project the new tuple version */ /* Project the new tuple version */
ExecProject(resultRelInfo->ri_onConflictSetProj, NULL); ExecProject(resultRelInfo->ri_onConflictSetProj);
/* /*
* Note that it is possible that the target tuple has been modified in * Note that it is possible that the target tuple has been modified in

View File

@ -81,27 +81,9 @@ ExecNestLoop(NestLoopState *node)
innerPlan = innerPlanState(node); innerPlan = innerPlanState(node);
econtext = node->js.ps.ps_ExprContext; econtext = node->js.ps.ps_ExprContext;
/*
* Check to see if we're still projecting out tuples from a previous join
* tuple (because there is a function-returning-set in the projection
* expressions). If so, try to project another one.
*/
if (node->js.ps.ps_TupFromTlist)
{
TupleTableSlot *result;
ExprDoneCond isDone;
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
if (isDone == ExprMultipleResult)
return result;
/* Done with that source tuple... */
node->js.ps.ps_TupFromTlist = false;
}
/* /*
* Reset per-tuple memory context to free any expression evaluation * Reset per-tuple memory context to free any expression evaluation
* storage allocated in the previous tuple cycle. Note this can't happen * storage allocated in the previous tuple cycle.
* until we're done projecting out tuples from a join tuple.
*/ */
ResetExprContext(econtext); ResetExprContext(econtext);
@ -201,19 +183,9 @@ ExecNestLoop(NestLoopState *node)
* the slot containing the result tuple using * the slot containing the result tuple using
* ExecProject(). * ExecProject().
*/ */
TupleTableSlot *result;
ExprDoneCond isDone;
ENL1_printf("qualification succeeded, projecting tuple"); ENL1_printf("qualification succeeded, projecting tuple");
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone); return ExecProject(node->js.ps.ps_ProjInfo);
if (isDone != ExprEndResult)
{
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
return result;
}
} }
else else
InstrCountFiltered2(node, 1); InstrCountFiltered2(node, 1);
@ -259,19 +231,9 @@ ExecNestLoop(NestLoopState *node)
* qualification was satisfied so we project and return the * qualification was satisfied so we project and return the
* slot containing the result tuple using ExecProject(). * slot containing the result tuple using ExecProject().
*/ */
TupleTableSlot *result;
ExprDoneCond isDone;
ENL1_printf("qualification succeeded, projecting tuple"); ENL1_printf("qualification succeeded, projecting tuple");
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone); return ExecProject(node->js.ps.ps_ProjInfo);
if (isDone != ExprEndResult)
{
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
return result;
}
} }
else else
InstrCountFiltered2(node, 1); InstrCountFiltered2(node, 1);
@ -377,7 +339,6 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags)
/* /*
* finally, wipe the current outer tuple clean. * finally, wipe the current outer tuple clean.
*/ */
nlstate->js.ps.ps_TupFromTlist = false;
nlstate->nl_NeedNewOuter = true; nlstate->nl_NeedNewOuter = true;
nlstate->nl_MatchedOuter = false; nlstate->nl_MatchedOuter = false;
@ -441,7 +402,6 @@ ExecReScanNestLoop(NestLoopState *node)
* outer Vars are used as run-time keys... * outer Vars are used as run-time keys...
*/ */
node->js.ps.ps_TupFromTlist = false;
node->nl_NeedNewOuter = true; node->nl_NeedNewOuter = true;
node->nl_MatchedOuter = false; node->nl_MatchedOuter = false;
} }

View File

@ -169,7 +169,7 @@ ExecProjectSRF(ProjectSetState *node, bool continuing)
else else
{ {
/* Non-SRF tlist expression, just evaluate normally. */ /* Non-SRF tlist expression, just evaluate normally. */
*result = ExecEvalExpr(gstate->arg, econtext, isnull, NULL); *result = ExecEvalExpr(gstate->arg, econtext, isnull);
*isdone = ExprSingleResult; *isdone = ExprSingleResult;
} }

View File

@ -67,10 +67,8 @@ TupleTableSlot *
ExecResult(ResultState *node) ExecResult(ResultState *node)
{ {
TupleTableSlot *outerTupleSlot; TupleTableSlot *outerTupleSlot;
TupleTableSlot *resultSlot;
PlanState *outerPlan; PlanState *outerPlan;
ExprContext *econtext; ExprContext *econtext;
ExprDoneCond isDone;
econtext = node->ps.ps_ExprContext; econtext = node->ps.ps_ExprContext;
@ -91,24 +89,9 @@ ExecResult(ResultState *node)
} }
} }
/*
* 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 * Reset per-tuple memory context to free any expression evaluation
* storage allocated in the previous tuple cycle. Note this can't happen * storage allocated in the previous tuple cycle.
* until we're done projecting out tuples from a scan tuple.
*/ */
ResetExprContext(econtext); ResetExprContext(econtext);
@ -147,18 +130,8 @@ ExecResult(ResultState *node)
node->rs_done = true; node->rs_done = true;
} }
/* /* form the result tuple using ExecProject(), and return it */
* form the result tuple using ExecProject(), and return it --- unless return ExecProject(node->ps.ps_ProjInfo);
* 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; return NULL;
@ -228,8 +201,6 @@ ExecInitResult(Result *node, EState *estate, int eflags)
*/ */
ExecAssignExprContext(estate, &resstate->ps); ExecAssignExprContext(estate, &resstate->ps);
resstate->ps.ps_TupFromTlist = false;
/* /*
* tuple table initialization * tuple table initialization
*/ */
@ -295,7 +266,6 @@ void
ExecReScanResult(ResultState *node) ExecReScanResult(ResultState *node)
{ {
node->rs_done = false; node->rs_done = false;
node->ps.ps_TupFromTlist = false;
node->rs_checkqual = (node->resconstantqual == NULL) ? false : true; node->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
/* /*

View File

@ -189,8 +189,6 @@ ExecInitSampleScan(SampleScan *node, EState *estate, int eflags)
*/ */
InitScanRelation(scanstate, estate, eflags); InitScanRelation(scanstate, estate, eflags);
scanstate->ss.ps.ps_TupFromTlist = false;
/* /*
* Initialize result tuple type and projection info. * Initialize result tuple type and projection info.
*/ */
@ -300,8 +298,7 @@ tablesample_init(SampleScanState *scanstate)
params[i] = ExecEvalExprSwitchContext(argstate, params[i] = ExecEvalExprSwitchContext(argstate,
econtext, econtext,
&isnull, &isnull);
NULL);
if (isnull) if (isnull)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLESAMPLE_ARGUMENT), (errcode(ERRCODE_INVALID_TABLESAMPLE_ARGUMENT),
@ -313,8 +310,7 @@ tablesample_init(SampleScanState *scanstate)
{ {
datum = ExecEvalExprSwitchContext(scanstate->repeatable, datum = ExecEvalExprSwitchContext(scanstate->repeatable,
econtext, econtext,
&isnull, &isnull);
NULL);
if (isnull) if (isnull)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLESAMPLE_REPEAT), (errcode(ERRCODE_INVALID_TABLESAMPLE_REPEAT),

View File

@ -206,8 +206,6 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
*/ */
InitScanRelation(scanstate, estate, eflags); InitScanRelation(scanstate, estate, eflags);
scanstate->ss.ps.ps_TupFromTlist = false;
/* /*
* Initialize result tuple type and projection info. * Initialize result tuple type and projection info.
*/ */

View File

@ -41,12 +41,10 @@
static Datum ExecSubPlan(SubPlanState *node, static Datum ExecSubPlan(SubPlanState *node,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, bool *isNull);
ExprDoneCond *isDone);
static Datum ExecAlternativeSubPlan(AlternativeSubPlanState *node, static Datum ExecAlternativeSubPlan(AlternativeSubPlanState *node,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, bool *isNull);
ExprDoneCond *isDone);
static Datum ExecHashSubPlan(SubPlanState *node, static Datum ExecHashSubPlan(SubPlanState *node,
ExprContext *econtext, ExprContext *econtext,
bool *isNull); bool *isNull);
@ -69,15 +67,12 @@ static bool slotNoNulls(TupleTableSlot *slot);
static Datum static Datum
ExecSubPlan(SubPlanState *node, ExecSubPlan(SubPlanState *node,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, bool *isNull)
ExprDoneCond *isDone)
{ {
SubPlan *subplan = (SubPlan *) node->xprstate.expr; SubPlan *subplan = (SubPlan *) node->xprstate.expr;
/* Set default values for result flags: non-null, not a set result */ /* Set non-null as default */
*isNull = false; *isNull = false;
if (isDone)
*isDone = ExprSingleResult;
/* Sanity checks */ /* Sanity checks */
if (subplan->subLinkType == CTE_SUBLINK) if (subplan->subLinkType == CTE_SUBLINK)
@ -128,7 +123,7 @@ ExecHashSubPlan(SubPlanState *node,
* have to set the econtext to use (hack alert!). * have to set the econtext to use (hack alert!).
*/ */
node->projLeft->pi_exprContext = econtext; node->projLeft->pi_exprContext = econtext;
slot = ExecProject(node->projLeft, NULL); slot = ExecProject(node->projLeft);
/* /*
* Note: because we are typically called in a per-tuple context, we have * Note: because we are typically called in a per-tuple context, we have
@ -285,8 +280,7 @@ ExecScanSubPlan(SubPlanState *node,
prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar), prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar),
econtext, econtext,
&(prm->isnull), &(prm->isnull));
NULL);
planstate->chgParam = bms_add_member(planstate->chgParam, paramid); planstate->chgParam = bms_add_member(planstate->chgParam, paramid);
} }
@ -403,7 +397,7 @@ ExecScanSubPlan(SubPlanState *node,
} }
rowresult = ExecEvalExprSwitchContext(node->testexpr, econtext, rowresult = ExecEvalExprSwitchContext(node->testexpr, econtext,
&rownull, NULL); &rownull);
if (subLinkType == ANY_SUBLINK) if (subLinkType == ANY_SUBLINK)
{ {
@ -572,7 +566,7 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
&(prmdata->isnull)); &(prmdata->isnull));
col++; col++;
} }
slot = ExecProject(node->projRight, NULL); slot = ExecProject(node->projRight);
/* /*
* If result contains any nulls, store separately or not at all. * If result contains any nulls, store separately or not at all.
@ -985,8 +979,7 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar), prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar),
econtext, econtext,
&(prm->isnull), &(prm->isnull));
NULL);
planstate->chgParam = bms_add_member(planstate->chgParam, paramid); planstate->chgParam = bms_add_member(planstate->chgParam, paramid);
} }
@ -1222,8 +1215,7 @@ ExecInitAlternativeSubPlan(AlternativeSubPlan *asplan, PlanState *parent)
static Datum static Datum
ExecAlternativeSubPlan(AlternativeSubPlanState *node, ExecAlternativeSubPlan(AlternativeSubPlanState *node,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, bool *isNull)
ExprDoneCond *isDone)
{ {
/* Just pass control to the active subplan */ /* Just pass control to the active subplan */
SubPlanState *activesp = (SubPlanState *) list_nth(node->subplans, SubPlanState *activesp = (SubPlanState *) list_nth(node->subplans,
@ -1231,8 +1223,5 @@ ExecAlternativeSubPlan(AlternativeSubPlanState *node,
Assert(IsA(activesp, SubPlanState)); Assert(IsA(activesp, SubPlanState));
return ExecSubPlan(activesp, return ExecSubPlan(activesp, econtext, isNull);
econtext,
isNull,
isDone);
} }

View File

@ -138,8 +138,6 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags)
*/ */
subquerystate->subplan = ExecInitNode(node->subplan, estate, eflags); subquerystate->subplan = ExecInitNode(node->subplan, estate, eflags);
subquerystate->ss.ps.ps_TupFromTlist = false;
/* /*
* Initialize scan tuple type (needed by ExecAssignScanProjectionInfo) * Initialize scan tuple type (needed by ExecAssignScanProjectionInfo)
*/ */

View File

@ -104,8 +104,7 @@ TidListCreate(TidScanState *tidstate)
itemptr = (ItemPointer) itemptr = (ItemPointer)
DatumGetPointer(ExecEvalExprSwitchContext(exstate, DatumGetPointer(ExecEvalExprSwitchContext(exstate,
econtext, econtext,
&isNull, &isNull));
NULL));
if (!isNull && if (!isNull &&
ItemPointerIsValid(itemptr) && ItemPointerIsValid(itemptr) &&
ItemPointerGetBlockNumber(itemptr) < nblocks) ItemPointerGetBlockNumber(itemptr) < nblocks)
@ -133,8 +132,7 @@ TidListCreate(TidScanState *tidstate)
exstate = (ExprState *) lsecond(saexstate->fxprstate.args); exstate = (ExprState *) lsecond(saexstate->fxprstate.args);
arraydatum = ExecEvalExprSwitchContext(exstate, arraydatum = ExecEvalExprSwitchContext(exstate,
econtext, econtext,
&isNull, &isNull);
NULL);
if (isNull) if (isNull)
continue; continue;
itemarray = DatumGetArrayTypeP(arraydatum); itemarray = DatumGetArrayTypeP(arraydatum);
@ -469,8 +467,6 @@ ExecInitTidScan(TidScan *node, EState *estate, int eflags)
*/ */
ExecAssignExprContext(estate, &tidstate->ss.ps); ExecAssignExprContext(estate, &tidstate->ss.ps);
tidstate->ss.ps.ps_TupFromTlist = false;
/* /*
* initialize child expressions * initialize child expressions
*/ */

View File

@ -140,8 +140,7 @@ ValuesNext(ValuesScanState *node)
values[resind] = ExecEvalExpr(estate, values[resind] = ExecEvalExpr(estate,
econtext, econtext,
&isnull[resind], &isnull[resind]);
NULL);
/* /*
* We must force any R/W expanded datums to read-only state, in * We must force any R/W expanded datums to read-only state, in
@ -272,8 +271,6 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
scanstate->exprlists[i++] = (List *) lfirst(vtl); scanstate->exprlists[i++] = (List *) lfirst(vtl);
} }
scanstate->ss.ps.ps_TupFromTlist = false;
/* /*
* Initialize result tuple type and projection info. * Initialize result tuple type and projection info.
*/ */

View File

@ -256,7 +256,7 @@ advance_windowaggregate(WindowAggState *winstate,
if (filter) if (filter)
{ {
bool isnull; bool isnull;
Datum res = ExecEvalExpr(filter, econtext, &isnull, NULL); Datum res = ExecEvalExpr(filter, econtext, &isnull);
if (isnull || !DatumGetBool(res)) if (isnull || !DatumGetBool(res))
{ {
@ -272,7 +272,7 @@ advance_windowaggregate(WindowAggState *winstate,
ExprState *argstate = (ExprState *) lfirst(arg); ExprState *argstate = (ExprState *) lfirst(arg);
fcinfo->arg[i] = ExecEvalExpr(argstate, econtext, fcinfo->arg[i] = ExecEvalExpr(argstate, econtext,
&fcinfo->argnull[i], NULL); &fcinfo->argnull[i]);
i++; i++;
} }
@ -433,7 +433,7 @@ advance_windowaggregate_base(WindowAggState *winstate,
if (filter) if (filter)
{ {
bool isnull; bool isnull;
Datum res = ExecEvalExpr(filter, econtext, &isnull, NULL); Datum res = ExecEvalExpr(filter, econtext, &isnull);
if (isnull || !DatumGetBool(res)) if (isnull || !DatumGetBool(res))
{ {
@ -449,7 +449,7 @@ advance_windowaggregate_base(WindowAggState *winstate,
ExprState *argstate = (ExprState *) lfirst(arg); ExprState *argstate = (ExprState *) lfirst(arg);
fcinfo->arg[i] = ExecEvalExpr(argstate, econtext, fcinfo->arg[i] = ExecEvalExpr(argstate, econtext,
&fcinfo->argnull[i], NULL); &fcinfo->argnull[i]);
i++; i++;
} }
@ -1584,15 +1584,12 @@ update_frametailpos(WindowObject winobj, TupleTableSlot *slot)
* ExecWindowAgg receives tuples from its outer subplan and * ExecWindowAgg receives tuples from its outer subplan and
* stores them into a tuplestore, then processes window functions. * stores them into a tuplestore, then processes window functions.
* This node doesn't reduce nor qualify any row so the number of * This node doesn't reduce nor qualify any row so the number of
* returned rows is exactly the same as its outer subplan's result * returned rows is exactly the same as its outer subplan's result.
* (ignoring the case of SRFs in the targetlist, that is).
* ----------------- * -----------------
*/ */
TupleTableSlot * TupleTableSlot *
ExecWindowAgg(WindowAggState *winstate) ExecWindowAgg(WindowAggState *winstate)
{ {
TupleTableSlot *result;
ExprDoneCond isDone;
ExprContext *econtext; ExprContext *econtext;
int i; int i;
int numfuncs; int numfuncs;
@ -1600,23 +1597,6 @@ ExecWindowAgg(WindowAggState *winstate)
if (winstate->all_done) if (winstate->all_done)
return NULL; return NULL;
/*
* Check to see if we're still projecting out tuples from a previous
* output tuple (because there is a function-returning-set in the
* projection expressions). If so, try to project another one.
*/
if (winstate->ss.ps.ps_TupFromTlist)
{
TupleTableSlot *result;
ExprDoneCond isDone;
result = ExecProject(winstate->ss.ps.ps_ProjInfo, &isDone);
if (isDone == ExprMultipleResult)
return result;
/* Done with that source tuple... */
winstate->ss.ps.ps_TupFromTlist = false;
}
/* /*
* Compute frame offset values, if any, during first call. * Compute frame offset values, if any, during first call.
*/ */
@ -1634,8 +1614,7 @@ ExecWindowAgg(WindowAggState *winstate)
Assert(winstate->startOffset != NULL); Assert(winstate->startOffset != NULL);
value = ExecEvalExprSwitchContext(winstate->startOffset, value = ExecEvalExprSwitchContext(winstate->startOffset,
econtext, econtext,
&isnull, &isnull);
NULL);
if (isnull) if (isnull)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
@ -1660,8 +1639,7 @@ ExecWindowAgg(WindowAggState *winstate)
Assert(winstate->endOffset != NULL); Assert(winstate->endOffset != NULL);
value = ExecEvalExprSwitchContext(winstate->endOffset, value = ExecEvalExprSwitchContext(winstate->endOffset,
econtext, econtext,
&isnull, &isnull);
NULL);
if (isnull) if (isnull)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
@ -1684,7 +1662,6 @@ ExecWindowAgg(WindowAggState *winstate)
winstate->all_first = false; winstate->all_first = false;
} }
restart:
if (winstate->buffer == NULL) if (winstate->buffer == NULL)
{ {
/* Initialize for first partition and set current row = 0 */ /* Initialize for first partition and set current row = 0 */
@ -1776,17 +1753,8 @@ restart:
* evaluated with respect to that row. * evaluated with respect to that row.
*/ */
econtext->ecxt_outertuple = winstate->ss.ss_ScanTupleSlot; econtext->ecxt_outertuple = winstate->ss.ss_ScanTupleSlot;
result = ExecProject(winstate->ss.ps.ps_ProjInfo, &isDone);
if (isDone == ExprEndResult) return ExecProject(winstate->ss.ps.ps_ProjInfo);
{
/* SRF in tlist returned no rows, so advance to next input tuple */
goto restart;
}
winstate->ss.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
return result;
} }
/* ----------------- /* -----------------
@ -1896,8 +1864,6 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags)
ExecAssignResultTypeFromTL(&winstate->ss.ps); ExecAssignResultTypeFromTL(&winstate->ss.ps);
ExecAssignProjectionInfo(&winstate->ss.ps, NULL); ExecAssignProjectionInfo(&winstate->ss.ps, NULL);
winstate->ss.ps.ps_TupFromTlist = false;
/* Set up data for comparing tuples */ /* Set up data for comparing tuples */
if (node->partNumCols > 0) if (node->partNumCols > 0)
winstate->partEqfunctions = execTuplesMatchPrepare(node->partNumCols, winstate->partEqfunctions = execTuplesMatchPrepare(node->partNumCols,
@ -2090,8 +2056,6 @@ ExecReScanWindowAgg(WindowAggState *node)
ExprContext *econtext = node->ss.ps.ps_ExprContext; ExprContext *econtext = node->ss.ps.ps_ExprContext;
node->all_done = false; node->all_done = false;
node->ss.ps.ps_TupFromTlist = false;
node->all_first = true; node->all_first = true;
/* release tuplestore et al */ /* release tuplestore et al */
@ -2712,7 +2676,7 @@ WinGetFuncArgInPartition(WindowObject winobj, int argno,
} }
econtext->ecxt_outertuple = slot; econtext->ecxt_outertuple = slot;
return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno), return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno),
econtext, isnull, NULL); econtext, isnull);
} }
} }
@ -2811,7 +2775,7 @@ WinGetFuncArgInFrame(WindowObject winobj, int argno,
} }
econtext->ecxt_outertuple = slot; econtext->ecxt_outertuple = slot;
return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno), return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno),
econtext, isnull, NULL); econtext, isnull);
} }
} }
@ -2841,5 +2805,5 @@ WinGetFuncArgCurrent(WindowObject winobj, int argno, bool *isnull)
econtext->ecxt_outertuple = winstate->ss.ss_ScanTupleSlot; econtext->ecxt_outertuple = winstate->ss.ss_ScanTupleSlot;
return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno), return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno),
econtext, isnull, NULL); econtext, isnull);
} }

View File

@ -174,8 +174,6 @@ ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags)
*/ */
ExecAssignResultTypeFromTL(&scanstate->ss.ps); ExecAssignResultTypeFromTL(&scanstate->ss.ps);
scanstate->ss.ps.ps_TupFromTlist = false;
return scanstate; return scanstate;
} }

View File

@ -4685,7 +4685,7 @@ evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod,
*/ */
const_val = ExecEvalExprSwitchContext(exprstate, const_val = ExecEvalExprSwitchContext(exprstate,
GetPerTupleExprContext(estate), GetPerTupleExprContext(estate),
&const_is_null, NULL); &const_is_null);
/* Get info needed about result datatype */ /* Get info needed about result datatype */
get_typlenbyval(result_type, &resultTypLen, &resultTypByVal); get_typlenbyval(result_type, &resultTypLen, &resultTypByVal);

View File

@ -1596,7 +1596,7 @@ operator_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
/* And execute it. */ /* And execute it. */
test_result = ExecEvalExprSwitchContext(test_exprstate, test_result = ExecEvalExprSwitchContext(test_exprstate,
GetPerTupleExprContext(estate), GetPerTupleExprContext(estate),
&isNull, NULL); &isNull);
/* Get back to outer memory context */ /* Get back to outer memory context */
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);

View File

@ -179,7 +179,7 @@ domain_check_input(Datum value, bool isnull, DomainIOData *my_extra)
conResult = ExecEvalExprSwitchContext(con->check_expr, conResult = ExecEvalExprSwitchContext(con->check_expr,
econtext, econtext,
&conIsNull, NULL); &conIsNull);
if (!conIsNull && if (!conIsNull &&
!DatumGetBool(conResult)) !DatumGetBool(conResult))

View File

@ -603,7 +603,7 @@ xmlelement(XmlExprState *xmlExpr, ExprContext *econtext)
bool isnull; bool isnull;
char *str; char *str;
value = ExecEvalExpr(e, econtext, &isnull, NULL); value = ExecEvalExpr(e, econtext, &isnull);
if (isnull) if (isnull)
str = NULL; str = NULL;
else else
@ -620,7 +620,7 @@ xmlelement(XmlExprState *xmlExpr, ExprContext *econtext)
bool isnull; bool isnull;
char *str; char *str;
value = ExecEvalExpr(e, econtext, &isnull, NULL); value = ExecEvalExpr(e, econtext, &isnull);
/* here we can just forget NULL elements immediately */ /* here we can just forget NULL elements immediately */
if (!isnull) if (!isnull)
{ {

View File

@ -70,8 +70,8 @@
* now it's just a macro invoking the function pointed to by an ExprState * now it's just a macro invoking the function pointed to by an ExprState
* node. Beware of double evaluation of the ExprState argument! * node. Beware of double evaluation of the ExprState argument!
*/ */
#define ExecEvalExpr(expr, econtext, isNull, isDone) \ #define ExecEvalExpr(expr, econtext, isNull) \
((*(expr)->evalfunc) (expr, econtext, isNull, isDone)) ((*(expr)->evalfunc) (expr, econtext, isNull))
/* Hook for plugins to get control in ExecutorStart() */ /* Hook for plugins to get control in ExecutorStart() */
@ -257,14 +257,13 @@ extern Datum ExecMakeFunctionResultSet(FuncExprState *fcache,
bool *isNull, bool *isNull,
ExprDoneCond *isDone); ExprDoneCond *isDone);
extern Datum ExecEvalExprSwitchContext(ExprState *expression, ExprContext *econtext, extern Datum ExecEvalExprSwitchContext(ExprState *expression, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
extern ExprState *ExecInitExpr(Expr *node, PlanState *parent); extern ExprState *ExecInitExpr(Expr *node, PlanState *parent);
extern ExprState *ExecPrepareExpr(Expr *node, EState *estate); extern ExprState *ExecPrepareExpr(Expr *node, EState *estate);
extern bool ExecQual(List *qual, ExprContext *econtext, bool resultForNull); extern bool ExecQual(List *qual, ExprContext *econtext, bool resultForNull);
extern int ExecTargetListLength(List *targetlist); extern int ExecTargetListLength(List *targetlist);
extern int ExecCleanTargetListLength(List *targetlist); extern int ExecCleanTargetListLength(List *targetlist);
extern TupleTableSlot *ExecProject(ProjectionInfo *projInfo, extern TupleTableSlot *ExecProject(ProjectionInfo *projInfo);
ExprDoneCond *isDone);
/* /*
* prototypes from functions in execScan.c * prototypes from functions in execScan.c

View File

@ -156,7 +156,8 @@ typedef struct ExprContext
} ExprContext; } ExprContext;
/* /*
* Set-result status returned by ExecEvalExpr() * Set-result status used when evaluating functions potentially returning a
* set.
*/ */
typedef enum typedef enum
{ {
@ -228,7 +229,6 @@ typedef struct ReturnSetInfo
* targetlist target list for projection (non-Var expressions only) * targetlist target list for projection (non-Var expressions only)
* exprContext expression context in which to evaluate targetlist * exprContext expression context in which to evaluate targetlist
* slot slot to place projection result in * slot slot to place projection result in
* itemIsDone workspace array for ExecProject
* directMap true if varOutputCols[] is an identity map * directMap true if varOutputCols[] is an identity map
* numSimpleVars number of simple Vars found in original tlist * numSimpleVars number of simple Vars found in original tlist
* varSlotOffsets array indicating which slot each simple Var is from * varSlotOffsets array indicating which slot each simple Var is from
@ -245,7 +245,6 @@ typedef struct ProjectionInfo
List *pi_targetlist; List *pi_targetlist;
ExprContext *pi_exprContext; ExprContext *pi_exprContext;
TupleTableSlot *pi_slot; TupleTableSlot *pi_slot;
ExprDoneCond *pi_itemIsDone;
bool pi_directMap; bool pi_directMap;
int pi_numSimpleVars; int pi_numSimpleVars;
int *pi_varSlotOffsets; int *pi_varSlotOffsets;
@ -586,8 +585,7 @@ typedef struct ExprState ExprState;
typedef Datum (*ExprStateEvalFunc) (ExprState *expression, typedef Datum (*ExprStateEvalFunc) (ExprState *expression,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, bool *isNull);
ExprDoneCond *isDone);
struct ExprState struct ExprState
{ {
@ -731,13 +729,6 @@ typedef struct FuncExprState
*/ */
bool setArgsValid; bool setArgsValid;
/*
* Flag to remember whether we found a set-valued argument to the
* function. This causes the function result to be a set as well. Valid
* only when setArgsValid is true or funcResultStore isn't NULL.
*/
bool setHasSetArg; /* some argument returns a set */
/* /*
* Flag to remember whether we have registered a shutdown callback for * Flag to remember whether we have registered a shutdown callback for
* this FuncExprState. We do so only if funcResultStore or setArgsValid * this FuncExprState. We do so only if funcResultStore or setArgsValid
@ -1081,8 +1072,6 @@ typedef struct PlanState
TupleTableSlot *ps_ResultTupleSlot; /* slot for my result tuples */ TupleTableSlot *ps_ResultTupleSlot; /* slot for my result tuples */
ExprContext *ps_ExprContext; /* node's expression-evaluation context */ ExprContext *ps_ExprContext; /* node's expression-evaluation context */
ProjectionInfo *ps_ProjInfo; /* info for doing tuple projection */ ProjectionInfo *ps_ProjInfo; /* info for doing tuple projection */
bool ps_TupFromTlist;/* state flag for processing set-valued
* functions in targetlist */
} PlanState; } PlanState;
/* ---------------- /* ----------------

View File

@ -5606,8 +5606,7 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate,
*/ */
*result = ExecEvalExpr(expr->expr_simple_state, *result = ExecEvalExpr(expr->expr_simple_state,
econtext, econtext,
isNull, isNull);
NULL);
/* Assorted cleanup */ /* Assorted cleanup */
expr->expr_simple_in_use = false; expr->expr_simple_in_use = false;
@ -6272,7 +6271,7 @@ exec_cast_value(PLpgSQL_execstate *estate,
cast_entry->cast_in_use = true; cast_entry->cast_in_use = true;
value = ExecEvalExpr(cast_entry->cast_exprstate, econtext, value = ExecEvalExpr(cast_entry->cast_exprstate, econtext,
isnull, NULL); isnull);
cast_entry->cast_in_use = false; cast_entry->cast_in_use = false;