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);