0f5ca02f53 introduces 3 new keywords.  It appears to be too much for relatively
small feature.  Given now we past feature freeze, it's already late for
discussion of the new syntax.  So, revert.

Discussion: https://postgr.es/m/28209.1586294824%40sss.pgh.pa.us
This commit is contained in:
Alexander Korotkov 2020-04-08 11:37:27 +03:00
parent 02a2e8b442
commit 1aac32df89
20 changed files with 10 additions and 585 deletions

View File

@ -21,7 +21,7 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
BEGIN [ WORK | TRANSACTION ] [ <replaceable class="parameter">transaction_mode</replaceable> [, ...] ] [ WAIT FOR LSN <replaceable class="parameter">lsn_value</replaceable> [TIMEOUT <replaceable class="parameter">number_of_milliseconds</replaceable> ] ]
BEGIN [ WORK | TRANSACTION ] [ <replaceable class="parameter">transaction_mode</replaceable> [, ...] ]
<phrase>where <replaceable class="parameter">transaction_mode</replaceable> is one of:</phrase>
@ -63,17 +63,6 @@ BEGIN [ WORK | TRANSACTION ] [ <replaceable class="parameter">transaction_mode</
<xref linkend="sql-set-transaction"/>
was executed.
</para>
<para>
The <literal>WAIT FOR</literal> clause allows to wait for the target log
sequence number (<acronym>LSN</acronym>) to be replayed on standby before
starting the transaction in <productname>PostgreSQL</productname> databases
with master-standby asynchronous replication. Wait time can be limited by
specifying a timeout, which is measured in milliseconds and must be a positive
integer. If <acronym>LSN</acronym> was not reached before timeout, transaction
doesn't begin. Waiting can be interrupted by cancelling
<literal>BEGIN</literal> command.
</para>
</refsect1>
<refsect1>
@ -157,10 +146,6 @@ BEGIN;
different purpose in embedded SQL. You are advised to be careful
about the transaction semantics when porting database applications.
</para>
<para>
There is no <literal>WAIT FOR</literal> clause in the SQL standard.
</para>
</refsect1>
<refsect1>

View File

@ -21,7 +21,7 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
START TRANSACTION [ <replaceable class="parameter">transaction_mode</replaceable> [, ...] ] [ WAIT FOR LSN <replaceable class="parameter">lsn_value</replaceable> [TIMEOUT <replaceable class="parameter">number_of_milliseconds</replaceable> ] ]
START TRANSACTION [ <replaceable class="parameter">transaction_mode</replaceable> [, ...] ]
<phrase>where <replaceable class="parameter">transaction_mode</replaceable> is one of:</phrase>
@ -40,17 +40,6 @@ START TRANSACTION [ <replaceable class="parameter">transaction_mode</replaceable
characteristics, as if <xref linkend="sql-set-transaction"/> was executed. This is the same
as the <xref linkend="sql-begin"/> command.
</para>
<para>
The <literal>WAIT FOR</literal> clause allows to wait for the target log
sequence number (<acronym>LSN</acronym>) to be replayed on standby before
starting the transaction in <productname>PostgreSQL</productname> databases
with master-standby asynchronous replication. Wait time can be limited by
specifying a timeout, which is measured in milliseconds and must be a positive
integer. If <acronym>LSN</acronym> was not reached before timeout, transaction
doesn't begin. Waiting can be interrupted by cancelling
<literal>START TRANSACTION</literal> command.
</para>
</refsect1>
<refsect1>
@ -89,10 +78,6 @@ START TRANSACTION [ <replaceable class="parameter">transaction_mode</replaceable
omitted.
</para>
<para>
There is no <literal>WAIT FOR</literal> clause in the SQL standard.
</para>
<para>
See also the compatibility section of <xref linkend="sql-set-transaction"/>.
</para>

View File

@ -42,7 +42,6 @@
#include "catalog/pg_database.h"
#include "commands/progress.h"
#include "commands/tablespace.h"
#include "commands/wait.h"
#include "common/controldata_utils.h"
#include "executor/instrument.h"
#include "miscadmin.h"
@ -7157,7 +7156,6 @@ StartupXLOG(void)
do
{
bool switchedTLI = false;
XLogRecPtr minWaitedLSN;
#ifdef WAL_DEBUG
if (XLOG_DEBUG ||
@ -7361,17 +7359,6 @@ StartupXLOG(void)
break;
}
/*
* If we replayed an LSN that someone was waiting for, set
* latches in shared memory array to notify the waiter.
*/
minWaitedLSN = WaitLSNGetMin();
if (!XLogRecPtrIsInvalid(minWaitedLSN) &&
minWaitedLSN <= XLogCtl->lastReplayedEndRecPtr)
{
WaitLSNSetLatch(XLogCtl->lastReplayedEndRecPtr);
}
/* Else, try to fetch the next WAL record */
record = ReadRecord(xlogreader, LOG, false);
} while (record != NULL);

View File

@ -57,7 +57,6 @@ OBJS = \
user.o \
vacuum.o \
variable.o \
view.o \
wait.o
view.o
include $(top_srcdir)/src/backend/common.mk

View File

@ -1,295 +0,0 @@
/*-------------------------------------------------------------------------
*
* wait.c
* Implements WAIT FOR clause for BEGIN and START TRANSACTION commands.
* This clause allows waiting for given LSN to be replayed on standby.
*
* Copyright (c) 2020, PostgreSQL Global Development Group
*
* IDENTIFICATION
* src/backend/commands/wait.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <math.h>
#include "access/xlog.h"
#include "access/xlogdefs.h"
#include "commands/wait.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "storage/backendid.h"
#include "storage/pmsignal.h"
#include "storage/proc.h"
#include "storage/shmem.h"
#include "storage/sinvaladt.h"
#include "storage/spin.h"
#include "utils/builtins.h"
#include "utils/pg_lsn.h"
#include "utils/timestamp.h"
/*
* Shared memory structure representing information about LSNs, which backends
* are waiting for replay.
*/
typedef struct
{
slock_t mutex; /* mutex protecting the fields below */
int max_backend_id; /* max backend_id present in lsns[] */
pg_atomic_uint64 min_lsn; /* minimal waited LSN */
/* per-backend array of waited LSNs */
XLogRecPtr lsns[FLEXIBLE_ARRAY_MEMBER];
} WaitLSNState;
static WaitLSNState * state;
/*
* Add the wait event of the current backend to shared memory array
*/
static void
WaitLSNAdd(XLogRecPtr lsn_to_wait)
{
SpinLockAcquire(&state->mutex);
if (state->max_backend_id < MyBackendId)
state->max_backend_id = MyBackendId;
state->lsns[MyBackendId] = lsn_to_wait;
if (lsn_to_wait < state->min_lsn.value)
state->min_lsn.value = lsn_to_wait;
SpinLockRelease(&state->mutex);
}
/*
* Delete wait event of the current backend from the shared memory array.
*/
void
WaitLSNDelete(void)
{
int i;
XLogRecPtr deleted_lsn;
SpinLockAcquire(&state->mutex);
deleted_lsn = state->lsns[MyBackendId];
state->lsns[MyBackendId] = InvalidXLogRecPtr;
/* If we are deleting the minimal LSN, then choose the next min_lsn */
if (!XLogRecPtrIsInvalid(deleted_lsn) &&
deleted_lsn == state->min_lsn.value)
{
state->min_lsn.value = InvalidXLogRecPtr;
for (i = 2; i <= state->max_backend_id; i++)
{
if (!XLogRecPtrIsInvalid(state->lsns[i]) &&
(state->lsns[i] < state->min_lsn.value ||
XLogRecPtrIsInvalid(state->min_lsn.value)))
{
state->min_lsn.value = state->lsns[i];
}
}
}
/* If deleting from the end of the array, shorten the array's used part */
if (state->max_backend_id == MyBackendId)
{
for (i = (MyBackendId); i >= 2; i--)
if (!XLogRecPtrIsInvalid(state->lsns[i]))
{
state->max_backend_id = i;
break;
}
}
SpinLockRelease(&state->mutex);
}
/*
* Report amount of shared memory space needed for WaitLSNState
*/
Size
WaitLSNShmemSize(void)
{
Size size;
size = offsetof(WaitLSNState, lsns);
size = add_size(size, mul_size(MaxBackends + 1, sizeof(XLogRecPtr)));
return size;
}
/*
* Initialize an shared memory structure for waiting for LSN
*/
void
WaitLSNShmemInit(void)
{
bool found;
uint32 i;
state = (WaitLSNState *) ShmemInitStruct("pg_wait_lsn",
WaitLSNShmemSize(),
&found);
if (!found)
{
SpinLockInit(&state->mutex);
for (i = 0; i < (MaxBackends + 1); i++)
state->lsns[i] = InvalidXLogRecPtr;
state->max_backend_id = 0;
pg_atomic_init_u64(&state->min_lsn, InvalidXLogRecPtr);
}
}
/*
* Set latches in shared memory to signal that new LSN has been replayed
*/
void
WaitLSNSetLatch(XLogRecPtr cur_lsn)
{
uint32 i;
int max_backend_id;
PGPROC *backend;
SpinLockAcquire(&state->mutex);
max_backend_id = state->max_backend_id;
for (i = 2; i <= max_backend_id; i++)
{
backend = BackendIdGetProc(i);
if (backend && state->lsns[i] != 0 &&
state->lsns[i] <= cur_lsn)
{
SetLatch(&backend->procLatch);
}
}
SpinLockRelease(&state->mutex);
}
/*
* Get minimal LSN that some backend is waiting for
*/
XLogRecPtr
WaitLSNGetMin(void)
{
return state->min_lsn.value;
}
/*
* On WAIT use a latch to wait till LSN is replayed, postmaster dies or timeout
* happens. Timeout is specified in milliseconds. Returns true if LSN was
* reached and false otherwise.
*/
bool
WaitLSNUtility(XLogRecPtr target_lsn, const int timeout_ms)
{
XLogRecPtr cur_lsn;
int latch_events;
float8 endtime;
bool res = false;
bool wait_forever = (timeout_ms <= 0);
endtime = GetNowFloat() + timeout_ms / 1000.0;
latch_events = WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH;
/* Check if we already reached the needed LSN */
cur_lsn = GetXLogReplayRecPtr(NULL);
if (cur_lsn >= target_lsn)
return true;
WaitLSNAdd(target_lsn);
ResetLatch(MyLatch);
/* Recheck if LSN was reached while WaitLSNAdd() and ResetLatch() */
cur_lsn = GetXLogReplayRecPtr(NULL);
if (cur_lsn >= target_lsn)
return true;
for (;;)
{
int rc;
float8 time_left = 0;
long time_left_ms = 0;
time_left = endtime - GetNowFloat();
/* Use 1 second as the default timeout to check for interrupts */
if (wait_forever || time_left < 0 || time_left > 1.0)
time_left_ms = 1000;
else
time_left_ms = (long) ceil(time_left * 1000.0);
/* If interrupt, LockErrorCleanup() will do WaitLSNDelete() for us */
CHECK_FOR_INTERRUPTS();
/* If postmaster dies, finish immediately */
if (!PostmasterIsAlive())
break;
rc = WaitLatch(MyLatch, latch_events, time_left_ms,
WAIT_EVENT_CLIENT_READ);
ResetLatch(MyLatch);
if (rc & WL_LATCH_SET)
cur_lsn = GetXLogReplayRecPtr(NULL);
if (rc & WL_TIMEOUT)
{
time_left = endtime - GetNowFloat();
/* If the time specified by user has passed, stop waiting */
if (!wait_forever && time_left <= 0.0)
break;
cur_lsn = GetXLogReplayRecPtr(NULL);
}
/* If LSN has been replayed */
if (target_lsn <= cur_lsn)
break;
}
WaitLSNDelete();
if (cur_lsn < target_lsn)
ereport(WARNING,
(errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
errmsg("didn't start transaction because LSN was not reached"),
errhint("Try to increase wait timeout.")));
else
res = true;
return res;
}
/*
* Implementation of WAIT FOR clause for BEGIN and START TRANSACTION commands
*/
int
WaitLSNMain(WaitClause *stmt, DestReceiver *dest)
{
TupleDesc tupdesc;
TupOutputState *tstate;
XLogRecPtr target_lsn;
bool res = false;
target_lsn = DatumGetLSN(DirectFunctionCall1(pg_lsn_in,
CStringGetDatum(stmt->lsn)));
res = WaitLSNUtility(target_lsn, stmt->timeout);
/* Need a tuple descriptor representing a single TEXT column */
tupdesc = CreateTemplateTupleDesc(1);
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "LSN reached", TEXTOID, -1, 0);
/* Prepare for projection of tuples */
tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsMinimalTuple);
/* Send the result */
do_text_output_oneline(tstate, res ? "t" : "f");
end_tup_output(tstate);
return res;
}

View File

@ -3748,22 +3748,10 @@ _copyTransactionStmt(const TransactionStmt *from)
COPY_STRING_FIELD(savepoint_name);
COPY_STRING_FIELD(gid);
COPY_SCALAR_FIELD(chain);
COPY_NODE_FIELD(wait);
return newnode;
}
static WaitClause *
_copyWaitClause(const WaitClause *from)
{
WaitClause *newnode = makeNode(WaitClause);
COPY_STRING_FIELD(lsn);
COPY_SCALAR_FIELD(timeout);
return newnode;
};
static CompositeTypeStmt *
_copyCompositeTypeStmt(const CompositeTypeStmt *from)
{
@ -5351,9 +5339,6 @@ copyObjectImpl(const void *from)
case T_TransactionStmt:
retval = _copyTransactionStmt(from);
break;
case T_WaitClause:
retval = _copyWaitClause(from);
break;
case T_CompositeTypeStmt:
retval = _copyCompositeTypeStmt(from);
break;

View File

@ -1541,16 +1541,6 @@ _equalTransactionStmt(const TransactionStmt *a, const TransactionStmt *b)
COMPARE_STRING_FIELD(savepoint_name);
COMPARE_STRING_FIELD(gid);
COMPARE_SCALAR_FIELD(chain);
COMPARE_NODE_FIELD(wait);
return true;
}
static bool
_equalWaitClause(const WaitClause *a, const WaitClause *b)
{
COMPARE_STRING_FIELD(lsn);
COMPARE_SCALAR_FIELD(timeout);
return true;
}
@ -3401,9 +3391,6 @@ equal(const void *a, const void *b)
case T_TransactionStmt:
retval = _equalTransactionStmt(a, b);
break;
case T_WaitClause:
retval = _equalWaitClause(a, b);
break;
case T_CompositeTypeStmt:
retval = _equalCompositeTypeStmt(a, b);
break;

