diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml
index 07078e6..ce1676b 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 5572cf7..fe432d7 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,14 @@ 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 5d7f497..d67bd3d 100644
--- a/src/pl/plpgsql/src/scan.l
+++ b/src/pl/plpgsql/src/scan.l
@@ -147,6 +147,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;			}
