čt 1. 11. 2018 v 13:00 odesílatel Pavel Stehule <pavel.steh...@gmail.com> 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;