diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/pl/plpgsql/src/gram.y | 22 | ||||
-rw-r--r-- | src/pl/plpgsql/src/pl_comp.c | 12 | ||||
-rw-r--r-- | src/pl/plpgsql/src/pl_handler.c | 24 | ||||
-rw-r--r-- | src/pl/plpgsql/src/pl_scanner.c | 6 | ||||
-rw-r--r-- | src/pl/plpgsql/src/plpgsql.h | 10 | ||||
-rw-r--r-- | src/test/regress/expected/plpgsql.out | 38 | ||||
-rw-r--r-- | src/test/regress/sql/plpgsql.sql | 28 |
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 |