Обсуждение: INOUT parameters in procedures

Поиск
Список
Период
Сортировка

INOUT parameters in procedures

От
Peter Eisentraut
Дата:
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

Вложения

Re: INOUT parameters in procedures

От
Pavel Stehule
Дата:
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

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

Re: INOUT parameters in procedures

От
Douglas Doole
Дата:
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

Re: INOUT parameters in procedures

От
Peter Eisentraut
Дата:
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

Вложения

Re: INOUT parameters in procedures

От
Pavel Stehule
Дата:


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.

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

Re: INOUT parameters in procedures

От
Pavel Stehule
Дата:


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.



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


Re: INOUT parameters in procedures

От
Pavel Stehule
Дата:


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




 

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

Re: INOUT parameters in procedures

От
Peter Eisentraut
Дата:
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

Вложения

Re: INOUT parameters in procedures

От
Pavel Stehule
Дата:
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


 

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

Re: INOUT parameters in procedures

От
Peter Eisentraut
Дата:
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

Вложения

Re: INOUT parameters in procedures

От
Pavel Stehule
Дата:


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

 

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

Re: INOUT parameters in procedures

От
Peter Eisentraut
Дата:
committed

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


Re: INOUT parameters in procedures

От
Jeff Janes
Дата:
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

Re: INOUT parameters in procedures

От
Tom Lane
Дата:
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


Re: INOUT parameters in procedures

От
Jeff Janes
Дата:
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

Re: INOUT parameters in procedures

От
Tom Lane
Дата:
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


Re: INOUT parameters in procedures

От
Rushabh Lathia
Дата:
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

Re: INOUT parameters in procedures

От
Peter Eisentraut
Дата:
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


Re: INOUT parameters in procedures

От
Rushabh Lathia
Дата:


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

Re: INOUT parameters in procedures

От
Merlin Moncure
Дата:
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


Re: INOUT parameters in procedures

От
Pavel Stehule
Дата:


2018-03-20 15:05 GMT+01:00 Merlin Moncure <mmoncure@gmail.com>:
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)

I wrote patch

Regards

Pavel
 


merlin


Вложения

Re: INOUT parameters in procedures

От
Merlin Moncure
Дата:
On Tue, Mar 20, 2018 at 9:09 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:
>> 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)
>
>
> I wrote patch

Confirmed this fixes the issue.

merlin


Re: INOUT parameters in procedures

От
Pavel Stehule
Дата:


2018-03-20 15:18 GMT+01:00 Merlin Moncure <mmoncure@gmail.com>:
On Tue, Mar 20, 2018 at 9:09 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:
>> 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)
>
>
> I wrote patch

Confirmed this fixes the issue.

Thanks for info

Pavel
 

merlin

Re: INOUT parameters in procedures

От
Merlin Moncure
Дата:
On Tue, Mar 20, 2018 at 10:09 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:
> 2018-03-20 15:18 GMT+01:00 Merlin Moncure <mmoncure@gmail.com>:
>> >> 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)
>> >
>> >
>> > I wrote patch
>>
>> Confirmed this fixes the issue.
>
> Thanks for info

You're welcome.  Working with this feature some more, I noticed that:
A) you can't assign output variables with into:
CALL p(1) INTO i;  // gives syntax error

B) you can't assign via assignment
i := p(1); // gives error, 'use CALL'

C) but you *can* via execute
EXECUTE 'CALL p(1)' INTO i;  // this works!

...I'm glad 'C' works, as without that there would be no useful way to
get values out of procedures called from within other
procedures/functions as things stand today.  'A' ideally also out to
work, but I'm not sure  'B' should be expected to work since it's
really a thin layer around SELECT.   What do you think?

merlin


Re: INOUT parameters in procedures

От
Merlin Moncure
Дата:
On Tue, Mar 20, 2018 at 4:19 PM, Merlin Moncure <mmoncure@gmail.com> wrote:
> A) you can't assign output variables with into:
> CALL p(1) INTO i;  // gives syntax error
>
> B) you can't assign via assignment
> i := p(1); // gives error, 'use CALL'
>
> C) but you *can* via execute
> EXECUTE 'CALL p(1)' INTO i;  // this works!
>
> ...I'm glad 'C' works, as without that there would be no useful way to
> get values out of procedures called from within other
> procedures/functions as things stand today.  'A' ideally also out to
> work, but I'm not sure  'B' should be expected to work since it's
> really a thin layer around SELECT.   What do you think?

Also (sorry for spam),
A procedure created via:
create procedure p() as $$begin call p(); end; $$ language plpgsql;
...will segfault when called -- there ought to be a stack depth check.

merlin