mirror of
https://github.com/postgres/postgres.git
synced 2026-04-05 01:07:27 -04:00
In logical replication mode, a WalSender is supposed to be able to execute any regular SQL command, as well as the special replication commands. Poor design of the replication-command parser caused it to fail in various cases, notably: * semicolons embedded in a command, or multiple SQL commands sent in a single message; * dollar-quoted literals containing odd numbers of single or double quote marks; * commands starting with a comment. The basic problem here is that we're trying to run repl_scanner.l across the entire input string even when it's not a replication command. Since repl_scanner.l does not understand all of the token types known to the core lexer, this is doomed to have failure modes. We certainly don't want to make repl_scanner.l as big as scan.l, so instead rejigger stuff so that we only lex the first token of a non-replication command. That will usually look like an IDENT to repl_scanner.l, though a comment would end up getting reported as a '-' or '/' single-character token. If the token is a replication command keyword, we push it back and proceed normally with repl_gram.y parsing. Otherwise, we can drop out of exec_replication_command() without examining the rest of the string. (It's still theoretically possible for repl_scanner.l to fail on the first token; but that could only happen if it's an unterminated single- or double-quoted string, in which case you'd have gotten largely the same error from the core lexer too.) In this way, repl_gram.y isn't involved at all in handling general SQL commands, so we can get rid of the SQLCmd node type. (In the back branches, we can't remove it because renumbering enum NodeTag would be an ABI break; so just leave it sit there unused.) I failed to resist the temptation to clean up some other sloppy coding in repl_scanner.l while at it. The only externally-visible behavior change from that is it now accepts \r and \f as whitespace, same as the core lexer. Per bug #17379 from Greg Rychlewski. Back-patch to all supported branches. Discussion: https://postgr.es/m/17379-6a5c6cfb3f1f5e77@postgresql.org
128 lines
3.5 KiB
C
128 lines
3.5 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* walsender_private.h
|
|
* Private definitions from replication/walsender.c.
|
|
*
|
|
* Portions Copyright (c) 2010-2022, PostgreSQL Global Development Group
|
|
*
|
|
* src/include/replication/walsender_private.h
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#ifndef _WALSENDER_PRIVATE_H
|
|
#define _WALSENDER_PRIVATE_H
|
|
|
|
#include "access/xlog.h"
|
|
#include "nodes/nodes.h"
|
|
#include "replication/syncrep.h"
|
|
#include "storage/latch.h"
|
|
#include "storage/shmem.h"
|
|
#include "storage/spin.h"
|
|
|
|
typedef enum WalSndState
|
|
{
|
|
WALSNDSTATE_STARTUP = 0,
|
|
WALSNDSTATE_BACKUP,
|
|
WALSNDSTATE_CATCHUP,
|
|
WALSNDSTATE_STREAMING,
|
|
WALSNDSTATE_STOPPING
|
|
} WalSndState;
|
|
|
|
/*
|
|
* Each walsender has a WalSnd struct in shared memory.
|
|
*
|
|
* This struct is protected by its 'mutex' spinlock field, except that some
|
|
* members are only written by the walsender process itself, and thus that
|
|
* process is free to read those members without holding spinlock. pid and
|
|
* needreload always require the spinlock to be held for all accesses.
|
|
*/
|
|
typedef struct WalSnd
|
|
{
|
|
pid_t pid; /* this walsender's PID, or 0 if not active */
|
|
|
|
WalSndState state; /* this walsender's state */
|
|
XLogRecPtr sentPtr; /* WAL has been sent up to this point */
|
|
bool needreload; /* does currently-open file need to be
|
|
* reloaded? */
|
|
|
|
/*
|
|
* The xlog locations that have been written, flushed, and applied by
|
|
* standby-side. These may be invalid if the standby-side has not offered
|
|
* values yet.
|
|
*/
|
|
XLogRecPtr write;
|
|
XLogRecPtr flush;
|
|
XLogRecPtr apply;
|
|
|
|
/* Measured lag times, or -1 for unknown/none. */
|
|
TimeOffset writeLag;
|
|
TimeOffset flushLag;
|
|
TimeOffset applyLag;
|
|
|
|
/*
|
|
* The priority order of the standby managed by this WALSender, as listed
|
|
* in synchronous_standby_names, or 0 if not-listed.
|
|
*/
|
|
int sync_standby_priority;
|
|
|
|
/* Protects shared variables shown above. */
|
|
slock_t mutex;
|
|
|
|
/*
|
|
* Pointer to the walsender's latch. Used by backends to wake up this
|
|
* walsender when it has work to do. NULL if the walsender isn't active.
|
|
*/
|
|
Latch *latch;
|
|
|
|
/*
|
|
* Timestamp of the last message received from standby.
|
|
*/
|
|
TimestampTz replyTime;
|
|
} WalSnd;
|
|
|
|
extern WalSnd *MyWalSnd;
|
|
|
|
/* There is one WalSndCtl struct for the whole database cluster */
|
|
typedef struct
|
|
{
|
|
/*
|
|
* Synchronous replication queue with one queue per request type.
|
|
* Protected by SyncRepLock.
|
|
*/
|
|
SHM_QUEUE SyncRepQueue[NUM_SYNC_REP_WAIT_MODE];
|
|
|
|
/*
|
|
* Current location of the head of the queue. All waiters should have a
|
|
* waitLSN that follows this value. Protected by SyncRepLock.
|
|
*/
|
|
XLogRecPtr lsn[NUM_SYNC_REP_WAIT_MODE];
|
|
|
|
/*
|
|
* Are any sync standbys defined? Waiting backends can't reload the
|
|
* config file safely, so checkpointer updates this value as needed.
|
|
* Protected by SyncRepLock.
|
|
*/
|
|
bool sync_standbys_defined;
|
|
|
|
WalSnd walsnds[FLEXIBLE_ARRAY_MEMBER];
|
|
} WalSndCtlData;
|
|
|
|
extern WalSndCtlData *WalSndCtl;
|
|
|
|
|
|
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 *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;
|
|
|
|
#endif /* _WALSENDER_PRIVATE_H */
|