Return yyparse() result not via global variable
authorPeter Eisentraut <[email protected]>
Fri, 24 Jan 2025 05:55:39 +0000 (06:55 +0100)
committerPeter Eisentraut <[email protected]>
Fri, 24 Jan 2025 05:55:39 +0000 (06:55 +0100)
Instead of passing the parse result from yyparse() via a global
variable, pass it via a function output argument.

This complements earlier work to make the parsers reentrant.

Discussion: Discussion: https://www.postgresql.org/message-id/flat/eb6faeac-2a8a-4b69-9189-c33c520e5b7b@eisentraut.org

18 files changed:
src/backend/nls.mk
src/backend/replication/repl_gram.y
src/backend/replication/repl_scanner.l
src/backend/replication/syncrep.c
src/backend/replication/syncrep_gram.y
src/backend/replication/syncrep_scanner.l
src/backend/replication/walsender.c
src/bin/pgbench/exprparse.y
src/bin/pgbench/exprscan.l
src/bin/pgbench/pgbench.c
src/bin/pgbench/pgbench.h
src/include/replication/syncrep.h
src/include/replication/walsender_private.h
src/pl/plpgsql/src/nls.mk
src/pl/plpgsql/src/pl_comp.c
src/pl/plpgsql/src/pl_gram.y
src/pl/plpgsql/src/pl_scanner.c
src/pl/plpgsql/src/plpgsql.h

index 5a5298b33f7cb979a3565044fb36eb6569cec7d0..b7d5dd46e4513f6de866e0b329d89acf0f99c6a8 100644 (file)
@@ -9,9 +9,9 @@ GETTEXT_TRIGGERS = $(BACKEND_COMMON_GETTEXT_TRIGGERS) \
                    yyerror \
                    jsonpath_yyerror:4 \
                    parser_yyerror \
-                   replication_yyerror:2 \
+                   replication_yyerror:3 \
                    scanner_yyerror \
-                   syncrep_yyerror:2 \
+                   syncrep_yyerror:4 \
                    report_invalid_record:2 \
                    ereport_startup_progress \
                    json_token_error:2 \
index 61e68d0727afcd33255db10f99cda8e4ccd73abd..7440aae5a1a7eb7c4008b41db280b44663cdef7a 100644 (file)
 #include "repl_gram.h"
 
 
-/* Result of the parsing is returned here */
-Node *replication_parse_result;
-
-
 /*
  * Bison doesn't allocate anything that needs to live across parser calls,
  * so we can easily have it use palloc instead of malloc.  This prevents
@@ -39,6 +35,7 @@ Node *replication_parse_result;
 
 %}
 
+%parse-param {Node **replication_parse_result_p}
 %parse-param {yyscan_t yyscanner}
 %lex-param   {yyscan_t yyscanner}
 %pure-parser
@@ -104,7 +101,7 @@ Node *replication_parse_result;
 
 firstcmd: command opt_semicolon
                {
-                   replication_parse_result = $1;
+                   *replication_parse_result_p = $1;
 
                    (void) yynerrs; /* suppress compiler warning */
                }
index de10cb5abd19bd6d6ace89e961ee682bcffd578c..014ea8d25c6b76a4f931fc85e1bdba22f24e5546 100644 (file)
@@ -156,7 +156,7 @@ UPLOAD_MANIFEST     { return K_UPLOAD_MANIFEST; }
                    uint32  hi,
                            lo;
                    if (sscanf(yytext, "%X/%X", &hi, &lo) != 2)
-                       replication_yyerror(yyscanner, "invalid  start location");
+                       replication_yyerror(NULL, yyscanner, "invalid  start location");
                    yylval->recptr = ((uint64) hi) << 32 | lo;
                    return RECPTR;
                }
@@ -213,7 +213,7 @@ UPLOAD_MANIFEST     { return K_UPLOAD_MANIFEST; }
                    return yytext[0];
                }
 
-<xq,xd><<EOF>> { replication_yyerror(yyscanner, "unterminated quoted string"); }
+<xq,xd><<EOF>> { replication_yyerror(NULL, yyscanner, "unterminated quoted string"); }
 
 
 <<EOF>>            {
@@ -252,8 +252,12 @@ addlitchar(unsigned char ychar, yyscan_t yyscanner)
    appendStringInfoChar(&yyextra->litbuf, ychar);
 }
 
+/*
+  * (The first argument is enforced by Bison to match the first argument of
+  * yyparse(), but it is not used here.)
+  */
 void
