INOUT parameters in procedures

Started by Peter Eisentrautabout 8 years ago25 messageshackers
Jump to latest
#1Peter Eisentraut
peter_e@gmx.net

This patch set adds support for INOUT parameters to procedures.
Currently, INOUT and OUT parameters are not supported.

A top-level CALL returns the output parameters as a result row. In
PL/pgSQL, I have added special support to pass the output back into the
variables, as one would expect.

These patches apply on top of the "prokind" patch set v2. (Tom has
submitted an updated version of that, which overlaps with some of the
changes I've made here. I will work on consolidating that soon.)

So ... no OUT parameters, though. I'm struggling to find a way to make
this compatible with everything else. For functions, the OUT parameters
don't appear in the signature. But that is not how this is specified in
the SQL standard for procedures (I think). In PL/pgSQL, you'd expect that

CREATE PROCEDURE foo(a int, OUT b int) ...

could be called like

CALL foo(x, y);

but that would require a different way of parsing function invocation.

At the top-level, it's even more dubious. In DB2, apparently you write

CALL foo(123, ?);

with a literal ? for the OUT parameters.

In Oracle, I've seen CALL ... INTO syntax.

Anyway, I'm leaving this out for now. It can be worked around by using
INOUT parameters. Future improvements would be mainly syntax/parsing
adjustments; the guts that I'm implementing here would remain valid.

--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

Attachments:

v1-0001-fixup-Add-prokind-column-replacing-proisagg-and-p.patchtext/plain; charset=UTF-8; name=v1-0001-fixup-Add-prokind-column-replacing-proisagg-and-p.patch; x-mac-creator=0; x-mac-type=0Download+11-12
v1-0002-Support-INOUT-parameters-in-procedures.patchtext/plain; charset=UTF-8; name=v1-0002-Support-INOUT-parameters-in-procedures.patch; x-mac-creator=0; x-mac-type=0Download+358-16
#2Pavel Stehule
pavel.stehule@gmail.com
In reply to: Peter Eisentraut (#1)
Re: INOUT parameters in procedures

Hi

2018-02-28 23:28 GMT+01:00 Peter Eisentraut <
peter.eisentraut@2ndquadrant.com>:

This patch set adds support for INOUT parameters to procedures.
Currently, INOUT and OUT parameters are not supported.

A top-level CALL returns the output parameters as a result row. In
PL/pgSQL, I have added special support to pass the output back into the
variables, as one would expect.

These patches apply on top of the "prokind" patch set v2. (Tom has
submitted an updated version of that, which overlaps with some of the
changes I've made here. I will work on consolidating that soon.)

So ... no OUT parameters, though. I'm struggling to find a way to make
this compatible with everything else. For functions, the OUT parameters
don't appear in the signature. But that is not how this is specified in
the SQL standard for procedures (I think). In PL/pgSQL, you'd expect that

CREATE PROCEDURE foo(a int, OUT b int) ...

could be called like

CALL foo(x, y);

but that would require a different way of parsing function invocation.

At the top-level, it's even more dubious. In DB2, apparently you write

CALL foo(123, ?);

with a literal ? for the OUT parameters.

In Oracle, I've seen CALL ... INTO syntax.

Anyway, I'm leaving this out for now. It can be worked around by using
INOUT parameters. Future improvements would be mainly syntax/parsing
adjustments; the guts that I'm implementing here would remain valid.

I am looking on attached code, and it looks pretty well. Can be really nice
if this code will be part of release 11, because it is very interesting,
important feature feature.

Regards

p.s. can be nice, if we allow same trick with calling of OUT variables
functions in plpgsql

fx(in a, out x, out y) return int -- but requires some special mark

do $$
declare x int, y int, z int;
begin
z := fx(10, x, y);
raise notice '% ....

Then migration from Oracle can be really easy and friendly

Pavel

Show quoted text

--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#3Douglas Doole
dougdoole@gmail.com
In reply to: Pavel Stehule (#2)
Re: INOUT parameters in procedures

At the top-level, it's even more dubious. In DB2, apparently you write

CALL foo(123, ?);

with a literal ? for the OUT parameters.

That's not actually as scary as it seems.

DB2 has two cases where you can use a ? like that:

1) In CLP (DB2's equivalent to psql)

DB2 draws a distinct line between procedures and functions, and you have to
invoke procedures with CALL FOO(...). Since CLP doesn't support variables
(and SQL variables didn't exist in DB2 when the CALL statement was
introduced), they needed a way to say "there's an output parameter here" so
they settled on using ? as the placeholder. (? was chosen because it ties
nicely into the next point.)

2) In dynamic SQL

DB2 has traditionally used ? as a parameter marker (placeholder for a
variable) in dynamic SQL. So the usage would look something like:

DECLARE res INTEGER;
DECLARE text VARCHAR(50);

SET text = 'CALL foo(123, ?)';
PREPARE stmt FROM text;
EXECUTE stmt INTO res; -- This invokes the statement and maps the ? into
the variable "res"

If you didn't need/want to use dynamic SQL, then you could have simply
written:

CALL foo(123, res);

- Doug Doole
Salesforce

#4Peter Eisentraut
peter_e@gmx.net
In reply to: Pavel Stehule (#2)
Re: INOUT parameters in procedures

On 3/5/18 11:00, Pavel Stehule wrote:

I am looking on attached code, and it looks pretty well. Can be really
nice if this code will be part of release 11, because it is very
interesting, important feature feature.

Here is an updated patch, rebased on top of several recent changes, also
added more documentation and tests in other PLs.

p.s. can be nice, if we allow same trick with calling of OUT variables
functions in plpgsql

fx(in a, out x, out y) return int -- but requires some special mark

do $$
declare x int, y int, z int;
begin
  z := fx(10, x, y);
  raise notice '% ....

Then migration from Oracle can be really easy and friendly

This would require some changes to how routines are looked up, because
we currently ignore OUT parameters there. That code does not exist yet.
But it's certainly a plausible extension for the future.

--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

Attachments:

v2-0001-Support-INOUT-parameters-in-procedures.patchtext/plain; charset=UTF-8; name=v2-0001-Support-INOUT-parameters-in-procedures.patch; x-mac-creator=0; x-mac-type=0Download+588-48
#5Pavel Stehule
pavel.stehule@gmail.com
In reply to: Peter Eisentraut (#4)
Re: INOUT parameters in procedures

2018-03-05 19:38 GMT+01:00 Peter Eisentraut <
peter.eisentraut@2ndquadrant.com>:

On 3/5/18 11:00, Pavel Stehule wrote:

I am looking on attached code, and it looks pretty well. Can be really
nice if this code will be part of release 11, because it is very
interesting, important feature feature.

Here is an updated patch, rebased on top of several recent changes, also
added more documentation and tests in other PLs.

p.s. can be nice, if we allow same trick with calling of OUT variables
functions in plpgsql

fx(in a, out x, out y) return int -- but requires some special mark

do $$
declare x int, y int, z int;
begin
z := fx(10, x, y);
raise notice '% ....

Then migration from Oracle can be really easy and friendly

This would require some changes to how routines are looked up, because
we currently ignore OUT parameters there. That code does not exist yet.
But it's certainly a plausible extension for the future.

sure - this is topic for 12 release. But it can fix more than one issue
when PL/SQL code is migrated.

note: in this case we should to return one parameter more. Out parameters +
RETURN expression result.

Show quoted text

--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#6Pavel Stehule
pavel.stehule@gmail.com
In reply to: Pavel Stehule (#5)
Re: INOUT parameters in procedures

2018-03-05 19:41 GMT+01:00 Pavel Stehule <pavel.stehule@gmail.com>:

2018-03-05 19:38 GMT+01:00 Peter Eisentraut <peter.eisentraut@2ndquadrant.
com>:

On 3/5/18 11:00, Pavel Stehule wrote:

I am looking on attached code, and it looks pretty well. Can be really
nice if this code will be part of release 11, because it is very
interesting, important feature feature.

Here is an updated patch, rebased on top of several recent changes, also
added more documentation and tests in other PLs.

p.s. can be nice, if we allow same trick with calling of OUT variables
functions in plpgsql

fx(in a, out x, out y) return int -- but requires some special mark

do $$
declare x int, y int, z int;
begin
z := fx(10, x, y);
raise notice '% ....

Then migration from Oracle can be really easy and friendly

This would require some changes to how routines are looked up, because
we currently ignore OUT parameters there. That code does not exist yet.
But it's certainly a plausible extension for the future.

sure - this is topic for 12 release. But it can fix more than one issue
when PL/SQL code is migrated.

note: in this case we should to return one parameter more. Out parameters
+ RETURN expression result.

this problem is simple/difficult. the type of function can be detected from
call context - when function is called with assigned out variable(s) (all
OUT variables should be assigned), then the behave should be classical -
and RETURN expression for non void functions should be required. Else, the
OUT variables should not be assigned, and function will be called in
postgresql style - the function returns tuple defined by OUT parameters and
RETURN expression is prohibited. Some hint can be returning type - if it is
not defined, then result is defined just by OUT variables, when it is
defined (and it is not RECORD), then RETURN expression is required. When
RETURNS type is RECORD, then we know nothing and decision should be based
on calling context.

Show quoted text

--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#7Pavel Stehule
pavel.stehule@gmail.com
In reply to: Peter Eisentraut (#4)
Re: INOUT parameters in procedures

2018-03-05 19:38 GMT+01:00 Peter Eisentraut <
peter.eisentraut@2ndquadrant.com>:

On 3/5/18 11:00, Pavel Stehule wrote:

I am looking on attached code, and it looks pretty well. Can be really
nice if this code will be part of release 11, because it is very
interesting, important feature feature.

Here is an updated patch, rebased on top of several recent changes, also
added more documentation and tests in other PLs.

why just OUT variables are disallowed?

The oracle initializes these values to NULL - we can do same?

Minimally this message is not too friendly, there should be hint - "only
INOUT is suported" - but better support OUT too - from TOP OUT variables
should not be passed. from PL should be required.

I wrote recursive procedure. The call finished by exception. Why?

create or replace procedure p(x int,inout a int, inout b numeric)
as $$
begin
raise notice 'xxx % %', a, b;
if (x > 1) then
a := x / 10;
b := x / 2;
call p(b::int, a, b);
end if;
end;
$$ language plpgsql;
CREATE PROCEDURE
postgres=# call p(100, -1, -1);
NOTICE: xxx -1 -1
NOTICE: xxx 10 50
NOTICE: xxx 5 25
NOTICE: xxx 2 12
NOTICE: xxx 1 6
NOTICE: xxx 0 3
NOTICE: xxx 0 1
ERROR: unsupported target
CONTEXT: PL/pgSQL function p(integer,integer,numeric) line 4 at CALL
SQL statement "CALL p(b::int, a, b)"
PL/pgSQL function p(integer,integer,numeric) line 4 at CALL
SQL statement "CALL p(b::int, a, b)"
PL/pgSQL function p(integer,integer,numeric) line 4 at CALL
SQL statement "CALL p(b::int, a, b)"
PL/pgSQL function p(integer,integer,numeric) line 4 at CALL
SQL statement "CALL p(b::int, a, b)"
PL/pgSQL function p(integer,integer,numeric) line 4 at CALL

Because these variables are INOUT then it should work.

This issue can be detected in compile time, maybe?

postgres=# create or replace procedure p(x int,inout a int, inout b numeric)
as $$
begin raise notice 'xxx % %', a, b;if (x > 1) then
a := x / 10;
b := x / 2; call p(b::int, a, 10); <--- can be detected in compile time?
end if;
end;
$$ language plpgsql;

Is terrible, how this patch is short.

Regards

Pavel

Show quoted text

--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#8Peter Eisentraut
peter_e@gmx.net
In reply to: Pavel Stehule (#7)
Re: INOUT parameters in procedures

On 3/6/18 04:22, Pavel Stehule wrote:

why just OUT variables are disallowed?

The oracle initializes these values to NULL - we can do same?

The problem is function call resolution. If we see a call like

CALL foo(a, b, c);

the this could be foo() with zero input and three output parameters, or
with one input parameter and two output parameters, etc. We have no
code to deal with that right now.

Minimally this message is not too friendly, there should be hint - "only
INOUT is suported" - but better support OUT too - from TOP OUT variables
should not be passed. from PL should be required.

Added a hint.

I wrote recursive procedure. The call finished by exception. Why?

Fixed. (memory context issue)

I added your example as a test case.

This issue can be detected in compile time, maybe?

postgres=# create or replace procedure p(x int,inout a int, inout b numeric)
as $$
begin raise notice 'xxx % %', a, b;if (x > 1) then
  a := x / 10;
  b := x / 2; call p(b::int, a, 10); <--- can be detected in compile time?
end if;
end;
$$ language plpgsql;

Function resolution doesn't happen at compile time. That would require
significant work in PL/pgSQL (possible perhaps, but major work). Right
now, we do parse analysis at first execution.

--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

Attachments:

v3-0001-Support-INOUT-parameters-in-procedures.patchtext/plain; charset=UTF-8; name=v3-0001-Support-INOUT-parameters-in-procedures.patch; x-mac-creator=0; x-mac-type=0Download+632-50
#9Pavel Stehule
pavel.stehule@gmail.com
In reply to: Peter Eisentraut (#8)
Re: INOUT parameters in procedures

Hi

2018-03-08 1:53 GMT+01:00 Peter Eisentraut <peter.eisentraut@2ndquadrant.com

:

On 3/6/18 04:22, Pavel Stehule wrote:

why just OUT variables are disallowed?

The oracle initializes these values to NULL - we can do same?

The problem is function call resolution. If we see a call like

CALL foo(a, b, c);

the this could be foo() with zero input and three output parameters, or
with one input parameter and two output parameters, etc. We have no
code to deal with that right now.

It looks like some error in this concept. The rules for enabling
overwriting procedures should modified, so this collision should not be
done.

When I using procedure from PL/pgSQL, then it is clear, so I place on *OUT
position variables. But when I call procedure from top, then I'll pass fake
parameters to get some result.

CREATE OR REPLACE PROCEDURE proc(IN a, OUT x, OUT y)
AS $$
BEGIN
x := a * 10;
y := a + 10;
END;
$$ LANGUAGE plpgsql;

CALL proc(10) -- has sense

but because just OUT variables are not possible, then the definition must
be changed to CREATE OR REPLACE PROCEDURE proc(IN a, INOUT x, INOUT y)

and CALL proc(10, NULL, NULL) -- looks little bit scarry

I understand so this is not easy solution (and it can be topic for other
releases), but I am thinking so it is solvable - but needs deeper change in
part, where is a routine is selected on signature. Now, this algorithm
doesn't calculate with OUT params.

This enhancing can be interesting for some purposes (and again it can helps
with migration from Oracle - although these techniques are usually used
inside system libraries):

a) taking more info from proc when it is required

PROCEDURE foo(a int);
PROCEDURE foo(a int, OUT detail text)

b) possible to directly specify expected result type

PROCEDURE from_json(a json, OUT int);
PROCEDURE from_json(a json, OUT date);
PROCEDURE from_json(a json, OUT text);

It is clear, so in environments when variables are not available, these
procedures cannot be called doe possible ambiguity.

This point can be closed now, I accept technical limits.

Minimally this message is not too friendly, there should be hint - "only
INOUT is suported" - but better support OUT too - from TOP OUT variables
should not be passed. from PL should be required.

Added a hint.

ok

I wrote recursive procedure. The call finished by exception. Why?

Fixed. (memory context issue)

tested, it is ok now

I added your example as a test case.

This issue can be detected in compile time, maybe?

postgres=# create or replace procedure p(x int,inout a int, inout b

numeric)

as $$
begin raise notice 'xxx % %', a, b;if (x > 1) then
a := x / 10;
b := x / 2; call p(b::int, a, 10); <--- can be detected in compile

time?

end if;
end;
$$ language plpgsql;

Function resolution doesn't happen at compile time. That would require
significant work in PL/pgSQL (possible perhaps, but major work). Right
now, we do parse analysis at first execution.

ok, understand

looks well

all test passed,
code is well commented,
there are tests

               if (argmodes && (argmodes[i] == PROARGMODE_INOUT ||
argmodes[i] == PROARGMODE_OUT))
+               {
+                   Param      *param;

Because PROARGMODE_OUT are disallowed, then this check is little bit messy.
Please, add some comment.

Regards

Pavel

Show quoted text

--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#10Peter Eisentraut
peter_e@gmx.net
In reply to: Pavel Stehule (#9)
Re: INOUT parameters in procedures

On 3/8/18 02:25, Pavel Stehule wrote:

It looks like some error in this concept. The rules for enabling
overwriting procedures should modified, so this collision should not be
done.

When I using procedure from PL/pgSQL, then it is clear, so I place on
*OUT position variables. But when I call procedure from top, then I'll
pass fake parameters to get some result.

What we'll probably want to do here is to make the OUT parameters part
of the identity signature of procedures, unlike in functions. This
should be a straightforward change, but it will require some legwork in
many parts of the code.

               if (argmodes && (argmodes[i] == PROARGMODE_INOUT ||
argmodes[i] == PROARGMODE_OUT))
+               {
+                   Param      *param;

Because PROARGMODE_OUT are disallowed, then this check is little bit
messy. Please, add some comment.

Fixed.

I discovered another issue, in LANGUAGE SQL procedures. Currently, if
you make a CALL with an INOUT parameter in an SQL procedure, the output
is thrown away (unless it's the last command). I would like to keep
open the option of assigning the results by name, like we do in
PL/pgSQL. So in this patch I have made a change to prohibit calling
procedures with INOUT parameters in LANGUAGE SQL routines (see
check_sql_fn_statements()). What do you think?

--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

Attachments:

v4-0001-Support-INOUT-parameters-in-procedures.patchtext/plain; charset=UTF-8; name=v4-0001-Support-INOUT-parameters-in-procedures.patch; x-mac-creator=0; x-mac-type=0Download+752-50
#11Pavel Stehule
pavel.stehule@gmail.com
In reply to: Peter Eisentraut (#10)
Re: INOUT parameters in procedures

2018-03-13 14:14 GMT+01:00 Peter Eisentraut <
peter.eisentraut@2ndquadrant.com>:

On 3/8/18 02:25, Pavel Stehule wrote:

It looks like some error in this concept. The rules for enabling
overwriting procedures should modified, so this collision should not be
done.

When I using procedure from PL/pgSQL, then it is clear, so I place on
*OUT position variables. But when I call procedure from top, then I'll
pass fake parameters to get some result.

What we'll probably want to do here is to make the OUT parameters part
of the identity signature of procedures, unlike in functions. This
should be a straightforward change, but it will require some legwork in
many parts of the code.

yes

if (argmodes && (argmodes[i] == PROARGMODE_INOUT ||
argmodes[i] == PROARGMODE_OUT))
+               {
+                   Param      *param;

Because PROARGMODE_OUT are disallowed, then this check is little bit
messy. Please, add some comment.

Fixed.

I discovered another issue, in LANGUAGE SQL procedures. Currently, if
you make a CALL with an INOUT parameter in an SQL procedure, the output
is thrown away (unless it's the last command). I would like to keep
open the option of assigning the results by name, like we do in
PL/pgSQL. So in this patch I have made a change to prohibit calling
procedures with INOUT parameters in LANGUAGE SQL routines (see
check_sql_fn_statements()). What do you think?

The disabling it, it is probably the best what is possible now. The
variables in SQL are more named parameters than variables. Is not necessary
to complicate it.

Regards

Pavel

Show quoted text

--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#12Peter Eisentraut
peter_e@gmx.net
In reply to: Pavel Stehule (#11)
Re: INOUT parameters in procedures

committed

--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#13Jeff Janes
jeff.janes@gmail.com
In reply to: Peter Eisentraut (#12)
Re: INOUT parameters in procedures

On Wed, Mar 14, 2018 at 10:46 AM, Peter Eisentraut <
peter.eisentraut@2ndquadrant.com> wrote:

committed

I'm getting compiler warnings:

pl_exec.c: In function 'exec_stmt_call':
pl_exec.c:2089:8: warning: variable 'numargs' set but not used
[-Wunused-but-set-variable]
int numargs;
^

select version();
PostgreSQL 11devel-6b960aa on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu
5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609, 64-bit

Cheers,

Jeff

#14Tom Lane
tgl@sss.pgh.pa.us
In reply to: Jeff Janes (#13)
Re: INOUT parameters in procedures

Jeff Janes <jeff.janes@gmail.com> writes:

I'm getting compiler warnings:
pl_exec.c: In function 'exec_stmt_call':
pl_exec.c:2089:8: warning: variable 'numargs' set but not used

Not fixed by 8df5a1c868cc28f89ac6221cff8e2b5c952d0eb6?

regards, tom lane

#15Jeff Janes
jeff.janes@gmail.com
In reply to: Tom Lane (#14)
Re: INOUT parameters in procedures

On Thu, Mar 15, 2018 at 6:58 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Jeff Janes <jeff.janes@gmail.com> writes:

I'm getting compiler warnings:
pl_exec.c: In function 'exec_stmt_call':
pl_exec.c:2089:8: warning: variable 'numargs' set but not used

Not fixed by 8df5a1c868cc28f89ac6221cff8e2b5c952d0eb6?

I think you meant to type "now fixed by". (unless your compiler is pickier
than mine)

Cheers

Jeff

#16Tom Lane
tgl@sss.pgh.pa.us
In reply to: Jeff Janes (#15)
Re: INOUT parameters in procedures

Jeff Janes <jeff.janes@gmail.com> writes:

On Thu, Mar 15, 2018 at 6:58 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Not fixed by 8df5a1c868cc28f89ac6221cff8e2b5c952d0eb6?

I think you meant to type "now fixed by". (unless your compiler is pickier
than mine)

Actually what I meant was "doesn't that commit fix it for you?"

regards, tom lane

#17Rushabh Lathia
rushabh.lathia@gmail.com
In reply to: Peter Eisentraut (#12)
Re: INOUT parameters in procedures

Thanks Peter for working on this. Sorry for the delay in raising this
questions.

1)

@@ -302,7 +304,9 @@ interpret_function_parameter_list(ParseState *pstate,
        /* handle output parameters */
        if (fp->mode != FUNC_PARAM_IN && fp->mode != FUNC_PARAM_VARIADIC)
        {
-           if (outCount == 0)  /* save first output param's type */
+           if (objtype == OBJECT_PROCEDURE)
+               *requiredResultType = RECORDOID;
+           else if (outCount == 0) /* save first output param's type */
                *requiredResultType = toid;
            outCount++;

For the FUNCTION when we have single OUT/INOUT parameter
the return type for that function will be set to the type of OUT parameter.
But in case of PROCEDURE, it's always RECORDOID, why this inconsistency?

postgres@39755=#select proname, prorettype from pg_proc where proname =
'foo';
proname | prorettype
---------+------------
foo | 23
(1 row)

postgres@39755=#CREATE PROCEDURE foo_pro(INOUT a int)
LANGUAGE plpgsql
AS $$
begin
SELECT 1 into a;
end;$$;
CREATE PROCEDURE
postgres@39755=#select proname, prorettype from pg_proc where proname =
'foo_pro';
proname | prorettype
---------+------------
foo_pro | 2249
(1 row)

2) Inconsistency in procedure behavior - compared to function.

drop procedure ptest4a;
drop procedure ptest4b;
CREATE PROCEDURE ptest4a(INOUT a int, INOUT b int)
LANGUAGE plpgsql
AS $$
begin
SELECT 1, 2 into a, b;
end;$$;

CREATE PROCEDURE ptest4b(INOUT b int, INOUT a int)
LANGUAGE SQL
AS $$
CALL ptest4a(a, b);
$$;
ERROR: calling procedures with output arguments is not supported in SQL
functions
CONTEXT: SQL function "ptest4b"

Above test throws an error saying calling procedures with output
arguments are not supported in SQL functions. Whereas similar test
do work with SQL functions:

CREATE FUNCTION ftest4a(INOUT a int, INOUT b int) returns record
LANGUAGE plpgsql
AS $$
begin
SELECT 1, 2 into a, b;
end;$$;

CREATE FUNCTION ftest4b(INOUT b int, INOUT a int) returns record
LANGUAGE SQL
AS $$
SELECT ftest4a(a, b);
$$;

postgres@39755=#SELECT ftest4b(null, null);
ftest4b
---------
(1,2)
(1 row)

3)

CREATE PROCEDURE ptest4b(INOUT b int, INOUT a int)
LANGUAGE SQL
AS $$
CALL ptest4a(a, b);
$$;
ERROR: calling procedures with output arguments is not supported in SQL
functions
CONTEXT: SQL function "ptest4b"

Here error message says that calling procedures with output arguments is not
supported in SQL functions. Whereas here it's getting called from the SQL
procedure. So error message needs to be changed.

Thanks,
Rushabh Lathia
www.EnterpriseDB.com

#18Peter Eisentraut
peter_e@gmx.net
In reply to: Rushabh Lathia (#17)
Re: INOUT parameters in procedures

On 3/19/18 03:25, Rushabh Lathia wrote:

For the FUNCTION when we have single OUT/INOUT parameter 
the return type for that function will be set to the type of OUT parameter.
But in case of PROCEDURE, it's always RECORDOID, why this inconsistency?

For procedures, this is just an implementation detail. The CALL command
returns a row in any case, so if we set the return type to a scalar
type, we'd have to add special code to reassemble a row anyway. For
functions, the inconsistency is (arguably) worth it, because it affects
how functions can be written and called, but for procedures, there would
be no point.

Above test throws an error saying calling procedures with output
arguments are not supported in SQL functions.  Whereas similar test
do work with SQL functions:

This was discussed earlier in the thread.

The behavior of output parameters in functions was, AFAICT, invented by
us. But for procedures, the SQL standard specifies it, so there might
be some differences.

ERROR:  calling procedures with output arguments is not supported in SQL
functions
CONTEXT:  SQL function "ptest4b"

Here error message says that calling procedures with output arguments is not
supported in SQL functions.  Whereas here it's getting called from the SQL
procedure.  So error message needs to be changed. 

Well, I don't think we are going to change every single error message
from "function" to a separate function and procedure variant.

--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#19Rushabh Lathia
rushabh.lathia@gmail.com
In reply to: Peter Eisentraut (#18)
Re: INOUT parameters in procedures

On Tue, Mar 20, 2018 at 6:38 AM, Peter Eisentraut <
peter.eisentraut@2ndquadrant.com> wrote:

On 3/19/18 03:25, Rushabh Lathia wrote:

For the FUNCTION when we have single OUT/INOUT parameter
the return type for that function will be set to the type of OUT

parameter.

But in case of PROCEDURE, it's always RECORDOID, why this inconsistency?

For procedures, this is just an implementation detail. The CALL command
returns a row in any case, so if we set the return type to a scalar
type, we'd have to add special code to reassemble a row anyway. For
functions, the inconsistency is (arguably) worth it, because it affects
how functions can be written and called, but for procedures, there would
be no point.

This feel like inconsistency with the existing system object FUNCTION.
It would be nice to be consistent with the FUNCTION - which set the
prorettype as the type of single IN/OUT in case of single argument.

If CALL command returns a row in any case, then I think adding logic
to build row while building the output for CALL statement make more sense.

Above test throws an error saying calling procedures with output
arguments are not supported in SQL functions. Whereas similar test
do work with SQL functions:

This was discussed earlier in the thread.

The behavior of output parameters in functions was, AFAICT, invented by
us. But for procedures, the SQL standard specifies it, so there might
be some differences.

Sorry, but I am still unable to understand the difference.
In case of PROCEDURE, it's calling the PROCEDURE with out parameter.
So if that we call the same PROCEURE in the psql prompt:

postgres@101361=#CALL ptest4a(null, null);
a | b
---+---
1 | 2
(1 row)

and same is the case if we call the FUNCTION in the psql prompt:

postgres@101361=#SELECT * from ftest4b(null, null);
b | a
---+---
1 | 2
(1 row)

So if I understand correctly, in the testcase where it's calling the CALL
within SQL procedure - has to throw similar output. Isn't it?

ERROR: calling procedures with output arguments is not supported in SQL

functions
CONTEXT: SQL function "ptest4b"

Here error message says that calling procedures with output arguments is

not

supported in SQL functions. Whereas here it's getting called from the

SQL

procedure. So error message needs to be changed.

Well, I don't think we are going to change every single error message
from "function" to a separate function and procedure variant.

I think we should, otherwise it pass the wrong message to the user. Like
here it says "calling procedures with output arguments is not supported in
SQL functions"
but actually test is calling the procedures from procedure. I think now
that
we have a way to ideintify FUNCTION/PROCEDURE (prokind) it's good
to give proper error message.

Recently commit 2c6f37ed62114bd5a092c20fe721bd11b3bcb91e and
8b9e9644dc6a9bd4b7a97950e6212f63880cf18b replace AclObjectKind and
GrantObjectType with ObjectType and with that we now getting proper
object type for the acl error message. In case of PROCEDURE
and FUNCTIONS also error message should send clear message.

Regards,
Rushabh Lathia
www.EnterpriseDB.com

#20Merlin Moncure
mmoncure@gmail.com
In reply to: Peter Eisentraut (#1)
Re: INOUT parameters in procedures

On Wed, Feb 28, 2018 at 4:28 PM, Peter Eisentraut
<peter.eisentraut@2ndquadrant.com> wrote:

This patch set adds support for INOUT parameters to procedures.
Currently, INOUT and OUT parameters are not supported.

A top-level CALL returns the output parameters as a result row. In
PL/pgSQL, I have added special support to pass the output back into the
variables, as one would expect.

These patches apply on top of the "prokind" patch set v2. (Tom has
submitted an updated version of that, which overlaps with some of the
changes I've made here. I will work on consolidating that soon.)

I did a pull from master to play around with INOUT parameters and got
some strange interactions with DEFAULT. Specifically, DEFAULT doesn't
do much beyond, 'return the last supplied value given'. I'm not sure
if this is expected behavior; it seems odd:

postgres=# create or replace procedure p(a inout int default 7) as $$
begin return; end; $$ language plpgsql;
CREATE PROCEDURE
postgres=# call p();
a
───

(1 row)

postgres=# call p(3);
a
───
3
(1 row)

postgres=# call p();
a
───
3
(1 row)

I got null,3,3. I would have expected 7,3,7. Default arguments might
remove quite some of the pain associated with having to supply bogus
arguments to get the INOUT parameters working.

Edit: In one case, after dropping the function and recreating it, I
got the procedure to return 0 where it had not before, so this smells
like a bug.
postgres=# call p();
2018-03-20 09:04:50.543 CDT [21494] ERROR: function p() does not
exist at character 6
2018-03-20 09:04:50.543 CDT [21494] HINT: No function matches the
given name and argument types. You might need to add explicit type
casts.
2018-03-20 09:04:50.543 CDT [21494] STATEMENT: call p();
ERROR: function p() does not exist
LINE 1: call p();
^
HINT: No function matches the given name and argument types. You
might need to add explicit type casts.
Time: 0.297 ms
postgres=# create or replace procedure p(a inout int default 7) as $$
begin return; end; $$ language plpgsql;
CREATE PROCEDURE
Time: 1.182 ms
postgres=# call p();
a
───
0
(1 row)

merlin

#21Pavel Stehule
pavel.stehule@gmail.com
In reply to: Merlin Moncure (#20)
#22Merlin Moncure
mmoncure@gmail.com
In reply to: Pavel Stehule (#21)
#23Pavel Stehule
pavel.stehule@gmail.com
In reply to: Merlin Moncure (#22)
#24Merlin Moncure
mmoncure@gmail.com
In reply to: Pavel Stehule (#23)
#25Merlin Moncure
mmoncure@gmail.com
In reply to: Merlin Moncure (#24)