č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;

Reply via email to