-<!-- $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>
</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
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 $$
<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>
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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;
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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;
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* ----------
*/
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;
* ----------
*/
PLpgSQL_nsitem *
-plpgsql_ns_lookup(char *name, char *label)
+plpgsql_ns_lookup(const char *name, const char *label)
{
PLpgSQL_ns *ns;
int i;
{
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 */
*/
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];
}
{
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)
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;
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
*/
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);
/* ----------
(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);
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);