Skip to content

Commit a0943db

Browse files
committed
Allow IMPORT FOREIGN SCHEMA within pl/pgsql.
Since IMPORT FOREIGN SCHEMA has an INTO clause, pl/pgsql needs to be aware of that and avoid capturing the INTO as an INTO-variables clause. This isn't hard, though it's annoying to have to make IMPORT a plpgsql keyword just for this. (Fortunately, we have the infrastructure now to make it an unreserved keyword, so at least this shouldn't break any existing pl/pgsql code.) Per report from Merlin Moncure. Back-patch to 9.5 where IMPORT FOREIGN SCHEMA was introduced. Report: <CAHyXU0wpHf2bbtKGL1gtUEFATCY86r=VKxfcACVcTMQ70mCyig@mail.gmail.com>
1 parent 2d22c3b commit a0943db

File tree

2 files changed

+39
-9
lines changed

2 files changed

+39
-9
lines changed

src/pl/plpgsql/src/pl_gram.y

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ static void check_raise_parameters(PLpgSQL_stmt_raise *stmt);
286286
%token <keyword> K_GET
287287
%token <keyword> K_HINT
288288
%token <keyword> K_IF
289+
%token <keyword> K_IMPORT
289290
%token <keyword> K_IN
290291
%token <keyword> K_INFO
291292
%token <keyword> K_INSERT
@@ -1891,7 +1892,11 @@ loop_body : proc_sect K_END K_LOOP opt_label ';'
18911892
* assignment. Give an appropriate complaint for that, instead of letting
18921893
* the core parser throw an unhelpful "syntax error".
18931894
*/
1894-
stmt_execsql : K_INSERT
1895+
stmt_execsql : K_IMPORT
1896+
{
1897+
$$ = make_execsql_stmt(K_IMPORT, @1);
1898+
}
1899+
| K_INSERT
18951900
{
18961901
$$ = make_execsql_stmt(K_INSERT, @1);
18971902
}
@@ -2369,6 +2374,7 @@ unreserved_keyword :
23692374
| K_FORWARD
23702375
| K_GET
23712376
| K_HINT
2377+
| K_IMPORT
23722378
| K_INFO
23732379
| K_INSERT
23742380
| K_IS
@@ -2794,12 +2800,32 @@ make_execsql_stmt(int firsttoken, int location)
27942800
plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_EXPR;
27952801

27962802
/*
2797-
* We have to special-case the sequence INSERT INTO, because we don't want
2798-
* that to be taken as an INTO-variables clause. Fortunately, this is the
2799-
* only valid use of INTO in a pl/pgsql SQL command, and INTO is already a
2800-
* fully reserved word in the main grammar. We have to treat it that way
2801-
* anywhere in the string, not only at the start; consider CREATE RULE
2802-
* containing an INSERT statement.
2803+
* Scan to the end of the SQL command. Identify any INTO-variables
2804+
* clause lurking within it, and parse that via read_into_target().
2805+
*
2806+
* Because INTO is sometimes used in the main SQL grammar, we have to be
2807+
* careful not to take any such usage of INTO as a pl/pgsql INTO clause.
2808+
* There are currently three such cases:
2809+
*
2810+
* 1. SELECT ... INTO. We don't care, we just override that with the
2811+
* pl/pgsql definition.
2812+
*
2813+
* 2. INSERT INTO. This is relatively easy to recognize since the words
2814+
* must appear adjacently; but we can't assume INSERT starts the command,
2815+
* because it can appear in CREATE RULE or WITH. Unfortunately, INSERT is
2816+
* *not* fully reserved, so that means there is a chance of a false match;
2817+
* but it's not very likely.
2818+
*
2819+
* 3. IMPORT FOREIGN SCHEMA ... INTO. This is not allowed in CREATE RULE
2820+
* or WITH, so we just check for IMPORT as the command's first token.
2821+
* (If IMPORT FOREIGN SCHEMA returned data someone might wish to capture
2822+
* with an INTO-variables clause, we'd have to work much harder here.)
2823+
*
2824+
* Fortunately, INTO is a fully reserved word in the main grammar, so
2825+
* at least we need not worry about it appearing as an identifier.
2826+
*
2827+
* Any future additional uses of INTO in the main grammar will doubtless
2828+
* break this logic again ... beware!
28032829
*/
28042830
tok = firsttoken;
28052831
for (;;)
@@ -2812,9 +2838,12 @@ make_execsql_stmt(int firsttoken, int location)
28122838
break;
28132839
if (tok == 0)
28142840
yyerror("unexpected end of function definition");
2815-
2816-
if (tok == K_INTO && prev_tok != K_INSERT)
2841+
if (tok == K_INTO)
28172842
{
2843+
if (prev_tok == K_INSERT)
2844+
continue; /* INSERT INTO is not an INTO-target */
2845+
if (firsttoken == K_IMPORT)
2846+
continue; /* IMPORT ... INTO is not an INTO-target */
28182847
if (have_into)
28192848
yyerror("INTO specified more than once");
28202849
have_into = true;

src/pl/plpgsql/src/pl_scanner.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ static const ScanKeyword unreserved_keywords[] = {
127127
PG_KEYWORD("forward", K_FORWARD, UNRESERVED_KEYWORD)
128128
PG_KEYWORD("get", K_GET, UNRESERVED_KEYWORD)
129129
PG_KEYWORD("hint", K_HINT, UNRESERVED_KEYWORD)
130+
PG_KEYWORD("import", K_IMPORT, UNRESERVED_KEYWORD)
130131
PG_KEYWORD("info", K_INFO, UNRESERVED_KEYWORD)
131132
PG_KEYWORD("insert", K_INSERT, UNRESERVED_KEYWORD)
132133
PG_KEYWORD("is", K_IS, UNRESERVED_KEYWORD)

0 commit comments

Comments
 (0)