-replication_yyerror(yyscan_t yyscanner, const char *message)
+replication_yyerror(Node **replication_parse_result_p, yyscan_t yyscanner, const char *message)
 {
    ereport(ERROR,
            (errcode(ERRCODE_SYNTAX_ERROR),
index 1ce8bc7533f7a1a466ed9daa85fca0e5e6360183..d75e3968035512b79ff9321cbd94684ccfd16fe9 100644 (file)
@@ -996,13 +996,13 @@ check_synchronous_standby_names(char **newval, void **extra, GucSource source)
        int         parse_rc;
        SyncRepConfigData *pconf;
 
-       /* Reset communication variables to ensure a fresh start */
-       syncrep_parse_result = NULL;
-       syncrep_parse_error_msg = NULL;
+       /* Result of parsing is returned in one of these two variables */
+       SyncRepConfigData *syncrep_parse_result = NULL;
+       char       *syncrep_parse_error_msg = NULL;
 
        /* Parse the synchronous_standby_names string */
        syncrep_scanner_init(*newval, &scanner);
-       parse_rc = syncrep_yyparse(scanner);
+       parse_rc = syncrep_yyparse(&syncrep_parse_result, &syncrep_parse_error_msg, scanner);
        syncrep_scanner_finish(scanner);
 
        if (parse_rc != 0 || syncrep_parse_result == NULL)
index 1a3b89ca674d637539a063dbafff594b81b1ab6c..22297bb151a70104a887f22204552d6b82308f09 100644 (file)
 
 #include "syncrep_gram.h"
 
-/* Result of parsing is returned in one of these two variables */
-SyncRepConfigData *syncrep_parse_result;
-char      *syncrep_parse_error_msg;
-
 static SyncRepConfigData *create_syncrep_config(const char *num_sync,
                    List *members, uint8 syncrep_method);
 
@@ -36,7 +32,10 @@ static SyncRepConfigData *create_syncrep_config(const char *num_sync,
 
 %}
 
+%parse-param {SyncRepConfigData **syncrep_parse_result_p}
+%parse-param {char **syncrep_parse_error_msg_p}
 %parse-param {yyscan_t yyscanner}
+%lex-param   {char **syncrep_parse_error_msg_p}
 %lex-param   {yyscan_t yyscanner}
 %pure-parser
 %expect 0
@@ -60,7 +59,7 @@ static SyncRepConfigData *create_syncrep_config(const char *num_sync,
 %%
 result:
        standby_config              {
-                                       syncrep_parse_result = $1;
+                                       *syncrep_parse_result_p = $1;
                                        (void) yynerrs; /* suppress compiler warning */
                                    }
    ;
index 05e5fdecf1b31925a989bd8a161258ee1dfd1b8a..7dec1f869c74542db727a7c1d623abc8d5c2e4b9 100644 (file)
@@ -42,6 +42,13 @@ struct syncrep_yy_extra_type
    StringInfoData xdbuf;
 };
 
+/*
+ * Better keep this definition here than put it in replication/syncrep.h and
+ * save a bit of duplication.  Putting it in replication/syncrep.h would 
+ * the definition to other parts and possibly affect other scanners.
+*/
+#define YY_DECL extern int syncrep_yylex(union YYSTYPE *yylval_param, char **syncrep_parse_error_msg_p, yyscan_t yyscanner)
+
 /* LCOV_EXCL_START */
 
 %}
@@ -104,7 +111,7 @@ xdinside        [^"]+
                return NAME;
        }
 <xd><<EOF>> {
-               syncrep_yyerror(yyscanner, "unterminated quoted identifier");
+               syncrep_yyerror(NULL, syncrep_parse_error_msg_p, yyscanner, "unterminated quoted identifier");
                return JUNK;
        }
 
@@ -136,12 +143,21 @@ xdinside      [^"]+
 #undef yyextra
 #define yyextra (((struct yyguts_t *) yyscanner)->yyextra_r)
 
-/* Needs to be here for access to yytext */
+/*
+ * This yyerror() function does not raise an error (elog or similar), it just
+ * collects the error message in *syncrep_parse_error_msg_p and leaves it to
+ * the ultimate caller of the syncrep parser to raise the error.  (The
+ * ultimate caller will do that with special GUC error functions.)
+ *
+ * (The first argument is enforced by Bison to match the first argument of
+ * yyparse(), but it is not used here.)
+ */
 void
-syncrep_yyerror(yyscan_t yyscanner, const char *message)
+syncrep_yyerror(SyncRepConfigData **syncrep_parse_result_p, char **syncrep_parse_error_msg_p, yyscan_t yyscanner, const char *message)
 {
    struct yyguts_t *yyg = (struct yyguts_t *) yyscanner;   /* needed for yytext
                                                             * macro */
+   char *syncrep_parse_error_msg = *syncrep_parse_error_msg_p;
 
    /* report only the first error in a parse operation */
    if (syncrep_parse_error_msg)
index a0782b1bbf67cff98e5121c5661f794901e578db..bac504b554e9ec890d4767b40081efb0a11e982b 100644 (file)
@@ -2017,7 +2017,7 @@ exec_replication_command(const char *cmd_string)
    /*
     * Looks like a WalSender command, so parse it.
     */
-   parse_rc = replication_yyparse(scanner);
+   parse_rc = replication_yyparse(&cmd_node, scanner);
    if (parse_rc != 0)
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
@@ -2025,8 +2025,6 @@ exec_replication_command(const char *cmd_string)
                                 parse_rc)));
    replication_scanner_finish(scanner);
 
-   cmd_node = replication_parse_result;
-
    /*
     * Report query to various monitoring facilities.  For this purpose, we
     * report replication commands just like SQL commands.
index 9b5ab8074ebe611efc8a231b75b0f1ffcd08c292..68a37e49e457dd955368b6a7d5bfebce4a6ea68d 100644 (file)
@@ -21,8 +21,6 @@
 #define PGBENCH_NARGS_HASH     (-3)
 #define PGBENCH_NARGS_PERMUTE  (-4)
 
-PgBenchExpr *expr_parse_result;
-
 static PgBenchExprList *make_elist(PgBenchExpr *expr, PgBenchExprList *list);
 static PgBenchExpr *make_null_constant(void);
 static PgBenchExpr *make_boolean_constant(bool bval);
@@ -42,6 +40,7 @@ static PgBenchExpr *make_case(yyscan_t yyscanner, PgBenchExprList *when_then_lis
 %expect 0
 %name-prefix="expr_yy"
 
+%parse-param {PgBenchExpr **expr_parse_result_p}
 %parse-param {yyscan_t yyscanner}
 %lex-param   {yyscan_t yyscanner}
 
@@ -81,7 +80,7 @@ static PgBenchExpr *make_case(yyscan_t yyscanner, PgBenchExprList *when_then_lis
 %%
 
 result: expr               {
-                               expr_parse_result = $1;
+                               *expr_parse_result_p = $1;
                                (void) yynerrs; /* suppress compiler warning */
                            }
 
