]> granicus.if.org Git - postgresql/commitdiff
Allow IMPORT FOREIGN SCHEMA within pl/pgsql.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 12 Jul 2016 22:06:50 +0000 (18:06 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 12 Jul 2016 22:07:03 +0000 (18:07 -0400)
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>

src/pl/plpgsql/src/pl_gram.y
src/pl/plpgsql/src/pl_scanner.c

index df09575e1232b76a9ee6b0f181e724f33027172f..0b41e3acb6c14cc2a2148b916b5cde8d412ea0bf 100644 (file)
@@ -287,6 +287,7 @@ static      void                    check_raise_parameters(PLpgSQL_stmt_raise *stmt);
 %token <keyword>       K_GET
 %token <keyword>       K_HINT
 %token <keyword>       K_IF
+%token <keyword>       K_IMPORT
 %token <keyword>       K_IN
 %token <keyword>       K_INFO
 %token <keyword>       K_INSERT
@@ -1929,7 +1930,11 @@ loop_body                : proc_sect K_END K_LOOP opt_label ';'
  * assignment.  Give an appropriate complaint for that, instead of letting
  * the core parser throw an unhelpful "syntax error".
  */
-stmt_execsql   : K_INSERT
+stmt_execsql   : K_IMPORT
+                                       {
+                                               $$ = make_execsql_stmt(K_IMPORT, @1);
+                                       }
+                               | K_INSERT
                                        {
                                                $$ = make_execsql_stmt(K_INSERT, @1);
                                        }
@@ -2418,6 +2423,7 @@ unreserved_keyword        :
                                | K_FORWARD
                                | K_GET
                                | K_HINT
+                               | K_IMPORT
                                | K_INFO
                                | K_INSERT
                                | K_IS
@@ -2843,12 +2849,32 @@ make_execsql_stmt(int firsttoken, int location)
        plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_EXPR;
 
        /*
-        * We have to special-case the sequence INSERT INTO, because we don't want
-        * that to be taken as an INTO-variables clause.  Fortunately, this is the
-        * only valid use of INTO in a pl/pgsql SQL command, and INTO is already a
-        * fully reserved word in the main grammar.  We have to treat it that way
-        * anywhere in the string, not only at the start; consider CREATE RULE
-        * containing an INSERT statement.
+        * Scan to the end of the SQL command.  Identify any INTO-variables
+        * clause lurking within it, and parse that via read_into_target().
+        *
+        * Because INTO is sometimes used in the main SQL grammar, we have to be
+        * careful not to take any such usage of INTO as a pl/pgsql INTO clause.
+        * There are currently three such cases:
+        *
+        * 1. SELECT ... INTO.  We don't care, we just override that with the
+        * pl/pgsql definition.
+        *
+        * 2. INSERT INTO.  This is relatively easy to recognize since the words
+        * must appear adjacently; but we can't assume INSERT starts the command,
+        * because it can appear in CREATE RULE or WITH.  Unfortunately, INSERT is
+        * *not* fully reserved, so that means there is a chance of a false match;
+        * but it's not very likely.
+        *
+        * 3. IMPORT FOREIGN SCHEMA ... INTO.  This is not allowed in CREATE RULE
+        * or WITH, so we just check for IMPORT as the command's first token.
+        * (If IMPORT FOREIGN SCHEMA returned data someone might wish to capture
+        * with an INTO-variables clause, we'd have to work much harder here.)
+        *
+        * Fortunately, INTO is a fully reserved word in the main grammar, so
+        * at least we need not worry about it appearing as an identifier.
+        *
+        * Any future additional uses of INTO in the main grammar will doubtless
+        * break this logic again ... beware!
         */
        tok = firsttoken;
        for (;;)
@@ -2861,9 +2887,12 @@ make_execsql_stmt(int firsttoken, int location)
                        break;
                if (tok == 0)
                        yyerror("unexpected end of function definition");
-
-               if (tok == K_INTO && prev_tok != K_INSERT)
+               if (tok == K_INTO)
                {
+                       if (prev_tok == K_INSERT)
+                               continue;               /* INSERT INTO is not an INTO-target */
+                       if (firsttoken == K_IMPORT)
+                               continue;               /* IMPORT ... INTO is not an INTO-target */
                        if (have_into)
                                yyerror("INTO specified more than once");
                        have_into = true;
index bb0f25b18ce2fcadf47839a384d16f899170fc21..2737fff3fbf9a63a52f8cd6a53ec0e5003bbbc39 100644 (file)
@@ -127,6 +127,7 @@ static const ScanKeyword unreserved_keywords[] = {
        PG_KEYWORD("forward", K_FORWARD, UNRESERVED_KEYWORD)
        PG_KEYWORD("get", K_GET, UNRESERVED_KEYWORD)
        PG_KEYWORD("hint", K_HINT, UNRESERVED_KEYWORD)
+       PG_KEYWORD("import", K_IMPORT, UNRESERVED_KEYWORD)
        PG_KEYWORD("info", K_INFO, UNRESERVED_KEYWORD)
        PG_KEYWORD("insert", K_INSERT, UNRESERVED_KEYWORD)
        PG_KEYWORD("is", K_IS, UNRESERVED_KEYWORD)