*** a/src/pl/plpgsql/src/pl_comp.c --- b/src/pl/plpgsql/src/pl_comp.c *************** *** 352,357 **** do_compile(FunctionCallInfo fcinfo, --- 352,358 ---- function->out_param_varno = -1; /* set up for no OUT param */ function->resolve_option = plpgsql_variable_conflict; function->print_strict_params = plpgsql_print_strict_params; + function->warn_shadow = plpgsql_warn_shadow; if (is_dml_trigger) function->fn_is_trigger = PLPGSQL_DML_TRIGGER; *** a/src/pl/plpgsql/src/pl_gram.y --- b/src/pl/plpgsql/src/pl_gram.y *************** *** 335,340 **** static List *read_raise_options(void); --- 335,341 ---- %token K_USE_VARIABLE %token K_USING %token K_VARIABLE_CONFLICT + %token K_WARN_SHADOW %token K_WARNING %token K_WHEN %token K_WHILE *************** *** 364,369 **** comp_option : '#' K_OPTION K_DUMP --- 365,379 ---- else elog(ERROR, "unrecognized print_strict_params option %s", $3); } + | '#' K_WARN_SHADOW option_value + { + if (strcmp($3, "on") == 0) + plpgsql_curr_compile->warn_shadow = true; + else if (strcmp($3, "off") == 0) + plpgsql_curr_compile->warn_shadow = false; + else + elog(ERROR, "unrecognized warn_shadow option %s", $3); + } | '#' K_VARIABLE_CONFLICT K_ERROR { plpgsql_curr_compile->resolve_option = PLPGSQL_RESOLVE_ERROR; *************** *** 727,732 **** decl_varname : T_WORD --- 737,754 ---- $1.ident, NULL, NULL, NULL) != NULL) yyerror("duplicate declaration"); + if (plpgsql_curr_compile->warn_shadow) + { + PLpgSQL_nsitem *nsi; + nsi = plpgsql_ns_lookup(plpgsql_ns_top(), false, + $1.ident, NULL, NULL, NULL); + if (nsi != NULL) + ereport(WARNING, + (errcode(ERRCODE_DUPLICATE_ALIAS), + errmsg("variable \"%s\" shadows a previously defined variable", + $1.ident), + parser_errposition(@1))); + } } | unreserved_keyword { *************** *** 740,745 **** decl_varname : T_WORD --- 762,779 ---- $1, NULL, NULL, NULL) != NULL) yyerror("duplicate declaration"); + if (plpgsql_curr_compile->warn_shadow) + { + PLpgSQL_nsitem *nsi; + nsi = plpgsql_ns_lookup(plpgsql_ns_top(), false, + $1, NULL, NULL, NULL); + if (nsi != NULL) + ereport(WARNING, + (errcode(ERRCODE_DUPLICATE_ALIAS), + errmsg("variable \"%s\" shadows a previously defined variable", + $1), + parser_errposition(@1))); + } } ; *** a/src/pl/plpgsql/src/pl_handler.c --- b/src/pl/plpgsql/src/pl_handler.c *************** *** 38,43 **** static const struct config_enum_entry variable_conflict_options[] = { --- 38,44 ---- int plpgsql_variable_conflict = PLPGSQL_RESOLVE_ERROR; bool plpgsql_print_strict_params = false; + bool plpgsql_warn_shadow = false; /* Hook for plugins */ PLpgSQL_plugin **plugin_ptr = NULL; *************** *** 76,81 **** _PG_init(void) --- 77,90 ---- PGC_USERSET, 0, NULL, NULL, NULL); + DefineCustomBoolVariable("plpgsql.warn_shadow", + gettext_noop("Display a warning when a variable declaration shadows another variable."), + NULL, + &plpgsql_warn_shadow, + false, + PGC_USERSET, 0, + NULL, NULL, NULL); + EmitWarningsOnPlaceholders("plpgsql"); plpgsql_HashTableInit(); *** a/src/pl/plpgsql/src/pl_scanner.c --- b/src/pl/plpgsql/src/pl_scanner.c *************** *** 161,166 **** static const ScanKeyword unreserved_keywords[] = { --- 161,167 ---- 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("warn_shadow", K_WARN_SHADOW, UNRESERVED_KEYWORD) PG_KEYWORD("warning", K_WARNING, UNRESERVED_KEYWORD) }; *** a/src/pl/plpgsql/src/plpgsql.h --- b/src/pl/plpgsql/src/plpgsql.h *************** *** 738,743 **** typedef struct PLpgSQL_function --- 738,744 ---- PLpgSQL_resolve_option resolve_option; bool print_strict_params; + bool warn_shadow; int ndatums; PLpgSQL_datum **datums; *************** *** 880,885 **** extern IdentifierLookup plpgsql_IdentifierLookup; --- 881,887 ---- extern int plpgsql_variable_conflict; extern bool plpgsql_print_strict_params; + extern bool plpgsql_warn_shadow; extern bool plpgsql_check_syntax; extern bool plpgsql_DumpExecTree; *** a/src/test/regress/sql/plpgsql.sql --- b/src/test/regress/sql/plpgsql.sql *************** *** 2689,2694 **** end$$ language plpgsql; --- 2689,2715 ---- select footest(); + -- test warnings when shadowing a variable + + set plpgsql.warn_shadow to true; + + create function test(in1 int, in2 int) + returns table(out1 int, out2 int) as $$ + declare + IN1 text; + IN2 text; + out1 text; + begin + + declare + out2 text; + in1 text; + begin + end; + end$$ language plpgsql; + + reset plpgsql.warn_shadow; + -- test scrollable cursor support create function sc_test() returns setof integer as $$