Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 7708899

Browse files
okbob@github.comCommitfest Bot
okbob@github.com
authored and
Commitfest Bot
committed
GUC session_variables_ambiguity_warning
Inside an query the session variables can be shadowed. This behaviour is by design, because this ensuring so new variables doesn't break existing queries. But this behaviour can be confusing, because shadowing is quiet. When new GUC session_variables_ambiguity_warning is on, then the warning is displayed, when some session variable can be used, but it is not used due shadowing. This feature should to help with investigation of unexpected behaviour. Note: PLpgSQL has an option that controls priority of identifier's spaces (SQL or PLpgSQL). Default behaviour doesn't allows collisions. I believe this default is the best. I cannot to implement similar very strict behaviour to session variables, because one unhappy named session variable can breaks an applications. The problems related to badly named PLpgSQL's varible is limitted just to only one routine.
1 parent 4a1db1c commit 7708899

File tree

10 files changed

+241
-4
lines changed

10 files changed

+241
-4
lines changed

doc/src/sgml/config.sgml

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11374,6 +11374,66 @@ dynamic_library_path = '/usr/local/lib/postgresql:$libdir'
1137411374
</listitem>
1137511375
</varlistentry>
1137611376

11377+
<varlistentry id="guc-session-variables-ambiguity-warning" xreflabel="session_variables_ambiguity_warning">
11378+
<term><varname>session_variables_ambiguity_warning</varname> (<type>boolean</type>)
11379+
<indexterm>
11380+
<primary><varname>session_variables_ambiguity_warning</varname> configuration parameter</primary>
11381+
</indexterm>
11382+
</term>
11383+
<listitem>
11384+
<para>
11385+
When on, a warning is raised when any identifier in a query could be
11386+
used as both a column identifier, routine variable or a session
11387+
variable identifier. The default is <literal>off</literal>.
11388+
</para>
11389+
<para>
11390+
Session variables can be shadowed by column references in a query, this
11391+
is an expected behavior. Previously working queries shouldn't error out
11392+
by creating any session variable, so session variables are always shadowed
11393+
if an identifier is ambiguous. Variables should be referenced using
11394+
anunambiguous identifier without any possibility for a collision with
11395+
identifier of other database objects (column names or record fields names).
11396+
The warning messages emitted when enabling <varname>session_variables_ambiguity_warning</varname>
11397+
can help finding such identifier collision.
11398+
<programlisting>
11399+
CREATE TABLE foo(a int);
11400+
INSERT INTO foo VALUES(10);
11401+
CREATE VARIABLE a int;
11402+
LET a = 100;
11403+
SELECT a FROM foo;
11404+
</programlisting>
11405+
11406+
<screen>
11407+
a
11408+
----
11409+
10
11410+
(1 row)
11411+
</screen>
11412+
11413+
<programlisting>
11414+
SET session_variables_ambiguity_warning TO on;
11415+
SELECT a FROM foo;
11416+
</programlisting>
11417+
11418+
<screen>
11419+
WARNING: session variable "a" is shadowed
11420+
LINE 1: SELECT a FROM foo;
11421+
^
11422+
DETAIL: Session variables can be shadowed by columns, routine's variables and routine's arguments with the same name.
11423+
a
11424+
----
11425+
10
11426+
(1 row)
11427+
</screen>
11428+
</para>
11429+
<para>
11430+
This feature can significantly increase log size, so it's disabled by
11431+
default. For testing or development environments it's recommended to
11432+
enable it if you use session variables.
11433+
</para>
11434+
</listitem>
11435+
</varlistentry>
11436+
1137711437
<varlistentry id="guc-standard-conforming-strings" xreflabel="standard_conforming_strings">
1137811438
<term><varname>standard_conforming_strings</varname> (<type>boolean</type>)
1137911439
<indexterm><primary>strings</primary><secondary>standard conforming</secondary></indexterm>

