From 478e694e5281a3bf91e44177ce925e6625cb44a5 Mon Sep 17 00:00:00 2001 From: Oskari Saarenmaa Date: Fri, 5 Sep 2014 22:31:22 +0300 Subject: [PATCH] parser: optionally warn about missing AS for column and table aliases Add a new GUC "missing_as_warning" (defaults to false, the previous behavior) to raise a WARNING when a column or table alias is used without the AS keyword. This allows catching some types of errors where another keyword or a comma was missing and a label is being used as an alias instead of something else, for example cases like: SELECT COUNT(*) files; SELECT * FROM files users; SELECT path size FROM files INTO f_path, f_size; --- src/backend/parser/gram.y | 24 +++++ src/backend/utils/misc/guc.c | 11 +++ src/include/parser/parser.h | 2 + src/test/regress/expected/select.out | 170 +++++++++++++++++++++++++++++++++++ src/test/regress/sql/select.sql | 47 ++++++++++ 5 files changed, 254 insertions(+) diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index b46dd7b..06a71dd 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -65,6 +65,10 @@ #include "utils/xml.h" +/* GUCs */ +bool missing_as_warning = false; + + /* * Location tracking support --- simpler than bison's default, since we only * want to track the start position not the end position of each nonterminal. @@ -10119,12 +10123,20 @@ alias_clause: } | ColId '(' name_list ')' { + if (missing_as_warning) + ereport(WARNING, + (errmsg("alias without explicit AS and missing_as_warning enabled"), + parser_errposition(@3))); $$ = makeNode(Alias); $$->aliasname = $1; $$->colnames = $3; } | ColId { + if (missing_as_warning) + ereport(WARNING, + (errmsg("alias without explicit AS and missing_as_warning enabled"), + parser_errposition(@1))); $$ = makeNode(Alias); $$->aliasname = $1; } @@ -10156,6 +10168,10 @@ func_alias_clause: | ColId '(' TableFuncElementList ')' { Alias *a = makeNode(Alias); + if (missing_as_warning) + ereport(WARNING, + (errmsg("alias without explicit AS and missing_as_warning enabled"), + parser_errposition(@1))); a->aliasname = $1; $$ = list_make2(a, $3); } @@ -10244,6 +10260,10 @@ relation_expr_opt_alias: relation_expr %prec UMINUS | relation_expr ColId { Alias *alias = makeNode(Alias); + if (missing_as_warning) + ereport(WARNING, + (errmsg("alias without explicit AS and missing_as_warning enabled"), + parser_errposition(@2))); alias->aliasname = $2; $1->alias = alias; $$ = $1; @@ -12577,6 +12597,10 @@ target_el: a_expr AS ColLabel */ | a_expr IDENT { + if (missing_as_warning) + ereport(WARNING, + (errmsg("alias without explicit AS and missing_as_warning enabled"), + parser_errposition(@2))); $$ = makeNode(ResTarget); $$->name = $2; $$->indirection = NIL; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index af667f5..03b7457 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1398,6 +1398,17 @@ static struct config_bool ConfigureNamesBool[] = }, { + {"missing_as_warning", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS, + gettext_noop("Warn about missing AS for column or table aliases."), + NULL, + GUC_REPORT + }, + &missing_as_warning, + false, + NULL, NULL, NULL + }, + + { {"escape_string_warning", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS, gettext_noop("Warn about backslash escapes in ordinary string literals."), NULL diff --git a/src/include/parser/parser.h b/src/include/parser/parser.h index 8d2068a..b3e8a71 100644 --- a/src/include/parser/parser.h +++ b/src/include/parser/parser.h @@ -30,6 +30,8 @@ extern int backslash_quote; extern bool escape_string_warning; extern PGDLLIMPORT bool standard_conforming_strings; +/* GUC variables in gram.y */ +extern bool missing_as_warning; /* Primary entry point for the raw parsing functions */ extern List *raw_parser(const char *str); diff --git a/src/test/regress/expected/select.out b/src/test/regress/expected/select.out index c376523..8cce371 100644 --- a/src/test/regress/expected/select.out +++ b/src/test/regress/expected/select.out @@ -781,3 +781,173 @@ select * from (values (2),(null),(1)) v(k) where k = k; 1 (2 rows) +-- Test warnings for missing AS for aliases +SET missing_as_warning TO false; +select 1 foo, 2 bar; + foo | bar +-----+----- + 1 | 2 +(1 row) + +select 1 as foo, 2 as bar; + foo | bar +-----+----- + 1 | 2 +(1 row) + +select count(*) foo; + foo +----- + 1 +(1 row) + +select 1 from onek o1 limit 1; + ?column? +---------- + 1 +(1 row) + +select 1 from onek o1, onek o2 limit 1; + ?column? +---------- + 1 +(1 row) + +select 1 from onek as o1, onek as o2 limit 1; + ?column? +---------- + 1 +(1 row) + +select un1 from onek ok (un1) where un1 = 88888888; + un1 +----- +(0 rows) + +select un1 from onek as ok (un1) where un1 = 88888888; + un1 +----- +(0 rows) + +update onek ok set unique1 = -88888888 where unique1 = 88888888; +update onek as ok set unique1 = -88888888 where unique1 = 88888888; +create function func_for_missing_as() returns record language sql as 'select 1::int'; +select * from func_for_missing_as() f (id int); + id +---- + 1 +(1 row) + +select * from func_for_missing_as() as f (id int); + id +---- + 1 +(1 row) + +SET missing_as_warning TO true; +select 1 foo, 2 bar; +WARNING: alias without explicit AS and missing_as_warning enabled +LINE 1: select 1 foo, 2 bar; + ^ +WARNING: alias without explicit AS and missing_as_warning enabled +LINE 1: select 1 foo, 2 bar; + ^ + foo | bar +-----+----- + 1 | 2 +(1 row) + +select 1 as foo, 2 as bar; + foo | bar +-----+----- + 1 | 2 +(1 row) + +select count(*) foo; +WARNING: alias without explicit AS and missing_as_warning enabled +LINE 1: select count(*) foo; + ^ + foo +----- + 1 +(1 row) + +do $$ +declare + i1 int; + i2 int; +begin + select unique1 unique2 FROM onek into i1, i2; + select unique1, unique2 FROM onek into i1, i2; +end; +$$; +WARNING: alias without explicit AS and missing_as_warning enabled +LINE 6: select unique1 unique2 FROM onek into i1, i2; + ^ +WARNING: alias without explicit AS and missing_as_warning enabled +LINE 1: select unique1 unique2 FROM onek + ^ +QUERY: select unique1 unique2 FROM onek +CONTEXT: PL/pgSQL function inline_code_block line 6 at SQL statement +select 1 from onek o1 limit 1; +WARNING: alias without explicit AS and missing_as_warning enabled +LINE 1: select 1 from onek o1 limit 1; + ^ + ?column? +---------- + 1 +(1 row) + +select 1 from onek o1, onek o2 limit 1; +WARNING: alias without explicit AS and missing_as_warning enabled +LINE 1: select 1 from onek o1, onek o2 limit 1; + ^ +WARNING: alias without explicit AS and missing_as_warning enabled +LINE 1: select 1 from onek o1, onek o2 limit 1; + ^ + ?column? +---------- + 1 +(1 row) + +select 1 from onek as o1, onek as o2 limit 1; + ?column? +---------- + 1 +(1 row) + +select un1 from onek ok (un1) where un1 = 88888888; +WARNING: alias without explicit AS and missing_as_warning enabled +LINE 1: select un1 from onek ok (un1) where un1 = 88888888; + ^ + un1 +----- +(0 rows) + +select un1 from onek as ok (un1) where un1 = 88888888; + un1 +----- +(0 rows) + +update onek ok set unique1 = -88888888 where unique1 = 88888888; +WARNING: alias without explicit AS and missing_as_warning enabled +LINE 1: update onek ok set unique1 = -88888888 where unique1 = 88888... + ^ +update onek as ok set unique1 = -88888888 where unique1 = 88888888; +select * from func_for_missing_as() f (id int); +WARNING: alias without explicit AS and missing_as_warning enabled +LINE 1: select * from func_for_missing_as() f (id int); + ^ + id +---- + 1 +(1 row) + +select * from func_for_missing_as() as f (id int); + id +---- + 1 +(1 row) + +drop function func_for_missing_as(); +SET missing_as_warning TO false; diff --git a/src/test/regress/sql/select.sql b/src/test/regress/sql/select.sql index b99fb13..50823b5 100644 --- a/src/test/regress/sql/select.sql +++ b/src/test/regress/sql/select.sql @@ -207,3 +207,50 @@ drop function sillysrf(int); -- (see bug #5084) select * from (values (2),(null),(1)) v(k) where k = k order by k; select * from (values (2),(null),(1)) v(k) where k = k; + +-- Test warnings for missing AS for aliases +SET missing_as_warning TO false; +select 1 foo, 2 bar; +select 1 as foo, 2 as bar; +select count(*) foo; + +select 1 from onek o1 limit 1; +select 1 from onek o1, onek o2 limit 1; +select 1 from onek as o1, onek as o2 limit 1; +select un1 from onek ok (un1) where un1 = 88888888; +select un1 from onek as ok (un1) where un1 = 88888888; +update onek ok set unique1 = -88888888 where unique1 = 88888888; +update onek as ok set unique1 = -88888888 where unique1 = 88888888; + +create function func_for_missing_as() returns record language sql as 'select 1::int'; +select * from func_for_missing_as() f (id int); +select * from func_for_missing_as() as f (id int); + +SET missing_as_warning TO true; +select 1 foo, 2 bar; +select 1 as foo, 2 as bar; +select count(*) foo; + +do $$ +declare + i1 int; + i2 int; +begin + select unique1 unique2 FROM onek into i1, i2; + select unique1, unique2 FROM onek into i1, i2; +end; +$$; + +select 1 from onek o1 limit 1; +select 1 from onek o1, onek o2 limit 1; +select 1 from onek as o1, onek as o2 limit 1; +select un1 from onek ok (un1) where un1 = 88888888; +select un1 from onek as ok (un1) where un1 = 88888888; +update onek ok set unique1 = -88888888 where unique1 = 88888888; +update onek as ok set unique1 = -88888888 where unique1 = 88888888; + +select * from func_for_missing_as() f (id int); +select * from func_for_missing_as() as f (id int); + +drop function func_for_missing_as(); +SET missing_as_warning TO false; -- 1.9.3