1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-05 07:41:25 +03:00

Allow => syntax for named cursor arguments in plpgsql.

We've traditionally accepted "name := value" syntax for
cursor arguments in plpgsql.  But it turns out that the
equivalent statements in Oracle use "name => value".
Since we accept both forms of punctuation for function
arguments, it makes sense to do the same here.

Author: Pavel Stehule <pavel.stehule@gmail.com>
Reviewed-by: Gilles Darold <gilles@darold.net>
Discussion: https://postgr.es/m/CAFj8pRA3d0ARQEMbABa1n6q25AUdNmyO8aGs56XNf9pD4sRMjQ@mail.gmail.com
This commit is contained in:
Tom Lane
2025-03-03 18:00:05 -05:00
parent b6904afae4
commit 246dedc5d0
4 changed files with 21 additions and 12 deletions

View File

@@ -3317,7 +3317,7 @@ OPEN curs1 FOR EXECUTE format('SELECT * FROM %I WHERE col1 = $1',tabname) USING
<title>Opening a Bound Cursor</title> <title>Opening a Bound Cursor</title>
<synopsis> <synopsis>
OPEN <replaceable>bound_cursorvar</replaceable> <optional> ( <optional> <replaceable>argument_name</replaceable> := </optional> <replaceable>argument_value</replaceable> <optional>, ...</optional> ) </optional>; OPEN <replaceable>bound_cursorvar</replaceable> <optional> ( <optional> <replaceable>argument_name</replaceable> { := | =&gt; } </optional> <replaceable>argument_value</replaceable> <optional>, ...</optional> ) </optional>;
</synopsis> </synopsis>
<para> <para>
@@ -3340,7 +3340,8 @@ OPEN <replaceable>bound_cursorvar</replaceable> <optional> ( <optional> <replace
Argument values can be passed using either <firstterm>positional</firstterm> Argument values can be passed using either <firstterm>positional</firstterm>
or <firstterm>named</firstterm> notation. In positional or <firstterm>named</firstterm> notation. In positional
notation, all arguments are specified in order. In named notation, notation, all arguments are specified in order. In named notation,
each argument's name is specified using <literal>:=</literal> to each argument's name is specified using <literal>:=</literal>
or <literal>=&gt;</literal> to
separate it from the argument expression. Similar to calling separate it from the argument expression. Similar to calling
functions, described in <xref linkend="sql-syntax-calling-funcs"/>, it functions, described in <xref linkend="sql-syntax-calling-funcs"/>, it
is also allowed to mix positional and named notation. is also allowed to mix positional and named notation.
@@ -3352,6 +3353,7 @@ OPEN <replaceable>bound_cursorvar</replaceable> <optional> ( <optional> <replace
OPEN curs2; OPEN curs2;
OPEN curs3(42); OPEN curs3(42);
OPEN curs3(key := 42); OPEN curs3(key := 42);
OPEN curs3(key =&gt; 42);
</programlisting> </programlisting>
</para> </para>
@@ -3672,7 +3674,7 @@ COMMIT;
<synopsis> <synopsis>
<optional> &lt;&lt;<replaceable>label</replaceable>&gt;&gt; </optional> <optional> &lt;&lt;<replaceable>label</replaceable>&gt;&gt; </optional>
FOR <replaceable>recordvar</replaceable> IN <replaceable>bound_cursorvar</replaceable> <optional> ( <optional> <replaceable>argument_name</replaceable> := </optional> <replaceable>argument_value</replaceable> <optional>, ...</optional> ) </optional> LOOP FOR <replaceable>recordvar</replaceable> IN <replaceable>bound_cursorvar</replaceable> <optional> ( <optional> <replaceable>argument_name</replaceable> { := | =&gt; } </optional> <replaceable>argument_value</replaceable> <optional>, ...</optional> ) </optional> LOOP
<replaceable>statements</replaceable> <replaceable>statements</replaceable>
END LOOP <optional> <replaceable>label</replaceable> </optional>; END LOOP <optional> <replaceable>label</replaceable> </optional>;
</synopsis> </synopsis>

View File

@@ -3955,9 +3955,12 @@ read_cursor_args(PLpgSQL_var *cursor, int until, YYSTYPE *yylvalp, YYLTYPE *yyll
tok2; tok2;
int arglocation; int arglocation;
/* Check if it's a named parameter: "param := value" */ /*
* Check if it's a named parameter: "param := value"
* or "param => value"
*/
plpgsql_peek2(&tok1, &tok2, &arglocation, NULL, yyscanner); plpgsql_peek2(&tok1, &tok2, &arglocation, NULL, yyscanner);
if (tok1 == IDENT && tok2 == COLON_EQUALS) if (tok1 == IDENT && (tok2 == COLON_EQUALS || tok2 == EQUALS_GREATER))
{ {
char *argname; char *argname;
IdentifierLookup save_IdentifierLookup; IdentifierLookup save_IdentifierLookup;
@@ -3983,11 +3986,11 @@ read_cursor_args(PLpgSQL_var *cursor, int until, YYSTYPE *yylvalp, YYLTYPE *yyll
parser_errposition(*yyllocp))); parser_errposition(*yyllocp)));
/* /*
* Eat the ":=". We already peeked, so the error should never * Eat the ":=" or "=>". We already peeked, so the error should
* happen. * never happen.
*/ */
tok2 = yylex(yylvalp, yyllocp, yyscanner); tok2 = yylex(yylvalp, yyllocp, yyscanner);
if (tok2 != COLON_EQUALS) if (tok2 != COLON_EQUALS && tok2 != EQUALS_GREATER)
yyerror(yyllocp, NULL, yyscanner, "syntax error"); yyerror(yyllocp, NULL, yyscanner, "syntax error");
any_named = true; any_named = true;

View File

@@ -2419,7 +2419,8 @@ declare
p2 int4 := 1006; p2 int4 := 1006;
n int4; n int4;
begin begin
open c1 (p1 := p1, p2 := p2, debug := 2); -- use both supported syntaxes for named arguments
open c1 (p1 := p1, p2 => p2, debug => 2);
fetch c1 into n; fetch c1 into n;
return n; return n;
end $$ language plpgsql; end $$ language plpgsql;
@@ -3487,7 +3488,8 @@ begin
raise notice '% from %', r.i, c; raise notice '% from %', r.i, c;
end loop; end loop;
-- again, to test if cursor was closed properly -- again, to test if cursor was closed properly
for r in c(9,10) loop -- (and while we're at it, test named-parameter notation)
for r in c(r2 := 10, r1 => 9) loop
raise notice '% from %', r.i, c; raise notice '% from %', r.i, c;
end loop; end loop;
-- and test a parameterless cursor -- and test a parameterless cursor

View File

@@ -2072,7 +2072,8 @@ declare
p2 int4 := 1006; p2 int4 := 1006;
n int4; n int4;
begin begin
open c1 (p1 := p1, p2 := p2, debug := 2); -- use both supported syntaxes for named arguments
open c1 (p1 := p1, p2 => p2, debug => 2);
fetch c1 into n; fetch c1 into n;
return n; return n;
end $$ language plpgsql; end $$ language plpgsql;
@@ -2934,7 +2935,8 @@ begin
raise notice '% from %', r.i, c; raise notice '% from %', r.i, c;
end loop; end loop;
-- again, to test if cursor was closed properly -- again, to test if cursor was closed properly
for r in c(9,10) loop -- (and while we're at it, test named-parameter notation)
for r in c(r2 := 10, r1 => 9) loop
raise notice '% from %', r.i, c; raise notice '% from %', r.i, c;
end loop; end loop;
-- and test a parameterless cursor -- and test a parameterless cursor