On May 21, 2009, at 10:52 AM, Tom Lane wrote:
It's probably time to bite the bullet and redo the parser as has been
suggested in the past, ie fix things so that the main parser is used.
Ideally I'd like to switch the name resolution priority to be more
Oracle-like, but even if we don't do that it would be a great
improvement to have actual syntactic knowledge behind the lookups.

That kind of refactoring is beyond my experience-level with the code, but I can't say I disagree with your analysis.

Just for the record, you'd have to put the same kluge into the T_RECORD
and T_ROW cases if we wanted to do it like this.

Patch updated.

diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml
index 80dbf45..f8e8ce4 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 @@ -3603,7 +3603,27 @@ CONTEXT: SQL statement in PL/PgSQL function "logfunc2" near line 5
    </para>

    <para>
-    Variable substitution does not happen in the command string given
+    There are two places where variable substitution does not happen.
+   </para>
+
+   <para>
+ Any label following the "AS" keyword is not replaced. 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 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..3b4e9b8 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)
@@ -2031,6 +2033,16 @@ read_sql_construct(int until,
                if (plpgsql_SpaceScanned)
                        plpgsql_dstring_append(&ds, " ");

+               /* A variable following AS is treated as a label */
+               if (prevtok == K_AS &&
+ (tok == T_SCALAR || tok == T_ROW || tok == T_RECORD))
+               {
+                       plpgsql_dstring_append(&ds, yytext);
+                       continue;
+               }
+
                switch (tok)
                {
                        case T_SCALAR:
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;                        }


--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to