View File

@ -2786,28 +2786,6 @@ _outDefElem(StringInfo str, const DefElem *node)
WRITE_LOCATION_FIELD(location);
}
static void
_outTransactionStmt(StringInfo str, const TransactionStmt *node)
{
WRITE_NODE_TYPE("TRANSACTIONSTMT");
WRITE_STRING_FIELD(savepoint_name);
WRITE_STRING_FIELD(gid);
WRITE_NODE_FIELD(options);
WRITE_BOOL_FIELD(chain);
WRITE_ENUM_FIELD(kind, TransactionStmtKind);
WRITE_NODE_FIELD(wait);
}
static void
_outWaitClause(StringInfo str, const WaitClause *node)
{
WRITE_NODE_TYPE("WAITCLAUSE");
WRITE_STRING_FIELD(lsn);
WRITE_UINT_FIELD(timeout);
}
static void
_outTableLikeClause(StringInfo str, const TableLikeClause *node)
{
@ -4358,12 +4336,6 @@ outNode(StringInfo str, const void *obj)
case T_PartitionRangeDatum:
_outPartitionRangeDatum(str, obj);
break;
case T_TransactionStmt:
_outTransactionStmt(str, obj);
break;
case T_WaitClause:
_outWaitClause(str, obj);
break;
default:

View File

@ -601,8 +601,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <partboundspec> PartitionBoundSpec
%type <list> hash_partbound
%type <defelt> hash_partbound_elem
%type <ival> wait_time
%type <node> wait_for
/*
* Non-keyword token types. These are hard-wired into the "flex" lexer.
@ -672,7 +670,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
LABEL LANGUAGE LARGE_P LAST_P LATERAL_P
LEADING LEAKPROOF LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL
LOCALTIME LOCALTIMESTAMP LOCATION LOCK_P LOCKED LOGGED LSN
LOCALTIME LOCALTIMESTAMP LOCATION LOCK_P LOCKED LOGGED
MAPPING MATCH MATERIALIZED MAXVALUE METHOD MINUTE_P MINVALUE MODE MONTH_P MOVE
@ -703,7 +701,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
SUBSCRIPTION SUBSTRING SUPPORT SYMMETRIC SYSID SYSTEM_P
TABLE TABLES TABLESAMPLE TABLESPACE TEMP TEMPLATE TEMPORARY TEXT_P THEN
TIES TIME TIMEOUT TIMESTAMP TO TRAILING TRANSACTION TRANSFORM
TIES TIME TIMESTAMP TO TRAILING TRANSACTION TRANSFORM
TREAT TRIGGER TRIM TRUE_P
TRUNCATE TRUSTED TYPE_P TYPES_P
@ -713,8 +711,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
VACUUM VALID VALIDATE VALIDATOR VALUE_P VALUES VARCHAR VARIADIC VARYING
VERBOSE VERSION_P VIEW VIEWS VOLATILE
WAIT WHEN WHERE WHITESPACE_P WINDOW
WITH WITHIN WITHOUT WORK WRAPPER WRITE
WHEN WHERE WHITESPACE_P WINDOW WITH WITHIN WITHOUT WORK WRAPPER WRITE
XML_P XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLEXISTS XMLFOREST XMLNAMESPACES
XMLPARSE XMLPI XMLROOT XMLSERIALIZE XMLTABLE
@ -9958,20 +9955,18 @@ TransactionStmt:
n->chain = $3;
$$ = (Node *)n;
}
| BEGIN_P opt_transaction transaction_mode_list_or_empty wait_for
| BEGIN_P opt_transaction transaction_mode_list_or_empty
{
TransactionStmt *n = makeNode(TransactionStmt);
n->kind = TRANS_STMT_BEGIN;
n->options = $3;
n->wait = $4;
$$ = (Node *)n;
}
| START TRANSACTION transaction_mode_list_or_empty wait_for
| START TRANSACTION transaction_mode_list_or_empty
{
TransactionStmt *n = makeNode(TransactionStmt);
n->kind = TRANS_STMT_START;
n->options = $3;
n->wait = $4;
$$ = (Node *)n;
}
| COMMIT opt_transaction opt_transaction_chain
@ -14245,25 +14240,6 @@ xml_passing_mech:
| BY VALUE_P
;
/*
* WAIT FOR clause of BEGIN and START TRANSACTION statements
*/
wait_for:
WAIT FOR LSN Sconst wait_time
{
WaitClause *n = makeNode(WaitClause);
n->lsn = $4;
n->timeout = $5;
$$ = (Node *)n;
}
| /* EMPTY */ { $$ = NULL; }
;
wait_time:
TIMEOUT Iconst { $$ = $2; }
| /* EMPTY */ { $$ = 0; }
;
/*
* Aggregate decoration clauses
@ -15415,7 +15391,6 @@ unreserved_keyword:
| LOCK_P
| LOCKED
| LOGGED
| LSN
| MAPPING
| MATCH
| MATERIALIZED
@ -15543,7 +15518,6 @@ unreserved_keyword:
| TEMPORARY
| TEXT_P
| TIES
| TIMEOUT
| TRANSACTION
| TRANSFORM
| TRIGGER
@ -15570,7 +15544,6 @@ unreserved_keyword:
| VIEW
| VIEWS
| VOLATILE
| WAIT
| WHITESPACE_P
| WITHIN
| WITHOUT

View File

@ -22,7 +22,6 @@
#include "access/subtrans.h"
#include "access/twophase.h"
#include "commands/async.h"
#include "commands/wait.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "postmaster/autovacuum.h"
@ -148,7 +147,6 @@ CreateSharedMemoryAndSemaphores(void)
size = add_size(size, BTreeShmemSize());
size = add_size(size, SyncScanShmemSize());
size = add_size(size, AsyncShmemSize());
size = add_size(size, WaitLSNShmemSize());
#ifdef EXEC_BACKEND
size = add_size(size, ShmemBackendArraySize());
#endif
@ -266,11 +264,6 @@ CreateSharedMemoryAndSemaphores(void)
SyncScanShmemInit();
AsyncShmemInit();
/*
* Init array of Latches in shared memory for WAIT
*/
WaitLSNShmemInit();
#ifdef EXEC_BACKEND
/*

View File

@ -38,7 +38,6 @@
#include "access/transam.h"
#include "access/twophase.h"
#include "access/xact.h"
#include "commands/wait.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "postmaster/autovacuum.h"
@ -718,9 +717,6 @@ LockErrorCleanup(void)
AbortStrongLockAcquire();
/* If BEGIN WAIT FOR LSN was interrupted, then stop waiting for that LSN */
WaitLSNDelete();
/* Nothing to do if we weren't waiting for a lock */
if (lockAwaited == NULL)
{

View File

@ -57,7 +57,6 @@
#include "commands/user.h"
#include "commands/vacuum.h"
#include "commands/view.h"
#include "commands/wait.h"
#include "miscadmin.h"
#include "parser/parse_utilcmd.h"
#include "postmaster/bgwriter.h"
@ -592,18 +591,6 @@ standard_ProcessUtility(PlannedStmt *pstmt,
case TRANS_STMT_START:
{
ListCell *lc;
WaitClause *waitstmt = (WaitClause *) stmt->wait;
/* WAIT FOR cannot be used on master */
if (stmt->wait && !RecoveryInProgress())
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("WAIT FOR can only be "
"used on standby")));
/* If needed to WAIT FOR something but failed */
if (stmt->wait && WaitLSNMain(waitstmt, dest) == 0)
break;
BeginTransactionBlock();
foreach(lc, stmt->options)

View File

@ -372,6 +372,8 @@ pg_sleep(PG_FUNCTION_ARGS)
* less than the specified time when WaitLatch is terminated early by a
* non-query-canceling signal such as SIGHUP.
*/
#define GetNowFloat() ((float8) GetCurrentTimestamp() / 1000000.0)
endtime = GetNowFloat() + secs;
for (;;)

View File

@ -1,26 +0,0 @@
/*-------------------------------------------------------------------------
*
* wait.h
* prototypes for commands/wait.c
*
* Copyright (c) 2020, PostgreSQL Global Development Group
*
* src/include/commands/wait.h
*
*-------------------------------------------------------------------------
*/
#ifndef WAIT_H
#define WAIT_H
#include "tcop/dest.h"
#include "nodes/parsenodes.h"
extern bool WaitLSNUtility(XLogRecPtr lsn, const int timeout_ms);
extern Size WaitLSNShmemSize(void);
extern void WaitLSNShmemInit(void);
extern void WaitLSNSetLatch(XLogRecPtr cur_lsn);
extern XLogRecPtr WaitLSNGetMin(void);
extern int WaitLSNMain(WaitClause *stmt, DestReceiver *dest);
extern void WaitLSNDelete(void);
#endif /* WAIT_H */

View File

@ -492,7 +492,6 @@ typedef enum NodeTag
T_StartReplicationCmd,
T_TimeLineHistoryCmd,
T_SQLCmd,
T_WaitClause,
/*
* TAGS FOR RANDOM OTHER STUFF

View File

@ -1431,17 +1431,6 @@ typedef struct OnConflictClause
int location; /* token location, or -1 if unknown */
} OnConflictClause;
/*
* WaitClause -
* representation of WAIT FOR clause for BEGIN and START TRANSACTION.
*/
typedef struct WaitClause
{
NodeTag type;
char *lsn; /* LSN to wait for */
int timeout; /* Number of milliseconds to limit wait time */
} WaitClause;
/*
* CommonTableExpr -
* representation of WITH list element
@ -3071,7 +3060,6 @@ typedef struct TransactionStmt
char *savepoint_name; /* for savepoint commands */
char *gid; /* for two-phase-commit related commands */
bool chain; /* AND CHAIN option */
Node *wait; /* WAIT FOR clause */
} TransactionStmt;
/* ----------------------

View File

@ -243,7 +243,6 @@ PG_KEYWORD("location", LOCATION, UNRESERVED_KEYWORD)
PG_KEYWORD("lock", LOCK_P, UNRESERVED_KEYWORD)
PG_KEYWORD("locked", LOCKED, UNRESERVED_KEYWORD)
PG_KEYWORD("logged", LOGGED, UNRESERVED_KEYWORD)
PG_KEYWORD("lsn", LSN, UNRESERVED_KEYWORD)
PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD)
PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD)
PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD)
@ -411,7 +410,6 @@ PG_KEYWORD("text", TEXT_P, UNRESERVED_KEYWORD)
PG_KEYWORD("then", THEN, RESERVED_KEYWORD)
PG_KEYWORD("ties", TIES, UNRESERVED_KEYWORD)
PG_KEYWORD("time", TIME, COL_NAME_KEYWORD)
PG_KEYWORD("timeout", TIMEOUT, UNRESERVED_KEYWORD)
PG_KEYWORD("timestamp", TIMESTAMP, COL_NAME_KEYWORD)
PG_KEYWORD("to", TO, RESERVED_KEYWORD)
PG_KEYWORD("trailing", TRAILING, RESERVED_KEYWORD)
@ -452,7 +450,6 @@ PG_KEYWORD("version", VERSION_P, UNRESERVED_KEYWORD)
PG_KEYWORD("view", VIEW, UNRESERVED_KEYWORD)
PG_KEYWORD("views", VIEWS, UNRESERVED_KEYWORD)
PG_KEYWORD("volatile", VOLATILE, UNRESERVED_KEYWORD)
PG_KEYWORD("wait", WAIT, UNRESERVED_KEYWORD)
PG_KEYWORD("when", WHEN, RESERVED_KEYWORD)
PG_KEYWORD("where", WHERE, RESERVED_KEYWORD)
PG_KEYWORD("whitespace", WHITESPACE_P, UNRESERVED_KEYWORD)

View File

@ -109,6 +109,4 @@ extern int date2isoyearday(int year, int mon, int mday);
extern bool TimestampTimestampTzRequiresRewrite(void);
#define GetNowFloat() ((float8) GetCurrentTimestamp() / 1000000.0)
#endif /* TIMESTAMP_H */