index 46f6ea0512106708e4819bc70923111cc3a0b708..8943a52e9f0471242b0e663d91e444b3a63e1a59 100644 (file)
@@ -296,8 +296,12 @@ expr_yyerror_more(yyscan_t yyscanner, const char *message, const char *more)
                 message, more, error_detection_offset - expr_start_offset);
 }
 
+/*
+ * (The first argument is enforced by Bison to match the first argument of
+ * yyparse(), but it is not used here.)
+ */
 void
-expr_yyerror(yyscan_t yyscanner, const char *message)
+expr_yyerror(PgBenchExpr **expr_parse_result_p, yyscan_t yyscanner, const char *message)
 {
    expr_yyerror_more(yyscanner, message, NULL);
 }
index c415e0f32c18fc04478d93b69b8d91ea5edd7907..40592e626065cacc1b698dd69a0e0edc1278e9a7 100644 (file)
@@ -5706,14 +5706,12 @@ process_backslash_command(PsqlScanState sstate, const char *source)
        yyscanner = expr_scanner_init(sstate, source, lineno, start_offset,
                                      my_command->argv[0]);
 
-       if (expr_yyparse(yyscanner) != 0)
+       if (expr_yyparse(&my_command->expr, yyscanner) != 0)
        {
            /* dead code: exit done from syntax_error called by yyerror */
            exit(1);
        }
 
-       my_command->expr = expr_parse_result;
-
        /* Save line, trimming any trailing newline */
        my_command->first_line =
            expr_scanner_get_substring(sstate,
index 4b607b7ee04526998d0f4dfb97a1b744278a8d46..f6a883611c51cf98b74cb6665eec481c1de58f87 100644 (file)
@@ -138,11 +138,9 @@ struct PgBenchExprList
    PgBenchExprLink *tail;
 };
 
-extern PgBenchExpr *expr_parse_result;
-
-extern int expr_yyparse(yyscan_t yyscanner);
+extern int expr_yyparse(PgBenchExpr **expr_parse_result_p, yyscan_t yyscanner);
 extern int expr_yylex(union YYSTYPE *yylval_param, yyscan_t yyscanner);
