Hi plpgsql generate lot of auto variables - FOUND, SQLERRM, cycle's control variable, TG_WHEN, TG_OP, ..
Currently these variables are not protected, what can be source of problems, mainly for not experienced users. I propose mark these variables as constant. -- today postgres=# do $$ begin for i in 1..10 loop raise notice 'i=%', i; i := 20; end loop; end; $$; NOTICE: i=1 NOTICE: i=2 NOTICE: i=3 NOTICE: i=4 NOTICE: i=5 NOTICE: i=6 NOTICE: i=7 NOTICE: i=8 NOTICE: i=9 NOTICE: i=10 DO -- after patch postgres=# do $$ begin for i in 1..10 loop raise notice 'i=%', i; i := 20; end loop; end; $$; ERROR: variable "i" is declared CONSTANT LINE 1: ... begin for i in 1..10 loop raise notice 'i=%', i; i := 20; e... These variables are protected in PL/SQL too. Comments, notes? Regards Pavel p.s. this is simple implementation - just for function demo. Maybe can be better to introduce new plpgsql_variable's flag like is_protected or similar than using isconst.
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 828ff5a288..a9b597810b 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -443,7 +443,7 @@ do_compile(FunctionCallInfo fcinfo, argvariable = plpgsql_build_variable((argnames && argnames[i][0] != '\0') ? argnames[i] : buf, - 0, argdtype, false); + 0, argdtype, false, false); if (argvariable->dtype == PLPGSQL_DTYPE_VAR) { @@ -579,7 +579,7 @@ do_compile(FunctionCallInfo fcinfo, -1, function->fn_input_collation, NULL), - true); + true, true); } ReleaseSysCache(typeTup); @@ -614,7 +614,7 @@ do_compile(FunctionCallInfo fcinfo, -1, function->fn_input_collation, NULL), - true); + true, true); Assert(var->dtype == PLPGSQL_DTYPE_VAR); var->dtype = PLPGSQL_DTYPE_PROMISE; ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_NAME; @@ -625,7 +625,7 @@ do_compile(FunctionCallInfo fcinfo, -1, function->fn_input_collation, NULL), - true); + true, true); Assert(var->dtype == PLPGSQL_DTYPE_VAR); var->dtype = PLPGSQL_DTYPE_PROMISE; ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_WHEN; @@ -636,7 +636,7 @@ do_compile(FunctionCallInfo fcinfo, -1, function->fn_input_collation, NULL), - true); + true, true); Assert(var->dtype == PLPGSQL_DTYPE_VAR); var->dtype = PLPGSQL_DTYPE_PROMISE; ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_LEVEL; @@ -647,7 +647,7 @@ do_compile(FunctionCallInfo fcinfo, -1, function->fn_input_collation, NULL), - true); + true, true); Assert(var->dtype == PLPGSQL_DTYPE_VAR); var->dtype = PLPGSQL_DTYPE_PROMISE; ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_OP; @@ -658,7 +658,7 @@ do_compile(FunctionCallInfo fcinfo, -1, InvalidOid, NULL), - true); + true, true); Assert(var->dtype == PLPGSQL_DTYPE_VAR); var->dtype = PLPGSQL_DTYPE_PROMISE; ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_RELID; @@ -669,7 +669,7 @@ do_compile(FunctionCallInfo fcinfo, -1, function->fn_input_collation, NULL), - true); + true, true); Assert(var->dtype == PLPGSQL_DTYPE_VAR); var->dtype = PLPGSQL_DTYPE_PROMISE; ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_TABLE_NAME; @@ -680,7 +680,7 @@ do_compile(FunctionCallInfo fcinfo, -1, function->fn_input_collation, NULL), - true); + true, true); Assert(var->dtype == PLPGSQL_DTYPE_VAR); var->dtype = PLPGSQL_DTYPE_PROMISE; ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_TABLE_NAME; @@ -691,7 +691,7 @@ do_compile(FunctionCallInfo fcinfo, -1, function->fn_input_collation, NULL), - true); + true, true); Assert(var->dtype == PLPGSQL_DTYPE_VAR); var->dtype = PLPGSQL_DTYPE_PROMISE; ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_TABLE_SCHEMA; @@ -702,7 +702,7 @@ do_compile(FunctionCallInfo fcinfo, -1, InvalidOid, NULL), - true); + true, true); Assert(var->dtype == PLPGSQL_DTYPE_VAR); var->dtype = PLPGSQL_DTYPE_PROMISE; ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_NARGS; @@ -713,7 +713,7 @@ do_compile(FunctionCallInfo fcinfo, -1, function->fn_input_collation, NULL), - true); + true, true); Assert(var->dtype == PLPGSQL_DTYPE_VAR); var->dtype = PLPGSQL_DTYPE_PROMISE; ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_ARGV; @@ -739,7 +739,7 @@ do_compile(FunctionCallInfo fcinfo, -1, function->fn_input_collation, NULL), - true); + true, true); Assert(var->dtype == PLPGSQL_DTYPE_VAR); var->dtype = PLPGSQL_DTYPE_PROMISE; ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_EVENT; @@ -750,7 +750,7 @@ do_compile(FunctionCallInfo fcinfo, -1, function->fn_input_collation, NULL), - true); + true, true); Assert(var->dtype == PLPGSQL_DTYPE_VAR); var->dtype = PLPGSQL_DTYPE_PROMISE; ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_TAG; @@ -774,7 +774,7 @@ do_compile(FunctionCallInfo fcinfo, -1, InvalidOid, NULL), - true); + true, true); function->found_varno = var->dno; /* @@ -929,7 +929,7 @@ plpgsql_compile_inline(char *proc_source) -1, InvalidOid, NULL), - true); + true, true); function->found_varno = var->dno; /* @@ -1843,7 +1843,7 @@ plpgsql_parse_cwordrowtype(List *idents) */ PLpgSQL_variable * plpgsql_build_variable(const char *refname, int lineno, PLpgSQL_type *dtype, - bool add2namespace) + bool add2namespace, bool isconst) { PLpgSQL_variable *result; @@ -1898,6 +1898,8 @@ plpgsql_build_variable(const char *refname, int lineno, PLpgSQL_type *dtype, break; } + result->isconst = isconst; + return result; } diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y index 6778d0e771..89a4c07e19 100644 --- a/src/pl/plpgsql/src/pl_gram.y +++ b/src/pl/plpgsql/src/pl_gram.y @@ -513,8 +513,7 @@ decl_statement : decl_varname decl_const decl_datatype decl_collate decl_notnull } var = plpgsql_build_variable($1.name, $1.lineno, - $3, true); - var->isconst = $2; + $3, true, $2); var->notnull = $5; var->default_val = $6; @@ -553,7 +552,7 @@ decl_statement : decl_varname decl_const decl_datatype decl_collate decl_notnull -1, InvalidOid, NULL), - true); + true, false); curname_def = palloc0(sizeof(PLpgSQL_expr)); @@ -655,7 +654,7 @@ decl_cursor_arg : decl_varname decl_datatype { $$ = (PLpgSQL_datum *) plpgsql_build_variable($1.name, $1.lineno, - $2, true); + $2, true, false); } ; @@ -1507,7 +1506,7 @@ for_control : for_variable K_IN -1, InvalidOid, NULL), - true); + true, true); new = palloc0(sizeof(PLpgSQL_stmt_fori)); new->cmd_type = PLPGSQL_STMT_FORI; @@ -2321,7 +2320,7 @@ exception_sect : -1, plpgsql_curr_compile->fn_input_collation, NULL), - true); + true, true); var->isconst = true; new->sqlstate_varno = var->dno; @@ -2330,7 +2329,7 @@ exception_sect : -1, plpgsql_curr_compile->fn_input_collation, NULL), - true); + true, true); var->isconst = true; new->sqlerrm_varno = var->dno; @@ -4089,7 +4088,7 @@ make_case(int location, PLpgSQL_expr *t_expr, -1, InvalidOid, NULL), - true); + true, true); new->t_varno = t_var->dno; foreach(l, case_when_list) diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index 1af2595e34..bfeca5dcf0 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -1254,7 +1254,8 @@ extern PLpgSQL_type *plpgsql_build_datatype(Oid typeOid, int32 typmod, TypeName *origtypname); extern PLpgSQL_variable *plpgsql_build_variable(const char *refname, int lineno, PLpgSQL_type *dtype, - bool add2namespace); + bool add2namespace, + bool isconst); extern PLpgSQL_rec *plpgsql_build_record(const char *refname, int lineno, PLpgSQL_type *dtype, Oid rectypeid, bool add2namespace);