]> granicus.if.org Git - postgresql/commitdiff
Allow plpgsql function parameter names to be qualified with the function's
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 16 Jul 2007 17:01:11 +0000 (17:01 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 16 Jul 2007 17:01:11 +0000 (17:01 +0000)
name.  With this patch, it is always possible for the user to qualify a
plpgsql variable name if needed to avoid ambiguity.  While there is much more
work to be done in this area, this simple change removes one unnecessary
incompatibility with Oracle.  Per discussion.

doc/src/sgml/plpgsql.sgml
src/pl/plpgsql/src/gram.y
src/pl/plpgsql/src/pl_comp.c
src/pl/plpgsql/src/pl_funcs.c
src/pl/plpgsql/src/plpgsql.h
src/test/regress/expected/plpgsql.out
src/test/regress/sql/plpgsql.sql

index 59ec377ea9de6f7a0b5ca601ea0474eeedc04d47..24bcf52a4f747f615bbf5476aa585697d7d0c7be 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.114 2007/07/15 00:45:16 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.115 2007/07/16 17:01:10 tgl Exp $ -->
 
 <chapter id="plpgsql"> 
   <title><application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language</title>
@@ -249,10 +249,23 @@ $$ LANGUAGE plpgsql;
 </programlisting>
     </para>
 
+    <note>
+     <para>
+      There is actually a hidden <quote>outer block</> surrounding the body
+      of any <application>PL/pgSQL</> function.  This block provides the
+      declarations of the function's parameters (if any), as well as some
+      special variables such as <literal>FOUND</literal> (see
+      <xref linkend="plpgsql-statements-diagnostics">).  The outer block is
+      labeled with the function's name, meaning that parameters and special
+      variables can be qualified with the function's name.
+     </para>
+    </note>
+
     <para>
      It is important not to confuse the use of
      <command>BEGIN</>/<command>END</> for grouping statements in
-     <application>PL/pgSQL</> with the database commands for transaction
+     <application>PL/pgSQL</> with the similarly-named SQL commands
+     for transaction
      control.  <application>PL/pgSQL</>'s <command>BEGIN</>/<command>END</>
      are only for grouping; they do not start or end a transaction.
      Functions and trigger procedures are always executed within a transaction
@@ -370,6 +383,19 @@ BEGIN
 END;
 $$ LANGUAGE plpgsql;
 </programlisting>
+     </para>
+
+    <note>
+     <para>
+      These two examples are not perfectly equivalent.  In the first case,
+      <literal>subtotal</> could be referenced as
+      <literal>sales_tax.subtotal</>, but in the second case it could not.
+      (Had we attached a label to the block, <literal>subtotal</> could
+      be qualified with that label, instead.)
+     </para>
+    </note>
+
+     <para>
       Some more examples:
 <programlisting>
 CREATE FUNCTION instr(varchar, integer) RETURNS integer AS $$
@@ -3618,12 +3644,12 @@ a_output := a_output || $$ if v_$$ || referrer_keys.kind || $$ like '$$
 
      <listitem>
       <para>
-       You cannot use parameter names that are the same as columns
-       that are referenced in the function. Oracle allows you to do this
-       if you qualify the parameter name using
-       <literal>function_name.parameter_name</>.
-       In <application>PL/pgSQL</>, you can instead avoid a conflict by
-       qualifying the column or table name.
+       If a name used in a SQL command could be either a column name of a
+       table or a reference to a variable of the function,
+       <application>PL/SQL</> treats it as a column name, while
+       <application>PL/pgSQL</> treats it as a variable name.  It's best
+       to avoid such ambiguities in the first place, but if necessary you
+       can fix them by properly qualifying the ambiguous name.
        (See <xref linkend="plpgsql-var-subst">.)
       </para>
      </listitem>
index 0f41c999724b5726fad8710064ecd7df0d74cf56..795d3c4c4bd49acec5a19736d49f085893b1c5e0 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.103 2007/07/15 02:15:04 tgl Exp $
+ *       $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.104 2007/07/16 17:01:10 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -366,7 +366,7 @@ decl_statement      : decl_varname decl_const decl_datatype decl_notnull decl_defval
                                                plpgsql_ns_rename($2, $4);
                                        }
                                | decl_varname opt_scrollable K_CURSOR
