1
0
mirror of https://github.com/postgres/postgres.git synced 2025-12-10 14:22:35 +03:00

Support named and default arguments in CALL

We need to call expand_function_arguments() to expand named and default
arguments.

In PL/pgSQL, we also need to deal with named and default INOUT arguments
when receiving the output values into variables.

Author: Pavel Stehule <pavel.stehule@gmail.com>
This commit is contained in:
Peter Eisentraut
2018-04-13 17:06:28 -04:00
parent 7c44c46deb
commit a8677e3ff6
8 changed files with 261 additions and 31 deletions

View File

@@ -152,6 +152,93 @@ CALL test_proc7(100, -1, -1);
0 | 1
(1 row)
-- named parameters and defaults
CREATE PROCEDURE test_proc8a(INOUT a int, INOUT b int)
LANGUAGE plpgsql
AS $$
BEGIN
RAISE NOTICE 'a: %, b: %', a, b;
a := a * 10;
b := b + 10;
END;
$$;
CALL test_proc8a(10, 20);
NOTICE: a: 10, b: 20
a | b
-----+----
100 | 30
(1 row)
CALL test_proc8a(b => 20, a => 10);
NOTICE: a: 10, b: 20
a | b
-----+----
100 | 30
(1 row)
DO $$
DECLARE _a int; _b int;
BEGIN
_a := 10; _b := 30;
CALL test_proc8a(_a, _b);
RAISE NOTICE '_a: %, _b: %', _a, _b;
CALL test_proc8a(b => _b, a => _a);
RAISE NOTICE '_a: %, _b: %', _a, _b;
END
$$;
NOTICE: a: 10, b: 30
NOTICE: _a: 100, _b: 40
NOTICE: a: 100, b: 40
NOTICE: _a: 1000, _b: 50
CREATE PROCEDURE test_proc8b(INOUT a int, INOUT b int, INOUT c int)
LANGUAGE plpgsql
AS $$
BEGIN
RAISE NOTICE 'a: %, b: %, c: %', a, b, c;
a := a * 10;
b := b + 10;
c := c * -10;
END;
$$;
DO $$
DECLARE _a int; _b int; _c int;
BEGIN
_a := 10; _b := 30; _c := 50;
CALL test_proc8b(_a, _b, _c);
RAISE NOTICE '_a: %, _b: %, _c: %', _a, _b, _c;
CALL test_proc8b(_a, c => _c, b => _b);
RAISE NOTICE '_a: %, _b: %, _c: %', _a, _b, _c;
END
$$;
NOTICE: a: 10, b: 30, c: 50
NOTICE: _a: 100, _b: 40, _c: -500
NOTICE: a: 100, b: 40, c: -500
NOTICE: _a: 1000, _b: 50, _c: 5000
CREATE PROCEDURE test_proc8c(INOUT a int, INOUT b int, INOUT c int DEFAULT 11)
LANGUAGE plpgsql
AS $$
BEGIN
RAISE NOTICE 'a: %, b: %, c: %', a, b, c;
a := a * 10;
b := b + 10;
c := c * -10;
END;
$$;
DO $$
DECLARE _a int; _b int; _c int;
BEGIN
_a := 10; _b := 30; _c := 50;
CALL test_proc8c(_a, _b);
RAISE NOTICE '_a: %, _b: %, _c: %', _a, _b, _c;
_a := 10; _b := 30; _c := 50;
CALL test_proc8c(_a, b => _b);
RAISE NOTICE '_a: %, _b: %, _c: %', _a, _b, _c;
END
$$;
NOTICE: a: 10, b: 30, c: 11
NOTICE: _a: 100, _b: 40, _c: 50
NOTICE: a: 10, b: 30, c: 11
NOTICE: _a: 100, _b: 40, _c: 50
-- transition variable assignment
TRUNCATE test1;
CREATE FUNCTION triggerfunc1() RETURNS trigger

View File

@@ -2146,7 +2146,6 @@ exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
FuncExpr *funcexpr;
int i;
HeapTuple tuple;
int numargs PG_USED_FOR_ASSERTS_ONLY;
Oid *argtypes;
char **argnames;
char *argmodes;
@@ -2169,11 +2168,9 @@ exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcexpr->funcid));
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for function %u", funcexpr->funcid);
numargs = get_func_arg_info(tuple, &argtypes, &argnames, &argmodes);
get_func_arg_info(tuple, &argtypes, &argnames, &argmodes);
ReleaseSysCache(tuple);
Assert(numargs == list_length(funcexpr->args));
/*
* Construct row
*/
@@ -2192,16 +2189,36 @@ exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
if (argmodes && argmodes[i] == PROARGMODE_INOUT)
{
Param *param;
if (IsA(n, Param))
{
Param *param = castNode(Param, n);
if (!IsA(n, Param))
/* paramid is offset by 1 (see make_datum_param()) */
row->varnos[nfields++] = param->paramid - 1;
}
else if (IsA(n, NamedArgExpr))
{
NamedArgExpr *nexpr = castNode(NamedArgExpr, n);
Param *param;
if (!IsA(nexpr->arg, Param))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("argument %d is an output argument but is not writable", i + 1)));
param = castNode(Param, nexpr->arg);
/*
* Named arguments must be after positional arguments,
* so we can increase nfields.
*/
row->varnos[nexpr->argnumber] = param->paramid - 1;
nfields++;
}
else
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("argument %d is an output argument but is not writable", i + 1)));
param = castNode(Param, n);
/* paramid is offset by 1 (see make_datum_param()) */
row->varnos[nfields++] = param->paramid - 1;
}
i++;
}

View File

@@ -142,6 +142,80 @@ $$;
CALL test_proc7(100, -1, -1);
-- named parameters and defaults
CREATE PROCEDURE test_proc8a(INOUT a int, INOUT b int)
LANGUAGE plpgsql
AS $$
BEGIN
RAISE NOTICE 'a: %, b: %', a, b;
a := a * 10;
b := b + 10;
END;
$$;
CALL test_proc8a(10, 20);
CALL test_proc8a(b => 20, a => 10);
DO $$
DECLARE _a int; _b int;
BEGIN
_a := 10; _b := 30;
CALL test_proc8a(_a, _b);
RAISE NOTICE '_a: %, _b: %', _a, _b;
CALL test_proc8a(b => _b, a => _a);
RAISE NOTICE '_a: %, _b: %', _a, _b;
END
$$;
CREATE PROCEDURE test_proc8b(INOUT a int, INOUT b int, INOUT c int)
LANGUAGE plpgsql
AS $$
BEGIN
RAISE NOTICE 'a: %, b: %, c: %', a, b, c;
a := a * 10;
b := b + 10;
c := c * -10;
END;
$$;
DO $$
DECLARE _a int; _b int; _c int;
BEGIN
_a := 10; _b := 30; _c := 50;
CALL test_proc8b(_a, _b, _c);
RAISE NOTICE '_a: %, _b: %, _c: %', _a, _b, _c;
CALL test_proc8b(_a, c => _c, b => _b);
RAISE NOTICE '_a: %, _b: %, _c: %', _a, _b, _c;
END
$$;
CREATE PROCEDURE test_proc8c(INOUT a int, INOUT b int, INOUT c int DEFAULT 11)
LANGUAGE plpgsql
AS $$
BEGIN
RAISE NOTICE 'a: %, b: %, c: %', a, b, c;
a := a * 10;
b := b + 10;
c := c * -10;
END;
$$;
DO $$
DECLARE _a int; _b int; _c int;
BEGIN
_a := 10; _b := 30; _c := 50;
CALL test_proc8c(_a, _b);
RAISE NOTICE '_a: %, _b: %, _c: %', _a, _b, _c;
_a := 10; _b := 30; _c := 50;
CALL test_proc8c(_a, b => _b);
RAISE NOTICE '_a: %, _b: %, _c: %', _a, _b, _c;
END
$$;
-- transition variable assignment
TRUNCATE test1;