aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/replication/repl_gram.y25
-rw-r--r--src/backend/replication/repl_scanner.l86
-rw-r--r--src/backend/replication/walsender.c43
-rw-r--r--src/include/replication/walsender_private.h1
4 files changed, 97 insertions, 58 deletions
diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y
index f93a0de2187..76bc6c0ee68 100644
--- a/src/backend/replication/repl_gram.y
+++ b/src/backend/replication/repl_gram.y
@@ -25,8 +25,6 @@
/* Result of the parsing is returned here */
Node *replication_parse_result;
-static SQLCmd *make_sqlcmd(void);
-
/*
* Bison doesn't allocate anything that needs to live across parser calls,
@@ -59,7 +57,6 @@ static SQLCmd *make_sqlcmd(void);
%token <str> SCONST IDENT
%token <uintval> UCONST
%token <recptr> RECPTR
-%token T_WORD
/* Keyword tokens. */
%token K_BASE_BACKUP
@@ -93,7 +90,7 @@ static SQLCmd *make_sqlcmd(void);
%type <node> command
%type <node> base_backup start_replication start_logical_replication
create_replication_slot drop_replication_slot identify_system
- timeline_history show sql_cmd
+ timeline_history show
%type <list> base_backup_opt_list
%type <defelt> base_backup_opt
%type <uintval> opt_timeline
@@ -126,7 +123,6 @@ command:
| drop_replication_slot
| timeline_history
| show
- | sql_cmd
;
/*
@@ -413,25 +409,6 @@ plugin_opt_arg:
| /* EMPTY */ { $$ = NULL; }
;
-sql_cmd:
- IDENT { $$ = (Node *) make_sqlcmd(); }
- ;
%%
-static SQLCmd *
-make_sqlcmd(void)
-{
- SQLCmd *cmd = makeNode(SQLCmd);
- int tok;
-
- /* Just move lexer to the end of command. */
- for (;;)
- {
- tok = yylex();
- if (tok == ';' || tok == 0)
- break;
- }
- return cmd;
-}
-
#include "repl_scanner.c"
diff --git a/src/backend/replication/repl_scanner.l b/src/backend/replication/repl_scanner.l
index 6fca2a91b63..40e19fd4f8d 100644
--- a/src/backend/replication/repl_scanner.l
+++ b/src/backend/replication/repl_scanner.l
@@ -31,6 +31,10 @@ fprintf_to_ereport(const char *fmt, const char *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;
+
+/* Work area for collecting literals */
static StringInfoData litbuf;
static void startlit(void);
@@ -51,7 +55,18 @@ static void addlitchar(unsigned char ychar);
%option warn
%option prefix="replication_yy"
-%x xq xd
+/*
+ * Exclusive states:
+ * <xd> delimited identifiers (double-quoted identifiers)
+ * <xq> standard single-quoted strings
+ */
+%x xd
+%x xq
+
+space [ \t\n\r\f]
+
+quote '
+quotestop {quote}
/* Extended quote
* xqdouble implements embedded quote, ''''
@@ -69,11 +84,8 @@ xdstop {dquote}
xddouble {dquote}{dquote}
xdinside [^"]+
-digit [0-9]+
-hexdigit [0-9A-Za-z]+
-
-quote '
-quotestop {quote}
+digit [0-9]
+hexdigit [0-9A-Fa-f]
ident_start [A-Za-z\200-\377_]
ident_cont [A-Za-z\200-\377_0-9\$]
@@ -82,6 +94,19 @@ identifier {ident_start}{ident_cont}*
%%
+%{
+ /* This code is inserted at the start of replication_yylex() */
+
+ /* If we have a pushed-back token, return that. */
+ if (repl_pushed_back_token)
+ {
+ int result = repl_pushed_back_token;
+
+ repl_pushed_back_token = 0;
+ return result;
+ }
+%}
+
BASE_BACKUP { return K_BASE_BACKUP; }
FAST { return K_FAST; }
IDENTIFY_SYSTEM { return K_IDENTIFY_SYSTEM; }
@@ -110,14 +135,7 @@ WAIT { return K_WAIT; }
MANIFEST { return K_MANIFEST; }
MANIFEST_CHECKSUMS { return K_MANIFEST_CHECKSUMS; }
-"," { return ','; }
-";" { return ';'; }
-"(" { return '('; }
-")" { return ')'; }
-
-[\n] ;
-[\t] ;
-" " ;
+{space}+ { /* do nothing */ }
{digit}+ {
yylval.uintval = strtoul(yytext, NULL, 10);
@@ -179,6 +197,11 @@ MANIFEST_CHECKSUMS { return K_MANIFEST_CHECKSUMS; }
return IDENT;
}
+. {
+ /* Any char not recognized above is returned as itself */
+ return yytext[0];
+ }
+
<xq,xd><<EOF>> { yyerror("unterminated quoted string"); }
@@ -186,9 +209,6 @@ MANIFEST_CHECKSUMS { return K_MANIFEST_CHECKSUMS; }
yyterminate();
}
-. {
- return T_WORD;
- }
%%
/* LCOV_EXCL_STOP */
@@ -248,6 +268,7 @@ replication_scanner_init(const char *str)
/* Make sure we start in proper state */
BEGIN(INITIAL);
+ repl_pushed_back_token = 0;
}
void
@@ -256,3 +277,34 @@ replication_scanner_finish(void)
yy_delete_buffer(scanbufhandle);
scanbufhandle = NULL;
}
+
+/*
+ * Check to see if the first token of a command is a WalSender keyword.
+ *
+ * To keep repl_scanner.l minimal, we don't ask it to know every construct
+ * that the core lexer knows. Therefore, we daren't lex more than the
+ * first token of a general SQL command. That will usually look like an
+ * IDENT token here, although some other cases are possible.
+ */
+bool
+replication_scanner_is_replication_command(void)
+{
+ int first_token = replication_yylex();
+
+ switch (first_token)
+ {
+ case K_IDENTIFY_SYSTEM:
+ case K_BASE_BACKUP:
+ case K_START_REPLICATION:
+ case K_CREATE_REPLICATION_SLOT:
+ case K_DROP_REPLICATION_SLOT:
+ case K_TIMELINE_HISTORY:
+ case K_SHOW:
+ /* Yes; push back the first token so we can parse later. */
+ repl_pushed_back_token = first_token;
+ return true;
+ default:
+ /* Nope; we don't bother to push back the token. */
+ return false;
+ }
+}
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 975139aff34..fe0d2ee2ed0 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -1535,7 +1535,8 @@ exec_replication_command(const char *cmd_string)
*/
if (MyWalSnd->state == WALSNDSTATE_STOPPING)
ereport(ERROR,
- (errmsg("cannot execute new commands while WAL sender is in stopping mode")));
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("cannot execute new commands while WAL sender is in stopping mode")));
/*
* CREATE_REPLICATION_SLOT ... LOGICAL exports a snapshot until the next
@@ -1546,7 +1547,7 @@ exec_replication_command(const char *cmd_string)
CHECK_FOR_INTERRUPTS();
/*
- * Parse the command.
+ * Prepare to parse and execute the command.
*/
cmd_context = AllocSetContextCreate(CurrentMemoryContext,
"Replication command context",
@@ -1554,34 +1555,42 @@ exec_replication_command(const char *cmd_string)
old_context = MemoryContextSwitchTo(cmd_context);
replication_scanner_init(cmd_string);
- parse_rc = replication_yyparse();
- if (parse_rc != 0)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg_internal("replication command parser returned %d",
- parse_rc)));
- replication_scanner_finish();
-
- cmd_node = replication_parse_result;
/*
- * If it's a SQL command, just clean up our mess and return false; the
- * caller will take care of executing it.
+ * Is it a WalSender command?
*/
- if (IsA(cmd_node, SQLCmd))
+ if (!replication_scanner_is_replication_command())
{
- if (MyDatabaseId == InvalidOid)
- ereport(ERROR,
- (errmsg("cannot execute SQL commands in WAL sender for physical replication")));
+ /* Nope; clean up and get out. */
+ replication_scanner_finish();
MemoryContextSwitchTo(old_context);
MemoryContextDelete(cmd_context);
+ /* XXX this is a pretty random place to make this check */
+ if (MyDatabaseId == InvalidOid)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot execute SQL commands in WAL sender for physical replication")));
+
/* Tell the caller that this wasn't a WalSender command. */
return false;
}
/*
+ * Looks like a WalSender command, so parse it.
+ */
+ parse_rc = replication_yyparse();
+ if (parse_rc != 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg_internal("replication command parser returned %d",
+ parse_rc)));
+ replication_scanner_finish();
+
+ cmd_node = replication_parse_result;
+
+ /*
* Report query to various monitoring facilities. For this purpose, we
* report replication commands just like SQL commands.
*/
diff --git a/src/include/replication/walsender_private.h b/src/include/replication/walsender_private.h
index 509856c057e..b7332655070 100644
--- a/src/include/replication/walsender_private.h
+++ b/src/include/replication/walsender_private.h
@@ -121,6 +121,7 @@ extern int replication_yylex(void);
extern void replication_yyerror(const char *str) pg_attribute_noreturn();
extern void replication_scanner_init(const char *query_string);
extern void replication_scanner_finish(void);
+extern bool replication_scanner_is_replication_command(void);
extern Node *replication_parse_result;