/* *Iffunctionisstrict,andthereareanyNULLarguments,skip *callingthefunctionandactlikeitreturnedNULL(oranempty *set,inthereturns-setcase).
*/ if (setexpr->func.fn_strict)
{ int i;
for (i = 0; i < fcinfo->nargs; i++)
{ if (fcinfo->args[i].isnull) goto no_function_result;
}
}
} else
{ /* Treat setexpr as a generic expression */
InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
}
/* Which protocol does function want to use? */ if (rsinfo.returnMode == SFRM_ValuePerCall)
{ /* *Checkforendofresultset.
*/ if (rsinfo.isDone == ExprEndResult) break;
/* *Storecurrentresultsetitem.
*/ if (returnsTuple)
{ if (!fcinfo->isnull)
{
HeapTupleHeader td = DatumGetHeapTupleHeader(result);
if (tupdesc == NULL)
{
MemoryContext oldcontext =
MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
/* *Thisisthefirstnon-NULLresultfromthe *function.Usethetypeinfoembeddedinthe *rowtypeDatumtolookuptheneededtupdesc.Make *acopyforthequery.
*/
tupdesc = lookup_rowtype_tupdesc_copy(HeapTupleHeaderGetTypeId(td),
HeapTupleHeaderGetTypMod(td));
rsinfo.setDesc = tupdesc;
MemoryContextSwitchTo(oldcontext);
} else
{ /* *Verifyalllaterreturnedrowshavesamesubtype; *necessaryincasethetypeisRECORD.
*/ if (HeapTupleHeaderGetTypeId(td) != tupdesc->tdtypeid ||
HeapTupleHeaderGetTypMod(td) != tupdesc->tdtypmod)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("rows returned by function are not all of the same row type")));
}
nullflags = (bool *) palloc(natts * sizeof(bool));
memset(nullflags, true, natts * sizeof(bool));
tuplestore_putvalues(tupstore, expectedDesc, NULL, nullflags);
}
} else
{ /* Scalar-type case: just store the function result */
tuplestore_putvalues(tupstore, tupdesc, &result, &fcinfo->isnull);
}
/* *Arewedone?
*/ if (rsinfo.isDone != ExprMultipleResult) break;
/* *Checkthatset-returningfunctionswereproperlydeclared. *(Note:forhistoricalreasons,wedon'tcomplainifanon-SRF *returnsExprEndResult;that'streatedasreturningNULL.)
*/ if (!returnsSet)
ereport(ERROR,
(errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
errmsg("table-function protocol for value-per-call mode was not followed")));
} elseif (rsinfo.returnMode == SFRM_Materialize)
{ /* check we're on the same page as the function author */ if (!first_time || rsinfo.isDone != ExprSingleResult || !returnsSet)
ereport(ERROR,
(errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
errmsg("table-function protocol for materialize mode was not followed"))); /* Done evaluating the set result */ break;
} else
ereport(ERROR,
(errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
errmsg("unrecognized table-function returnMode: %d",
(int) rsinfo.returnMode)));
if (foundTup)
{
*isDone = ExprMultipleResult; if (fcache->funcReturnsTuple)
{ /* We must return the whole tuple as a Datum. */
*isNull = false; return ExecFetchSlotHeapTupleDatum(fcache->funcResultSlot);
} else
{ /* Extract the first column and return it as a scalar. */ return slot_getattr(fcache->funcResultSlot, 1, isNull);
}
} /* Exhausted the tuplestore, so clean up */
tuplestore_end(fcache->funcResultStore);
fcache->funcResultStore = NULL;
*isDone = ExprEndResult;
*isNull = true; return (Datum) 0;
}
ExecEvalFuncArgs(fcinfo, arguments, econtext);
MemoryContextSwitchTo(oldContext);
} else
{ /* Reset flag (we may set it again below) */
fcache->setArgsValid = false;
}
pgstat_end_function_usage(&fcusage,
rsinfo.isDone != ExprMultipleResult);
} else
{ /* for a strict SRF, result for NULL is an empty set */
result = (Datum) 0;
*isNull = true;
*isDone = ExprEndResult;
}
/* Which protocol does function want to use? */ if (rsinfo.returnMode == SFRM_ValuePerCall)
{ if (*isDone != ExprEndResult)
{ /* *Savethecurrentargumentvaluestore-useonthenextcall.
*/ if (*isDone == ExprMultipleResult)
{
fcache->setArgsValid = true; /* Register cleanup callback if we didn't already */ if (!fcache->shutdown_reg)
{
RegisterExprContextCallback(econtext,
ShutdownSetExpr,
PointerGetDatum(fcache));
fcache->shutdown_reg = true;
}
}
}
} elseif (rsinfo.returnMode == SFRM_Materialize)
{ /* check we're on the same page as the function author */ if (rsinfo.isDone != ExprSingleResult)
ereport(ERROR,
(errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
errmsg("table-function protocol for materialize mode was not followed"))); if (rsinfo.setResult != NULL)
{ /* prepare to return values from the tuplestore */
ExecPrepareTuplestoreResult(fcache, econtext,
rsinfo.setResult,
rsinfo.setDesc); /* loop back to top to start returning from tuplestore */ goto restart;
} /* if setResult was left null, treat it as empty set */
*isDone = ExprEndResult;
*isNull = true;
result = (Datum) 0;
} else
ereport(ERROR,
(errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
errmsg("unrecognized table-function returnMode: %d",
(int) rsinfo.returnMode)));
/* Check permission to call function */
aclresult = object_aclcheck(ProcedureRelationId, foid, GetUserId(), ACL_EXECUTE); if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid));
InvokeFunctionExecuteHook(foid);
/* *Safetycheckonnargs.Undernormalcircumstancesthisshouldnever *fail,asparsershouldchecksooner.Butpossiblyitmightfailif *serverhasbeencompiledwithFUNC_MAX_ARGSsmallerthansomefunctions *declaredinpg_proc?
*/ if (list_length(sexpr->args) > FUNC_MAX_ARGS)
ereport(ERROR,
(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
errmsg_plural("cannot pass more than %d argument to a function", "cannot pass more than %d arguments to a function",
FUNC_MAX_ARGS,
FUNC_MAX_ARGS)));
/* Set up the primary fmgr lookup information */
fmgr_info_cxt(foid, &(sexpr->func), sexprCxt);
fmgr_info_set_expr((Node *) sexpr->expr, &(sexpr->func));
/* Initialize the function call parameter struct as well */
sexpr->fcinfo =
(FunctionCallInfo) palloc(SizeForFunctionCallInfo(numargs));
InitFunctionCallInfoData(*sexpr->fcinfo, &(sexpr->func),
numargs,
input_collation, NULL, NULL);
/* If function returns set, check if that's allowed by caller */ if (sexpr->func.fn_retset && !allowSRF)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("set-valued function called in context that cannot accept a set"),
parent ? executor_errposition(parent->state,
exprLocation((Node *) node)) : 0));
/* Otherwise, caller should have marked the sexpr correctly */
Assert(sexpr->func.fn_retset == sexpr->funcReturnsSet);
/* If function returns set, prepare expected tuple descriptor */ if (sexpr->func.fn_retset && needDescForSRF)
{
TypeFuncClass functypclass;
Oid funcrettype;
TupleDesc tupdesc;
MemoryContext oldcontext;
/* Must save tupdesc in sexpr's context */
oldcontext = MemoryContextSwitchTo(sexprCxt);
if (functypclass == TYPEFUNC_COMPOSITE ||
functypclass == TYPEFUNC_COMPOSITE_DOMAIN)
{ /* Composite data type, e.g. a table's row type */
Assert(tupdesc); /* Must copy it out of typcache for safety */
sexpr->funcResultDesc = CreateTupleDescCopy(tupdesc);
sexpr->funcReturnsTuple = true;
} elseif (functypclass == TYPEFUNC_SCALAR)
{ /* Base data type, i.e. scalar */
tupdesc = CreateTemplateTupleDesc(1);
TupleDescInitEntry(tupdesc,
(AttrNumber) 1,
NULL,
funcrettype,
-1, 0);
sexpr->funcResultDesc = tupdesc;
sexpr->funcReturnsTuple = false;
} elseif (functypclass == TYPEFUNC_RECORD)
{ /* This will work if function doesn't need an expectedDesc */
sexpr->funcResultDesc = NULL;
sexpr->funcReturnsTuple = true;
} else
{ /* Else, we will fail if function needs an expectedDesc */
sexpr->funcResultDesc = NULL;
}
if (dst_tupdesc->natts != src_tupdesc->natts)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("function return row and query-specified return row do not match"),
errdetail_plural("Returned row contains %d attribute, but query expects %d.", "Returned row contains %d attributes, but query expects %d.",
src_tupdesc->natts,
src_tupdesc->natts, dst_tupdesc->natts)));
for (i = 0; i < dst_tupdesc->natts; i++)
{
Form_pg_attribute dattr = TupleDescAttr(dst_tupdesc, i);
Form_pg_attribute sattr = TupleDescAttr(src_tupdesc, i);
if (IsBinaryCoercible(sattr->atttypid, dattr->atttypid)) continue; /* no worries */ if (!dattr->attisdropped)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("function return row and query-specified return row do not match"),
errdetail("Returned type %s at ordinal position %d, but query expects %s.",
format_type_be(sattr->atttypid),
i + 1,
format_type_be(dattr->atttypid))));
if (dattr->attlen != sattr->attlen ||
dattr->attalign != sattr->attalign)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("function return row and query-specified return row do not match"),
errdetail("Physical storage mismatch on dropped attribute at ordinal position %d.",
i + 1)));
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.32 Sekunden
(vorverarbeitet am 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.