doc/src/sgml/ddl.sgml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5446,6 +5446,17 @@ SELECT name FROM foo;
54465446
Alice
54475447
</programlisting>
54485448
</para>
5449+
5450+
<para>
5451+
When a query contains identifiers or qualified identifiers that could be
5452+
used as both a session variable identifiers and as column identifier,
5453+
then the column identifier is preferred every time. Warnings can be
5454+
emitted when this situation happens by enabling configuration parameter <xref
5455+
linkend="guc-session-variables-ambiguity-warning"/>. User can explicitly
5456+
qualify the source object by syntax <literal>table.column</literal> or
5457+
<literal>schema.variable</literal>. It is strongly recommended to rename
5458+
shadowed variables or use qualified names always.
5459+
</para>
54495460
</sect1>
54505461

54515462
<sect1 id="ddl-others">

src/backend/parser/parse_expr.c

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545

4646
/* GUC parameters */
4747
bool Transform_null_equals = false;
48+
bool session_variables_ambiguity_warning = false;
4849

4950

5051
static Node *transformExprRecurse(ParseState *pstate, Node *expr);
@@ -960,11 +961,51 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
960961
*
961962
* SELECT foo.a, foo.b, foo.c FROM foo;
962963
*
963-
* However, that is very confusing, so we disallow it. We don't try to
964-
* identify a variable if we know that it would be shadowed.
965-
* -----
964+
* However, that is very confusing, so we disallow it.
965+
*
966+
* When session_variables_ambiguity_warning is requested, then we
967+
* need to identify a variable although we know, so this variable
968+
* would be shadowed.
966969
*/
967-
if (!node && !(relname && crerr == CRERR_NO_COLUMN))
970+
if (node || (relname && crerr == CRERR_NO_COLUMN))
971+
{
972+
/*
973+
* In this path we just try (if it is wanted) detect if session
974+
* variable is shadowed.
975+
*/
976+
if (session_variables_ambiguity_warning)
977+
{
978+
/*
979+
* The AccessShareLock is created on related session variable.
980+
* The lock will be kept for the whole transaction.
981+
*/
982+
varid = IdentifyVariable(cref->fields, &attrname, &not_unique, true);
983+
984+
if (OidIsValid(varid))
985+
{
986+
/* this path will ending by WARNING. Unlock variable first */
987+
UnlockDatabaseObject(VariableRelationId, varid, 0, AccessShareLock);
988+
989+
if (node)
990+
ereport(WARNING,
991+
(errcode(ERRCODE_AMBIGUOUS_COLUMN),
992+
errmsg("session variable \"%s\" is shadowed",
993+
NameListToString(cref->fields)),
994+
errdetail("Session variables can be shadowed by columns, routine's variables and routine's arguments with the same name."),
995+
parser_errposition(pstate, cref->location)));
996+
else
997+
/* session variable is shadowed by RTE */
998+
ereport(WARNING,
999+
(errcode(ERRCODE_AMBIGUOUS_COLUMN),
1000+
errmsg("session variable \"%s.%s\" is shadowed",
1001+
get_namespace_name(get_session_variable_namespace(varid)),
1002+
get_session_variable_name(varid)),
1003+
errdetail("Session variables can be shadowed by tables or table's aliases with the same name."),
1004+
parser_errposition(pstate, cref->location)));
1005+
}
1006+
}
1007+
}
1008+
else
9681009
{
9691010
/* takes an AccessShareLock on the session variable */
9701011
varid = IdentifyVariable(cref->fields, &attrname, &not_unique, false);

src/backend/utils/misc/guc_tables.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1644,6 +1644,15 @@ struct config_bool ConfigureNamesBool[] =
16441644
false,
16451645
NULL, NULL, NULL
16461646
},
1647+
{
1648+
{"session_variables_ambiguity_warning", PGC_USERSET, CLIENT_CONN_STATEMENT,
1649+
gettext_noop("Raise a warning when reference to a session variable is ambiguous."),
1650+
NULL
1651+
},
1652+
&session_variables_ambiguity_warning,
1653+
false,
1654+
NULL, NULL, NULL
1655+
},
16471656
{
16481657
{"default_transaction_read_only", PGC_USERSET, CLIENT_CONN_STATEMENT,
16491658
gettext_noop("Sets the default read-only status of new transactions."),

src/backend/utils/misc/postgresql.conf.sample

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,7 @@ autovacuum_worker_slots = 16 # autovacuum worker slots to allocate
760760
#default_transaction_read_only = off
761761
#default_transaction_deferrable = off
762762
#session_replication_role = 'origin'
763+
#session_variables_ambiguity_warning = off
763764
#statement_timeout = 0 # in milliseconds, 0 is disabled
764765
#transaction_timeout = 0 # in milliseconds, 0 is disabled
765766
#lock_timeout = 0 # in milliseconds, 0 is disabled

src/include/parser/parse_expr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
/* GUC parameters */
1919
extern PGDLLIMPORT bool Transform_null_equals;
20+
extern PGDLLIMPORT bool session_variables_ambiguity_warning;
2021

2122
extern Node *transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind);
2223

src/pl/plpgsql/src/expected/plpgsql_session_variable.out

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,39 @@ $$;
354354
NOTICE: session variable is 100
355355
NOTICE: plpgsql variable is 1000
356356
NOTICE: variable is 1000
357+
-- againt with session_variables_ambiguity_warning(on)
358+
SET session_variables_ambiguity_warning TO on;
359+
DO $$
360+
<<myblock>>
361+
DECLARE plpgsql_sv_var1 int;
362+
BEGIN
363+
LET plpgsql_sv_var1 = 100;
364+
365+
-- should be ok without warning
366+
plpgsql_sv_var1 := 1000;
367+
368+
-- should be ok without warning
369+
-- print 100;
370+
RAISE NOTICE 'session variable is %', public.plpgsql_sv_var1;
371+
372+
-- should be ok without warning
373+
-- print 1000
374+
RAISE NOTICE 'plpgsql variable is %', myblock.plpgsql_sv_var1;
375+
376+
-- should to print plpgsql variable with warning
377+
-- print 1000
378+
RAISE NOTICE 'variable is %', plpgsql_sv_var1;
379+
END;
380+
$$;
381+
NOTICE: session variable is 100
382+
NOTICE: plpgsql variable is 1000
383+
WARNING: session variable "plpgsql_sv_var1" is shadowed
384+
LINE 1: plpgsql_sv_var1
385+
^
386+
DETAIL: Session variables can be shadowed by columns, routine's variables and routine's arguments with the same name.
387+
QUERY: plpgsql_sv_var1
388+
NOTICE: variable is 1000
389+
SET session_variables_ambiguity_warning TO off;
357390
DROP VARIABLE plpgsql_sv_var1;
358391
-- the value should not be corrupted
359392
CREATE VARIABLE plpgsql_sv_v text;

src/pl/plpgsql/src/sql/plpgsql_session_variable.sql

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,35 @@ BEGIN
260260
END;
261261
$$;
262262

263+
-- againt with session_variables_ambiguity_warning(on)
264+
265+
SET session_variables_ambiguity_warning TO on;
266+
267+
DO $$
268+
<<myblock>>
269+
DECLARE plpgsql_sv_var1 int;
270+
BEGIN
271+
LET plpgsql_sv_var1 = 100;
272+
273+
-- should be ok without warning
274+
plpgsql_sv_var1 := 1000;
275+
276+
-- should be ok without warning
277+
-- print 100;
278+
RAISE NOTICE 'session variable is %', public.plpgsql_sv_var1;
279+
280+
-- should be ok without warning
281+
-- print 1000
282+
RAISE NOTICE 'plpgsql variable is %', myblock.plpgsql_sv_var1;
283+
284+
-- should to print plpgsql variable with warning
285+
-- print 1000
286+
RAISE NOTICE 'variable is %', plpgsql_sv_var1;
287+
END;
288+
$$;
289+
290+
SET session_variables_ambiguity_warning TO off;
291+
263292
DROP VARIABLE plpgsql_sv_var1;
264293

265294
-- the value should not be corrupted

src/test/regress/expected/session_variables.out

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1524,6 +1524,9 @@ CREATE TABLE vartest_foo(a int, b int);
15241524
INSERT INTO vartest_foo VALUES(10,20), (30,40);
15251525
CREATE VARIABLE var1 AS vartest_foo;
15261526
LET var1 = (100,200);
1527+
-- no variable is shadowed here
1528+
-- no warning expected
1529+
SET session_variables_ambiguity_warning TO on;
15271530
-- should to fail
15281531
SELECT var1.* FROM vartest_foo;
15291532
ERROR: missing FROM-clause entry for table "var1"
@@ -1549,6 +1552,7 @@ SELECT count(var1.*) FROM vartest_foo var1;
15491552
2
15501553
(1 row)
15511554

1555+
SET session_variables_ambiguity_warning TO off;
15521556
SET SEARCH_PATH TO DEFAULT;
15531557
DROP SCHEMA vartest CASCADE;
15541558
NOTICE: drop cascades to 2 other objects
@@ -1943,3 +1947,25 @@ SELECT var1;
19431947
(1 row)
19441948

19451949
DROP VARIABLE var1, var2;
1950+
-- test session_variables_ambiguity_warning
1951+
CREATE SCHEMA xxtab;
1952+
CREATE VARIABLE xxtab.avar int;
1953+
CREATE TABLE public.xxtab(avar int);
1954+
INSERT INTO public.xxtab VALUES(1);
1955+
LET xxtab.avar = 20;
1956+
SET session_variables_ambiguity_warning TO on;
1957+
--- should to raise warning, show 1
1958+
SELECT xxtab.avar FROM public.xxtab;
1959+
WARNING: session variable "xxtab.avar" is shadowed
1960+
LINE 1: SELECT xxtab.avar FROM public.xxtab;
1961+
^
1962+
DETAIL: Session variables can be shadowed by columns, routine's variables and routine's arguments with the same name.
1963+
avar
1964+
------
1965+
1
1966+
(1 row)
1967+
1968+
SET session_variables_ambiguity_warning TO off;
1969+
DROP TABLE public.xxtab;
1970+
DROP SCHEMA xxtab CASCADE;
1971+
NOTICE: drop cascades to session variable xxtab.avar

src/test/regress/sql/session_variables.sql

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,10 @@ INSERT INTO vartest_foo VALUES(10,20), (30,40);
10791079
CREATE VARIABLE var1 AS vartest_foo;
10801080
LET var1 = (100,200);
10811081

1082+
-- no variable is shadowed here
1083+
-- no warning expected
1084+
SET session_variables_ambiguity_warning TO on;
1085+
10821086
-- should to fail
10831087
SELECT var1.* FROM vartest_foo;
10841088

@@ -1091,6 +1095,8 @@ SELECT count(var1.*) FROM vartest_foo;
10911095
-- should be ok
10921096
SELECT count(var1.*) FROM vartest_foo var1;
10931097

1098+
SET session_variables_ambiguity_warning TO off;
1099+
10941100
SET SEARCH_PATH TO DEFAULT;
10951101
DROP SCHEMA vartest CASCADE;
10961102

@@ -1334,3 +1340,23 @@ BEGIN; DROP VARIABLE var1; ROLLBACK;
13341340
SELECT var1;
13351341

13361342
DROP VARIABLE var1, var2;
1343+
1344+
-- test session_variables_ambiguity_warning
1345+
CREATE SCHEMA xxtab;
1346+
1347+
CREATE VARIABLE xxtab.avar int;
1348+
1349+
CREATE TABLE public.xxtab(avar int);
1350+
1351+
INSERT INTO public.xxtab VALUES(1);
1352+
1353+
LET xxtab.avar = 20;
1354+
1355+
SET session_variables_ambiguity_warning TO on;
1356+
--- should to raise warning, show 1
1357+
SELECT xxtab.avar FROM public.xxtab;
1358+
1359+
SET session_variables_ambiguity_warning TO off;
1360+
1361+
DROP TABLE public.xxtab;
1362+
DROP SCHEMA xxtab CASCADE;

0 commit comments

Comments
 (0)