[PATCH] 8.5 plpgsql change for named notation: treat word following AS keyword as label v2

From: Steve Prentice <prentice(at)cisco(dot)com>
To: pgsql-hackers(at)postgresql(dot)org
Subject: [PATCH] 8.5 plpgsql change for named notation: treat word following AS keyword as label v2
Date: 2009-05-21 17:31:55
Message-ID: EB83C343-28E1-4DFB-86E5-09BD98E7E2C0@cisco.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hello,

This patch is intended to supplement Pavel's patch for named and mixed
notation support in 8.5. This patch makes it so a plpgsql function can
call another function with the same parameter names using the named
parameters notation. Without this patch, the following example will
have a syntax errors:

CREATE FUNCTION fun1(a INT DEFAULT 1) RETURNS INT AS 'SELECT $1'
LANGUAGE SQL;
CREATE FUNCTION fun2(a INT) RETURNS INT AS $$
DECLARE
t INT;
BEGIN
t := fun1(1 as a); -- syntax error: "SELECT fun1(1 as $1 )"
t := fun1(a as a); -- syntax error: "SELECT fun1( $1 as $1 )"
RETURN 0;
END;
$$ LANGUAGE plpgsql;

The patch adds the "AS" keyword to the plpgsql grammar and doesn't
assign an expression parameter to the sql construct if the scalar
follows the AS keyword.

(v1 of this patch was in the "plpgsql + named parameters" thread, but
it didn't include the doc changes.)

-Steve

diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml
index 80dbf45..9b99314 100644
--- a/doc/src/sgml/plpgsql.sgml
+++ b/doc/src/sgml/plpgsql.sgml
@@ -3510,7 +3510,7 @@ PREPARE <replaceable>statement_name</>(text,
timestamp) AS
</para>

<para>
- <emphasis>The substitution mechanism will replace any token that
matches a
+ <emphasis>The substitution mechanism will replace most tokens
that match a
known variable's name.</> This poses various traps for the unwary.
For example, it is a bad idea
to use a variable name that is the same as any table or column name
@@ -3601,9 +3601,29 @@ CONTEXT: SQL statement in PL/PgSQL function
"logfunc2" near line 5
interpreted the <quote>wrong</> way. But it is useful for
clarifying
the intent of potentially-ambiguous code.
</para>
-
+
+ <para>
+ There are two places where variable substitution does not happen.
+ </para>
+
+ <para>
+ Any label following the "AS" keyword is not replace. This allows
passing
+ parameters by name to functions that have parameters of the same
name as
+ the calling function. For example,
+<programlisting>
+ CREATE FUNCTION logfunc(v_logtxt text) RETURNS void AS $$
+ BEGIN
+ INSERT INTO logtable (logtxt) VALUES (v_logtxt);
+ PERFORM tracefunc(v_logtxt AS v_logtxt);
+ END;
+ $$ LANGUAGE plpgsql;
+</programlisting>
+ All occurances of v_logtxt in the function are replaced except the
one
+ following "AS".
+ </para>
+
<para>
- Variable substitution does not happen in the command string given
+ Variable substitution also does not happen in the command string
given
to <command>EXECUTE</> or one of its variants. If you need to
insert a varying value into such a command, do so as part of
constructing the string value, as illustrated in
diff --git a/src/pl/plpgsql/src/gram.y b/src/pl/plpgsql/src/gram.y
index 06704cf..647daab 100644
--- a/src/pl/plpgsql/src/gram.y
+++ b/src/pl/plpgsql/src/gram.y
@@ -177,6 +177,7 @@ static List *read_raise_options(void);
* Keyword tokens
*/
%token K_ALIAS
+%token K_AS
%token K_ASSIGN
%token K_BEGIN
%token K_BY
@@ -1977,6 +1978,7 @@ read_sql_construct(int until,
int *endtoken)
{
int tok;
+ int prevtok = 0;
int lno;
PLpgSQL_dstring ds;
int parenlevel = 0;
@@ -1989,7 +1991,7 @@ read_sql_construct(int until,
plpgsql_dstring_init(&ds);
plpgsql_dstring_append(&ds, sqlstart);

- for (;;)
+ for (;;prevtok = tok)
{
tok = yylex();
if (tok == until && parenlevel == 0)
@@ -2034,10 +2036,16 @@ read_sql_construct(int until,
switch (tok)
{
case T_SCALAR:
- snprintf(buf, sizeof(buf), " $%d ",
- assign_expr_param(yylval.scalar->dno,
- params, &nparams));
- plpgsql_dstring_append(&ds, buf);
+ /* A scalar following AS is treated as a label */
+ if (prevtok == K_AS)
+ plpgsql_dstring_append(&ds, yytext);
+ else
+ {
+ snprintf(buf, sizeof(buf), " $%d ",
+ assign_expr_param(yylval.scalar->dno,
+ params, &nparams));
+ plpgsql_dstring_append(&ds, buf);
+ }
break;

case T_ROW:
diff --git a/src/pl/plpgsql/src/scan.l b/src/pl/plpgsql/src/scan.l
index 1917eef..e3a5c45 100644
--- a/src/pl/plpgsql/src/scan.l
+++ b/src/pl/plpgsql/src/scan.l
@@ -149,6 +149,7 @@ param \${digit}+
= { return K_ASSIGN; }
\.\. { return K_DOTDOT; }
alias { return K_ALIAS; }
+as { return K_AS; }
begin { return K_BEGIN; }
by { return K_BY; }
case { return K_CASE; }

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Tom Lane 2009-05-21 17:52:59 Re: [PATCH] 8.5 plpgsql change for named notation: treat word following AS keyword as label v2
Previous Message Tom Lane 2009-05-21 16:26:08 Re: Fast ALTER TABLE ... ADD COLUMN ... DEFAULT xxx?