[PATCH] 8.5 plpgsql change for named notation: treat word following AS keyword as label v2 - Mailing list pgsql-hackers

From Steve Prentice
Subject [PATCH] 8.5 plpgsql change for named notation: treat word following AS keyword as label v2
Date
Msg-id EB83C343-28E1-4DFB-86E5-09BD98E7E2C0@cisco.com
Whole thread Raw
Responses Re: [PATCH] 8.5 plpgsql change for named notation: treat word following AS keyword as label v2  (Tom Lane <tgl@sss.pgh.pa.us>)
Re: [PATCH] 8.5 plpgsql change for named notation: treat word following AS keyword as label v2  (Josh Berkus <josh@agliodbs.com>)
List 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 $$
DECLAREt INT;
BEGINt := 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
touse 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,
doso 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;            }


pgsql-hackers by date:

Previous
From: Tom Lane
Date:
Subject: Re: Fast ALTER TABLE ... ADD COLUMN ... DEFAULT xxx?
Next
From: Tom Lane
Date:
Subject: Re: [PATCH] 8.5 plpgsql change for named notation: treat word following AS keyword as label v2