View File

@ -1,85 +0,0 @@
# Checks for BEGIN WAIT FOR LSN
use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 8;
# Initialize master node
my $node_master = get_new_node('master');
$node_master->init(allows_streaming => 1);
$node_master->start;
# And some content and take a backup
$node_master->safe_psql('postgres',
"CREATE TABLE wait_test AS SELECT generate_series(1,10) AS a");
my $backup_name = 'my_backup';
$node_master->backup($backup_name);
# Using the backup, create a streaming standby with a 1 second delay
my $node_standby = get_new_node('standby');
my $delay = 1;
$node_standby->init_from_backup($node_master, $backup_name,
has_streaming => 1);
$node_standby->append_conf('postgresql.conf', qq[
recovery_min_apply_delay = '${delay}s'
]);
$node_standby->start;
# Check that timeouts make us wait for the specified time (1s here)
my $current_time = $node_standby->safe_psql('postgres', "SELECT now()");
my $two_seconds = 2000; # in milliseconds
my $start_time = time();
$node_standby->safe_psql('postgres',
"BEGIN WAIT FOR LSN '0/FFFFFFFF' TIMEOUT $two_seconds");
my $time_waited = (time() - $start_time) * 1000; # convert to milliseconds
ok($time_waited >= $two_seconds, "WAIT FOR TIMEOUT waits for enough time");
# Check that timeouts let us stop waiting right away, before reaching target LSN
$node_master->safe_psql('postgres',
"INSERT INTO wait_test VALUES (generate_series(11, 20))");
my $lsn1 = $node_master->safe_psql('postgres', "SELECT pg_current_wal_lsn()");
my ($ret, $out, $err) = $node_standby->psql('postgres',
"BEGIN WAIT FOR LSN '$lsn1' TIMEOUT 1");
ok($ret == 0, "zero return value when failed to WAIT FOR LSN on standby");
ok($err =~ /WARNING: didn't start transaction because LSN was not reached/,
"correct error message when failed to WAIT FOR LSN on standby");
ok($out eq "f", "if given too little wait time, WAIT doesn't reach target LSN");
# Check that WAIT FOR works fine and reaches target LSN if given no timeout
# Add data on master, memorize master's last LSN
$node_master->safe_psql('postgres',
"INSERT INTO wait_test VALUES (generate_series(21, 30))");
my $lsn2 = $node_master->safe_psql('postgres', "SELECT pg_current_wal_lsn()");
# Wait for it to appear on replica, memorize replica's last LSN
$node_standby->safe_psql('postgres',
"BEGIN WAIT FOR LSN '$lsn2'");
my $reached_lsn = $node_standby->safe_psql('postgres',
"SELECT pg_last_wal_replay_lsn()");
# Make sure that master's and replica's LSNs are the same after WAIT
my $compare_lsns = $node_standby->safe_psql('postgres',
"SELECT pg_lsn_cmp('$reached_lsn'::pg_lsn, '$lsn2'::pg_lsn)");
ok($compare_lsns eq 0,
"standby reached the same LSN as master before starting transaction");
# Make sure that it's not allowed to use WAIT FOR on master
($ret, $out, $err) = $node_master->psql('postgres',
"BEGIN WAIT FOR LSN '0/FFFFFFFF'");
ok($ret != 0, "non-zero return value when trying to WAIT FOR LSN on master");
ok($err =~ /ERROR: WAIT FOR can only be used on standby/,
"correct error message when trying to WAIT FOR LSN on master");
ok($out eq '', "empty output when trying to WAIT FOR LSN on master");
$node_standby->stop;
$node_master->stop;

View File

@ -2621,7 +2621,6 @@ WSABUF
WSADATA
WSANETWORKEVENTS
WSAPROTOCOL_INFO
WaitClause
WaitEvent
WaitEventActivity
WaitEventClient
@ -2629,7 +2628,6 @@ WaitEventIO
WaitEventIPC
WaitEventSet
WaitEventTimeout
WaitLSNState
WaitPMResult
WalCloseMethod
WalLevel