-
+
PL/pgSQL - SQL Procedural Language
- There are two types of comments in
PL/pgSQL>. A double
- dash (--) starts a comment that extends to the end of
- the line. A /* starts a block comment that extends to
- the next occurrence of */. Block comments nest,
- just as in ordinary SQL.
+ Comments work the same way in
PL/pgSQL> code as in
+ ordinary SQL. A double dash (--) starts a comment
+ that extends to the end of the line. A /* starts a
+ block comment that extends to the matching occurrence of
+ */. Block comments nest.
to the variable when the block is entered. If the DEFAULT> clause
is not given then the variable is initialized to the
- The CONSTANT> option prevents the variable from being assigned to,
- so that its value remains constant for the duration of the block.
+ The CONSTANT> option prevents the variable from being
+ assigned to, so that its value will remain constant for the duration of
+ the block.
If NOT NULL>
is specified, an assignment of a null value results in a run-time
error. All variables declared as NOT NULL>
IF x < y THEN ...
- what happens behind the scenes is
+ what happens behind the scenes is equivalent to
PREPARE statement_name>(integer, integer) AS SELECT $1 < $2;
An assignment of a value to a
PL/pgSQL
- variable or row/record field is written as:
+ variable is written as:
variable := expression;
- As explained above, the expression in such a statement is evaluated
+ As explained previously, the expression in such a statement is evaluated
by means of an SQL SELECT> command sent to the main
- database engine. The expression must yield a single value.
+ database engine. The expression must yield a single value (possibly
+ a row value, if the variable is a row or record variable). The target
+ variable can be a simple variable (optionally qualified with a block
+ name), a field of a row or record variable, or an element of an array
+ that is a simple variable or field.
Any
PL/pgSQL variable name appearing
- in the command text is replaced by a parameter symbol, and then the
+ in the command text is treated as a parameter, and then the
current value of the variable is provided as the parameter value
at run time. This is exactly like the processing described earlier
for expressions; for details see .
- As an example, if you write:
-DECLARE
- key TEXT;
- delta INTEGER;
-BEGIN
- ...
- UPDATE mytab SET val = val + delta WHERE id = key;
-
- the command text seen by the main SQL engine will look like:
- UPDATE mytab SET val = val + $1 WHERE id = $2;
-
- Although you don't normally have to think about this, it's helpful
- to know it when you need to make sense of syntax-error messages.
-
-
PL/pgSQL will substitute for any identifier
- matching one of the function's declared variables; it is not bright
- enough to know whether that's what you meant! Thus, it is a bad idea
- to use a variable name that is the same as any table, column, or
- function name that you need to reference in commands within the
- function. For more discussion see .
-
-
-
When executing a SQL command in this way,
PL/pgSQL plans the command just once
If a row or a variable list is used as target, the query's result columns
must exactly match the structure of the target as to number and data
- types, or a run-time error
+ types, or else a run-time error
occurs. When a record variable is the target, it automatically
configures itself to the row type of the query result columns.
INTO c
USING checked_user, checked_date;
+
Note that parameter symbols can only be used for data values
— if you want to use dynamically determined table or column
names, you must insert them into the command string textually.
INTO c
USING checked_user, checked_date;
+ Another restriction on parameter symbols is that they only work in
+ SELECT>, INSERT>, UPDATE>, and
+ DELETE> commands. In other statement
+ types (generically called utility statements), you must insert
+ values textually even if they are just data values.
type boolean. FOUND starts out
false within each
PL/pgSQL function call.
It is set by each of the following types of statements:
+
+ Other
PL/pgSQL statements do not change
+ the state of FOUND.
+ Note in particular that EXECUTE
+ changes the output of GET DIAGNOSTICS, but
+ does not change FOUND.
+
+
FOUND is a local variable within each
PL/pgSQL function; any changes to it
- affect only the current function. EXECUTE
- changes the output of GET DIAGNOSTICS, but
- does not change the state of FOUND.
+ affect only the current function.
RETURN with an expression terminates the
function and returns the value of
expression to the caller. This form
- is
to be used for
PL/pgSQL> functions that do
+ is used for
PL/pgSQL> functions that do
not return a set.
or deleted using the cursor to identify the row. There are
restrictions on what the cursor's query can be (in particular,
no grouping) and it's best to use FOR UPDATE> in the
- cursor. For additional information see the
+ cursor. For more information see the
reference page.
Data type array of text; the arguments from
- the CREATE TRIGGER statement.
+ the CREATE TRIGGER statement.
The index counts from 0. Invalid
- indices (less than 0 or greater than or equal to tg_nargs>) result in a null value.
+ indexes (less than 0 or greater than or equal to tg_nargs>)
+ result in a null value.
Variable Substitution
- When
PL/pgSQL> prepares a SQL statement or expression
- for execution, any
PL/pgSQL variable name
- appearing in the statement or expression is replaced by a parameter symbol,
- $n. The current value
- of the variable is then provided as the value for the parameter whenever
- the statement or expression is executed. As an example, consider the
- function
+ SQL statements and expressions within a
PL/pgSQL> function
+ can refer to variables and parameters of the function. Behind the scenes,
+
PL/pgSQL> substitutes query parameters for such references.
+ Parameters will only be substituted in places where a parameter or
+ column reference is syntactically allowed. As an extreme case, consider
+ this example of poor programming style:
-CREATE FUNCTION logfunc(logtxt text) RETURNS void AS $$
- DECLARE
- curtime timestamp := now();
- BEGIN
- INSERT INTO logtable VALUES (logtxt, curtime);
- END;
-$$ LANGUAGE plpgsql;
-
- The INSERT> statement will effectively be processed as
-PREPARE statement_name>(text, timestamp) AS
- INSERT INTO logtable VALUES ($1, $2);
+ INSERT INTO foo (foo) VALUES (foo);
- followed on each execution by EXECUTE> with the current
- actual values of the two variables. (Note: here we are speaking of
- the main SQL engine's
- command,
- not
PL/pgSQL's
EXECUTE>.)
+ The first occurrence of foo> must syntactically be a table
+ name, so it will not be substituted, even if the function has a variable
+ named foo>. The second occurrence must be the name of a
+ column of the table, so it will not be substituted either. Only the
+ third occurrence is a candidate to be a reference to the function's
+ variable.
+
+
PostgreSQL versions before 8.5 would try
+ to substitute the variable in all three cases, leading to syntax errors.
+
+
+
- The substitution mechanism will replace any token that matches 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
- that you need to reference in queries within the function, because
- what you think is a table or column name will still get replaced.
- In the above example, suppose that logtable> has
- column names logtxt> and logtime>,
- and we try to write the INSERT> as
- INSERT INTO logtable (logtxt, logtime) VALUES (logtxt, curtime);
-
- This will be fed to the main SQL parser as
+ Since the names of variables are syntactically no different from the names
+ of table columns, there can be ambiguity in statements that also refer to
+ tables: is a given name meant to refer to a table column, or a variable?
+ Let's change the previous example to
- INSERT INTO logtable ($1, logtime) VALUES ($1, $2);
+ INSERT INTO dest (col) SELECT foo + bar FROM src;
- resulting in a syntax error like this:
-
-ERROR: syntax error at or near "$1"
-LINE 1: INSERT INTO logtable ( $1 , logtime) VALUES ( $1 , $2 )
- ^
-QUERY: INSERT INTO logtable ( $1 , logtime) VALUES ( $1 , $2 )
-CONTEXT: SQL statement in PL/PgSQL function "logfunc2" near line 5
-
+ Here, dest> and src> must be table names, and
+ col> must be a column of dest>, but foo>
+ and bar> might reasonably be either variables of the function
+ or columns of src>.
- This example is fairly easy to diagnose, since it leads to an
- obvious syntax error. Much nastier are cases where the substitution
- is syntactically permissible, since the only symptom may be misbehavior
- of the function. In one case, a user wrote something like this:
- DECLARE
- val text;
- search_key integer;
- BEGIN
- ...
- FOR val IN SELECT val FROM table WHERE key = search_key LOOP ...
-
- and wondered why all his table entries seemed to be NULL. Of course
- what happened here was that the query became
- SELECT $1 FROM table WHERE key = $2
-
- and thus it was just an expensive way of assigning val>'s
- current value back to itself for each row.
+ By default,
PL/pgSQL> will report an error if a name
+ in a SQL statement could refer to either a variable or a table column.
+ You can fix such a problem by renaming the variable or column,
+ or by qualifying the ambiguous reference, or by telling
+
PL/pgSQL> which interpretation to prefer.
- A commonly used coding rule for avoiding such traps is to use a
+ The simplest solution is to rename the variable or column.
+ A common coding rule is to use a
different naming convention for
PL/pgSQL
- variables than you use for table and column names. For example,
- if all your variables are named
+ variables than you use for column names. For example,
+ if you consistently name function variables
v_something> while none of your
- table or column names start with v_>, you're pretty safe.
+ column names start with v_>, no conflicts will occur.
- Another workaround is to use qualified (dotted) names for SQL entities.
- For instance we could safely have written the above example as
+ Alternatively you can qualify ambiguous references to make them clear.
+ In the above example, src.foo> would be an unambiguous reference
+ to the table column. To create an unambiguous reference to a variable,
+ declare it in a labeled block and use the block's label
+ (see ). For example,
- FOR val IN SELECT table.val FROM table WHERE key = search_key LOOP ...
+ <<block>>
+ DECLARE
+ foo int;
+ BEGIN
+ foo := ...;
+ INSERT INTO dest (col) SELECT block.foo + bar FROM src;
- because
PL/pgSQL will not substitute a
- variable for a trailing component of a qualified name.
- However this solution does not work in every case — you can't
- qualify a name in an INSERT>'s column name list, for instance.
- Another point is that record and row variable names will be matched to
- the first components of qualified names, so a qualified SQL name is
- still vulnerable in some cases.
- In such cases choosing a non-conflicting variable name is the only way.
+ Here block.foo> means the variable even if there is a column
+ foo> in src>. Function parameters, as well as
+ special variables such as FOUND>, can be qualified by the
+ function's name, because they are implicitly declared in an outer block
+ labeled with the function's name.
- Another technique you can use is to attach a label to the block in
- which your variables are declared, and then qualify the variable names
- in your SQL commands (see ).
- For example,
+ Sometimes it is impractical to fix all the ambiguous references in a
+ large body of
PL/pgSQL> code. In such cases you can
+ specify that
PL/pgSQL> should resolve ambiguous references
+ as the variable (which is compatible with
PL/pgSQL>'s
+ behavior before
PostgreSQL 8.5), or as the
+ table column (which is compatible with some other systems such as
+
+
+
+
plpgsql.variable_conflict> configuration parameter
+
+
+ To change this behavior on a system-wide basis, set the configuration
+ parameter plpgsql.variable_conflict> to one of
+ error>, use_variable>, or
+ use_column> (where error> is the factory default).
+ This parameter affects subsequent compilations
+ of statements in
PL/pgSQL> functions, but not statements
+ already compiled in the current session. To set the parameter before
+
PL/pgSQL> has been loaded, it is necessary to have added
+
plpgsql>> to the
+ linkend="guc-custom-variable-classes"> list in
+ postgresql.conf. Because changing this setting
+ can cause unexpected changes in the behavior of
PL/pgSQL>
+ functions, it can only be changed by a superuser.
+
+
+ You can also set the behavior on a function-by-function basis, by
+ inserting one of these special commands at the start of the function
+ text:
+#variable_conflict error
+#variable_conflict use_variable
+#variable_conflict use_column
+
+ These commands affect only the function they are written in, and override
+ the setting of plpgsql.variable_conflict>. An example is
- <<pl>>
+CREATE FUNCTION stamp_user(id int, comment text) RETURNS void AS $$
+ #variable_conflict use_variable
DECLARE
- val text;
+ curtime timestamp := now();
BEGIN
- ...
- UPDATE table SET col = pl.val WHERE ...
+ UPDATE users SET last_modified = curtime, comment = comment
+ WHERE users.id = id;
+ END;
+$$ LANGUAGE plpgsql;
+
+ In the UPDATE> command, curtime>, comment>,
+ and id> will refer to the function's variable and parameters
+ whether or not users> has columns of those names. Notice
+ that we had to qualify the reference to users.id> in the
+ WHERE> clause to make it refer to the table column.
+ But we did not have to qualify the reference to comment>
+ as a target in the UPDATE> list, because syntactically
+ that must be a column of users>. We could write the same
+ function without depending on the variable_conflict> setting
+ in this way:
+CREATE FUNCTION stamp_user(id int, comment text) RETURNS void AS $$
+ <<fn>>
+ DECLARE
+ curtime timestamp := now();
+ BEGIN
+ UPDATE users SET last_modified = fn.curtime, comment = stamp_user.comment
+ WHERE users.id = stamp_user.id;
+ END;
+$$ LANGUAGE plpgsql;
- This is not in itself a solution to the problem of conflicts,
- since an unqualified name in a SQL command is still at risk of being
- interpreted the wrong> way. But it is useful for clarifying
- the intent of potentially-ambiguous code.
Variable substitution does not happen in the command string given
to 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
+ constructing the string value, or use USING>, as illustrated in
.
Variable substitution currently works only in SELECT>,
INSERT>, UPDATE>, and DELETE> commands,
- because the main SQL engine allows parameter symbols only in these
+ because the main SQL engine allows query parameters only in these
commands. To use a non-constant name or value in other statement
types (generically called utility statements), you must construct
the utility statement as a string and EXECUTE> it.
- Once
PL/pgSQL> has made an execution plan for a particular
- command in a function, it will reuse that plan for the life of the
- database connection. This is usually a win for performance, but it
- can cause some problems if you dynamically
- alter your database schema. For example:
-
-CREATE FUNCTION populate() RETURNS integer AS $$
-DECLARE
- -- declarations
-BEGIN
- PERFORM my_function();
-END;
-$$ LANGUAGE plpgsql;
-
-
- If you execute the above function, it will reference the OID for
- my_function() in the execution plan produced for
- the PERFORM statement. Later, if you
- drop and recreate my_function(), then
- populate() will not be able to find
- my_function() anymore. You would then have to
- start a new database session so that populate()
- will be compiled afresh, before it will work again. You can avoid
- this problem by using CREATE OR REPLACE FUNCTION
- when updating the definition of
- my_function, since when a function is
- replaced
, its OID is not changed.
+ A saved plan will be re-planned automatically if there is any schema
+ change to any table used in the query, or if any user-defined function
+ used in the query is redefined. This makes the re-use of prepared plans
+ transparent in most cases, but there are corner cases where a stale plan
+ might be re-used. An example is that dropping and re-creating a
+ user-defined operator won't affect already-cached plans; they'll continue
+ to call the original operator's underlying function, if that has not been
+ changed. When necessary, the cache can be flushed by starting a fresh
+ database session.
-
- In
PostgreSQL 8.3 and later, saved plans
- will be replaced whenever any schema changes have occurred to any
- tables they reference. This eliminates one of the major disadvantages
- of saved plans. However, there is no such mechanism for function
- references, and thus the above example involving a reference to a
- deleted function is still valid.
-
-
-
Because
PL/pgSQL saves execution plans
in this way, SQL commands that appear directly in a
-
- There are no default values for parameters in
PostgreSQL>.
-
-
-
-
- You can overload function names in
PostgreSQL>. This is
- often used to work around the lack of default parameters.
-
-
-
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,
-
PL/SQL> treats it as a column name, while
-
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 .)
+
PL/SQL> treats it as a column name. This corresponds
+ plpgsql.variable_conflict> = use_column>
+ behavior, which is not the default,
+ as explained in .
+ It's often best to avoid such ambiguities in the first place,
+ but if you have to port a large amount of code that depends on
+ this behavior, setting variable_conflict> may be the
+ best solution.
The exception names supported by
PL/pgSQL> are
different from Oracle's. The set of built-in exception names
is much larger (see ). There
- is not currently a way to declare user-defined exception names.
+ is not currently a way to declare user-defined exception names,
+ although you can throw user-chosen SQLSTATE values instead.
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.135 2009/11/12 00:13:00 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.136 2009/11/13 22:43:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
%token K_ELSIF
%token K_END
%token K_ERRCODE
+%token K_ERROR
%token K_EXCEPTION
%token K_EXECUTE
%token K_EXIT
%token K_THEN
%token K_TO
%token K_TYPE
+%token K_USE_COLUMN
+%token K_USE_VARIABLE
%token K_USING
+%token K_VARIABLE_CONFLICT
%token K_WARNING
%token K_WHEN
%token K_WHILE
{
plpgsql_DumpExecTree = true;
}
+ | '#' K_VARIABLE_CONFLICT K_ERROR
+ {
+ plpgsql_curr_compile->resolve_option = PLPGSQL_RESOLVE_ERROR;
+ }
+ | '#' K_VARIABLE_CONFLICT K_USE_VARIABLE
+ {
+ plpgsql_curr_compile->resolve_option = PLPGSQL_RESOLVE_VARIABLE;
+ }
+ | '#' K_VARIABLE_CONFLICT K_USE_COLUMN
+ {
+ plpgsql_curr_compile->resolve_option = PLPGSQL_RESOLVE_COLUMN;
+ }
;
opt_semi :
| K_DETAIL
| K_DUMP
| K_ERRCODE
+ | K_ERROR
| K_FIRST
| K_FORWARD
| K_HINT
| K_SCROLL
| K_SQLSTATE
| K_TYPE
+ | K_USE_COLUMN
+ | K_USE_VARIABLE
+ | K_VARIABLE_CONFLICT
| K_WARNING
;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.145 2009/11/12 00:13:00 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.146 2009/11/13 22:43:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
function->fn_is_trigger = is_trigger;
function->fn_cxt = func_cxt;
function->out_param_varno = -1; /* set up for no OUT param */
- function->resolve_option = PLPGSQL_RESOLVE_BEFORE;
+ function->resolve_option = plpgsql_variable_conflict;
/*
* Initialize the compiler, particularly the namespace stack. The
function->fn_is_trigger = false;
function->fn_cxt = func_cxt;
function->out_param_varno = -1; /* set up for no OUT param */
- function->resolve_option = PLPGSQL_RESOLVE_BEFORE;
+ function->resolve_option = plpgsql_variable_conflict;
plpgsql_ns_init();
plpgsql_ns_push(func_name);
{
PLpgSQL_expr *expr = (PLpgSQL_expr *) pstate->p_ref_hook_state;
- if (expr->func->resolve_option == PLPGSQL_RESOLVE_BEFORE)
+ if (expr->func->resolve_option == PLPGSQL_RESOLVE_VARIABLE)
return resolve_column_ref(expr, cref);
else
return NULL;
PLpgSQL_expr *expr = (PLpgSQL_expr *) pstate->p_ref_hook_state;
Node *myvar;
- if (expr->func->resolve_option == PLPGSQL_RESOLVE_BEFORE)
+ if (expr->func->resolve_option == PLPGSQL_RESOLVE_VARIABLE)
return NULL; /* we already found there's no match */
- if (expr->func->resolve_option == PLPGSQL_RESOLVE_AFTER && var != NULL)
+ if (expr->func->resolve_option == PLPGSQL_RESOLVE_COLUMN && var != NULL)
return NULL; /* there's a table column, prefer that */
myvar = resolve_column_ref(expr, cref);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.47 2009/11/04 22:26:07 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.48 2009/11/13 22:43:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
PG_MODULE_MAGIC;
+/* Custom GUC variable */
+static const struct config_enum_entry variable_conflict_options[] = {
+ {"error", PLPGSQL_RESOLVE_ERROR, false},
+ {"use_variable", PLPGSQL_RESOLVE_VARIABLE, false},
+ {"use_column", PLPGSQL_RESOLVE_COLUMN, false},
+ {NULL, 0, false}
+};
+
+int plpgsql_variable_conflict = PLPGSQL_RESOLVE_ERROR;
+
+/* Hook for plugins */
PLpgSQL_plugin **plugin_ptr = NULL;
pg_bindtextdomain(TEXTDOMAIN);
+ DefineCustomEnumVariable("plpgsql.variable_conflict",
+ gettext_noop("Sets handling of conflicts between PL/pgSQL variable names and table column names."),
+ NULL,
+ &plpgsql_variable_conflict,
+ PLPGSQL_RESOLVE_ERROR,
+ variable_conflict_options,
+ PGC_SUSET, 0,
+ NULL, NULL);
+
+ EmitWarningsOnPlaceholders("plpgsql");
+
plpgsql_HashTableInit();
RegisterXactCallback(plpgsql_xact_cb, NULL);
RegisterSubXactCallback(plpgsql_subxact_cb, NULL);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_scanner.c,v 1.1 2009/11/12 00:13:00 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_scanner.c,v 1.2 2009/11/13 22:43:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
PG_KEYWORD("detail", K_DETAIL, UNRESERVED_KEYWORD)
PG_KEYWORD("dump", K_DUMP, UNRESERVED_KEYWORD)
PG_KEYWORD("errcode", K_ERRCODE, UNRESERVED_KEYWORD)
+ PG_KEYWORD("error", K_ERROR, UNRESERVED_KEYWORD)
PG_KEYWORD("first", K_FIRST, UNRESERVED_KEYWORD)
PG_KEYWORD("forward", K_FORWARD, UNRESERVED_KEYWORD)
PG_KEYWORD("hint", K_HINT, UNRESERVED_KEYWORD)
PG_KEYWORD("scroll", K_SCROLL, UNRESERVED_KEYWORD)
PG_KEYWORD("sqlstate", K_SQLSTATE, UNRESERVED_KEYWORD)
PG_KEYWORD("type", K_TYPE, UNRESERVED_KEYWORD)
+ PG_KEYWORD("use_column", K_USE_COLUMN, UNRESERVED_KEYWORD)
+ PG_KEYWORD("use_variable", K_USE_VARIABLE, UNRESERVED_KEYWORD)
+ PG_KEYWORD("variable_conflict", K_VARIABLE_CONFLICT, UNRESERVED_KEYWORD)
PG_KEYWORD("warning", K_WARNING, UNRESERVED_KEYWORD)
};
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.124 2009/11/12 00:13:00 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.125 2009/11/13 22:43:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
typedef enum
{
- PLPGSQL_RESOLVE_BEFORE, /* prefer plpgsql var to table column */
- PLPGSQL_RESOLVE_AFTER, /* prefer table column to plpgsql var */
- PLPGSQL_RESOLVE_ERROR /* throw error if ambiguous */
+ PLPGSQL_RESOLVE_ERROR, /* throw error if ambiguous */
+ PLPGSQL_RESOLVE_VARIABLE, /* prefer plpgsql var to table column */
+ PLPGSQL_RESOLVE_COLUMN /* prefer table column to plpgsql var */
} PLpgSQL_resolve_option;
* Global variable declarations
**********************************************************************/
+extern int plpgsql_variable_conflict;
+
extern bool plpgsql_check_syntax;
extern bool plpgsql_DumpExecTree;
extern bool plpgsql_LookupIdentifiers;
drop function scope_test();
-- Check handling of conflicts between plpgsql vars and table columns.
+set plpgsql.variable_conflict = error;
create function conflict_test() returns setof int8_tbl as $$
declare r record;
q1 bigint := 42;
end loop;
end;
$$ language plpgsql;
+select * from conflict_test();
+ERROR: column reference "q1" is ambiguous
+LINE 1: select q1,q2 from int8_tbl
+ ^
+DETAIL: It could refer to either a PL/pgSQL variable or a table column.
+QUERY: select q1,q2 from int8_tbl
+CONTEXT: PL/pgSQL function "conflict_test" line 4 at FOR over SELECT rows
+create or replace function conflict_test() returns setof int8_tbl as $$
+#variable_conflict use_variable
+declare r record;
+ q1 bigint := 42;
+begin
+ for r in select q1,q2 from int8_tbl loop
+ return next r;
+ end loop;
+end;
+$$ language plpgsql;
select * from conflict_test();
q1 | q2
----+-------------------
42 | -4567890123456789
(5 rows)
+create or replace function conflict_test() returns setof int8_tbl as $$
+#variable_conflict use_column
+declare r record;
+ q1 bigint := 42;
+begin
+ for r in select q1,q2 from int8_tbl loop
+ return next r;
+ end loop;
+end;
+$$ language plpgsql;
+select * from conflict_test();
+ q1 | q2
+------------------+-------------------
+ 123 | 456
+ 123 | 4567890123456789
+ 4567890123456789 | 123
+ 4567890123456789 | 4567890123456789
+ 4567890123456789 | -4567890123456789
+(5 rows)
+
drop function conflict_test();
-- Check that an unreserved keyword can be used as a variable name
create function unreserved_test() returns int as $$
-- Check handling of conflicts between plpgsql vars and table columns.
+set plpgsql.variable_conflict = error;
+
create function conflict_test() returns setof int8_tbl as $$
declare r record;
q1 bigint := 42;
select * from conflict_test();
+create or replace function conflict_test() returns setof int8_tbl as $$
+#variable_conflict use_variable
+declare r record;
+ q1 bigint := 42;
+begin
+ for r in select q1,q2 from int8_tbl loop
+ return next r;
+ end loop;
+end;
+$$ language plpgsql;
+
+select * from conflict_test();
+
+create or replace function conflict_test() returns setof int8_tbl as $$
+#variable_conflict use_column
+declare r record;
+ q1 bigint := 42;
+begin
+ for r in select q1,q2 from int8_tbl loop
+ return next r;
+ end loop;
+end;
+$$ language plpgsql;
+
+select * from conflict_test();
+
drop function conflict_test();
-- Check that an unreserved keyword can be used as a variable name