1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-24 00:23:06 +03:00
Files
postgres/src/backend/replication/syncrep_scanner.l
Robert Haas dcc9820a35 Avoid throwing away the error message in syncrep_yyerror.
Commit 473a575e05 purported to make this
function stash the error message in *syncrep_parse_result_p, but
it didn't actually.

As a result, an attempt to set synchronous_standby_names to any value
that does not parse resulted in a generic "parser failed." message
rather than anything more specific. This fixes that.

Discussion: http://postgr.es/m/CA+TgmoYF9wPNZ-Q_EMfib_espgHycY-eX__6Tzo2GpYpVXqCdQ@mail.gmail.com
Backpatch-through: 18
2025-07-28 10:35:05 -04:00

221 lines
4.8 KiB
Plaintext

%top{
/*-------------------------------------------------------------------------
*
* syncrep_scanner.l
* a lexical scanner for synchronous_standby_names
*
* Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* src/backend/replication/syncrep_scanner.l
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "lib/stringinfo.h"
#include "nodes/pg_list.h"
/*
* NB: include syncrep_gram.h only AFTER including syncrep.h, because syncrep.h
* includes node definitions needed for YYSTYPE.
*/
#include "replication/syncrep.h"
#include "syncrep_gram.h"
}
%{
/* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
#undef fprintf
#define fprintf(file, fmt, msg) fprintf_to_ereport(fmt, msg)
static void
fprintf_to_ereport(const char *fmt, const char *msg)
{
ereport(ERROR, (errmsg_internal("%s", msg)));
}
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 leak
* 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 */
%}
%option reentrant
%option bison-bridge
%option 8bit
%option never-interactive
%option nodefault
%option noinput
%option nounput
%option noyywrap
%option noyyalloc
%option noyyrealloc
%option noyyfree
%option warn
%option prefix="syncrep_yy"
%option extra-type="struct syncrep_yy_extra_type *"
/*
* <xd> delimited identifiers (double-quoted identifiers)
*/
%x xd
space [ \t\n\r\f\v]
digit [0-9]
ident_start [A-Za-z\200-\377_]
ident_cont [A-Za-z\200-\377_0-9\$]
identifier {ident_start}{ident_cont}*
dquote \"
xdstart {dquote}
xdstop {dquote}
xddouble {dquote}{dquote}
xdinside [^"]+
%%
{space}+ { /* ignore */ }
/* brute-force case insensitivity is safer than relying on flex -i */
[Aa][Nn][Yy] { return ANY; }
[Ff][Ii][Rr][Ss][Tt] { return FIRST; }
{xdstart} {
initStringInfo(&yyextra->xdbuf);
BEGIN(xd);
}
<xd>{xddouble} {
appendStringInfoChar(&yyextra->xdbuf, '"');
}
<xd>{xdinside} {
appendStringInfoString(&yyextra->xdbuf, yytext);
}
<xd>{xdstop} {
yylval->str = yyextra->xdbuf.data;
yyextra->xdbuf.data = NULL;
BEGIN(INITIAL);
return NAME;
}
<xd><<EOF>> {
syncrep_yyerror(NULL, syncrep_parse_error_msg_p, yyscanner, "unterminated quoted identifier");
return JUNK;
}
{identifier} {
yylval->str = pstrdup(yytext);
return NAME;
}
{digit}+ {
yylval->str = pstrdup(yytext);
return NUM;
}
"*" {
yylval->str = "*";
return NAME;
}
"," { return ','; }
"(" { return '('; }
")" { return ')'; }
. { return JUNK; }
%%
/* LCOV_EXCL_STOP */
/* see scan.l */
#undef yyextra
#define yyextra (((struct yyguts_t *) yyscanner)->yyextra_r)
/*
* 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(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 */
/* report only the first error in a parse operation */
if (*syncrep_parse_error_msg_p)
return;
if (yytext[0])
*syncrep_parse_error_msg_p = psprintf("%s at or near \"%s\"",
message, yytext);
else
*syncrep_parse_error_msg_p = psprintf("%s at end of input",
message);
}
void
syncrep_scanner_init(const char *str, yyscan_t *yyscannerp)
{
yyscan_t yyscanner;
struct syncrep_yy_extra_type *yyext = palloc0_object(struct syncrep_yy_extra_type);
if (yylex_init(yyscannerp) != 0)
elog(ERROR, "yylex_init() failed: %m");
yyscanner = *yyscannerp;
yyset_extra(yyext, yyscanner);
yy_scan_string(str, yyscanner);
}
void
syncrep_scanner_finish(yyscan_t yyscanner)
{
pfree(yyextra);
yylex_destroy(yyscanner);
}
/*
* Interface functions to make flex use palloc() instead of malloc().
* It'd be better to make these static, but flex insists otherwise.
*/
void *
yyalloc(yy_size_t size, yyscan_t yyscanner)
{
return palloc(size);
}
void *
yyrealloc(void *ptr, yy_size_t size, yyscan_t yyscanner)
{
if (ptr)
return repalloc(ptr, size);
else
return palloc(size);
}
void
yyfree(void *ptr, yyscan_t yyscanner)
{
if (ptr)
pfree(ptr);
}