2011-01-14 16:30:33 +01:00
|
|
|
%{
|
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* repl_scanner.l
|
|
|
|
* a lexical scanner for the replication commands
|
|
|
|
*
|
2014-01-07 22:05:30 +01:00
|
|
|
* Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
|
2011-01-14 16:30:33 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
|
|
|
* src/backend/replication/repl_scanner.l
|
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
#include "utils/builtins.h"
|
2014-02-01 04:45:17 +01:00
|
|
|
#include "parser/scansup.h"
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
|
2011-01-14 16:30:33 +01:00
|
|
|
/* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
|
|
|
|
#undef fprintf
|
Improve handling of ereport(ERROR) and elog(ERROR).
In commit 71450d7fd6c7cf7b3e38ac56e363bff6a681973c, we added code to inform
suitably-intelligent compilers that ereport() doesn't return if the elevel
is ERROR or higher. This patch extends that to elog(), and also fixes a
double-evaluation hazard that the previous commit created in ereport(),
as well as reducing the emitted code size.
The elog() improvement requires the compiler to support __VA_ARGS__, which
should be available in just about anything nowadays since it's required by
C99. But our minimum language baseline is still C89, so add a configure
test for that.
The previous commit assumed that ereport's elevel could be evaluated twice,
which isn't terribly safe --- there are already counterexamples in xlog.c.
On compilers that have __builtin_constant_p, we can use that to protect the
second test, since there's no possible optimization gain if the compiler
doesn't know the value of elevel. Otherwise, use a local variable inside
the macros to prevent double evaluation. The local-variable solution is
inferior because (a) it leads to useless code being emitted when elevel
isn't constant, and (b) it increases the optimization level needed for the
compiler to recognize that subsequent code is unreachable. But it seems
better than not teaching non-gcc compilers about unreachability at all.
Lastly, if the compiler has __builtin_unreachable(), we can use that
instead of abort(), resulting in a noticeable code savings since no
function call is actually emitted. However, it seems wise to do this only
in non-assert builds. In an assert build, continue to use abort(), so that
the behavior will be predictable and debuggable if the "impossible"
happens.
These changes involve making the ereport and elog macros emit do-while
statement blocks not just expressions, which forces small changes in
a few call sites.
Andres Freund, Tom Lane, Heikki Linnakangas
2013-01-14 00:39:20 +01:00
|
|
|
#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)));
|
|
|
|
}
|
2011-01-14 16:30:33 +01:00
|
|
|
|
|
|
|
/* Handle to the buffer that the lexer uses internally */
|
|
|
|
static YY_BUFFER_STATE scanbufhandle;
|
|
|
|
|
|
|
|
static StringInfoData litbuf;
|
|
|
|
|
|
|
|
static void startlit(void);
|
|
|
|
static char *litbufdup(void);
|
|
|
|
static void addlit(char *ytext, int yleng);
|
|
|
|
static void addlitchar(unsigned char ychar);
|
|
|
|
|
|
|
|
%}
|
|
|
|
|
|
|
|
%option 8bit
|
|
|
|
%option never-interactive
|
|
|
|
%option nodefault
|
|
|
|
%option noinput
|
|
|
|
%option nounput
|
|
|
|
%option noyywrap
|
|
|
|
%option warn
|
|
|
|
%option prefix="replication_yy"
|
|
|
|
|
2014-02-01 04:45:17 +01:00
|
|
|
%x xq xd
|
2011-01-14 16:30:33 +01:00
|
|
|
|
|
|
|
/* Extended quote
|
|
|
|
* xqdouble implements embedded quote, ''''
|
|
|
|
*/
|
|
|
|
xqstart {quote}
|
|
|
|
xqdouble {quote}{quote}
|
|
|
|
xqinside [^']+
|
|
|
|
|
2014-02-01 04:45:17 +01:00
|
|
|
/* Double quote
|
|
|
|
* Allows embedded spaces and other special characters into identifiers.
|
|
|
|
*/
|
|
|
|
dquote \"
|
|
|
|
xdstart {dquote}
|
|
|
|
xdstop {dquote}
|
|
|
|
xddouble {dquote}{dquote}
|
|
|
|
xdinside [^"]+
|
|
|
|
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
digit [0-9]+
|
2011-01-14 16:30:33 +01:00
|
|
|
hexdigit [0-9A-Za-z]+
|
|
|
|
|
|
|
|
quote '
|
|
|
|
quotestop {quote}
|
|
|
|
|
2014-02-01 04:45:17 +01:00
|
|
|
ident_start [A-Za-z\200-\377_]
|
|
|
|
ident_cont [A-Za-z\200-\377_0-9\$]
|
|
|
|
|
|
|
|
identifier {ident_start}{ident_cont}*
|
|
|
|
|
2011-01-14 16:30:33 +01:00
|
|
|
%%
|
|
|
|
|
|
|
|
BASE_BACKUP { return K_BASE_BACKUP; }
|
2011-01-23 12:21:23 +01:00
|
|
|
FAST { return K_FAST; }
|
2011-01-14 16:30:33 +01:00
|
|
|
IDENTIFY_SYSTEM { return K_IDENTIFY_SYSTEM; }
|
|
|
|
LABEL { return K_LABEL; }
|
2011-02-09 10:59:53 +01:00
|
|
|
NOWAIT { return K_NOWAIT; }
|
2011-01-14 16:30:33 +01:00
|
|
|
PROGRESS { return K_PROGRESS; }
|
2011-01-30 21:30:09 +01:00
|
|
|
WAL { return K_WAL; }
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
TIMELINE { return K_TIMELINE; }
|
2011-01-14 16:30:33 +01:00
|
|
|
START_REPLICATION { return K_START_REPLICATION; }
|
2014-02-01 04:45:17 +01:00
|
|
|
CREATE_REPLICATION_SLOT { return K_CREATE_REPLICATION_SLOT; }
|
|
|
|
DROP_REPLICATION_SLOT { return K_DROP_REPLICATION_SLOT; }
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
TIMELINE_HISTORY { return K_TIMELINE_HISTORY; }
|
2014-02-01 04:45:17 +01:00
|
|
|
PHYSICAL { return K_PHYSICAL; }
|
|
|
|
SLOT { return K_SLOT; }
|
|
|
|
|
2011-01-14 16:30:33 +01:00
|
|
|
"," { return ','; }
|
|
|
|
";" { return ';'; }
|
2014-02-01 04:45:17 +01:00
|
|
|
"(" { return '('; }
|
|
|
|
")" { return ')'; }
|
2011-01-14 16:30:33 +01:00
|
|
|
|
|
|
|
[\n] ;
|
|
|
|
[\t] ;
|
|
|
|
" " ;
|
|
|
|
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
{digit}+ {
|
2013-08-15 05:18:49 +02:00
|
|
|
yylval.uintval = strtoul(yytext, NULL, 10);
|
|
|
|
return UCONST;
|
Allow a streaming replication standby to follow a timeline switch.
Before this patch, streaming replication would refuse to start replicating
if the timeline in the primary doesn't exactly match the standby. The
situation where it doesn't match is when you have a master, and two
standbys, and you promote one of the standbys to become new master.
Promoting bumps up the timeline ID, and after that bump, the other standby
would refuse to continue.
There's significantly more timeline related logic in streaming replication
now. First of all, when a standby connects to primary, it will ask the
primary for any timeline history files that are missing from the standby.
The missing files are sent using a new replication command TIMELINE_HISTORY,
and stored in standby's pg_xlog directory. Using the timeline history files,
the standby can follow the latest timeline present in the primary
(recovery_target_timeline='latest'), just as it can follow new timelines
appearing in an archive directory.
START_REPLICATION now takes a TIMELINE parameter, to specify exactly which
timeline to stream WAL from. This allows the standby to request the primary
to send over WAL that precedes the promotion. The replication protocol is
changed slightly (in a backwards-compatible way although there's little hope
of streaming replication working across major versions anyway), to allow
replication to stop when the end of timeline reached, putting the walsender
back into accepting a replication command.
Many thanks to Amit Kapila for testing and reviewing various versions of
this patch.
2012-12-13 18:00:00 +01:00
|
|
|
}
|
|
|
|
|
2011-01-14 16:30:33 +01:00
|
|
|
{hexdigit}+\/{hexdigit}+ {
|
2012-06-24 17:51:37 +02:00
|
|
|
uint32 hi,
|
|
|
|
lo;
|
|
|
|
if (sscanf(yytext, "%X/%X", &hi, &lo) != 2)
|
2011-01-14 16:30:33 +01:00
|
|
|
yyerror("invalid streaming start location");
|
2012-06-24 17:51:37 +02:00
|
|
|
yylval.recptr = ((uint64) hi) << 32 | lo;
|
2011-01-14 16:30:33 +01:00
|
|
|
return RECPTR;
|
|
|
|
}
|
|
|
|
|
|
|
|
{xqstart} {
|
|
|
|
BEGIN(xq);
|
|
|
|
startlit();
|
|
|
|
}
|
2014-02-01 04:45:17 +01:00
|
|
|
|
2011-01-14 16:30:33 +01:00
|
|
|
<xq>{quotestop} {
|
|
|
|
yyless(1);
|
|
|
|
BEGIN(INITIAL);
|
|
|
|
yylval.str = litbufdup();
|
|
|
|
return SCONST;
|
|
|
|
}
|
2014-02-01 04:45:17 +01:00
|
|
|
|
|
|
|
<xq>{xqdouble} {
|
2011-01-14 16:30:33 +01:00
|
|
|
addlitchar('\'');
|
|
|
|
}
|
2014-02-01 04:45:17 +01:00
|
|
|
|
2011-01-14 16:30:33 +01:00
|
|
|
<xq>{xqinside} {
|
|
|
|
addlit(yytext, yyleng);
|
|
|
|
}
|
|
|
|
|
2014-02-01 04:45:17 +01:00
|
|
|
{xdstart} {
|
|
|
|
BEGIN(xd);
|
|
|
|
startlit();
|
|
|
|
}
|
|
|
|
|
|
|
|
<xd>{xdstop} {
|
|
|
|
int len;
|
|
|
|
yyless(1);
|
|
|
|
BEGIN(INITIAL);
|
|
|
|
yylval.str = litbufdup();
|
|
|
|
len = strlen(yylval.str);
|
|
|
|
truncate_identifier(yylval.str, len, true);
|
|
|
|
return IDENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
<xd>{xdinside} {
|
|
|
|
addlit(yytext, yyleng);
|
|
|
|
}
|
|
|
|
|
|
|
|
{identifier} {
|
|
|
|
int len = strlen(yytext);
|
|
|
|
|
|
|
|
yylval.str = downcase_truncate_identifier(yytext, len, true);
|
|
|
|
return IDENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
<xq,xd><<EOF>> { yyerror("unterminated quoted string"); }
|
2011-01-14 16:30:33 +01:00
|
|
|
|
|
|
|
|
|
|
|
<<EOF>> {
|
|
|
|
yyterminate();
|
|
|
|
}
|
|
|
|
|
|
|
|
. {
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("syntax error: unexpected character \"%s\"", yytext)));
|
|
|
|
}
|
|
|
|
%%
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
startlit(void)
|
|
|
|
{
|
2011-11-01 20:50:00 +01:00
|
|
|
initStringInfo(&litbuf);
|
2011-01-14 16:30:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
litbufdup(void)
|
|
|
|
{
|
2011-11-01 20:50:00 +01:00
|
|
|
return litbuf.data;
|
2011-01-14 16:30:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
addlit(char *ytext, int yleng)
|
|
|
|
{
|
|
|
|
appendBinaryStringInfo(&litbuf, ytext, yleng);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
addlitchar(unsigned char ychar)
|
|
|
|
{
|
2011-11-01 20:50:00 +01:00
|
|
|
appendStringInfoChar(&litbuf, ychar);
|
2011-01-14 16:30:33 +01:00
|
|
|
}
|
|
|
|
|
2013-02-12 13:13:22 +01:00
|
|
|
void __attribute__((noreturn))
|
2011-01-14 16:30:33 +01:00
|
|
|
yyerror(const char *message)
|
|
|
|
{
|
2011-11-01 20:50:00 +01:00
|
|
|
ereport(ERROR,
|
2011-01-14 16:30:33 +01:00
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg_internal("%s", message)));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
replication_scanner_init(const char *str)
|
|
|
|
{
|
|
|
|
Size slen = strlen(str);
|
|
|
|
char *scanbuf;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Might be left over after ereport()
|
|
|
|
*/
|
|
|
|
if (YY_CURRENT_BUFFER)
|
|
|
|
yy_delete_buffer(YY_CURRENT_BUFFER);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make a scan buffer with special termination needed by flex.
|
|
|
|
*/
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
replication_scanner_finish()
|
|
|
|
{
|
|
|
|
yy_delete_buffer(scanbufhandle);
|
|
|
|
scanbufhandle = NULL;
|
|
|
|
}
|