Skip to content

Commit 0836683

Browse files
committed
Improve error report for PL/pgSQL reserved word used as a field name.
The current code in resolve_column_ref (dating to commits 01f7d29 and fe24d78) believes that not finding a RECFIELD datum is a can't-happen case, in consequence of which I didn't spend a whole lot of time considering what to do if it did happen. But it turns out that it *can* happen if the would-be field name is a fully-reserved PL/pgSQL keyword. Change the error message to describe that situation, and add a test case demonstrating it. This might need further refinement if anyone can find other ways to trigger a failure here; but without an example it's not clear what other error to throw. Author: Tom Lane <tgl@sss.pgh.pa.us> Reviewed-by: Pavel Stehule <pavel.stehule@gmail.com> Discussion: https://postgr.es/m/2185258.1745617445@sss.pgh.pa.us
1 parent 999f172 commit 0836683

File tree

3 files changed

+50
-7
lines changed

3 files changed

+50
-7
lines changed

src/pl/plpgsql/src/expected/plpgsql_misc.out

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,25 @@ begin
7979
end $$;
8080
NOTICE: execute = 10
8181
NOTICE: r.strict = 1
82+
-- Test handling of a reserved keyword as a record field name.
83+
do $$ declare r record;
84+
begin
85+
select 1 as x, 2 as foreach into r;
86+
raise notice 'r.x = %', r.x;
87+
raise notice 'r.foreach = %', r.foreach; -- fails
88+
end $$;
89+
NOTICE: r.x = 1
90+
ERROR: field name "foreach" is a reserved key word
91+
LINE 1: r.foreach
92+
^
93+
HINT: Use double quotes to quote it.
94+
QUERY: r.foreach
95+
CONTEXT: PL/pgSQL function inline_code_block line 5 at RAISE
96+
do $$ declare r record;
97+
begin
98+
select 1 as x, 2 as foreach into r;
99+
raise notice 'r.x = %', r.x;
100+
raise notice 'r."foreach" = %', r."foreach"; -- ok
101+
end $$;
102+
NOTICE: r.x = 1
103+
NOTICE: r."foreach" = 2

src/pl/plpgsql/src/pl_comp.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,17 +1211,22 @@ resolve_column_ref(ParseState *pstate, PLpgSQL_expr *expr,
12111211
}
12121212

12131213
/*
1214-
* We should not get here, because a RECFIELD datum should
1215-
* have been built at parse time for every possible qualified
1216-
* reference to fields of this record. But if we do, handle
1217-
* it like field-not-found: throw error or return NULL.
1214+
* Ideally we'd never get here, because a RECFIELD datum
1215+
* should have been built at parse time for every qualified
1216+
* reference to a field of this record that appears in the
1217+
* source text. However, plpgsql_yylex will not build such a
1218+
* datum unless the field name lexes as token type IDENT.
1219+
* Hence, if the would-be field name is a PL/pgSQL reserved
1220+
* word, we lose. Assume that that's what happened and tell
1221+
* the user to quote it, unless the caller prefers we just
1222+
* return NULL.
12181223
*/
12191224
if (error_if_no_field)
12201225
ereport(ERROR,
1221-
(errcode(ERRCODE_UNDEFINED_COLUMN),
1222-
errmsg("record \"%s\" has no field \"%s\"",
1223-
(nnames_field == 1) ? name1 : name2,
1226+
(errcode(ERRCODE_SYNTAX_ERROR),
1227+
errmsg("field name \"%s\" is a reserved key word",
12241228
colname),
1229+
errhint("Use double quotes to quote it."),
12251230
parser_errposition(pstate, cref->location)));
12261231
}
12271232
break;

src/pl/plpgsql/src/sql/plpgsql_misc.sql

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,19 @@ begin
5050
select 1 as strict into r;
5151
raise notice 'r.strict = %', r.strict;
5252
end $$;
53+
54+
-- Test handling of a reserved keyword as a record field name.
55+
56+
do $$ declare r record;
57+
begin
58+
select 1 as x, 2 as foreach into r;
59+
raise notice 'r.x = %', r.x;
60+
raise notice 'r.foreach = %', r.foreach; -- fails
61+
end $$;
62+
63+
do $$ declare r record;
64+
begin
65+
select 1 as x, 2 as foreach into r;
66+
raise notice 'r.x = %', r.x;
67+
raise notice 'r."foreach" = %', r."foreach"; -- ok
68+
end $$;

0 commit comments

Comments
 (0)