-extern void expr_yyerror(yyscan_t yyscanner, const char *message) pg_attribute_noreturn();
+extern void expr_yyerror(PgBenchExpr **expr_parse_result_p, yyscan_t yyscanner, const char *message) pg_attribute_noreturn();
 extern void expr_yyerror_more(yyscan_t yyscanner, const char *message,
                              const char *more) pg_attribute_noreturn();
 extern bool expr_lex_one_word(PsqlScanState state, PQExpBuffer word_buf,
index 33b9cdb18f72178241b51cbe242dcc3db5009b4f..675669a79f7d3f34380f890c0cb0fd885219cb91 100644 (file)
@@ -73,10 +73,6 @@ typedef struct SyncRepConfigData
 
 extern PGDLLIMPORT SyncRepConfigData *SyncRepConfig;
 
-/* communication variables for parsing synchronous_standby_names GUC */
-extern PGDLLIMPORT SyncRepConfigData *syncrep_parse_result;
-extern PGDLLIMPORT char *syncrep_parse_error_msg;
-
 /* user-settable parameters for synchronous replication */
 extern PGDLLIMPORT char *SyncRepStandbyNames;
 
@@ -105,9 +101,9 @@ union YYSTYPE;
 #define YY_TYPEDEF_YY_SCANNER_T
 typedef void *yyscan_t;
 #endif
-extern int syncrep_yyparse(yyscan_t yyscanner);
-extern int syncrep_yylex(union YYSTYPE *yylval_param, yyscan_t yyscanner);
-extern void syncrep_yyerror(yyscan_t yyscanner, const char *str);
+extern int syncrep_yyparse(SyncRepConfigData **syncrep_parse_result_p, char **syncrep_parse_error_msg_p, yyscan_t yyscanner);
+extern int syncrep_yylex(union YYSTYPE *yylval_param, char **syncrep_parse_error_msg_p, yyscan_t yyscanner);
+extern void syncrep_yyerror(SyncRepConfigData **syncrep_parse_result_p, char **syncrep_parse_error_msg_p, yyscan_t yyscanner, const char *str);
 extern void syncrep_scanner_init(const char *str, yyscan_t *yyscannerp);
 extern void syncrep_scanner_finish(yyscan_t yyscanner);
 
index 5ab96ed5f7d13190b94886c43b5ffb3dfbaf5b7c..814b812432a31d12e521d2d08229c948b0c6f29e 100644 (file)
@@ -130,13 +130,11 @@ union YYSTYPE;
 #define YY_TYPEDEF_YY_SCANNER_T
 typedef void *yyscan_t;
 #endif
-extern int replication_yyparse(yyscan_t yyscanner);
+extern int replication_yyparse(Node **replication_parse_result_p, yyscan_t yyscanner);
 extern int replication_yylex(union YYSTYPE *yylval_param, yyscan_t yyscanner);
-extern void replication_yyerror(yyscan_t yyscanner, const char *message) pg_attribute_noreturn();
+extern void replication_yyerror(Node **replication_parse_result_p, yyscan_t yyscanner, const char *message) pg_attribute_noreturn();
 extern void replication_scanner_init(const char *str, yyscan_t *yyscannerp);
 extern void replication_scanner_finish(yyscan_t yyscanner);
 extern bool replication_scanner_is_replication_command(yyscan_t yyscanner);
 
-extern PGDLLIMPORT Node *replication_parse_result;
-
 #endif                         /* _WALSENDER_PRIVATE_H */
index eb06336675cebe71d78000d93d0d7914761ff103..dd1c1e1440f4bad05375a15925f4b530b973cc6c 100644 (file)
@@ -6,5 +6,5 @@ GETTEXT_FILES    = pl_comp.c \
                    pl_funcs.c \
                    pl_handler.c \
                    pl_scanner.c
-GETTEXT_TRIGGERS = $(BACKEND_COMMON_GETTEXT_TRIGGERS) yyerror:3 plpgsql_yyerror:3
+GETTEXT_TRIGGERS = $(BACKEND_COMMON_GETTEXT_TRIGGERS) yyerror:4 plpgsql_yyerror:4
 GETTEXT_FLAGS    = $(BACKEND_COMMON_GETTEXT_FLAGS)
index 9dc8218292ddf8eacaa48f57c2004dfcbed189dc..a2de0880fb7ed879ca05bc6df57d4afd15404f82 100644 (file)
@@ -38,8 +38,6 @@
  * Our own local and global variables
  * ----------
  */
-PLpgSQL_stmt_block *plpgsql_parse_result;
-
 static int datums_alloc;
 int            plpgsql_nDatums;
 PLpgSQL_datum **plpgsql_Datums;
@@ -787,10 +785,9 @@ do_compile(FunctionCallInfo fcinfo,
    /*
     * Now parse the function's text
     */
-   parse_rc = plpgsql_yyparse(scanner);
+   parse_rc = plpgsql_yyparse(&function->action, scanner);
    if (parse_rc != 0)
        elog(ERROR, "plpgsql parser returned %d", parse_rc);
-   function->action = plpgsql_parse_result;
 
    plpgsql_scanner_finish(scanner);
    pfree(proc_source);
@@ -945,10 +942,9 @@ plpgsql_compile_inline(char *proc_source)
    /*
     * Now parse the function's text
     */
-   parse_rc = plpgsql_yyparse(scanner);
+   parse_rc = plpgsql_yyparse(&function->action, scanner);
    if (parse_rc != 0)
        elog(ERROR, "plpgsql parser returned %d", parse_rc);
-   function->action = plpgsql_parse_result;
 
    plpgsql_scanner_finish(scanner);
 
index 063ed81f053446779ff6c3f138a6f9fd29b038f2..64d2c362bf987c2d5f084b8d8f1911fed634b061 100644 (file)
@@ -116,6 +116,7 @@ static  void            check_raise_parameters(PLpgSQL_stmt_raise *stmt);
 
 %}
 
+%parse-param {PLpgSQL_stmt_block **plpgsql_parse_result_p}
 %parse-param {yyscan_t yyscanner}
 %lex-param   {yyscan_t yyscanner}
 %pure-parser
@@ -368,7 +369,7 @@ static  void            check_raise_parameters(PLpgSQL_stmt_raise *stmt);
 
 pl_function        : comp_options pl_block opt_semi
                    {
-                       plpgsql_parse_result = (PLpgSQL_stmt_block *) $2;
+                       *plpgsql_parse_result_p = (PLpgSQL_stmt_block *) $2;
                        (void) yynerrs;     /* suppress compiler warning */
                    }
                ;
@@ -712,7 +713,7 @@ decl_varname    : T_WORD
                        if (plpgsql_ns_lookup(plpgsql_ns_top(), true,
                                              $1.ident, NULL, NULL,
                                              NULL) != NULL)
-                           yyerror(&yylloc, yyscanner, "duplicate declaration");
+                           yyerror(&yylloc, NULL, yyscanner, "duplicate declaration");
 
                        if (plpgsql_curr_compile->extra_warnings & PLPGSQL_XCHECK_SHADOWVAR ||
                            plpgsql_curr_compile->extra_errors & PLPGSQL_XCHECK_SHADOWVAR)
@@ -740,7 +741,7 @@ decl_varname    : T_WORD
                        if (plpgsql_ns_lookup(plpgsql_ns_top(), true,
                                              $1, NULL, NULL,
                                              NULL) != NULL)
-                           yyerror(&yylloc, yyscanner, "duplicate declaration");
+                           yyerror(&yylloc, NULL, yyscanner, "duplicate declaration");
 
                        if (plpgsql_curr_compile->extra_warnings & PLPGSQL_XCHECK_SHADOWVAR ||
                            plpgsql_curr_compile->extra_errors & PLPGSQL_XCHECK_SHADOWVAR)
@@ -1143,7 +1144,7 @@ getdiag_item :
                                                K_RETURNED_SQLSTATE, "returned_sqlstate"))
                            $$ = PLPGSQL_GETDIAG_RETURNED_SQLSTATE;
                        else
