Commit ea15e186 authored by Andres Freund's avatar Andres Freund

Remove obsoleted code relating to targetlist SRF evaluation.

Since 69f4b9c8 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
parent 8eace46d
...@@ -3444,7 +3444,7 @@ process_query_params(ExprContext *econtext, ...@@ -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
......
...@@ -1805,8 +1805,7 @@ FormIndexDatum(IndexInfo *indexInfo, ...@@ -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;
......
...@@ -1358,7 +1358,7 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec) ...@@ -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, ...@@ -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;
......
...@@ -3394,7 +3394,7 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext, ...@@ -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;
......
...@@ -413,8 +413,7 @@ EvaluateParams(PreparedStatement *pstmt, List *params, ...@@ -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++;
} }
......
...@@ -4460,8 +4460,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode) ...@@ -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);
} }
/* /*
......
...@@ -2735,7 +2735,7 @@ validateDomainConstraint(Oid domainoid, char *ccbin) ...@@ -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))
{ {
......
...@@ -59,7 +59,6 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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.
......
...@@ -64,40 +64,40 @@ ...@@ -64,40 +64,40 @@
/* static function decls */ /* static function decls */
static Datum ExecEvalArrayRef(ArrayRefExprState *astate, static Datum ExecEvalArrayRef(ArrayRefExprState *astate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static bool isAssignmentIndirectionExpr(ExprState *exprstate); static bool isAssignmentIndirectionExpr(ExprState *exprstate);
static Datum ExecEvalAggref(AggrefExprState *aggref, static Datum ExecEvalAggref(AggrefExprState *aggref,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalWindowFunc(WindowFuncExprState *wfunc, static Datum ExecEvalWindowFunc(WindowFuncExprState *wfunc,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalScalarVar(ExprState *exprstate, ExprContext *econtext, static Datum ExecEvalScalarVar(ExprState *exprstate, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalScalarVarFast(ExprState *exprstate, ExprContext *econtext, static Datum ExecEvalScalarVarFast(ExprState *exprstate, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalWholeRowVar(WholeRowVarExprState *wrvstate, static Datum ExecEvalWholeRowVar(WholeRowVarExprState *wrvstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalWholeRowFast(WholeRowVarExprState *wrvstate, static Datum ExecEvalWholeRowFast(WholeRowVarExprState *wrvstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalWholeRowSlow(WholeRowVarExprState *wrvstate, static Datum ExecEvalWholeRowSlow(WholeRowVarExprState *wrvstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalConst(ExprState *exprstate, ExprContext *econtext, static Datum ExecEvalConst(ExprState *exprstate, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalParamExec(ExprState *exprstate, ExprContext *econtext, static Datum ExecEvalParamExec(ExprState *exprstate, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalParamExtern(ExprState *exprstate, ExprContext *econtext, static Datum ExecEvalParamExtern(ExprState *exprstate, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static void init_fcache(Oid foid, Oid input_collation, FuncExprState *fcache, static void init_fcache(Oid foid, Oid input_collation, FuncExprState *fcache,
MemoryContext fcacheCxt, bool allowSRF, bool needDescForSRF); MemoryContext fcacheCxt, bool allowSRF, bool needDescForSRF);
static void ShutdownFuncExpr(Datum arg); static void ShutdownFuncExpr(Datum arg);
static TupleDesc get_cached_rowtype(Oid type_id, int32 typmod, static TupleDesc get_cached_rowtype(Oid type_id, int32 typmod,
TupleDesc *cache_field, ExprContext *econtext); TupleDesc *cache_field, ExprContext *econtext);
static void ShutdownTupleDescRef(Datum arg); static void ShutdownTupleDescRef(Datum arg);
static ExprDoneCond ExecEvalFuncArgs(FunctionCallInfo fcinfo, static void ExecEvalFuncArgs(FunctionCallInfo fcinfo,
List *argList, ExprContext *econtext); List *argList, ExprContext *econtext);
static void ExecPrepareTuplestoreResult(FuncExprState *fcache, static void ExecPrepareTuplestoreResult(FuncExprState *fcache,
ExprContext *econtext, ExprContext *econtext,
...@@ -106,85 +106,85 @@ static void ExecPrepareTuplestoreResult(FuncExprState *fcache, ...@@ -106,85 +106,85 @@ static void ExecPrepareTuplestoreResult(FuncExprState *fcache,
static void tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc); static void tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc);
static Datum ExecMakeFunctionResultNoSets(FuncExprState *fcache, static Datum ExecMakeFunctionResultNoSets(FuncExprState *fcache,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalFunc(FuncExprState *fcache, ExprContext *econtext, static Datum ExecEvalFunc(FuncExprState *fcache, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalOper(FuncExprState *fcache, ExprContext *econtext, static Datum ExecEvalOper(FuncExprState *fcache, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalDistinct(FuncExprState *fcache, ExprContext *econtext, static Datum ExecEvalDistinct(FuncExprState *fcache, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate, static Datum ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalNot(BoolExprState *notclause, ExprContext *econtext, static Datum ExecEvalNot(BoolExprState *notclause, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext, static Datum ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext, static Datum ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalConvertRowtype(ConvertRowtypeExprState *cstate, static Datum ExecEvalConvertRowtype(ConvertRowtypeExprState *cstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, static Datum ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalCaseTestExpr(ExprState *exprstate, static Datum ExecEvalCaseTestExpr(ExprState *exprstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalArray(ArrayExprState *astate, static Datum ExecEvalArray(ArrayExprState *astate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalRow(RowExprState *rstate, static Datum ExecEvalRow(RowExprState *rstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalRowCompare(RowCompareExprState *rstate, static Datum ExecEvalRowCompare(RowCompareExprState *rstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalCoalesce(CoalesceExprState *coalesceExpr, static Datum ExecEvalCoalesce(CoalesceExprState *coalesceExpr,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalMinMax(MinMaxExprState *minmaxExpr, static Datum ExecEvalMinMax(MinMaxExprState *minmaxExpr,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalSQLValueFunction(ExprState *svfExpr, static Datum ExecEvalSQLValueFunction(ExprState *svfExpr,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext, static Datum ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalNullIf(FuncExprState *nullIfExpr, static Datum ExecEvalNullIf(FuncExprState *nullIfExpr,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalNullTest(NullTestState *nstate, static Datum ExecEvalNullTest(NullTestState *nstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalBooleanTest(GenericExprState *bstate, static Datum ExecEvalBooleanTest(GenericExprState *bstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalCoerceToDomain(CoerceToDomainState *cstate, static Datum ExecEvalCoerceToDomain(CoerceToDomainState *cstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalCoerceToDomainValue(ExprState *exprstate, static Datum ExecEvalCoerceToDomainValue(ExprState *exprstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalFieldSelect(FieldSelectState *fstate, static Datum ExecEvalFieldSelect(FieldSelectState *fstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalFieldStore(FieldStoreState *fstate, static Datum ExecEvalFieldStore(FieldStoreState *fstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalRelabelType(GenericExprState *exprstate, static Datum ExecEvalRelabelType(GenericExprState *exprstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalCoerceViaIO(CoerceViaIOState *iostate, static Datum ExecEvalCoerceViaIO(CoerceViaIOState *iostate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate, static Datum ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalCurrentOfExpr(ExprState *exprstate, ExprContext *econtext, static Datum ExecEvalCurrentOfExpr(ExprState *exprstate, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
static Datum ExecEvalGroupingFuncExpr(GroupingFuncExprState *gstate, static Datum ExecEvalGroupingFuncExpr(GroupingFuncExprState *gstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull);
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
...@@ -195,8 +195,7 @@ static Datum ExecEvalGroupingFuncExpr(GroupingFuncExprState *gstate, ...@@ -195,8 +195,7 @@ static Datum ExecEvalGroupingFuncExpr(GroupingFuncExprState *gstate,
* Each of the following routines having the signature * Each of the following routines having the signature
* Datum ExecEvalFoo(ExprState *expression, * Datum ExecEvalFoo(ExprState *expression,
* ExprContext *econtext, * ExprContext *econtext,
* bool *isNull, * bool *isNull);
* ExprDoneCond *isDone);
* is responsible for evaluating one type or subtype of ExprState node. * is responsible for evaluating one type or subtype of ExprState node.
* They are normally called via the ExecEvalExpr macro, which makes use of * They are normally called via the ExecEvalExpr macro, which makes use of
* the function pointer set up when the ExprState node was built by * the function pointer set up when the ExprState node was built by
...@@ -220,22 +219,6 @@ static Datum ExecEvalGroupingFuncExpr(GroupingFuncExprState *gstate, ...@@ -220,22 +219,6 @@ static Datum ExecEvalGroupingFuncExpr(GroupingFuncExprState *gstate,
* return value: Datum value of result * return value: Datum value of result
* *isNull: set to TRUE if result is NULL (actual return value is * *isNull: set to TRUE if result is NULL (actual return value is
* meaningless if so); set to FALSE if non-null result * meaningless if so); set to FALSE if non-null result
* *isDone: set to indicator of set-result status
*
* A caller that can only accept a singleton (non-set) result should pass
* NULL for isDone; if the expression computes a set result then an error
* will be reported via ereport. If the caller does pass an isDone pointer
* then *isDone is set to one of these three states:
* ExprSingleResult singleton result (not a set)
* ExprMultipleResult return value is one element of a set
* ExprEndResult there are no more elements in the set
* When ExprMultipleResult is returned, the caller should invoke
* ExecEvalExpr() repeatedly until ExprEndResult is returned. ExprEndResult
* is returned after the last real set element. For convenience isNull will
* always be set TRUE when ExprEndResult is returned, but this should not be
* taken as indicating a NULL element of the set. Note that these return
* conventions allow us to distinguish among a singleton NULL, a NULL element
* of a set, and an empty set.
* *
* The caller should already have switched into the temporary memory * The caller should already have switched into the temporary memory
* context econtext->ecxt_per_tuple_memory. The convenience entry point * context econtext->ecxt_per_tuple_memory. The convenience entry point
...@@ -260,8 +243,7 @@ static Datum ExecEvalGroupingFuncExpr(GroupingFuncExprState *gstate, ...@@ -260,8 +243,7 @@ static Datum ExecEvalGroupingFuncExpr(GroupingFuncExprState *gstate,
static Datum static Datum
ExecEvalArrayRef(ArrayRefExprState *astate, ExecEvalArrayRef(ArrayRefExprState *astate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, bool *isNull)
ExprDoneCond *isDone)
{ {
ArrayRef *arrayRef = (ArrayRef *) astate->xprstate.expr; ArrayRef *arrayRef = (ArrayRef *) astate->xprstate.expr;
Datum array_source; Datum array_source;
...@@ -278,8 +260,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate, ...@@ -278,8 +260,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
array_source = ExecEvalExpr(astate->refexpr, array_source = ExecEvalExpr(astate->refexpr,
econtext, econtext,
isNull, isNull);
isDone);
/* /*
* If refexpr yields NULL, and it's a fetch, then result is NULL. In the * If refexpr yields NULL, and it's a fetch, then result is NULL. In the
...@@ -287,8 +268,6 @@ ExecEvalArrayRef(ArrayRefExprState *astate, ...@@ -287,8 +268,6 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
*/ */
if (*isNull) if (*isNull)
{ {
if (isDone && *isDone == ExprEndResult)
return (Datum) NULL; /* end of set result */
if (!isAssignment) if (!isAssignment)
return (Datum) NULL; return (Datum) NULL;
} }
...@@ -314,8 +293,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate, ...@@ -314,8 +293,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
upper.indx[i++] = DatumGetInt32(ExecEvalExpr(eltstate, upper.indx[i++] = DatumGetInt32(ExecEvalExpr(eltstate,
econtext, econtext,
&eisnull, &eisnull));
NULL));
/* If any index expr yields NULL, result is NULL or error */ /* If any index expr yields NULL, result is NULL or error */
if (eisnull) if (eisnull)
{ {
...@@ -350,8 +328,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate, ...@@ -350,8 +328,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
lower.indx[j++] = DatumGetInt32(ExecEvalExpr(eltstate, lower.indx[j++] = DatumGetInt32(ExecEvalExpr(eltstate,
econtext, econtext,
&eisnull, &eisnull));
NULL));
/* If any index expr yields NULL, result is NULL or error */ /* If any index expr yields NULL, result is NULL or error */
if (eisnull) if (eisnull)
{ {
...@@ -438,8 +415,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate, ...@@ -438,8 +415,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
*/ */
sourceData = ExecEvalExpr(astate->refassgnexpr, sourceData = ExecEvalExpr(astate->refassgnexpr,
econtext, econtext,
&eisnull, &eisnull);
NULL);
econtext->caseValue_datum = save_datum; econtext->caseValue_datum = save_datum;
econtext->caseValue_isNull = save_isNull; econtext->caseValue_isNull = save_isNull;
...@@ -542,11 +518,8 @@ isAssignmentIndirectionExpr(ExprState *exprstate) ...@@ -542,11 +518,8 @@ isAssignmentIndirectionExpr(ExprState *exprstate)
*/ */
static Datum static Datum
ExecEvalAggref(AggrefExprState *aggref, ExprContext *econtext, ExecEvalAggref(AggrefExprState *aggref, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
if (isDone)
*isDone = ExprSingleResult;
if (econtext->ecxt_aggvalues == NULL) /* safety check */ if (econtext->ecxt_aggvalues == NULL) /* safety check */
elog(ERROR, "no aggregates in this expression context"); elog(ERROR, "no aggregates in this expression context");
...@@ -563,11 +536,8 @@ ExecEvalAggref(AggrefExprState *aggref, ExprContext *econtext, ...@@ -563,11 +536,8 @@ ExecEvalAggref(AggrefExprState *aggref, ExprContext *econtext,
*/ */
static Datum static Datum
ExecEvalWindowFunc(WindowFuncExprState *wfunc, ExprContext *econtext, ExecEvalWindowFunc(WindowFuncExprState *wfunc, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
if (isDone)
*isDone = ExprSingleResult;
if (econtext->ecxt_aggvalues == NULL) /* safety check */ if (econtext->ecxt_aggvalues == NULL) /* safety check */
elog(ERROR, "no window functions in this expression context"); elog(ERROR, "no window functions in this expression context");
...@@ -588,15 +558,12 @@ ExecEvalWindowFunc(WindowFuncExprState *wfunc, ExprContext *econtext, ...@@ -588,15 +558,12 @@ ExecEvalWindowFunc(WindowFuncExprState *wfunc, ExprContext *econtext,
*/ */
static Datum static Datum
ExecEvalScalarVar(ExprState *exprstate, ExprContext *econtext, ExecEvalScalarVar(ExprState *exprstate, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
Var *variable = (Var *) exprstate->expr; Var *variable = (Var *) exprstate->expr;
TupleTableSlot *slot; TupleTableSlot *slot;
AttrNumber attnum; AttrNumber attnum;
if (isDone)
*isDone = ExprSingleResult;
/* Get the input slot and attribute number we want */ /* Get the input slot and attribute number we want */
switch (variable->varno) switch (variable->varno)
{ {
...@@ -677,15 +644,12 @@ ExecEvalScalarVar(ExprState *exprstate, ExprContext *econtext, ...@@ -677,15 +644,12 @@ ExecEvalScalarVar(ExprState *exprstate, ExprContext *econtext,
*/ */
static Datum static Datum
ExecEvalScalarVarFast(ExprState *exprstate, ExprContext *econtext, ExecEvalScalarVarFast(ExprState *exprstate, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
Var *variable = (Var *) exprstate->expr; Var *variable = (Var *) exprstate->expr;
TupleTableSlot *slot; TupleTableSlot *slot;
AttrNumber attnum; AttrNumber attnum;
if (isDone)
*isDone = ExprSingleResult;
/* Get the input slot and attribute number we want */ /* Get the input slot and attribute number we want */
switch (variable->varno) switch (variable->varno)
{ {
...@@ -725,7 +689,7 @@ ExecEvalScalarVarFast(ExprState *exprstate, ExprContext *econtext, ...@@ -725,7 +689,7 @@ ExecEvalScalarVarFast(ExprState *exprstate, ExprContext *econtext,
*/ */
static Datum static Datum
ExecEvalWholeRowVar(WholeRowVarExprState *wrvstate, ExprContext *econtext, ExecEvalWholeRowVar(WholeRowVarExprState *wrvstate, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
Var *variable = (Var *) wrvstate->xprstate.expr; Var *variable = (Var *) wrvstate->xprstate.expr;
TupleTableSlot *slot; TupleTableSlot *slot;
...@@ -733,9 +697,6 @@ ExecEvalWholeRowVar(WholeRowVarExprState *wrvstate, ExprContext *econtext, ...@@ -733,9 +697,6 @@ ExecEvalWholeRowVar(WholeRowVarExprState *wrvstate, ExprContext *econtext,
MemoryContext oldcontext; MemoryContext oldcontext;
bool needslow = false; bool needslow = false;
if (isDone)
*isDone = ExprSingleResult;
/* This was checked by ExecInitExpr */ /* This was checked by ExecInitExpr */
Assert(variable->varattno == InvalidAttrNumber); Assert(variable->varattno == InvalidAttrNumber);
...@@ -941,7 +902,7 @@ ExecEvalWholeRowVar(WholeRowVarExprState *wrvstate, ExprContext *econtext, ...@@ -941,7 +902,7 @@ ExecEvalWholeRowVar(WholeRowVarExprState *wrvstate, ExprContext *econtext,
/* Fetch the value */ /* Fetch the value */
return (*wrvstate->xprstate.evalfunc) ((ExprState *) wrvstate, econtext, return (*wrvstate->xprstate.evalfunc) ((ExprState *) wrvstate, econtext,
isNull, isDone); isNull);
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
...@@ -952,14 +913,12 @@ ExecEvalWholeRowVar(WholeRowVarExprState *wrvstate, ExprContext *econtext, ...@@ -952,14 +913,12 @@ ExecEvalWholeRowVar(WholeRowVarExprState *wrvstate, ExprContext *econtext,
*/ */
static Datum static Datum
ExecEvalWholeRowFast(WholeRowVarExprState *wrvstate, ExprContext *econtext, ExecEvalWholeRowFast(WholeRowVarExprState *wrvstate, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
Var *variable = (Var *) wrvstate->xprstate.expr; Var *variable = (Var *) wrvstate->xprstate.expr;
TupleTableSlot *slot; TupleTableSlot *slot;
HeapTupleHeader dtuple; HeapTupleHeader dtuple;
if (isDone)
*isDone = ExprSingleResult;
*isNull = false; *isNull = false;
/* Get the input slot we want */ /* Get the input slot we want */
...@@ -1008,7 +967,7 @@ ExecEvalWholeRowFast(WholeRowVarExprState *wrvstate, ExprContext *econtext, ...@@ -1008,7 +967,7 @@ ExecEvalWholeRowFast(WholeRowVarExprState *wrvstate, ExprContext *econtext,
*/ */
static Datum static Datum
ExecEvalWholeRowSlow(WholeRowVarExprState *wrvstate, ExprContext *econtext, ExecEvalWholeRowSlow(WholeRowVarExprState *wrvstate, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
Var *variable = (Var *) wrvstate->xprstate.expr; Var *variable = (Var *) wrvstate->xprstate.expr;
TupleTableSlot *slot; TupleTableSlot *slot;
...@@ -1018,8 +977,6 @@ ExecEvalWholeRowSlow(WholeRowVarExprState *wrvstate, ExprContext *econtext, ...@@ -1018,8 +977,6 @@ ExecEvalWholeRowSlow(WholeRowVarExprState *wrvstate, ExprContext *econtext,
HeapTupleHeader dtuple; HeapTupleHeader dtuple;
int i; int i;
if (isDone)
*isDone = ExprSingleResult;
*isNull = false; *isNull = false;
/* Get the input slot we want */ /* Get the input slot we want */
...@@ -1097,13 +1054,10 @@ ExecEvalWholeRowSlow(WholeRowVarExprState *wrvstate, ExprContext *econtext, ...@@ -1097,13 +1054,10 @@ ExecEvalWholeRowSlow(WholeRowVarExprState *wrvstate, ExprContext *econtext,
*/ */
static Datum static Datum
ExecEvalConst(ExprState *exprstate, ExprContext *econtext, ExecEvalConst(ExprState *exprstate, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
Const *con = (Const *) exprstate->expr; Const *con = (Const *) exprstate->expr;
if (isDone)
*isDone = ExprSingleResult;
*isNull = con->constisnull; *isNull = con->constisnull;
return con->constvalue; return con->constvalue;
} }
...@@ -1116,15 +1070,12 @@ ExecEvalConst(ExprState *exprstate, ExprContext *econtext, ...@@ -1116,15 +1070,12 @@ ExecEvalConst(ExprState *exprstate, ExprContext *econtext,
*/ */
static Datum static Datum
ExecEvalParamExec(ExprState *exprstate, ExprContext *econtext, ExecEvalParamExec(ExprState *exprstate, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
Param *expression = (Param *) exprstate->expr; Param *expression = (Param *) exprstate->expr;
int thisParamId = expression->paramid; int thisParamId = expression->paramid;
ParamExecData *prm; ParamExecData *prm;
if (isDone)
*isDone = ExprSingleResult;
/* /*
* PARAM_EXEC params (internal executor parameters) are stored in the * PARAM_EXEC params (internal executor parameters) are stored in the
* ecxt_param_exec_vals array, and can be accessed by array index. * ecxt_param_exec_vals array, and can be accessed by array index.
...@@ -1149,15 +1100,12 @@ ExecEvalParamExec(ExprState *exprstate, ExprContext *econtext, ...@@ -1149,15 +1100,12 @@ ExecEvalParamExec(ExprState *exprstate, ExprContext *econtext,
*/ */
static Datum static Datum
ExecEvalParamExtern(ExprState *exprstate, ExprContext *econtext, ExecEvalParamExtern(ExprState *exprstate, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
Param *expression = (Param *) exprstate->expr; Param *expression = (Param *) exprstate->expr;
int thisParamId = expression->paramid; int thisParamId = expression->paramid;
ParamListInfo paramInfo = econtext->ecxt_param_list_info; ParamListInfo paramInfo = econtext->ecxt_param_list_info;
if (isDone)
*isDone = ExprSingleResult;
/* /*
* PARAM_EXTERN parameters must be sought in ecxt_param_list_info. * PARAM_EXTERN parameters must be sought in ecxt_param_list_info.
*/ */
...@@ -1421,7 +1369,6 @@ init_fcache(Oid foid, Oid input_collation, FuncExprState *fcache, ...@@ -1421,7 +1369,6 @@ init_fcache(Oid foid, Oid input_collation, FuncExprState *fcache,
/* Initialize additional state */ /* Initialize additional state */
fcache->funcResultStore = NULL; fcache->funcResultStore = NULL;
fcache->funcResultSlot = NULL; fcache->funcResultSlot = NULL;
fcache->setArgsValid = false;
fcache->shutdown_reg = false; fcache->shutdown_reg = false;
} }
...@@ -1508,47 +1455,26 @@ ShutdownTupleDescRef(Datum arg) ...@@ -1508,47 +1455,26 @@ ShutdownTupleDescRef(Datum arg)
/* /*
* Evaluate arguments for a function. * Evaluate arguments for a function.
*/ */
static ExprDoneCond static void
ExecEvalFuncArgs(FunctionCallInfo fcinfo, ExecEvalFuncArgs(FunctionCallInfo fcinfo,
List *argList, List *argList,
ExprContext *econtext) ExprContext *econtext)
{ {
ExprDoneCond argIsDone;
int i; int i;
ListCell *arg; ListCell *arg;
argIsDone = ExprSingleResult; /* default assumption */
i = 0; i = 0;
foreach(arg, argList) foreach(arg, argList)
{ {
ExprState *argstate = (ExprState *) lfirst(arg); ExprState *argstate = (ExprState *) lfirst(arg);
ExprDoneCond thisArgIsDone;
fcinfo->arg[i] = ExecEvalExpr(argstate, fcinfo->arg[i] = ExecEvalExpr(argstate,
econtext, econtext,
&fcinfo->argnull[i], &fcinfo->argnull[i]);
&thisArgIsDone);
if (thisArgIsDone != ExprSingleResult)
{
/*
* We allow only one argument to have a set value; we'd need much
* more complexity to keep track of multiple set arguments (cf.
* ExecTargetList) and it doesn't seem worth it.
*/
if (argIsDone != ExprSingleResult)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("functions and operators can take at most one set argument")));
argIsDone = thisArgIsDone;
}
i++; i++;
} }
Assert(i == fcinfo->nargs); Assert(i == fcinfo->nargs);
return argIsDone;
} }
/* /*
...@@ -1694,9 +1620,8 @@ ExecMakeFunctionResultSet(FuncExprState *fcache, ...@@ -1694,9 +1620,8 @@ ExecMakeFunctionResultSet(FuncExprState *fcache,
Datum result; Datum result;
FunctionCallInfo fcinfo; FunctionCallInfo fcinfo;
PgStat_FunctionCallUsage fcusage; PgStat_FunctionCallUsage fcusage;
ReturnSetInfo rsinfo; /* for functions returning sets */ ReturnSetInfo rsinfo;
ExprDoneCond argDone; bool callit;
bool hasSetArg;
int i; int i;
restart: restart:
...@@ -1727,6 +1652,9 @@ restart: ...@@ -1727,6 +1652,9 @@ restart:
else else
elog(ERROR, "unrecognized node type: %d", elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(fcache->xprstate.expr)); (int) nodeTag(fcache->xprstate.expr));
/* shouldn't get here otherwise */
Assert(fcache->func.fn_retset);
} }
/* /*
...@@ -1736,7 +1664,6 @@ restart: ...@@ -1736,7 +1664,6 @@ restart:
*/ */
if (fcache->funcResultStore) if (fcache->funcResultStore)
{ {
Assert(isDone); /* it was provided before ... */
if (tuplestore_gettupleslot(fcache->funcResultStore, true, false, if (tuplestore_gettupleslot(fcache->funcResultStore, true, false,
fcache->funcResultSlot)) fcache->funcResultSlot))
{ {
...@@ -1756,16 +1683,10 @@ restart: ...@@ -1756,16 +1683,10 @@ restart:
/* Exhausted the tuplestore, so clean up */ /* Exhausted the tuplestore, so clean up */
tuplestore_end(fcache->funcResultStore); tuplestore_end(fcache->funcResultStore);
fcache->funcResultStore = NULL; fcache->funcResultStore = NULL;
/* We are done unless there was a set-valued argument */
if (!fcache->setHasSetArg)
{
*isDone = ExprEndResult; *isDone = ExprEndResult;
*isNull = true; *isNull = true;
return (Datum) 0; return (Datum) 0;
} }
/* If there was, continue evaluating the argument values */
Assert(!fcache->setArgsValid);
}
/* /*
* arguments is a list of expressions to evaluate before passing to the * arguments is a list of expressions to evaluate before passing to the
...@@ -1776,18 +1697,9 @@ restart: ...@@ -1776,18 +1697,9 @@ restart:
fcinfo = &fcache->fcinfo_data; fcinfo = &fcache->fcinfo_data;
arguments = fcache->args; arguments = fcache->args;
if (!fcache->setArgsValid) if (!fcache->setArgsValid)
{ ExecEvalFuncArgs(fcinfo, arguments, econtext);
argDone = ExecEvalFuncArgs(fcinfo, arguments, econtext);
if (argDone != ExprSingleResult)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("set-valued function called in context that cannot accept a set")));
hasSetArg = false;
}
else else
{ {
/* Re-use callinfo from previous evaluation */
hasSetArg = fcache->setHasSetArg;
/* Reset flag (we may set it again below) */ /* Reset flag (we may set it again below) */
fcache->setArgsValid = false; fcache->setArgsValid = false;
} }
...@@ -1795,23 +1707,8 @@ restart: ...@@ -1795,23 +1707,8 @@ restart:
/* /*
* Now call the function, passing the evaluated parameter values. * Now call the function, passing the evaluated parameter values.
*/ */
if (fcache->func.fn_retset || hasSetArg)
{
/*
* We need to return a set result. Complain if caller not ready to
* accept one.
*/
if (isDone == NULL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("set-valued function called in context that cannot accept a set")));
/* /* Prepare a resultinfo node for communication. */
* Prepare a resultinfo node for communication. If the function
* doesn't itself return set, we don't pass the resultinfo to the
* function, but we need to fill it in anyway for internal use.
*/
if (fcache->func.fn_retset)
fcinfo->resultinfo = (Node *) &rsinfo; fcinfo->resultinfo = (Node *) &rsinfo;
rsinfo.type = T_ReturnSetInfo; rsinfo.type = T_ReturnSetInfo;
rsinfo.econtext = econtext; rsinfo.econtext = econtext;
...@@ -1824,21 +1721,10 @@ restart: ...@@ -1824,21 +1721,10 @@ restart:
rsinfo.setDesc = NULL; rsinfo.setDesc = NULL;
/* /*
* This loop handles the situation where we have both a set argument * If function is strict, and there are any NULL arguments, skip calling
* and a set-valued function. Once we have exhausted the function's * the function.
* value(s) for a particular argument value, we have to get the next
* argument value and start the function over again. We might have to
* do it more than once, if the function produces an empty result set
* for a particular input value.
*/
for (;;)
{
/*
* If function is strict, and there are any NULL arguments, skip
* calling the function (at least for this set of args).
*/ */
bool callit = true; callit = true;
if (fcache->func.fn_strict) if (fcache->func.fn_strict)
{ {
for (i = 0; i < fcinfo->nargs; i++) for (i = 0; i < fcinfo->nargs; i++)
...@@ -1864,20 +1750,13 @@ restart: ...@@ -1864,20 +1750,13 @@ restart:
pgstat_end_function_usage(&fcusage, pgstat_end_function_usage(&fcusage,
rsinfo.isDone != ExprMultipleResult); rsinfo.isDone != ExprMultipleResult);
} }
else if (fcache->func.fn_retset) else
{ {
/* for a strict SRF, result for NULL is an empty set */ /* for a strict SRF, result for NULL is an empty set */
result = (Datum) 0; result = (Datum) 0;
*isNull = true; *isNull = true;
*isDone = ExprEndResult; *isDone = ExprEndResult;
} }
else
{
/* for a strict non-SRF, result for NULL is a NULL */
result = (Datum) 0;
*isNull = true;
*isDone = ExprSingleResult;
}
/* Which protocol does function want to use? */ /* Which protocol does function want to use? */
if (rsinfo.returnMode == SFRM_ValuePerCall) if (rsinfo.returnMode == SFRM_ValuePerCall)
...@@ -1885,14 +1764,10 @@ restart: ...@@ -1885,14 +1764,10 @@ restart:
if (*isDone != ExprEndResult) if (*isDone != ExprEndResult)
{ {
/* /*
* Got a result from current argument. If function itself * Save the current argument values to re-use on the next call.
* returns set, save the current argument values to re-use
* on the next call.
*/ */
if (fcache->func.fn_retset && if (*isDone == ExprMultipleResult)
*isDone == ExprMultipleResult)
{ {
fcache->setHasSetArg = hasSetArg;
fcache->setArgsValid = true; fcache->setArgsValid = true;
/* Register cleanup callback if we didn't already */ /* Register cleanup callback if we didn't already */
if (!fcache->shutdown_reg) if (!fcache->shutdown_reg)
...@@ -1903,14 +1778,6 @@ restart: ...@@ -1903,14 +1778,6 @@ restart:
fcache->shutdown_reg = true; fcache->shutdown_reg = true;
} }
} }
/*
* Make sure we say we are returning a set, even if the
* function itself doesn't return sets.
*/
if (hasSetArg)
*isDone = ExprMultipleResult;
break;
} }
} }
else if (rsinfo.returnMode == SFRM_Materialize) else if (rsinfo.returnMode == SFRM_Materialize)
...@@ -1926,8 +1793,6 @@ restart: ...@@ -1926,8 +1793,6 @@ restart:
ExecPrepareTuplestoreResult(fcache, econtext, ExecPrepareTuplestoreResult(fcache, econtext,
rsinfo.setResult, rsinfo.setResult,
rsinfo.setDesc); rsinfo.setDesc);
/* remember whether we had set arguments */
fcache->setHasSetArg = hasSetArg;
/* loop back to top to start returning from tuplestore */ /* loop back to top to start returning from tuplestore */
goto restart; goto restart;
} }
...@@ -1942,67 +1807,6 @@ restart: ...@@ -1942,67 +1807,6 @@ restart:
errmsg("unrecognized table-function returnMode: %d", errmsg("unrecognized table-function returnMode: %d",
(int) rsinfo.returnMode))); (int) rsinfo.returnMode)));
/* Else, done with this argument */
if (!hasSetArg)
break; /* input not a set, so done */
/* Re-eval args to get the next element of the input set */
argDone = ExecEvalFuncArgs(fcinfo, arguments, econtext);
if (argDone != ExprMultipleResult)
{
/* End of argument set, so we're done. */
*isNull = true;
*isDone = ExprEndResult;
result = (Datum) 0;
break;
}
/*
* If we reach here, loop around to run the function on the new
* argument.
*/
}
}
else
{
/*
* Non-set case: much easier.
*
* In common cases, this code path is unreachable because we'd have
* selected ExecMakeFunctionResultNoSets instead. However, it's
* possible to get here if an argument sometimes produces set results
* and sometimes scalar results. For example, a CASE expression might
* call a set-returning function in only some of its arms.
*/
if (isDone)
*isDone = ExprSingleResult;
/*
* If function is strict, and there are any NULL arguments, skip
* calling the function and return NULL.
*/
if (fcache->func.fn_strict)
{
for (i = 0; i < fcinfo->nargs; i++)
{
if (fcinfo->argnull[i])
{
*isNull = true;
return (Datum) 0;
}
}
}
pgstat_init_function_usage(fcinfo, &fcusage);
fcinfo->isnull = false;
result = FunctionCallInvoke(fcinfo);
*isNull = fcinfo->isnull;
pgstat_end_function_usage(&fcusage, true);
}
return result; return result;
} }
...@@ -2015,8 +1819,7 @@ restart: ...@@ -2015,8 +1819,7 @@ restart:
static Datum static Datum
ExecMakeFunctionResultNoSets(FuncExprState *fcache, ExecMakeFunctionResultNoSets(FuncExprState *fcache,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, bool *isNull)
ExprDoneCond *isDone)
{ {
ListCell *arg; ListCell *arg;
Datum result; Datum result;
...@@ -2027,9 +1830,6 @@ ExecMakeFunctionResultNoSets(FuncExprState *fcache, ...@@ -2027,9 +1830,6 @@ ExecMakeFunctionResultNoSets(FuncExprState *fcache,
/* Guard against stack overflow due to overly complex expressions */ /* Guard against stack overflow due to overly complex expressions */
check_stack_depth(); check_stack_depth();
if (isDone)
*isDone = ExprSingleResult;
/* inlined, simplified version of ExecEvalFuncArgs */ /* inlined, simplified version of ExecEvalFuncArgs */
fcinfo = &fcache->fcinfo_data; fcinfo = &fcache->fcinfo_data;
i = 0; i = 0;
...@@ -2039,8 +1839,7 @@ ExecMakeFunctionResultNoSets(FuncExprState *fcache, ...@@ -2039,8 +1839,7 @@ ExecMakeFunctionResultNoSets(FuncExprState *fcache,
fcinfo->arg[i] = ExecEvalExpr(argstate, fcinfo->arg[i] = ExecEvalExpr(argstate,
econtext, econtext,
&fcinfo->argnull[i], &fcinfo->argnull[i]);
NULL);
i++; i++;
} }
...@@ -2137,7 +1936,6 @@ ExecMakeTableFunctionResult(ExprState *funcexpr, ...@@ -2137,7 +1936,6 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
IsA(funcexpr->expr, FuncExpr)) IsA(funcexpr->expr, FuncExpr))
{ {
FuncExprState *fcache = (FuncExprState *) funcexpr; FuncExprState *fcache = (FuncExprState *) funcexpr;
ExprDoneCond argDone;
/* /*
* This path is similar to ExecMakeFunctionResultSet. * This path is similar to ExecMakeFunctionResultSet.
...@@ -2172,15 +1970,9 @@ ExecMakeTableFunctionResult(ExprState *funcexpr, ...@@ -2172,15 +1970,9 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
*/ */
MemoryContextReset(argContext); MemoryContextReset(argContext);
oldcontext = MemoryContextSwitchTo(argContext); oldcontext = MemoryContextSwitchTo(argContext);
argDone = ExecEvalFuncArgs(&fcinfo, fcache->args, econtext); ExecEvalFuncArgs(&fcinfo, fcache->args, econtext);
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
/* We don't allow sets in the arguments of the table function */
if (argDone != ExprSingleResult)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("set-valued function called in context that cannot accept a set")));
/* /*
* If function is strict, and there are any NULL arguments, skip * If function is strict, and there are any NULL arguments, skip
* calling the function and act like it returned NULL (or an empty * calling the function and act like it returned NULL (or an empty
...@@ -2240,8 +2032,8 @@ ExecMakeTableFunctionResult(ExprState *funcexpr, ...@@ -2240,8 +2032,8 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
} }
else else
{ {
result = ExecEvalExpr(funcexpr, econtext, result = ExecEvalExpr(funcexpr, econtext, &fcinfo.isnull);
&fcinfo.isnull, &rsinfo.isDone); rsinfo.isDone = ExprSingleResult;
} }
/* Which protocol does function want to use? */ /* Which protocol does function want to use? */
...@@ -2435,8 +2227,7 @@ no_function_result: ...@@ -2435,8 +2227,7 @@ no_function_result:
static Datum static Datum
ExecEvalFunc(FuncExprState *fcache, ExecEvalFunc(FuncExprState *fcache,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, bool *isNull)
ExprDoneCond *isDone)
{ {
/* This is called only the first time through */ /* This is called only the first time through */
FuncExpr *func = (FuncExpr *) fcache->xprstate.expr; FuncExpr *func = (FuncExpr *) fcache->xprstate.expr;
...@@ -2447,7 +2238,7 @@ ExecEvalFunc(FuncExprState *fcache, ...@@ -2447,7 +2238,7 @@ ExecEvalFunc(FuncExprState *fcache,
/* Change the evalfunc pointer to save a few cycles in additional calls */ /* Change the evalfunc pointer to save a few cycles in additional calls */
fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResultNoSets; fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResultNoSets;
return ExecMakeFunctionResultNoSets(fcache, econtext, isNull, isDone); return ExecMakeFunctionResultNoSets(fcache, econtext, isNull);
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
...@@ -2457,8 +2248,7 @@ ExecEvalFunc(FuncExprState *fcache, ...@@ -2457,8 +2248,7 @@ ExecEvalFunc(FuncExprState *fcache,
static Datum static Datum
ExecEvalOper(FuncExprState *fcache, ExecEvalOper(FuncExprState *fcache,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, bool *isNull)
ExprDoneCond *isDone)
{ {
/* This is called only the first time through */ /* This is called only the first time through */
OpExpr *op = (OpExpr *) fcache->xprstate.expr; OpExpr *op = (OpExpr *) fcache->xprstate.expr;
...@@ -2469,7 +2259,7 @@ ExecEvalOper(FuncExprState *fcache, ...@@ -2469,7 +2259,7 @@ ExecEvalOper(FuncExprState *fcache,
/* Change the evalfunc pointer to save a few cycles in additional calls */ /* Change the evalfunc pointer to save a few cycles in additional calls */
fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResultNoSets; fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResultNoSets;
return ExecMakeFunctionResultNoSets(fcache, econtext, isNull, isDone); return ExecMakeFunctionResultNoSets(fcache, econtext, isNull);
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
...@@ -2486,17 +2276,13 @@ ExecEvalOper(FuncExprState *fcache, ...@@ -2486,17 +2276,13 @@ ExecEvalOper(FuncExprState *fcache,
static Datum static Datum
ExecEvalDistinct(FuncExprState *fcache, ExecEvalDistinct(FuncExprState *fcache,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, bool *isNull)
ExprDoneCond *isDone)
{ {
Datum result; Datum result;
FunctionCallInfo fcinfo; FunctionCallInfo fcinfo;
ExprDoneCond argDone;
/* 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;
/* /*
* Initialize function cache if first time through * Initialize function cache if first time through
...@@ -2513,11 +2299,7 @@ ExecEvalDistinct(FuncExprState *fcache, ...@@ -2513,11 +2299,7 @@ ExecEvalDistinct(FuncExprState *fcache,
* Evaluate arguments * Evaluate arguments
*/ */
fcinfo = &fcache->fcinfo_data; fcinfo = &fcache->fcinfo_data;
argDone = ExecEvalFuncArgs(fcinfo, fcache->args, econtext); ExecEvalFuncArgs(fcinfo, fcache->args, econtext);
if (argDone != ExprSingleResult)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("IS DISTINCT FROM does not support set arguments")));
Assert(fcinfo->nargs == 2); Assert(fcinfo->nargs == 2);
if (fcinfo->argnull[0] && fcinfo->argnull[1]) if (fcinfo->argnull[0] && fcinfo->argnull[1])
...@@ -2553,7 +2335,7 @@ ExecEvalDistinct(FuncExprState *fcache, ...@@ -2553,7 +2335,7 @@ ExecEvalDistinct(FuncExprState *fcache,
static Datum static Datum
ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate, ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) sstate->fxprstate.xprstate.expr; ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) sstate->fxprstate.xprstate.expr;
bool useOr = opexpr->useOr; bool useOr = opexpr->useOr;
...@@ -2562,7 +2344,6 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate, ...@@ -2562,7 +2344,6 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
Datum result; Datum result;
bool resultnull; bool resultnull;
FunctionCallInfo fcinfo; FunctionCallInfo fcinfo;
ExprDoneCond argDone;
int i; int i;
int16 typlen; int16 typlen;
bool typbyval; bool typbyval;
...@@ -2571,10 +2352,8 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate, ...@@ -2571,10 +2352,8 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
bits8 *bitmap; bits8 *bitmap;
int bitmask; int bitmask;
/* 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;
/* /*
* Initialize function cache if first time through * Initialize function cache if first time through
...@@ -2589,11 +2368,7 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate, ...@@ -2589,11 +2368,7 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
* Evaluate arguments * Evaluate arguments
*/ */
fcinfo = &sstate->fxprstate.fcinfo_data; fcinfo = &sstate->fxprstate.fcinfo_data;
argDone = ExecEvalFuncArgs(fcinfo, sstate->fxprstate.args, econtext); ExecEvalFuncArgs(fcinfo, sstate->fxprstate.args, econtext);
if (argDone != ExprSingleResult)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("op ANY/ALL (array) does not support set arguments")));
Assert(fcinfo->nargs == 2); Assert(fcinfo->nargs == 2);
/* /*
...@@ -2739,15 +2514,12 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate, ...@@ -2739,15 +2514,12 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
*/ */
static Datum static Datum
ExecEvalNot(BoolExprState *notclause, ExprContext *econtext, ExecEvalNot(BoolExprState *notclause, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
ExprState *clause = linitial(notclause->args); ExprState *clause = linitial(notclause->args);
Datum expr_value; Datum expr_value;
if (isDone) expr_value = ExecEvalExpr(clause, econtext, isNull);
*isDone = ExprSingleResult;
expr_value = ExecEvalExpr(clause, econtext, isNull, NULL);
/* /*
* if the expression evaluates to null, then we just cascade the null back * if the expression evaluates to null, then we just cascade the null back
...@@ -2769,15 +2541,12 @@ ExecEvalNot(BoolExprState *notclause, ExprContext *econtext, ...@@ -2769,15 +2541,12 @@ ExecEvalNot(BoolExprState *notclause, ExprContext *econtext,
*/ */
static Datum static Datum
ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext, ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
List *clauses = orExpr->args; List *clauses = orExpr->args;
ListCell *clause; ListCell *clause;
bool AnyNull; bool AnyNull;
if (isDone)
*isDone = ExprSingleResult;
AnyNull = false; AnyNull = false;
/* /*
...@@ -2798,7 +2567,7 @@ ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext, ...@@ -2798,7 +2567,7 @@ ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext,
ExprState *clausestate = (ExprState *) lfirst(clause); ExprState *clausestate = (ExprState *) lfirst(clause);
Datum clause_value; Datum clause_value;
clause_value = ExecEvalExpr(clausestate, econtext, isNull, NULL); clause_value = ExecEvalExpr(clausestate, econtext, isNull);
/* /*
* if we have a non-null true result, then return it. * if we have a non-null true result, then return it.
...@@ -2820,15 +2589,12 @@ ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext, ...@@ -2820,15 +2589,12 @@ ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext,
*/ */
static Datum static Datum
ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext, ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
List *clauses = andExpr->args; List *clauses = andExpr->args;
ListCell *clause; ListCell *clause;
bool AnyNull; bool AnyNull;
if (isDone)
*isDone = ExprSingleResult;
AnyNull = false; AnyNull = false;
/* /*
...@@ -2845,7 +2611,7 @@ ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext, ...@@ -2845,7 +2611,7 @@ ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext,
ExprState *clausestate = (ExprState *) lfirst(clause); ExprState *clausestate = (ExprState *) lfirst(clause);
Datum clause_value; Datum clause_value;
clause_value = ExecEvalExpr(clausestate, econtext, isNull, NULL); clause_value = ExecEvalExpr(clausestate, econtext, isNull);
/* /*
* if we have a non-null false result, then return it. * if we have a non-null false result, then return it.
...@@ -2871,7 +2637,7 @@ ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext, ...@@ -2871,7 +2637,7 @@ ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext,
static Datum static Datum
ExecEvalConvertRowtype(ConvertRowtypeExprState *cstate, ExecEvalConvertRowtype(ConvertRowtypeExprState *cstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) cstate->xprstate.expr; ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) cstate->xprstate.expr;
HeapTuple result; HeapTuple result;
...@@ -2879,7 +2645,7 @@ ExecEvalConvertRowtype(ConvertRowtypeExprState *cstate, ...@@ -2879,7 +2645,7 @@ ExecEvalConvertRowtype(ConvertRowtypeExprState *cstate,
HeapTupleHeader tuple; HeapTupleHeader tuple;
HeapTupleData tmptup; HeapTupleData tmptup;
tupDatum = ExecEvalExpr(cstate->arg, econtext, isNull, isDone); tupDatum = ExecEvalExpr(cstate->arg, econtext, isNull);
/* this test covers the isDone exception too: */ /* this test covers the isDone exception too: */
if (*isNull) if (*isNull)
...@@ -2955,16 +2721,13 @@ ExecEvalConvertRowtype(ConvertRowtypeExprState *cstate, ...@@ -2955,16 +2721,13 @@ ExecEvalConvertRowtype(ConvertRowtypeExprState *cstate,
*/ */
static Datum static Datum
ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
List *clauses = caseExpr->args; List *clauses = caseExpr->args;
ListCell *clause; ListCell *clause;
Datum save_datum; Datum save_datum;
bool save_isNull; bool save_isNull;
if (isDone)
*isDone = ExprSingleResult;
/* /*
* If there's a test expression, we have to evaluate it and save the value * If there's a test expression, we have to evaluate it and save the value
* where the CaseTestExpr placeholders can find it. We must save and * where the CaseTestExpr placeholders can find it. We must save and
...@@ -2989,8 +2752,7 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, ...@@ -2989,8 +2752,7 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
arg_value = ExecEvalExpr(caseExpr->arg, arg_value = ExecEvalExpr(caseExpr->arg,
econtext, econtext,
&arg_isNull, &arg_isNull);
NULL);
/* Since caseValue_datum may be read multiple times, force to R/O */ /* Since caseValue_datum may be read multiple times, force to R/O */
econtext->caseValue_datum = econtext->caseValue_datum =
MakeExpandedObjectReadOnly(arg_value, MakeExpandedObjectReadOnly(arg_value,
...@@ -3012,8 +2774,7 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, ...@@ -3012,8 +2774,7 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
clause_value = ExecEvalExpr(wclause->expr, clause_value = ExecEvalExpr(wclause->expr,
econtext, econtext,
&clause_isNull, &clause_isNull);
NULL);
/* /*
* if we have a true test, then we return the result, since the case * if we have a true test, then we return the result, since the case
...@@ -3026,8 +2787,7 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, ...@@ -3026,8 +2787,7 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
econtext->caseValue_isNull = save_isNull; econtext->caseValue_isNull = save_isNull;
return ExecEvalExpr(wclause->result, return ExecEvalExpr(wclause->result,
econtext, econtext,
isNull, isNull);
isDone);
} }
} }
...@@ -3038,8 +2798,7 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, ...@@ -3038,8 +2798,7 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
{ {
return ExecEvalExpr(caseExpr->defresult, return ExecEvalExpr(caseExpr->defresult,
econtext, econtext,
isNull, isNull);
isDone);
} }
*isNull = true; *isNull = true;
...@@ -3054,10 +2813,8 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, ...@@ -3054,10 +2813,8 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
static Datum static Datum
ExecEvalCaseTestExpr(ExprState *exprstate, ExecEvalCaseTestExpr(ExprState *exprstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
if (isDone)
*isDone = ExprSingleResult;
*isNull = econtext->caseValue_isNull; *isNull = econtext->caseValue_isNull;
return econtext->caseValue_datum; return econtext->caseValue_datum;
} }
...@@ -3074,17 +2831,13 @@ ExecEvalCaseTestExpr(ExprState *exprstate, ...@@ -3074,17 +2831,13 @@ ExecEvalCaseTestExpr(ExprState *exprstate,
static Datum static Datum
ExecEvalGroupingFuncExpr(GroupingFuncExprState *gstate, ExecEvalGroupingFuncExpr(GroupingFuncExprState *gstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, bool *isNull)
ExprDoneCond *isDone)
{ {
int result = 0; int result = 0;
int attnum = 0; int attnum = 0;
Bitmapset *grouped_cols = gstate->aggstate->grouped_cols; Bitmapset *grouped_cols = gstate->aggstate->grouped_cols;
ListCell *lc; ListCell *lc;
if (isDone)
*isDone = ExprSingleResult;
*isNull = false; *isNull = false;
foreach(lc, (gstate->clauses)) foreach(lc, (gstate->clauses))
...@@ -3106,7 +2859,7 @@ ExecEvalGroupingFuncExpr(GroupingFuncExprState *gstate, ...@@ -3106,7 +2859,7 @@ ExecEvalGroupingFuncExpr(GroupingFuncExprState *gstate,
*/ */
static Datum static Datum
ExecEvalArray(ArrayExprState *astate, ExprContext *econtext, ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
ArrayExpr *arrayExpr = (ArrayExpr *) astate->xprstate.expr; ArrayExpr *arrayExpr = (ArrayExpr *) astate->xprstate.expr;
ArrayType *result; ArrayType *result;
...@@ -3116,10 +2869,8 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext, ...@@ -3116,10 +2869,8 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
int dims[MAXDIM]; int dims[MAXDIM];
int lbs[MAXDIM]; int lbs[MAXDIM];
/* 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;
if (!arrayExpr->multidims) if (!arrayExpr->multidims)
{ {
...@@ -3144,7 +2895,7 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext, ...@@ -3144,7 +2895,7 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
{ {
ExprState *e = (ExprState *) lfirst(element); ExprState *e = (ExprState *) lfirst(element);
dvalues[i] = ExecEvalExpr(e, econtext, &dnulls[i], NULL); dvalues[i] = ExecEvalExpr(e, econtext, &dnulls[i]);
i++; i++;
} }
...@@ -3194,7 +2945,7 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext, ...@@ -3194,7 +2945,7 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
ArrayType *array; ArrayType *array;
int this_ndims; int this_ndims;
arraydatum = ExecEvalExpr(e, econtext, &eisnull, NULL); arraydatum = ExecEvalExpr(e, econtext, &eisnull);
/* temporarily ignore null subarrays */ /* temporarily ignore null subarrays */
if (eisnull) if (eisnull)
{ {
...@@ -3333,7 +3084,7 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext, ...@@ -3333,7 +3084,7 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
static Datum static Datum
ExecEvalRow(RowExprState *rstate, ExecEvalRow(RowExprState *rstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
HeapTuple tuple; HeapTuple tuple;
Datum *values; Datum *values;
...@@ -3342,10 +3093,8 @@ ExecEvalRow(RowExprState *rstate, ...@@ -3342,10 +3093,8 @@ ExecEvalRow(RowExprState *rstate,
ListCell *arg; ListCell *arg;
int i; int i;
/* 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;
/* Allocate workspace */ /* Allocate workspace */
natts = rstate->tupdesc->natts; natts = rstate->tupdesc->natts;
...@@ -3361,7 +3110,7 @@ ExecEvalRow(RowExprState *rstate, ...@@ -3361,7 +3110,7 @@ ExecEvalRow(RowExprState *rstate,
{ {
ExprState *e = (ExprState *) lfirst(arg); ExprState *e = (ExprState *) lfirst(arg);
values[i] = ExecEvalExpr(e, econtext, &isnull[i], NULL); values[i] = ExecEvalExpr(e, econtext, &isnull[i]);
i++; i++;
} }
...@@ -3380,7 +3129,7 @@ ExecEvalRow(RowExprState *rstate, ...@@ -3380,7 +3129,7 @@ ExecEvalRow(RowExprState *rstate,
static Datum static Datum
ExecEvalRowCompare(RowCompareExprState *rstate, ExecEvalRowCompare(RowCompareExprState *rstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
bool result; bool result;
RowCompareType rctype = ((RowCompareExpr *) rstate->xprstate.expr)->rctype; RowCompareType rctype = ((RowCompareExpr *) rstate->xprstate.expr)->rctype;
...@@ -3389,8 +3138,6 @@ ExecEvalRowCompare(RowCompareExprState *rstate, ...@@ -3389,8 +3138,6 @@ ExecEvalRowCompare(RowCompareExprState *rstate,
ListCell *r; ListCell *r;
int i; int i;
if (isDone)
*isDone = ExprSingleResult;
*isNull = true; /* until we get a result */ *isNull = true; /* until we get a result */
i = 0; i = 0;
...@@ -3404,9 +3151,9 @@ ExecEvalRowCompare(RowCompareExprState *rstate, ...@@ -3404,9 +3151,9 @@ ExecEvalRowCompare(RowCompareExprState *rstate,
rstate->collations[i], rstate->collations[i],
NULL, NULL); NULL, NULL);
locfcinfo.arg[0] = ExecEvalExpr(le, econtext, locfcinfo.arg[0] = ExecEvalExpr(le, econtext,
&locfcinfo.argnull[0], NULL); &locfcinfo.argnull[0]);
locfcinfo.arg[1] = ExecEvalExpr(re, econtext, locfcinfo.arg[1] = ExecEvalExpr(re, econtext,
&locfcinfo.argnull[1], NULL); &locfcinfo.argnull[1]);
if (rstate->funcs[i].fn_strict && if (rstate->funcs[i].fn_strict &&
(locfcinfo.argnull[0] || locfcinfo.argnull[1])) (locfcinfo.argnull[0] || locfcinfo.argnull[1]))
return (Datum) 0; /* force NULL result */ return (Datum) 0; /* force NULL result */
...@@ -3450,20 +3197,17 @@ ExecEvalRowCompare(RowCompareExprState *rstate, ...@@ -3450,20 +3197,17 @@ ExecEvalRowCompare(RowCompareExprState *rstate,
*/ */
static Datum static Datum
ExecEvalCoalesce(CoalesceExprState *coalesceExpr, ExprContext *econtext, ExecEvalCoalesce(CoalesceExprState *coalesceExpr, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
ListCell *arg; ListCell *arg;
if (isDone)
*isDone = ExprSingleResult;
/* Simply loop through until something NOT NULL is found */ /* Simply loop through until something NOT NULL is found */
foreach(arg, coalesceExpr->args) foreach(arg, coalesceExpr->args)
{ {
ExprState *e = (ExprState *) lfirst(arg); ExprState *e = (ExprState *) lfirst(arg);
Datum value; Datum value;
value = ExecEvalExpr(e, econtext, isNull, NULL); value = ExecEvalExpr(e, econtext, isNull);
if (!*isNull) if (!*isNull)
return value; return value;
} }
...@@ -3479,7 +3223,7 @@ ExecEvalCoalesce(CoalesceExprState *coalesceExpr, ExprContext *econtext, ...@@ -3479,7 +3223,7 @@ ExecEvalCoalesce(CoalesceExprState *coalesceExpr, ExprContext *econtext,
*/ */
static Datum static Datum
ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext, ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
Datum result = (Datum) 0; Datum result = (Datum) 0;
MinMaxExpr *minmax = (MinMaxExpr *) minmaxExpr->xprstate.expr; MinMaxExpr *minmax = (MinMaxExpr *) minmaxExpr->xprstate.expr;
...@@ -3488,8 +3232,6 @@ ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext, ...@@ -3488,8 +3232,6 @@ ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext,
FunctionCallInfoData locfcinfo; FunctionCallInfoData locfcinfo;
ListCell *arg; ListCell *arg;
if (isDone)
*isDone = ExprSingleResult;
*isNull = true; /* until we get a result */ *isNull = true; /* until we get a result */
InitFunctionCallInfoData(locfcinfo, &minmaxExpr->cfunc, 2, InitFunctionCallInfoData(locfcinfo, &minmaxExpr->cfunc, 2,
...@@ -3504,7 +3246,7 @@ ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext, ...@@ -3504,7 +3246,7 @@ ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext,
bool valueIsNull; bool valueIsNull;
int32 cmpresult; int32 cmpresult;
value = ExecEvalExpr(e, econtext, &valueIsNull, NULL); value = ExecEvalExpr(e, econtext, &valueIsNull);
if (valueIsNull) if (valueIsNull)
continue; /* ignore NULL inputs */ continue; /* ignore NULL inputs */
...@@ -3540,14 +3282,12 @@ ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext, ...@@ -3540,14 +3282,12 @@ ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext,
static Datum static Datum
ExecEvalSQLValueFunction(ExprState *svfExpr, ExecEvalSQLValueFunction(ExprState *svfExpr,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
Datum result = (Datum) 0; Datum result = (Datum) 0;
SQLValueFunction *svf = (SQLValueFunction *) svfExpr->expr; SQLValueFunction *svf = (SQLValueFunction *) svfExpr->expr;
FunctionCallInfoData fcinfo; FunctionCallInfoData fcinfo;
if (isDone)
*isDone = ExprSingleResult;
*isNull = false; *isNull = false;
/* /*
...@@ -3608,7 +3348,7 @@ ExecEvalSQLValueFunction(ExprState *svfExpr, ...@@ -3608,7 +3348,7 @@ ExecEvalSQLValueFunction(ExprState *svfExpr,
*/ */
static Datum static Datum
ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext, ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
XmlExpr *xexpr = (XmlExpr *) xmlExpr->xprstate.expr; XmlExpr *xexpr = (XmlExpr *) xmlExpr->xprstate.expr;
Datum value; Datum value;
...@@ -3616,8 +3356,6 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext, ...@@ -3616,8 +3356,6 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
ListCell *arg; ListCell *arg;
ListCell *narg; ListCell *narg;
if (isDone)
*isDone = ExprSingleResult;
*isNull = true; /* until we get a result */ *isNull = true; /* until we get a result */
switch (xexpr->op) switch (xexpr->op)
...@@ -3630,7 +3368,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext, ...@@ -3630,7 +3368,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
{ {
ExprState *e = (ExprState *) lfirst(arg); ExprState *e = (ExprState *) lfirst(arg);
value = ExecEvalExpr(e, econtext, &isnull, NULL); value = ExecEvalExpr(e, econtext, &isnull);
if (!isnull) if (!isnull)
values = lappend(values, DatumGetPointer(value)); values = lappend(values, DatumGetPointer(value));
} }
...@@ -3655,7 +3393,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext, ...@@ -3655,7 +3393,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
ExprState *e = (ExprState *) lfirst(arg); ExprState *e = (ExprState *) lfirst(arg);
char *argname = strVal(lfirst(narg)); char *argname = strVal(lfirst(narg));
value = ExecEvalExpr(e, econtext, &isnull, NULL); value = ExecEvalExpr(e, econtext, &isnull);
if (!isnull) if (!isnull)
{ {
appendStringInfo(&buf, "<%s>%s</%s>", appendStringInfo(&buf, "<%s>%s</%s>",
...@@ -3698,13 +3436,13 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext, ...@@ -3698,13 +3436,13 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
Assert(list_length(xmlExpr->args) == 2); Assert(list_length(xmlExpr->args) == 2);
e = (ExprState *) linitial(xmlExpr->args); e = (ExprState *) linitial(xmlExpr->args);
value = ExecEvalExpr(e, econtext, &isnull, NULL); value = ExecEvalExpr(e, econtext, &isnull);
if (isnull) if (isnull)
return (Datum) 0; return (Datum) 0;
data = DatumGetTextP(value); data = DatumGetTextP(value);
e = (ExprState *) lsecond(xmlExpr->args); e = (ExprState *) lsecond(xmlExpr->args);
value = ExecEvalExpr(e, econtext, &isnull, NULL); value = ExecEvalExpr(e, econtext, &isnull);
if (isnull) /* probably can't happen */ if (isnull) /* probably can't happen */
return (Datum) 0; return (Datum) 0;
preserve_whitespace = DatumGetBool(value); preserve_whitespace = DatumGetBool(value);
...@@ -3728,7 +3466,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext, ...@@ -3728,7 +3466,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
if (xmlExpr->args) if (xmlExpr->args)
{ {
e = (ExprState *) linitial(xmlExpr->args); e = (ExprState *) linitial(xmlExpr->args);
value = ExecEvalExpr(e, econtext, &isnull, NULL); value = ExecEvalExpr(e, econtext, &isnull);
if (isnull) if (isnull)
arg = NULL; arg = NULL;
else else
...@@ -3755,20 +3493,20 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext, ...@@ -3755,20 +3493,20 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
Assert(list_length(xmlExpr->args) == 3); Assert(list_length(xmlExpr->args) == 3);
e = (ExprState *) linitial(xmlExpr->args); e = (ExprState *) linitial(xmlExpr->args);
value = ExecEvalExpr(e, econtext, &isnull, NULL); value = ExecEvalExpr(e, econtext, &isnull);
if (isnull) if (isnull)
return (Datum) 0; return (Datum) 0;
data = DatumGetXmlP(value); data = DatumGetXmlP(value);
e = (ExprState *) lsecond(xmlExpr->args); e = (ExprState *) lsecond(xmlExpr->args);
value = ExecEvalExpr(e, econtext, &isnull, NULL); value = ExecEvalExpr(e, econtext, &isnull);
if (isnull) if (isnull)
version = NULL; version = NULL;
else else
version = DatumGetTextP(value); version = DatumGetTextP(value);
e = (ExprState *) lthird(xmlExpr->args); e = (ExprState *) lthird(xmlExpr->args);
value = ExecEvalExpr(e, econtext, &isnull, NULL); value = ExecEvalExpr(e, econtext, &isnull);
standalone = DatumGetInt32(value); standalone = DatumGetInt32(value);
*isNull = false; *isNull = false;
...@@ -3787,7 +3525,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext, ...@@ -3787,7 +3525,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
Assert(list_length(xmlExpr->args) == 1); Assert(list_length(xmlExpr->args) == 1);
e = (ExprState *) linitial(xmlExpr->args); e = (ExprState *) linitial(xmlExpr->args);
value = ExecEvalExpr(e, econtext, &isnull, NULL); value = ExecEvalExpr(e, econtext, &isnull);
if (isnull) if (isnull)
return (Datum) 0; return (Datum) 0;
...@@ -3805,7 +3543,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext, ...@@ -3805,7 +3543,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
Assert(list_length(xmlExpr->args) == 1); Assert(list_length(xmlExpr->args) == 1);
e = (ExprState *) linitial(xmlExpr->args); e = (ExprState *) linitial(xmlExpr->args);
value = ExecEvalExpr(e, econtext, &isnull, NULL); value = ExecEvalExpr(e, econtext, &isnull);
if (isnull) if (isnull)
return (Datum) 0; return (Datum) 0;
else else
...@@ -3832,14 +3570,10 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext, ...@@ -3832,14 +3570,10 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
static Datum static Datum
ExecEvalNullIf(FuncExprState *nullIfExpr, ExecEvalNullIf(FuncExprState *nullIfExpr,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
Datum result; Datum result;
FunctionCallInfo fcinfo; FunctionCallInfo fcinfo;
ExprDoneCond argDone;
if (isDone)
*isDone = ExprSingleResult;
/* /*
* Initialize function cache if first time through * Initialize function cache if first time through
...@@ -3856,11 +3590,7 @@ ExecEvalNullIf(FuncExprState *nullIfExpr, ...@@ -3856,11 +3590,7 @@ ExecEvalNullIf(FuncExprState *nullIfExpr,
* Evaluate arguments * Evaluate arguments
*/ */
fcinfo = &nullIfExpr->fcinfo_data; fcinfo = &nullIfExpr->fcinfo_data;
argDone = ExecEvalFuncArgs(fcinfo, nullIfExpr->args, econtext); ExecEvalFuncArgs(fcinfo, nullIfExpr->args, econtext);
if (argDone != ExprSingleResult)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("NULLIF does not support set arguments")));
Assert(fcinfo->nargs == 2); Assert(fcinfo->nargs == 2);
/* if either argument is NULL they can't be equal */ /* if either argument is NULL they can't be equal */
...@@ -3890,16 +3620,12 @@ ExecEvalNullIf(FuncExprState *nullIfExpr, ...@@ -3890,16 +3620,12 @@ ExecEvalNullIf(FuncExprState *nullIfExpr,
static Datum static Datum
ExecEvalNullTest(NullTestState *nstate, ExecEvalNullTest(NullTestState *nstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, bool *isNull)
ExprDoneCond *isDone)
{ {
NullTest *ntest = (NullTest *) nstate->xprstate.expr; NullTest *ntest = (NullTest *) nstate->xprstate.expr;
Datum result; Datum result;
result = ExecEvalExpr(nstate->arg, econtext, isNull, isDone); result = ExecEvalExpr(nstate->arg, econtext, isNull);
if (isDone && *isDone == ExprEndResult)
return result; /* nothing to check */
if (ntest->argisrow && !(*isNull)) if (ntest->argisrow && !(*isNull))
{ {
...@@ -3999,16 +3725,12 @@ ExecEvalNullTest(NullTestState *nstate, ...@@ -3999,16 +3725,12 @@ ExecEvalNullTest(NullTestState *nstate,
static Datum static Datum
ExecEvalBooleanTest(GenericExprState *bstate, ExecEvalBooleanTest(GenericExprState *bstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, bool *isNull)
ExprDoneCond *isDone)
{ {
BooleanTest *btest = (BooleanTest *) bstate->xprstate.expr; BooleanTest *btest = (BooleanTest *) bstate->xprstate.expr;
Datum result; Datum result;
result = ExecEvalExpr(bstate->arg, econtext, isNull, isDone); result = ExecEvalExpr(bstate->arg, econtext, isNull);
if (isDone && *isDone == ExprEndResult)
return result; /* nothing to check */
switch (btest->booltesttype) switch (btest->booltesttype)
{ {
...@@ -4084,16 +3806,13 @@ ExecEvalBooleanTest(GenericExprState *bstate, ...@@ -4084,16 +3806,13 @@ ExecEvalBooleanTest(GenericExprState *bstate,
*/ */
static Datum static Datum
ExecEvalCoerceToDomain(CoerceToDomainState *cstate, ExprContext *econtext, ExecEvalCoerceToDomain(CoerceToDomainState *cstate, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
CoerceToDomain *ctest = (CoerceToDomain *) cstate->xprstate.expr; CoerceToDomain *ctest = (CoerceToDomain *) cstate->xprstate.expr;
Datum result; Datum result;
ListCell *l; ListCell *l;
result = ExecEvalExpr(cstate->arg, econtext, isNull, isDone); result = ExecEvalExpr(cstate->arg, econtext, isNull);
if (isDone && *isDone == ExprEndResult)
return result; /* nothing to check */
/* Make sure we have up-to-date constraints */ /* Make sure we have up-to-date constraints */
UpdateDomainConstraintRef(cstate->constraint_ref); UpdateDomainConstraintRef(cstate->constraint_ref);
...@@ -4138,8 +3857,8 @@ ExecEvalCoerceToDomain(CoerceToDomainState *cstate, ExprContext *econtext, ...@@ -4138,8 +3857,8 @@ ExecEvalCoerceToDomain(CoerceToDomainState *cstate, ExprContext *econtext,
cstate->constraint_ref->tcache->typlen); cstate->constraint_ref->tcache->typlen);
econtext->domainValue_isNull = *isNull; econtext->domainValue_isNull = *isNull;
conResult = ExecEvalExpr(con->check_expr, conResult = ExecEvalExpr(con->check_expr, econtext,
econtext, &conIsNull, NULL); &conIsNull);
if (!conIsNull && if (!conIsNull &&
!DatumGetBool(conResult)) !DatumGetBool(conResult))
...@@ -4174,10 +3893,8 @@ ExecEvalCoerceToDomain(CoerceToDomainState *cstate, ExprContext *econtext, ...@@ -4174,10 +3893,8 @@ ExecEvalCoerceToDomain(CoerceToDomainState *cstate, ExprContext *econtext,
static Datum static Datum
ExecEvalCoerceToDomainValue(ExprState *exprstate, ExecEvalCoerceToDomainValue(ExprState *exprstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
if (isDone)
*isDone = ExprSingleResult;
*isNull = econtext->domainValue_isNull; *isNull = econtext->domainValue_isNull;
return econtext->domainValue_datum; return econtext->domainValue_datum;
} }
...@@ -4191,8 +3908,7 @@ ExecEvalCoerceToDomainValue(ExprState *exprstate, ...@@ -4191,8 +3908,7 @@ ExecEvalCoerceToDomainValue(ExprState *exprstate,
static Datum static Datum
ExecEvalFieldSelect(FieldSelectState *fstate, ExecEvalFieldSelect(FieldSelectState *fstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, bool *isNull)
ExprDoneCond *isDone)
{ {
FieldSelect *fselect = (FieldSelect *) fstate->xprstate.expr; FieldSelect *fselect = (FieldSelect *) fstate->xprstate.expr;
AttrNumber fieldnum = fselect->fieldnum; AttrNumber fieldnum = fselect->fieldnum;
...@@ -4205,9 +3921,8 @@ ExecEvalFieldSelect(FieldSelectState *fstate, ...@@ -4205,9 +3921,8 @@ ExecEvalFieldSelect(FieldSelectState *fstate,
Form_pg_attribute attr; Form_pg_attribute attr;
HeapTupleData tmptup; HeapTupleData tmptup;
tupDatum = ExecEvalExpr(fstate->arg, econtext, isNull, isDone); tupDatum = ExecEvalExpr(fstate->arg, econtext, isNull);
/* this test covers the isDone exception too: */
if (*isNull) if (*isNull)
return tupDatum; return tupDatum;
...@@ -4270,8 +3985,7 @@ ExecEvalFieldSelect(FieldSelectState *fstate, ...@@ -4270,8 +3985,7 @@ ExecEvalFieldSelect(FieldSelectState *fstate,
static Datum static Datum
ExecEvalFieldStore(FieldStoreState *fstate, ExecEvalFieldStore(FieldStoreState *fstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, bool *isNull)
ExprDoneCond *isDone)
{ {
FieldStore *fstore = (FieldStore *) fstate->xprstate.expr; FieldStore *fstore = (FieldStore *) fstate->xprstate.expr;
HeapTuple tuple; HeapTuple tuple;
...@@ -4284,10 +3998,7 @@ ExecEvalFieldStore(FieldStoreState *fstate, ...@@ -4284,10 +3998,7 @@ ExecEvalFieldStore(FieldStoreState *fstate,
ListCell *l1, ListCell *l1,
*l2; *l2;
tupDatum = ExecEvalExpr(fstate->arg, econtext, isNull, isDone); tupDatum = ExecEvalExpr(fstate->arg, econtext, isNull);
if (isDone && *isDone == ExprEndResult)
return tupDatum;
/* Lookup tupdesc if first time through or after rescan */ /* Lookup tupdesc if first time through or after rescan */
tupDesc = get_cached_rowtype(fstore->resulttype, -1, tupDesc = get_cached_rowtype(fstore->resulttype, -1,
...@@ -4347,8 +4058,7 @@ ExecEvalFieldStore(FieldStoreState *fstate, ...@@ -4347,8 +4058,7 @@ ExecEvalFieldStore(FieldStoreState *fstate,
values[fieldnum - 1] = ExecEvalExpr(newval, values[fieldnum - 1] = ExecEvalExpr(newval,
econtext, econtext,
&isnull[fieldnum - 1], &isnull[fieldnum - 1]);
NULL);
} }
econtext->caseValue_datum = save_datum; econtext->caseValue_datum = save_datum;
...@@ -4371,9 +4081,9 @@ ExecEvalFieldStore(FieldStoreState *fstate, ...@@ -4371,9 +4081,9 @@ ExecEvalFieldStore(FieldStoreState *fstate,
static Datum static Datum
ExecEvalRelabelType(GenericExprState *exprstate, ExecEvalRelabelType(GenericExprState *exprstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
return ExecEvalExpr(exprstate->arg, econtext, isNull, isDone); return ExecEvalExpr(exprstate->arg, econtext, isNull);
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
...@@ -4385,16 +4095,13 @@ ExecEvalRelabelType(GenericExprState *exprstate, ...@@ -4385,16 +4095,13 @@ ExecEvalRelabelType(GenericExprState *exprstate,
static Datum static Datum
ExecEvalCoerceViaIO(CoerceViaIOState *iostate, ExecEvalCoerceViaIO(CoerceViaIOState *iostate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
Datum result; Datum result;
Datum inputval; Datum inputval;
char *string; char *string;
inputval = ExecEvalExpr(iostate->arg, econtext, isNull, isDone); inputval = ExecEvalExpr(iostate->arg, econtext, isNull);
if (isDone && *isDone == ExprEndResult)
return inputval; /* nothing to do */
if (*isNull) if (*isNull)
string = NULL; /* output functions are not called on nulls */ string = NULL; /* output functions are not called on nulls */
...@@ -4419,16 +4126,14 @@ ExecEvalCoerceViaIO(CoerceViaIOState *iostate, ...@@ -4419,16 +4126,14 @@ ExecEvalCoerceViaIO(CoerceViaIOState *iostate,
static Datum static Datum
ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate, ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) astate->xprstate.expr; ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) astate->xprstate.expr;
Datum result; Datum result;
FunctionCallInfoData locfcinfo; FunctionCallInfoData locfcinfo;
result = ExecEvalExpr(astate->arg, econtext, isNull, isDone); result = ExecEvalExpr(astate->arg, econtext, isNull);
if (isDone && *isDone == ExprEndResult)
return result; /* nothing to do */
if (*isNull) if (*isNull)
return result; /* nothing to do */ return result; /* nothing to do */
...@@ -4496,7 +4201,7 @@ ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate, ...@@ -4496,7 +4201,7 @@ ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate,
*/ */
static Datum static Datum
ExecEvalCurrentOfExpr(ExprState *exprstate, ExprContext *econtext, ExecEvalCurrentOfExpr(ExprState *exprstate, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull)
{ {
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
...@@ -4513,14 +4218,13 @@ ExecEvalCurrentOfExpr(ExprState *exprstate, ExprContext *econtext, ...@@ -4513,14 +4218,13 @@ ExecEvalCurrentOfExpr(ExprState *exprstate, ExprContext *econtext,
Datum Datum
ExecEvalExprSwitchContext(ExprState *expression, ExecEvalExprSwitchContext(ExprState *expression,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, bool *isNull)
ExprDoneCond *isDone)
{ {
Datum retDatum; Datum retDatum;
MemoryContext oldContext; MemoryContext oldContext;
oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory); oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
retDatum = ExecEvalExpr(expression, econtext, isNull, isDone); retDatum = ExecEvalExpr(expression, econtext, isNull);
MemoryContextSwitchTo(oldContext); MemoryContextSwitchTo(oldContext);
return retDatum; return retDatum;
} }
...@@ -5387,7 +5091,7 @@ ExecQual(List *qual, ExprContext *econtext, bool resultForNull) ...@@ -5387,7 +5091,7 @@ ExecQual(List *qual, ExprContext *econtext, bool resultForNull)
Datum expr_value; Datum expr_value;
bool isNull; bool isNull;
expr_value = ExecEvalExpr(clause, econtext, &isNull, NULL); expr_value = ExecEvalExpr(clause, econtext, &isNull);
if (isNull) if (isNull)
{ {
...@@ -5445,17 +5149,11 @@ ExecCleanTargetListLength(List *targetlist) ...@@ -5445,17 +5149,11 @@ ExecCleanTargetListLength(List *targetlist)
/* /*
* ExecTargetList * ExecTargetList
* Evaluates a targetlist with respect to the given * Evaluates a targetlist with respect to the given
* expression context. Returns TRUE if we were able to create * expression context.
* a result, FALSE if we have exhausted a set-valued expression.
* *
* Results are stored into the passed values and isnull arrays. * tupdesc must describe the rowtype of the expected result.
* The caller must provide an itemIsDone array that persists across calls.
* *
* As with ExecEvalExpr, the caller should pass isDone = NULL if not * Results are stored into the passed values and isnull arrays.
* prepared to deal with sets of result tuples. Otherwise, a return
* of *isDone = ExprMultipleResult signifies a set element, and a return
* of *isDone = ExprEndResult signifies end of the set of tuple.
* We assume that *isDone has been initialized to ExprSingleResult by caller.
* *
* Since fields of the result tuple might be multiply referenced in higher * Since fields of the result tuple might be multiply referenced in higher
* plan nodes, we have to force any read/write expanded values to read-only * plan nodes, we have to force any read/write expanded values to read-only
...@@ -5464,19 +5162,16 @@ ExecCleanTargetListLength(List *targetlist) ...@@ -5464,19 +5162,16 @@ ExecCleanTargetListLength(List *targetlist)
* actually-multiply-referenced Vars and insert an expression node that * actually-multiply-referenced Vars and insert an expression node that
* would do that only where really required. * would do that only where really required.
*/ */
static bool static void
ExecTargetList(List *targetlist, ExecTargetList(List *targetlist,
TupleDesc tupdesc, TupleDesc tupdesc,
ExprContext *econtext, ExprContext *econtext,
Datum *values, Datum *values,
bool *isnull, bool *isnull)
ExprDoneCond *itemIsDone,
ExprDoneCond *isDone)
{ {
Form_pg_attribute *att = tupdesc->attrs; Form_pg_attribute *att = tupdesc->attrs;
MemoryContext oldContext; MemoryContext oldContext;
ListCell *tl; ListCell *tl;
bool haveDoneSets;
/* /*
* Run in short-lived per-tuple context while computing expressions. * Run in short-lived per-tuple context while computing expressions.
...@@ -5486,127 +5181,22 @@ ExecTargetList(List *targetlist, ...@@ -5486,127 +5181,22 @@ ExecTargetList(List *targetlist,
/* /*
* evaluate all the expressions in the target list * evaluate all the expressions in the target list
*/ */
haveDoneSets = false; /* any exhausted set exprs in tlist? */
foreach(tl, targetlist)
{
GenericExprState *gstate = (GenericExprState *) lfirst(tl);
TargetEntry *tle = (TargetEntry *) gstate->xprstate.expr;
AttrNumber resind = tle->resno - 1;
values[resind] = ExecEvalExpr(gstate->arg,
econtext,
&isnull[resind],
&itemIsDone[resind]);
values[resind] = MakeExpandedObjectReadOnly(values[resind],
isnull[resind],
att[resind]->attlen);
if (itemIsDone[resind] != ExprSingleResult)
{
/* We have a set-valued expression in the tlist */
if (isDone == NULL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("set-valued function called in context that cannot accept a set")));
if (itemIsDone[resind] == ExprMultipleResult)
{
/* we have undone sets in the tlist, set flag */
*isDone = ExprMultipleResult;
}
else
{
/* we have done sets in the tlist, set flag for that */
haveDoneSets = true;
}
}
}
if (haveDoneSets)
{
/*
* note: can't get here unless we verified isDone != NULL
*/
if (*isDone == ExprSingleResult)
{
/*
* all sets are done, so report that tlist expansion is complete.
*/
*isDone = ExprEndResult;
MemoryContextSwitchTo(oldContext);
return false;
}
else
{
/*
* We have some done and some undone sets. Restart the done ones
* so that we can deliver a tuple (if possible).
*/
foreach(tl, targetlist) foreach(tl, targetlist)
{ {
GenericExprState *gstate = (GenericExprState *) lfirst(tl); GenericExprState *gstate = (GenericExprState *) lfirst(tl);
TargetEntry *tle = (TargetEntry *) gstate->xprstate.expr; TargetEntry *tle = (TargetEntry *) gstate->xprstate.expr;
AttrNumber resind = tle->resno - 1; AttrNumber resind = tle->resno - 1;
if (itemIsDone[resind] == ExprEndResult)
{
values[resind] = ExecEvalExpr(gstate->arg, values[resind] = ExecEvalExpr(gstate->arg,
econtext, econtext,
&isnull[resind], &isnull[resind]);
&itemIsDone[resind]);
values[resind] = MakeExpandedObjectReadOnly(values[resind], values[resind] = MakeExpandedObjectReadOnly(values[resind],
isnull[resind], isnull[resind],
att[resind]->attlen); att[resind]->attlen);
if (itemIsDone[resind] == ExprEndResult)
{
/*
* Oh dear, this item is returning an empty set. Guess
* we can't make a tuple after all.
*/
*isDone = ExprEndResult;
break;
}
}
}
/*
* If we cannot make a tuple because some sets are empty, we still
* have to cycle the nonempty sets to completion, else resources
* will not be released from subplans etc.
*
* XXX is that still necessary?
*/
if (*isDone == ExprEndResult)
{
foreach(tl, targetlist)
{
GenericExprState *gstate = (GenericExprState *) lfirst(tl);
TargetEntry *tle = (TargetEntry *) gstate->xprstate.expr;
AttrNumber resind = tle->resno - 1;
while (itemIsDone[resind] == ExprMultipleResult)
{
values[resind] = ExecEvalExpr(gstate->arg,
econtext,
&isnull[resind],
&itemIsDone[resind]);
/* no need for MakeExpandedObjectReadOnly */
}
} }
MemoryContextSwitchTo(oldContext); MemoryContextSwitchTo(oldContext);
return false;
}
}
}
/* Report success */
MemoryContextSwitchTo(oldContext);
return true;
} }
/* /*
...@@ -5623,7 +5213,7 @@ ExecTargetList(List *targetlist, ...@@ -5623,7 +5213,7 @@ ExecTargetList(List *targetlist,
* result slot. * result slot.
*/ */
TupleTableSlot * TupleTableSlot *
ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone) ExecProject(ProjectionInfo *projInfo)
{ {
TupleTableSlot *slot; TupleTableSlot *slot;
ExprContext *econtext; ExprContext *econtext;
...@@ -5640,14 +5230,9 @@ ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone) ...@@ -5640,14 +5230,9 @@ ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone)
slot = projInfo->pi_slot; slot = projInfo->pi_slot;
econtext = projInfo->pi_exprContext; econtext = projInfo->pi_exprContext;
/* Assume single result row until proven otherwise */
if (isDone)
*isDone = ExprSingleResult;
/* /*
* Clear any former contents of the result slot. This makes it safe for * Clear any former contents of the result slot. This makes it safe for
* us to use the slot's Datum/isnull arrays as workspace. (Also, we can * us to use the slot's Datum/isnull arrays as workspace.
* return the slot as-is if we decide no rows can be projected.)
*/ */
ExecClearTuple(slot); ExecClearTuple(slot);
...@@ -5711,26 +5296,19 @@ ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone) ...@@ -5711,26 +5296,19 @@ ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone)
} }
/* /*
* If there are any generic expressions, evaluate them. It's possible * If there are any generic expressions, evaluate them.
* that there are set-returning functions in such expressions; if so and
* we have reached the end of the set, we return the result slot, which we
* already marked empty.
*/ */
if (projInfo->pi_targetlist) if (projInfo->pi_targetlist)
{ {
if (!ExecTargetList(projInfo->pi_targetlist, ExecTargetList(projInfo->pi_targetlist,
slot->tts_tupleDescriptor, slot->tts_tupleDescriptor,
econtext, econtext,
slot->tts_values, slot->tts_values,
slot->tts_isnull, slot->tts_isnull);
projInfo->pi_itemIsDone,
isDone))
return slot; /* no more result rows, return empty slot */
} }
/* /*
* Successfully formed a result row. Mark the result slot as containing a * Mark the result slot as containing a valid virtual tuple.
* valid virtual tuple.
*/ */
return ExecStoreVirtualTuple(slot); return ExecStoreVirtualTuple(slot);
} }
...@@ -125,8 +125,6 @@ ExecScan(ScanState *node, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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)
{ {
......
...@@ -586,12 +586,6 @@ ExecBuildProjectionInfo(List *targetList, ...@@ -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;
} }
......
...@@ -854,7 +854,7 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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)
{ {
/* /*
......
...@@ -575,8 +575,6 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags) ...@@ -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
*/ */
......
...@@ -269,8 +269,6 @@ ExecInitCteScan(CteScan *node, EState *estate, int eflags) ...@@ -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;
} }
......
...@@ -48,8 +48,6 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags) ...@@ -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,
......
...@@ -152,8 +152,6 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags) ...@@ -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
*/ */
......
...@@ -331,8 +331,6 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags) ...@@ -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
*/ */
......
...@@ -100,8 +100,6 @@ ExecInitGather(Gather *node, EState *estate, int eflags) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
......
...@@ -49,23 +49,6 @@ ExecGroup(GroupState *node) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
......
...@@ -959,7 +959,7 @@ ExecHashGetHashValue(HashJoinTable hashtable, ...@@ -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
......
...@@ -66,7 +66,6 @@ ExecHashJoin(HashJoinState *node) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
......
...@@ -412,8 +412,6 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags) ...@@ -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
* *
......
...@@ -336,8 +336,7 @@ EvalOrderByExpressions(IndexScanState *node, ExprContext *econtext) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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
* *
......
...@@ -239,8 +239,7 @@ recompute_limits(LimitState *node) ...@@ -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) ...@@ -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) ...@@ -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));
} }
} }
......
...@@ -313,7 +313,7 @@ MJEvalOuterValues(MergeJoinState *mergestate) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
......
...@@ -175,7 +175,7 @@ ExecProcessReturning(ResultRelInfo *resultRelInfo, ...@@ -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, ...@@ -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
......
...@@ -81,27 +81,9 @@ ExecNestLoop(NestLoopState *node) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
} }
...@@ -169,7 +169,7 @@ ExecProjectSRF(ProjectSetState *node, bool continuing) ...@@ -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;
} }
......
...@@ -67,10 +67,8 @@ TupleTableSlot * ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 ...@@ -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;
/* /*
......
...@@ -189,8 +189,6 @@ ExecInitSampleScan(SampleScan *node, EState *estate, int eflags) ...@@ -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) ...@@ -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) ...@@ -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),
......
...@@ -206,8 +206,6 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags) ...@@ -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.
*/ */
......
...@@ -41,12 +41,10 @@ ...@@ -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); ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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);
} }
...@@ -138,8 +138,6 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags) ...@@ -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)
*/ */
......
...@@ -104,8 +104,7 @@ TidListCreate(TidScanState *tidstate) ...@@ -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) ...@@ -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) ...@@ -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
*/ */
......
...@@ -140,8 +140,7 @@ ValuesNext(ValuesScanState *node) ...@@ -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) ...@@ -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.
*/ */
......
...@@ -256,7 +256,7 @@ advance_windowaggregate(WindowAggState *winstate, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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: ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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);
} }
...@@ -174,8 +174,6 @@ ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags) ...@@ -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;
} }
......
...@@ -4685,7 +4685,7 @@ evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod, ...@@ -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);
......
...@@ -1596,7 +1596,7 @@ operator_predicate_proof(Expr *predicate, Node *clause, bool refute_it) ...@@ -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);
......
...@@ -179,7 +179,7 @@ domain_check_input(Datum value, bool isnull, DomainIOData *my_extra) ...@@ -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))
......
...@@ -603,7 +603,7 @@ xmlelement(XmlExprState *xmlExpr, ExprContext *econtext) ...@@ -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) ...@@ -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)
{ {
......
...@@ -70,8 +70,8 @@ ...@@ -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, ...@@ -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
......
...@@ -156,7 +156,8 @@ typedef struct ExprContext ...@@ -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 ...@@ -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 ...@@ -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; ...@@ -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 ...@@ -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 ...@@ -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;
/* ---------------- /* ----------------
......
...@@ -5606,8 +5606,7 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate, ...@@ -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, ...@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment