1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-14 18:42:34 +03:00

Support for OUT parameters in procedures

Unlike for functions, OUT parameters for procedures are part of the
signature.  Therefore, they have to be listed in pg_proc.proargtypes
as well as mentioned in ALTER PROCEDURE and DROP PROCEDURE.

Reviewed-by: Andrew Dunstan <andrew.dunstan@2ndquadrant.com>
Reviewed-by: Pavel Stehule <pavel.stehule@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/2b8490fe-51af-e671-c504-47359dc453c5@2ndquadrant.com
This commit is contained in:
Peter Eisentraut
2020-10-05 09:09:09 +02:00
parent e899742081
commit 2453ea1422
28 changed files with 416 additions and 93 deletions

View File

@ -194,8 +194,8 @@ interpret_function_parameter_list(ParseState *pstate,
Oid *requiredResultType)
{
int parameterCount = list_length(parameters);
Oid *inTypes;
int inCount = 0;
Oid *sigArgTypes;
int sigArgCount = 0;
Datum *allTypes;
Datum *paramModes;
Datum *paramNames;
@ -209,7 +209,7 @@ interpret_function_parameter_list(ParseState *pstate,
*variadicArgType = InvalidOid; /* default result */
*requiredResultType = InvalidOid; /* default result */
inTypes = (Oid *) palloc(parameterCount * sizeof(Oid));
sigArgTypes = (Oid *) palloc(parameterCount * sizeof(Oid));
allTypes = (Datum *) palloc(parameterCount * sizeof(Datum));
paramModes = (Datum *) palloc(parameterCount * sizeof(Datum));
paramNames = (Datum *) palloc0(parameterCount * sizeof(Datum));
@ -281,25 +281,21 @@ interpret_function_parameter_list(ParseState *pstate,
errmsg("functions cannot accept set arguments")));
}
if (objtype == OBJECT_PROCEDURE)
{
if (fp->mode == FUNC_PARAM_OUT)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("procedures cannot have OUT arguments"),
errhint("INOUT arguments are permitted.")));
}
/* handle input parameters */
if (fp->mode != FUNC_PARAM_OUT && fp->mode != FUNC_PARAM_TABLE)
isinput = true;
/* handle signature parameters */
if (fp->mode == FUNC_PARAM_IN || fp->mode == FUNC_PARAM_INOUT ||
(objtype == OBJECT_PROCEDURE && fp->mode == FUNC_PARAM_OUT) ||
fp->mode == FUNC_PARAM_VARIADIC)
{
/* other input parameters can't follow a VARIADIC parameter */
/* other signature parameters can't follow a VARIADIC parameter */
if (varCount > 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("VARIADIC parameter must be the last input parameter")));
inTypes[inCount++] = toid;
isinput = true;
errmsg("VARIADIC parameter must be the last signature parameter")));
sigArgTypes[sigArgCount++] = toid;
}
/* handle output parameters */
@ -429,7 +425,7 @@ interpret_function_parameter_list(ParseState *pstate,
}
/* Now construct the proper outputs as needed */
*parameterTypes = buildoidvector(inTypes, inCount);
*parameterTypes = buildoidvector(sigArgTypes, sigArgCount);
if (outCount > 0 || varCount > 0)
{
@ -2067,6 +2063,9 @@ ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver
int nargs;
int i;
AclResult aclresult;
Oid *argtypes;
char **argnames;
char *argmodes;
FmgrInfo flinfo;
CallContext *callcontext;
EState *estate;
@ -2127,6 +2126,8 @@ ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver
tp);
nargs = list_length(fexpr->args);
get_func_arg_info(tp, &argtypes, &argnames, &argmodes);
ReleaseSysCache(tp);
/* safety check; see ExecInitFunc() */
@ -2156,16 +2157,24 @@ ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver
i = 0;
foreach(lc, fexpr->args)
{
ExprState *exprstate;
Datum val;
bool isnull;
if (argmodes && argmodes[i] == PROARGMODE_OUT)
{
fcinfo->args[i].value = 0;
fcinfo->args[i].isnull = true;
}
else
{
ExprState *exprstate;
Datum val;
bool isnull;
exprstate = ExecPrepareExpr(lfirst(lc), estate);
exprstate = ExecPrepareExpr(lfirst(lc), estate);
val = ExecEvalExprSwitchContext(exprstate, econtext, &isnull);
val = ExecEvalExprSwitchContext(exprstate, econtext, &isnull);
fcinfo->args[i].value = val;
fcinfo->args[i].isnull = isnull;
fcinfo->args[i].value = val;
fcinfo->args[i].isnull = isnull;
}
i++;
}