aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/pl/plpgsql/src/gram.y22
-rw-r--r--src/pl/plpgsql/src/pl_comp.c12
-rw-r--r--src/pl/plpgsql/src/pl_handler.c24
-rw-r--r--src/pl/plpgsql/src/pl_scanner.c6
-rw-r--r--src/pl/plpgsql/src/plpgsql.h10
-rw-r--r--src/test/regress/expected/plpgsql.out38
-rw-r--r--src/test/regress/sql/plpgsql.sql28
7 files changed, 127 insertions, 13 deletions
diff --git a/src/pl/plpgsql/src/gram.y b/src/pl/plpgsql/src/gram.y
index 6edd01c4d8d..08d7b9162d3 100644
--- a/src/pl/plpgsql/src/gram.y
+++ b/src/pl/plpgsql/src/gram.y
@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@@ -256,6 +256,7 @@ static List *read_raise_options(void);
%token <keyword> K_ELSIF
%token <keyword> K_END
%token <keyword> K_ERRCODE
+%token <keyword> K_ERROR
%token <keyword> K_EXCEPTION
%token <keyword> K_EXECUTE
%token <keyword> K_EXIT
@@ -301,7 +302,10 @@ static List *read_raise_options(void);
%token <keyword> K_THEN
%token <keyword> K_TO
%token <keyword> K_TYPE
+%token <keyword> K_USE_COLUMN
+%token <keyword> K_USE_VARIABLE
%token <keyword> K_USING
+%token <keyword> K_VARIABLE_CONFLICT
%token <keyword> K_WARNING
%token <keyword> K_WHEN
%token <keyword> K_WHILE
@@ -322,6 +326,18 @@ comp_option : '#' K_OPTION K_DUMP
{
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 :
@@ -1969,6 +1985,7 @@ unreserved_keyword :
| K_DETAIL
| K_DUMP
| K_ERRCODE
+ | K_ERROR
| K_FIRST
| K_FORWARD
| K_HINT
@@ -1991,6 +2008,9 @@ unreserved_keyword :
| K_SCROLL
| K_SQLSTATE
| K_TYPE
+ | K_USE_COLUMN
+ | K_USE_VARIABLE
+ | K_VARIABLE_CONFLICT
| K_WARNING
;
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index bc0cde6c767..6cfc5195fac 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@@ -351,7 +351,7 @@ do_compile(FunctionCallInfo fcinfo,
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
@@ -782,7 +782,7 @@ plpgsql_compile_inline(char *proc_source)
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);
@@ -948,7 +948,7 @@ plpgsql_pre_column_ref(ParseState *pstate, ColumnRef *cref)
{
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;
@@ -963,10 +963,10 @@ plpgsql_post_column_ref(ParseState *pstate, ColumnRef *cref, Node *var)
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);
diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c
index 7741308f287..4bd03298686 100644
--- a/src/pl/plpgsql/src/pl_handler.c
+++ b/src/pl/plpgsql/src/pl_handler.c
@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@@ -26,6 +26,17 @@
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;
@@ -45,6 +56,17 @@ _PG_init(void)
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);
diff --git a/src/pl/plpgsql/src/pl_scanner.c b/src/pl/plpgsql/src/pl_scanner.c
index 523a0952cb1..fb4abc1454f 100644
--- a/src/pl/plpgsql/src/pl_scanner.c
+++ b/src/pl/plpgsql/src/pl_scanner.c
@@ -9,7 +9,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@@ -113,6 +113,7 @@ static const ScanKeyword unreserved_keywords[] = {
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)
@@ -135,6 +136,9 @@ static const ScanKeyword unreserved_keywords[] = {
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)
};
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index 1c05f5d4c2f..25d1c036999 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@@ -147,9 +147,9 @@ enum
*/
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;
@@ -794,6 +794,8 @@ typedef struct
* Global variable declarations
**********************************************************************/
+extern int plpgsql_variable_conflict;
+
extern bool plpgsql_check_syntax;
extern bool plpgsql_DumpExecTree;
extern bool plpgsql_LookupIdentifiers;
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index 877ed329a67..e126f616fe1 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -4004,6 +4004,7 @@ select scope_test();
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;
@@ -4014,6 +4015,23 @@ begin
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 | 456
@@ -4023,6 +4041,26 @@ select * from conflict_test();
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 $$
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index f0a77469d92..79756f6a01c 100644
--- a/src/test/regress/sql/plpgsql.sql
+++ b/src/test/regress/sql/plpgsql.sql
@@ -3176,6 +3176,8 @@ 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;
@@ -3188,6 +3190,32 @@ $$ language plpgsql;
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