čt 1. 11. 2018 v 13:00 odesílatel Pavel Stehule <[email protected]>
napsal:
> Hi
>
> The processing of named parameters inside CALL statement is not correct.
>
> It is my code :-/. I am sorry
>
> Attached patch fix it.
>
> This still doesn't fix INOUT variables with default value - so is not
> fully correct, but in this moment, it can show, where is a core of this
> issue.
>
This version disallow INOUT default variables from plpgsql
> Regards
>
> Pavel
>
>
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 45526383f2..21c8c398e0 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -2171,7 +2171,6 @@ exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
Node *node;
ListCell *lc;
FuncExpr *funcexpr;
- int i;
HeapTuple tuple;
Oid *argtypes;
char **argnames;
@@ -2210,45 +2209,62 @@ exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
row->varnos = palloc(sizeof(int) * FUNC_MAX_ARGS);
nfields = 0;
- i = 0;
- foreach(lc, funcexpr->args)
+
+ /*
+ * The argmodes can be in different order than funcexpr->args due
+ * named args. When we should to check INOUT parameters and prepare
+ * target variable, we should to reorder a arguments first.
+ */
+ if (argmodes)
{
- Node *n = lfirst(lc);
+ Node **args;
+ int i = 0;
+ int nargs = list_length(funcexpr->args);
+
+ args = palloc0(sizeof(Node *) * FUNC_MAX_ARGS);
- if (argmodes && argmodes[i] == PROARGMODE_INOUT)
+ foreach(lc, funcexpr->args)
{
- if (IsA(n, Param))
- {
- Param *param = castNode(Param, n);
+ Node *n = lfirst(lc);
- /* paramid is offset by 1 (see make_datum_param()) */
- row->varnos[nfields++] = param->paramid - 1;
- }
- else if (IsA(n, NamedArgExpr))
+ if (IsA(n, NamedArgExpr))
{
NamedArgExpr *nexpr = castNode(NamedArgExpr, n);
- Param *param;
- if (!IsA(nexpr->arg, Param))
+ args[nexpr->argnumber] = (Node *) nexpr->arg;
+ }
+ else
+ args[i++] = n;
+ }
+
+ for (i = 0; i < nargs; i++)
+ {
+ Node *n = args[i];
+
+ if (argmodes[i] == PROARGMODE_INOUT)
+ {
+ if (!n)
+ {
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("argument %d is an output argument but is not writable", i + 1)));
+ errmsg("argument %d is an output argument but is not passed", i + 1)));
+ }
+ else if (IsA(n, Param))
+ {
+ Param *param = castNode(Param, n);
- param = castNode(Param, nexpr->arg);
+ /* paramid is offset by 1 (see make_datum_param()) */
- /*
- * Named arguments must be after positional arguments,
- * so we can increase nfields.
- */
- row->varnos[nexpr->argnumber] = param->paramid - 1;
- nfields++;
+ row->varnos[nfields++] = param->paramid - 1;
+ }
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("argument %d is an output argument but is not writable", i + 1)));
}
- else
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("argument %d is an output argument but is not writable", i + 1)));
}
- i++;
+
+ pfree(args);
}
row->nfields = nfields;