-                           yyerror(&yylloc, yyscanner, "unrecognized GET DIAGNOSTICS item");
+                           yyerror(&yylloc, NULL, yyscanner, "unrecognized GET DIAGNOSTICS item");
                    }
                ;
 
@@ -1777,7 +1778,7 @@ stmt_return       : K_RETURN
 
                        tok = yylex(&yylval, &yylloc, yyscanner);
                        if (tok == 0)
-                           yyerror(&yylloc, yyscanner, "unexpected end of function definition");
+                           yyerror(&yylloc, NULL, yyscanner, "unexpected end of function definition");
 
                        if (tok_is_keyword(tok, &yylval,
                                           K_NEXT, "next"))
@@ -1815,7 +1816,7 @@ stmt_raise        : K_RAISE
 
                        tok = yylex(&yylval, &yylloc, yyscanner);
                        if (tok == 0)
-                           yyerror(&yylloc, yyscanner, "unexpected end of function definition");
+                           yyerror(&yylloc, NULL, yyscanner, "unexpected end of function definition");
 
                        /*
                         * We could have just RAISE, meaning to re-throw
@@ -1863,7 +1864,7 @@ stmt_raise        : K_RAISE
                                tok = yylex(&yylval, &yylloc, yyscanner);
                            }
                            if (tok == 0)
-                               yyerror(&yylloc, yyscanner, "unexpected end of function definition");
+                               yyerror(&yylloc, NULL, yyscanner, "unexpected end of function definition");
 
                            /*
                             * Next we can have a condition name, or
@@ -1883,7 +1884,7 @@ stmt_raise        : K_RAISE
                                 */
                                tok = yylex(&yylval, &yylloc, yyscanner);
                                if (tok != ',' && tok != ';' && tok != K_USING)
-                                   yyerror(&yylloc, yyscanner, "syntax error");
+                                   yyerror(&yylloc, NULL, yyscanner, "syntax error");
 
                                while (tok == ',')
                                {
@@ -1908,13 +1909,13 @@ stmt_raise      : K_RAISE
                                    char       *sqlstatestr;
 
                                    if (yylex(&yylval, &yylloc, yyscanner) != SCONST)
-                                       yyerror(&yylloc, yyscanner, "syntax error");
+                                       yyerror(&yylloc, NULL, yyscanner, "syntax error");
                                    sqlstatestr = yylval.str;
 
                                    if (strlen(sqlstatestr) != 5)
-                                       yyerror(&yylloc, yyscanner, "invalid SQLSTATE code");
+                                       yyerror(&yylloc, NULL, yyscanner, "invalid SQLSTATE code");
                                    if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5)
-                                       yyerror(&yylloc, yyscanner, "invalid SQLSTATE code");
+                                       yyerror(&yylloc, NULL, yyscanner, "invalid SQLSTATE code");
                                    new->condname = sqlstatestr;
                                }
                                else
@@ -1924,13 +1925,13 @@ stmt_raise      : K_RAISE
                                    else if (plpgsql_token_is_unreserved_keyword(tok))
                                        new->condname = pstrdup(yylval.keyword);
                                    else
