From 8795bab6faff0d58586062cbf5719c7e8f77815e Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Mon, 2 Dec 2024 10:35:37 +0100 Subject: [PATCH v2 01/11] replication parser: pure parser and reentrant scanner --- src/backend/replication/repl_gram.y | 9 ++-- src/backend/replication/repl_scanner.l | 54 ++++++++++----------- src/backend/replication/walsender.c | 11 +++-- src/include/replication/walsender_private.h | 21 +++++--- 4 files changed, 50 insertions(+), 45 deletions(-) diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y index 06daa954813..4fa71377e20 100644 --- a/src/backend/replication/repl_gram.y +++ b/src/backend/replication/repl_gram.y @@ -24,10 +24,6 @@ #include "repl_gram.h" -/* silence -Wmissing-variable-declarations */ -extern int replication_yychar; -extern int replication_yynerrs; - /* Result of the parsing is returned here */ Node *replication_parse_result; @@ -43,6 +39,9 @@ Node *replication_parse_result; %} +%parse-param {yyscan_t yyscanner} +%lex-param {yyscan_t yyscanner} +%pure-parser %expect 0 %name-prefix="replication_yy" @@ -106,6 +105,8 @@ Node *replication_parse_result; firstcmd: command opt_semicolon { replication_parse_result = $1; + + (void) yynerrs; /* suppress compiler warning */ } ; diff --git a/src/backend/replication/repl_scanner.l b/src/backend/replication/repl_scanner.l index 5b10658a58b..32eedb812fe 100644 --- a/src/backend/replication/repl_scanner.l +++ b/src/backend/replication/repl_scanner.l @@ -38,14 +38,11 @@ fprintf_to_ereport(const char *fmt, const char *msg) ereport(ERROR, (errmsg_internal("%s", msg))); } -/* Handle to the buffer that the lexer uses internally */ -static YY_BUFFER_STATE scanbufhandle; - /* Pushed-back token (we only handle one) */ -static int repl_pushed_back_token; +static int repl_pushed_back_token; /* FIXME */ /* Work area for collecting literals */ -static StringInfoData litbuf; +static StringInfoData litbuf; /* FIXME */ static void startlit(void); static char *litbufdup(void); @@ -56,6 +53,8 @@ static void addlitchar(unsigned char ychar); %} +%option reentrant +%option bison-bridge %option 8bit %option never-interactive %option nodefault @@ -142,7 +141,7 @@ UPLOAD_MANIFEST { return K_UPLOAD_MANIFEST; } {space}+ { /* do nothing */ } {digit}+ { - replication_yylval.uintval = strtoul(yytext, NULL, 10); + yylval->uintval = strtoul(yytext, NULL, 10); return UCONST; } @@ -150,8 +149,8 @@ UPLOAD_MANIFEST { return K_UPLOAD_MANIFEST; } uint32 hi, lo; if (sscanf(yytext, "%X/%X", &hi, &lo) != 2) - replication_yyerror("invalid streaming start location"); - replication_yylval.recptr = ((uint64) hi) << 32 | lo; + replication_yyerror(yyscanner, "invalid streaming start location"); + yylval->recptr = ((uint64) hi) << 32 | lo; return RECPTR; } @@ -163,7 +162,7 @@ UPLOAD_MANIFEST { return K_UPLOAD_MANIFEST; } {quotestop} { yyless(1); BEGIN(INITIAL); - replication_yylval.str = litbufdup(); + yylval->str = litbufdup(); return SCONST; } @@ -185,9 +184,9 @@ UPLOAD_MANIFEST { return K_UPLOAD_MANIFEST; } yyless(1); BEGIN(INITIAL); - replication_yylval.str = litbufdup(); - len = strlen(replication_yylval.str); - truncate_identifier(replication_yylval.str, len, true); + yylval->str = litbufdup(); + len = strlen(yylval->str); + truncate_identifier(yylval->str, len, true); return IDENT; } @@ -198,7 +197,7 @@ UPLOAD_MANIFEST { return K_UPLOAD_MANIFEST; } {identifier} { int len = strlen(yytext); - replication_yylval.str = downcase_truncate_identifier(yytext, len, true); + yylval->str = downcase_truncate_identifier(yytext, len, true); return IDENT; } @@ -207,7 +206,7 @@ UPLOAD_MANIFEST { return K_UPLOAD_MANIFEST; } return yytext[0]; } -<> { replication_yyerror("unterminated quoted string"); } +<> { replication_yyerror(yyscanner, "unterminated quoted string"); } <> { @@ -243,7 +242,7 @@ addlitchar(unsigned char ychar) } void -replication_yyerror(const char *message) +replication_yyerror(yyscan_t yyscanner, const char *message) { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), @@ -251,16 +250,16 @@ replication_yyerror(const char *message) } void -replication_scanner_init(const char *str) +replication_scanner_init(const char *str, yyscan_t *yyscannerp) { Size slen = strlen(str); char *scanbuf; + yyscan_t yyscanner; - /* - * Might be left over after ereport() - */ - if (YY_CURRENT_BUFFER) - yy_delete_buffer(YY_CURRENT_BUFFER); + if (yylex_init(yyscannerp) != 0) + elog(ERROR, "yylex_init() failed: %m"); + + yyscanner = *yyscannerp; /* * Make a scan buffer with special termination needed by flex. @@ -268,18 +267,16 @@ replication_scanner_init(const char *str) scanbuf = (char *) palloc(slen + 2); memcpy(scanbuf, str, slen); scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR; - scanbufhandle = yy_scan_buffer(scanbuf, slen + 2); + yy_scan_buffer(scanbuf, slen + 2, yyscanner); /* Make sure we start in proper state */ - BEGIN(INITIAL); repl_pushed_back_token = 0; } void -replication_scanner_finish(void) +replication_scanner_finish(yyscan_t yyscanner) { - yy_delete_buffer(scanbufhandle); - scanbufhandle = NULL; + yylex_destroy(yyscanner); } /* @@ -291,9 +288,10 @@ replication_scanner_finish(void) * IDENT token here, although some other cases are possible. */ bool -replication_scanner_is_replication_command(void) +replication_scanner_is_replication_command(yyscan_t yyscanner) { - int first_token = replication_yylex(); + YYSTYPE dummy; + int first_token = replication_yylex(&dummy, yyscanner); switch (first_token) { diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c index 371eef3dddc..dc25dd6af91 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -1951,6 +1951,7 @@ WalSndWaitForWal(XLogRecPtr loc) bool exec_replication_command(const char *cmd_string) { + yyscan_t scanner; int parse_rc; Node *cmd_node; const char *cmdtag; @@ -1990,15 +1991,15 @@ exec_replication_command(const char *cmd_string) ALLOCSET_DEFAULT_SIZES); old_context = MemoryContextSwitchTo(cmd_context); - replication_scanner_init(cmd_string); + replication_scanner_init(cmd_string, &scanner); /* * Is it a WalSender command? */ - if (!replication_scanner_is_replication_command()) + if (!replication_scanner_is_replication_command(scanner)) { /* Nope; clean up and get out. */ - replication_scanner_finish(); + replication_scanner_finish(scanner); MemoryContextSwitchTo(old_context); MemoryContextDelete(cmd_context); @@ -2016,13 +2017,13 @@ exec_replication_command(const char *cmd_string) /* * Looks like a WalSender command, so parse it. */ - parse_rc = replication_yyparse(); + parse_rc = replication_yyparse(scanner); if (parse_rc != 0) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg_internal("replication command parser returned %d", parse_rc))); - replication_scanner_finish(); + replication_scanner_finish(scanner); cmd_node = replication_parse_result; diff --git a/src/include/replication/walsender_private.h b/src/include/replication/walsender_private.h index 41ac736b953..f487d3ad9e9 100644 --- a/src/include/replication/walsender_private.h +++ b/src/include/replication/walsender_private.h @@ -125,13 +125,18 @@ extern void WalSndSetState(WalSndState state); * Internal functions for parsing the replication grammar, in repl_gram.y and * repl_scanner.l */ -extern int replication_yyparse(void); -extern int replication_yylex(void); -extern void replication_yyerror(const char *message) pg_attribute_noreturn(); -extern void replication_scanner_init(const char *str); -extern void replication_scanner_finish(void); -extern bool replication_scanner_is_replication_command(void); - -extern PGDLLIMPORT Node *replication_parse_result; +union YYSTYPE; +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void *yyscan_t; +#endif +extern int replication_yyparse(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_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; /* FIXME */ #endif /* _WALSENDER_PRIVATE_H */ base-commit: 31b0a8f040042c1dfb9ac359fffbb6b8f9375999 -- 2.47.1