-                                       { plpgsql_ns_push(NULL); }
+                                       { plpgsql_ns_push($1.name); }
                                  decl_cursor_args decl_is_for decl_cursor_query
                                        {
                                                PLpgSQL_var *new;
index 0293bc3fe072ff0e3b615a1ab49afb9b48da0ab6..db150632f0555d3e8e80543220e25504540b98bc 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.116 2007/06/26 16:48:09 alvherre Exp $
+ *       $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.117 2007/07/16 17:01:10 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -306,10 +306,12 @@ do_compile(FunctionCallInfo fcinfo,
        error_context_stack = &plerrcontext;
 
        /*
-        * Initialize the compiler
+        * Initialize the compiler, particularly the namespace stack.  The
+        * outermost namespace contains function parameters and other special
+        * variables (such as FOUND), and is named after the function itself.
         */
        plpgsql_ns_init();
-       plpgsql_ns_push(NULL);
+       plpgsql_ns_push(NameStr(procStruct->proname));
        plpgsql_DumpExecTree = false;
 
        datums_alloc = 128;
index 4d5eba73e3b43e7c3c96f74e6844cff37d7b1f3c..da128daa7f7f39ae0c22216a3541fadf322947c4 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.60 2007/07/15 02:15:04 tgl Exp $
+ *       $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.61 2007/07/16 17:01:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -147,15 +147,14 @@ plpgsql_ns_setlocal(bool flag)
  * ----------
  */
 void
-plpgsql_ns_push(char *label)
+plpgsql_ns_push(const char *label)
 {
        PLpgSQL_ns *new;
 
        if (label == NULL)
                label = "";
 
-       new = palloc(sizeof(PLpgSQL_ns));
-       memset(new, 0, sizeof(PLpgSQL_ns));
+       new = palloc0(sizeof(PLpgSQL_ns));
        new->upper = ns_current;
        ns_current = new;
 
@@ -224,7 +223,7 @@ plpgsql_ns_additem(int itemtype, int itemno, const char *name)
  * ----------
  */
 PLpgSQL_nsitem *
-plpgsql_ns_lookup(char *name, char *label)
+plpgsql_ns_lookup(const char *name, const char *label)
 {
        PLpgSQL_ns *ns;
        int                     i;
@@ -236,11 +235,11 @@ plpgsql_ns_lookup(char *name, char *label)
        {
                for (ns = ns_current; ns != NULL; ns = ns->upper)
                {
-                       if (!strcmp(ns->items[0]->name, label))
+                       if (strcmp(ns->items[0]->name, label) == 0)
                        {
                                for (i = 1; i < ns->items_used; i++)
                                {
-                                       if (!strcmp(ns->items[i]->name, name))
+                                       if (strcmp(ns->items[i]->name, name) == 0)
                                                return ns->items[i];
                                }
                                return NULL;    /* name not found in specified label */
@@ -254,7 +253,7 @@ plpgsql_ns_lookup(char *name, char *label)
         */
        for (ns = ns_current; ns != NULL; ns = ns->upper)
        {
-               if (!strcmp(ns->items[0]->name, name))
+               if (strcmp(ns->items[0]->name, name) == 0)
                        return ns->items[0];
        }
 
@@ -265,7 +264,7 @@ plpgsql_ns_lookup(char *name, char *label)
        {
                for (i = 1; i < ns->items_used; i++)
                {
-                       if (!strcmp(ns->items[i]->name, name))
+                       if (strcmp(ns->items[i]->name, name) == 0)
                                return ns->items[i];
                }
                if (ns_localmode)
@@ -288,14 +287,13 @@ plpgsql_ns_rename(char *oldname, char *newname)
        int                     i;
 
        /*
-        * Lookup name in the namestack; do the lookup in the current namespace
-        * only.
+        * Lookup name in the namestack
         */
        for (ns = ns_current; ns != NULL; ns = ns->upper)
        {
                for (i = 1; i < ns->items_used; i++)
                {
-                       if (!strcmp(ns->items[i]->name, oldname))
+                       if (strcmp(ns->items[i]->name, oldname) == 0)
                        {
                                newitem = palloc(sizeof(PLpgSQL_nsitem) + strlen(newname));
                                newitem->itemtype = ns->items[i]->itemtype;
index dce7be2b1bd29fe3f09c71d45812ed6b08e13dca..6ffb8b419584faaf55dd6692d7a9bb3d7dcb0cf6 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.89 2007/07/15 02:15:04 tgl Exp $
+ *       $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.90 2007/07/16 17:01:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -770,10 +770,10 @@ extern char *plpgsql_dstring_get(PLpgSQL_dstring *ds);
  */
 extern void plpgsql_ns_init(void);
 extern bool plpgsql_ns_setlocal(bool flag);
-extern void plpgsql_ns_push(char *label);
+extern void plpgsql_ns_push(const char *label);
 extern void plpgsql_ns_pop(void);
 extern void plpgsql_ns_additem(int itemtype, int itemno, const char *name);
-extern PLpgSQL_nsitem *plpgsql_ns_lookup(char *name, char *nsname);
+extern PLpgSQL_nsitem *plpgsql_ns_lookup(const char *name, const char *nsname);
 extern void plpgsql_ns_rename(char *oldname, char *newname);
 
 /* ----------
index ddb44a72527d960033065293b05aa5127df168b5..6d97b63e5c93806a2e8bcb61b919efcf0138bcae 100644 (file)
@@ -3051,3 +3051,31 @@ select * from sc_test();
 (3 rows)
 
 drop function sc_test();
+-- test qualified variable names
+create function pl_qual_names (param1 int) returns void as $$
+<<outerblock>>
+declare
+  param1 int := 1;
+begin
+  <<innerblock>>
+  declare
+    param1 int := 2;
+  begin
+    raise notice 'param1 = %', param1;
+    raise notice 'pl_qual_names.param1 = %', pl_qual_names.param1;
+    raise notice 'outerblock.param1 = %', outerblock.param1;
+    raise notice 'innerblock.param1 = %', innerblock.param1;
+  end;
+end;
+$$ language plpgsql;
+select pl_qual_names(42);
+NOTICE:  param1 = 2
+NOTICE:  pl_qual_names.param1 = 42
+NOTICE:  outerblock.param1 = 1
+NOTICE:  innerblock.param1 = 2
+ pl_qual_names 
+---------------
+(1 row)
+
+drop function pl_qual_names(int);
index ee9de0a5838e142ae2057eb9132b7f0420f33d44..d1c715e8d4cc299b1aeeee8e0e553bd51614f350 100644 (file)
@@ -2535,3 +2535,25 @@ select * from sc_test();
 
 drop function sc_test();
 
+-- test qualified variable names
+
+create function pl_qual_names (param1 int) returns void as $$
+<<outerblock>>
+declare
+  param1 int := 1;
+begin
+  <<innerblock>>
+  declare
+    param1 int := 2;
+  begin
+    raise notice 'param1 = %', param1;
+    raise notice 'pl_qual_names.param1 = %', pl_qual_names.param1;
+    raise notice 'outerblock.param1 = %', outerblock.param1;
+    raise notice 'innerblock.param1 = %', innerblock.param1;
+  end;
+end;
+$$ language plpgsql;
+
+select pl_qual_names(42);
+
+drop function pl_qual_names(int);