-                                       yyerror(&yylloc, yyscanner, "syntax error");
+                                       yyerror(&yylloc, NULL, yyscanner, "syntax error");
                                    plpgsql_recognize_err_condition(new->condname,
                                                                    false);
                                }
                                tok = yylex(&yylval, &yylloc, yyscanner);
                                if (tok != ';' && tok != K_USING)
-                                   yyerror(&yylloc, yyscanner, "syntax error");
+                                   yyerror(&yylloc, NULL, yyscanner, "syntax error");
                            }
 
                            if (tok == K_USING)
@@ -2056,7 +2057,7 @@ stmt_dynexecute : K_EXECUTE
                            if (endtoken == K_INTO)
                            {
                                if (new->into)          /* multiple INTO */
-                                   yyerror(&yylloc, yyscanner, "syntax error");
+                                   yyerror(&yylloc, NULL, yyscanner, "syntax error");
                                new->into = true;
                                read_into_target(&new->target, &new->strict, &yylval, &yylloc, yyscanner);
                                endtoken = yylex(&yylval, &yylloc, yyscanner);
@@ -2064,7 +2065,7 @@ stmt_dynexecute : K_EXECUTE
                            else if (endtoken == K_USING)
                            {
                                if (new->params)        /* multiple USING */
-                                   yyerror(&yylloc, yyscanner, "syntax error");
+                                   yyerror(&yylloc, NULL, yyscanner, "syntax error");
                                do
                                {
                                    expr = read_sql_construct(',', ';', K_INTO,
@@ -2079,7 +2080,7 @@ stmt_dynexecute : K_EXECUTE
                            else if (endtoken == ';')
                                break;
                            else
-                               yyerror(&yylloc, yyscanner, "syntax error");
+                               yyerror(&yylloc, NULL, yyscanner, "syntax error");
                        }
 
                        $$ = (PLpgSQL_stmt *) new;
@@ -2122,7 +2123,7 @@ stmt_open     : K_OPEN cursor_variable
                            }
 
                            if (tok != K_FOR)
-                               yyerror(&yylloc, yyscanner, "syntax error, expected \"FOR\"");
+                               yyerror(&yylloc, NULL, yyscanner, "syntax error, expected \"FOR\"");
 
                            tok = yylex(&yylval, &yylloc, yyscanner);
                            if (tok == K_EXECUTE)
@@ -2174,7 +2175,7 @@ stmt_fetch        : K_FETCH opt_fetch_direction cursor_variable K_INTO
                        read_into_target(&target, NULL, &yylval, &yylloc, yyscanner);
 
                        if (yylex(&yylval, &yylloc, yyscanner) != ';')
-                           yyerror(&yylloc, yyscanner, "syntax error");
+                           yyerror(&yylloc, NULL, yyscanner, "syntax error");
 
                        /*
                         * We don't allow multiple rows in PL/pgSQL's FETCH
@@ -2398,13 +2399,13 @@ proc_condition  : any_identifier
 
                                /* next token should be a string literal */
                                if (yylex(&yylval, &yylloc, yyscanner) != SCONST)
-                                   yyerror(&yylloc, yyscanner, "syntax error");
+                                   yyerror(&yylloc, NULL, yyscanner, "syntax error");
                                sqlstatestr = yylval.str;
 
                                if (strlen(sqlstatestr) != 5)
-                                   yyerror(&yylloc, yyscanner, "invalid SQLSTATE code");
+                                   yyerror(&yylloc, NULL, yyscanner, "invalid SQLSTATE code");
                                if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5)
-                                   yyerror(&yylloc, yyscanner, "invalid SQLSTATE code");
+                                   yyerror(&yylloc, NULL, yyscanner, "invalid SQLSTATE code");
 
                                new = palloc(sizeof(PLpgSQL_condition));
                                new->sqlerrstate =
@@ -2488,7 +2489,7 @@ any_identifier    : T_WORD
                | T_DATUM
                    {
                        if ($1.ident == NULL) /* composite name not OK */
-                           yyerror(&yylloc, yyscanner, "syntax error");
+                           yyerror(&yylloc, NULL, yyscanner, "syntax error");
                        $$ = $1.ident;
                    }
                ;
@@ -2647,7 +2648,7 @@ current_token_is_not_variable(int tok, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yysca
    else if (tok == T_CWORD)
        cword_is_not_variable(&(yylvalp->cword), *yyllocp, yyscanner);
    else
-       yyerror(yyllocp, yyscanner, "syntax error");
+       yyerror(yyllocp, NULL, yyscanner, "syntax error");
 }
 
 /* Convenience routine to read an expression with one possible terminator */
@@ -2739,7 +2740,7 @@ read_sql_construct(int until,
        {
            parenlevel--;
            if (parenlevel < 0)
-               yyerror(yyllocp, yyscanner, "mismatched parentheses");
+               yyerror(yyllocp, NULL, yyscanner, "mismatched parentheses");
        }
 
        /*
@@ -2750,7 +2751,7 @@ read_sql_construct(int until,
        if (tok == 0 || tok == ';')
        {
            if (parenlevel != 0)
-               yyerror(yyllocp, yyscanner, "mismatched parentheses");
+               yyerror(yyllocp, NULL, yyscanner, "mismatched parentheses");
            if (isexpression)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
@@ -2779,9 +2780,9 @@ read_sql_construct(int until,
    if (startlocation >= endlocation)
    {
        if (isexpression)
-           yyerror(yyllocp, yyscanner, "missing expression");
+           yyerror(yyllocp, NULL, yyscanner, "missing expression");
        else
-           yyerror(yyllocp, yyscanner, "missing SQL statement");
+           yyerror(yyllocp, NULL, yyscanner, "missing SQL statement");
    }
 
    /*
@@ -2910,7 +2911,7 @@ read_datatype(int tok, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
            if (tok == ICONST)
                tok = yylex(yylvalp, yyllocp, yyscanner);
            if (tok != ']')
-               yyerror(yyllocp, yyscanner, "syntax error, expected \"]\"");
+               yyerror(yyllocp, NULL, yyscanner, "syntax error, expected \"]\"");
            tok = yylex(yylvalp, yyllocp, yyscanner);
        }
        plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner);
@@ -2932,9 +2933,9 @@ read_datatype(int tok, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
        if (tok == 0)
        {
            if (parenlevel != 0)
-               yyerror(yyllocp, yyscanner, "mismatched parentheses");
+               yyerror(yyllocp, NULL, yyscanner, "mismatched parentheses");
            else
-               yyerror(yyllocp, yyscanner, "incomplete data type declaration");
+               yyerror(yyllocp, NULL, yyscanner, "incomplete data type declaration");
        }
        /* Possible followers for datatype in a declaration */
        if (tok == K_COLLATE || tok == K_NOT ||
@@ -2957,7 +2958,7 @@ read_datatype(int tok, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
    type_name = ds.data;
 
    if (type_name[0] == '\0')
-       yyerror(yyllocp, yyscanner, "missing data type declaration");
+       yyerror(yyllocp, NULL, yyscanner, "missing data type declaration");
 
    result = parse_datatype(type_name, startlocation, yyscanner);
 
@@ -3082,7 +3083,7 @@ make_execsql_stmt(int firsttoken, int location, PLword *word, YYSTYPE *yylvalp,
        if (tok == ';' && paren_depth == 0 && begin_depth == 0)
            break;
        if (tok == 0)
-           yyerror(yyllocp, yyscanner, "unexpected end of function definition");
+           yyerror(yyllocp, NULL, yyscanner, "unexpected end of function definition");
        if (tok == K_INTO)
        {
            if (prev_tok == K_INSERT)
@@ -3092,7 +3093,7 @@ make_execsql_stmt(int firsttoken, int location, PLword *word, YYSTYPE *yylvalp,
            if (firsttoken == K_IMPORT)
                continue;       /* IMPORT ... INTO is not an INTO-target */
            if (have_into)
-               yyerror(yyllocp, yyscanner, "INTO specified more than once");
+               yyerror(yyllocp, NULL, yyscanner, "INTO specified more than once");
            have_into = true;
            into_start_loc = *yyllocp;
            plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
@@ -3170,7 +3171,7 @@ read_fetch_direction(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
 
    tok = yylex(yylvalp, yyllocp, yyscanner);
    if (tok == 0)
-       yyerror(yyllocp, yyscanner, "unexpected end of function definition");
+       yyerror(yyllocp, NULL, yyscanner, "unexpected end of function definition");
 
    if (tok_is_keyword(tok, yylvalp,
                       K_NEXT, "next"))
@@ -3262,7 +3263,7 @@ read_fetch_direction(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
    {
        tok = yylex(yylvalp, yyllocp, yyscanner);
        if (tok != K_FROM && tok != K_IN)
-           yyerror(yyllocp, yyscanner, "expected FROM or IN");
+           yyerror(yyllocp, NULL, yyscanner, "expected FROM or IN");
    }
 
    return fetch;
@@ -3281,7 +3282,7 @@ complete_direction(PLpgSQL_stmt_fetch *fetch, bool *check_FROM, YYSTYPE *yylvalp
 
    tok = yylex(yylvalp, yyllocp, yyscanner);
    if (tok == 0)
-       yyerror(yyllocp, yyscanner, "unexpected end of function definition");
+       yyerror(yyllocp, NULL, yyscanner, "unexpected end of function definition");
 
    if (tok == K_FROM || tok == K_IN)
    {
@@ -3882,7 +3883,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until, YYSTYPE *yylvalp, YYLTYPE *yyll
                     parser_errposition(*yyllocp)));
 
        if (tok != until)
-           yyerror(yyllocp, yyscanner, "syntax error");
+           yyerror(yyllocp, NULL, yyscanner, "syntax error");
 
        return NULL;
    }
@@ -3943,7 +3944,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until, YYSTYPE *yylvalp, YYLTYPE *yyll
             */
            tok2 = yylex(yylvalp, yyllocp, yyscanner);
            if (tok2 != COLON_EQUALS)
-               yyerror(yyllocp, yyscanner, "syntax error");
+               yyerror(yyllocp, NULL, yyscanner, "syntax error");
 
            any_named = true;
        }
@@ -4017,7 +4018,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until, YYSTYPE *yylvalp, YYLTYPE *yyll
    /* Next we'd better find the until token */
    tok = yylex(yylvalp, yyllocp, yyscanner);
    if (tok != until)
-       yyerror(yyllocp, yyscanner, "syntax error");
+       yyerror(yyllocp, NULL, yyscanner, "syntax error");
 
    return expr;
 }
@@ -4036,7 +4037,7 @@ read_raise_options(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
        int         tok;
 
        if ((tok = yylex(yylvalp, yyllocp, yyscanner)) == 0)
-           yyerror(yyllocp, yyscanner, "unexpected end of function definition");
+           yyerror(yyllocp, NULL, yyscanner, "unexpected end of function definition");
 
        opt = (PLpgSQL_raise_option *) palloc(sizeof(PLpgSQL_raise_option));
 
@@ -4068,11 +4069,11 @@ read_raise_options(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
                                K_SCHEMA, "schema"))
            opt->opt_type = PLPGSQL_RAISEOPTION_SCHEMA;
        else
-           yyerror(yyllocp, yyscanner, "unrecognized RAISE statement option");
+           yyerror(yyllocp, NULL, yyscanner, "unrecognized RAISE statement option");
 
        tok = yylex(yylvalp, yyllocp, yyscanner);
        if (tok != '=' && tok != COLON_EQUALS)
-           yyerror(yyllocp, yyscanner, "syntax error, expected \"=\"");
+           yyerror(yyllocp, NULL, yyscanner, "syntax error, expected \"=\"");
 
        opt->expr = read_sql_expression2(',', ';', ", or ;", &tok, yylvalp, yyllocp, yyscanner);
 
index 11d79a8a6837ada89e55634e13f1489a8dc52599..d08187dafcb4cb06f138354f7d912f7f1219d527 100644 (file)
@@ -526,9 +526,12 @@ plpgsql_scanner_errposition(int location, yyscan_t yyscanner)
  * parsers report error as soon as the first unparsable token is reached.
  * Beware of using yyerror for other purposes, as the cursor position might
  * be misleading!
+ *
+ * (The second argument is enforced by Bison to match the second argument of
+ * yyparse(), but it is not used here.)
  */
 void
-plpgsql_yyerror(YYLTYPE *yyllocp, yyscan_t yyscanner, const char *message)
+plpgsql_yyerror(YYLTYPE *yyllocp, PLpgSQL_stmt_block **plpgsql_parse_result_p, yyscan_t yyscanner, const char *message)
 {
    char       *yytext = yyextra->core_yy_extra.scanbuf + *yyllocp;
 
index c3ce4161a32c9eae41fba6d6ce28a9bee8baa8df..441df5354e2547d0295649f6884191e300570f50 100644 (file)
@@ -1212,8 +1212,6 @@ extern int    plpgsql_extra_errors;
 extern bool plpgsql_check_syntax;
 extern bool plpgsql_DumpExecTree;
 
-extern PLpgSQL_stmt_block *plpgsql_parse_result;
-
 extern int plpgsql_nDatums;
 extern PLpgSQL_datum **plpgsql_Datums;
 
@@ -1332,7 +1330,7 @@ extern int    plpgsql_peek(yyscan_t yyscanner);
 extern void plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc,
                          int *tok2_loc, yyscan_t yyscanner);
 extern int plpgsql_scanner_errposition(int location, yyscan_t yyscanner);
-extern void plpgsql_yyerror(YYLTYPE *yyllocp, yyscan_t yyscanner, const char *message) pg_attribute_noreturn();
+extern void plpgsql_yyerror(YYLTYPE *yyllocp, PLpgSQL_stmt_block **plpgsql_parse_result_p, yyscan_t yyscanner, const char *message) pg_attribute_noreturn();
 extern int plpgsql_location_to_lineno(int location, yyscan_t yyscanner);
 extern int plpgsql_latest_lineno(yyscan_t yyscanner);
 extern yyscan_t plpgsql_scanner_init(const char *str);
@@ -1341,6 +1339,6 @@ extern void plpgsql_scanner_finish(yyscan_t yyscanner);
 /*
  * Externs in pl_gram.y
  */
-extern int plpgsql_yyparse(yyscan_t yyscanner);
+extern int plpgsql_yyparse(PLpgSQL_stmt_block **plpgsql_parse_result_p, yyscan_t yyscanner);
 
 #endif                         /* PLPGSQL_H */