[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
Re: [PATCH] 8.5 plpgsql change for named notation: treat word following AS keyword as label v2 |
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: