Make plpgsql complain about conflicting IN and OUT parameter names.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 23 May 2011 20:34:27 +0000 (16:34 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 23 May 2011 20:35:22 +0000 (16:35 -0400)
The core CREATE FUNCTION code only enforces that IN parameter names are
non-duplicate, and that OUT parameter names are separately non-duplicate.
This is because some function languages might not have any confusion
between the two.  But in plpgsql, such names are all in the same namespace,
so we'd better disallow it.

Per a recent complaint from Dan S.  Not back-patching since this is a small
issue and the change could cause unexpected failures if we started to
enforce it in a minor release.

src/pl/plpgsql/src/pl_comp.c

index a80235cd2aaf76e493f125c80a15bae9bc1b11ce..75098ec6deb21a70dc49c13544e95c3b99a4ded4 100644 (file)
@@ -95,6 +95,7 @@ static PLpgSQL_function *do_compile(FunctionCallInfo fcinfo,
           PLpgSQL_func_hashkey *hashkey,
           bool forValidator);
 static void plpgsql_compile_error_callback(void *arg);
+static void add_parameter_name(int itemtype, int itemno, const char *name);
 static void add_dummy_return(PLpgSQL_function *function);
 static Node *plpgsql_pre_column_ref(ParseState *pstate, ColumnRef *cref);
 static Node *plpgsql_post_column_ref(ParseState *pstate, ColumnRef *cref, Node *var);
@@ -451,11 +452,11 @@ do_compile(FunctionCallInfo fcinfo,
                    out_arg_variables[num_out_args++] = argvariable;
 
                /* Add to namespace under the $n name */
-               plpgsql_ns_additem(argitemtype, argvariable->dno, buf);
+               add_parameter_name(argitemtype, argvariable->dno, buf);
 
                /* If there's a name for the argument, make an alias */
                if (argnames && argnames[i][0] != '\0')
-                   plpgsql_ns_additem(argitemtype, argvariable->dno,
+                   add_parameter_name(argitemtype, argvariable->dno,
                                       argnames[i]);
            }
 
@@ -913,6 +914,31 @@ plpgsql_compile_error_callback(void *arg)
 }
 
 
+/*
+ * Add a name for a function parameter to the function's namespace
+ */
+static void
+add_parameter_name(int itemtype, int itemno, const char *name)
+{
+   /*
+    * Before adding the name, check for duplicates.  We need this even though
+    * functioncmds.c has a similar check, because that code explicitly
+    * doesn't complain about conflicting IN and OUT parameter names.  In
+    * plpgsql, such names are in the same namespace, so there is no way to
+    * disambiguate.
+    */
+   if (plpgsql_ns_lookup(plpgsql_ns_top(), true,
+                         name, NULL, NULL,
+                         NULL) != NULL)
+       ereport(ERROR,
+               (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+                errmsg("parameter name \"%s\" used more than once",
+                       name)));
+
+   /* OK, add the name */
+   plpgsql_ns_additem(itemtype, itemno, name);
+}
+
 /*
  * Add a dummy RETURN statement to the given function's body
  */