mirror of
https://github.com/postgres/postgres.git
synced 2025-07-15 19:21:59 +03:00
Add decoding of sequences to built-in replication
This commit adds support for decoding of sequences to the built-in
replication (the infrastructure was added by commit 0da92dc530
).
The syntax and behavior mostly mimics handling of tables, i.e. a
publication may be defined as FOR ALL SEQUENCES (replicating all
sequences in a database), FOR ALL SEQUENCES IN SCHEMA (replicating
all sequences in a particular schema) or individual sequences.
To publish sequence modifications, the publication has to include
'sequence' action. The protocol is extended with a new message,
describing sequence increments.
A new system view pg_publication_sequences lists all the sequences
added to a publication, both directly and indirectly. Various psql
commands (\d and \dRp) are improved to also display publications
including a given sequence, or sequences included in a publication.
Author: Tomas Vondra, Cary Huang
Reviewed-by: Peter Eisentraut, Amit Kapila, Hannu Krosing, Andres
Freund, Petr Jelinek
Discussion: https://postgr.es/m/d045f3c2-6cfb-06d3-5540-e63c320df8bc@enterprisedb.com
Discussion: https://postgr.es/m/1710ed7e13b.cd7177461430746.3372264562543607781@highgo.ca
This commit is contained in:
@ -100,6 +100,7 @@
|
||||
#include "catalog/pg_subscription_rel.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "commands/copy.h"
|
||||
#include "commands/sequence.h"
|
||||
#include "miscadmin.h"
|
||||
#include "parser/parse_relation.h"
|
||||
#include "pgstat.h"
|
||||
@ -999,6 +1000,95 @@ copy_table(Relation rel)
|
||||
logicalrep_rel_close(relmapentry, NoLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetch sequence data (current state) from the remote node.
|
||||
*/
|
||||
static void
|
||||
fetch_sequence_data(char *nspname, char *relname,
|
||||
int64 *last_value, int64 *log_cnt, bool *is_called)
|
||||
{
|
||||
WalRcvExecResult *res;
|
||||
StringInfoData cmd;
|
||||
TupleTableSlot *slot;
|
||||
Oid tableRow[3] = {INT8OID, INT8OID, BOOLOID};
|
||||
|
||||
initStringInfo(&cmd);
|
||||
appendStringInfo(&cmd, "SELECT last_value, log_cnt, is_called\n"
|
||||
" FROM %s", quote_qualified_identifier(nspname, relname));
|
||||
|
||||
res = walrcv_exec(LogRepWorkerWalRcvConn, cmd.data, 3, tableRow);
|
||||
pfree(cmd.data);
|
||||
|
||||
if (res->status != WALRCV_OK_TUPLES)
|
||||
ereport(ERROR,
|
||||
(errmsg("could not receive list of replicated tables from the publisher: %s",
|
||||
res->err)));
|
||||
|
||||
/* Process the sequence. */
|
||||
slot = MakeSingleTupleTableSlot(res->tupledesc, &TTSOpsMinimalTuple);
|
||||
while (tuplestore_gettupleslot(res->tuplestore, true, false, slot))
|
||||
{
|
||||
bool isnull;
|
||||
|
||||
*last_value = DatumGetInt64(slot_getattr(slot, 1, &isnull));
|
||||
Assert(!isnull);
|
||||
|
||||
*log_cnt = DatumGetInt64(slot_getattr(slot, 2, &isnull));
|
||||
Assert(!isnull);
|
||||
|
||||
*is_called = DatumGetBool(slot_getattr(slot, 3, &isnull));
|
||||
Assert(!isnull);
|
||||
|
||||
ExecClearTuple(slot);
|
||||
}
|
||||
ExecDropSingleTupleTableSlot(slot);
|
||||
|
||||
walrcv_clear_result(res);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy existing data of a sequence from publisher.
|
||||
*
|
||||
* Caller is responsible for locking the local relation.
|
||||
*/
|
||||
static void
|
||||
copy_sequence(Relation rel)
|
||||
{
|
||||
LogicalRepRelMapEntry *relmapentry;
|
||||
LogicalRepRelation lrel;
|
||||
List *qual = NIL;
|
||||
StringInfoData cmd;
|
||||
int64 last_value = 0,
|
||||
log_cnt = 0;
|
||||
bool is_called = 0;
|
||||
|
||||
/* Get the publisher relation info. */
|
||||
fetch_remote_table_info(get_namespace_name(RelationGetNamespace(rel)),
|
||||
RelationGetRelationName(rel), &lrel, &qual);
|
||||
|
||||
/* sequences don't have row filters */
|
||||
Assert(!qual);
|
||||
|
||||
/* Put the relation into relmap. */
|
||||
logicalrep_relmap_update(&lrel);
|
||||
|
||||
/* Map the publisher relation to local one. */
|
||||
relmapentry = logicalrep_rel_open(lrel.remoteid, NoLock);
|
||||
Assert(rel == relmapentry->localrel);
|
||||
|
||||
/* Start copy on the publisher. */
|
||||
initStringInfo(&cmd);
|
||||
|
||||
Assert(lrel.relkind == RELKIND_SEQUENCE);
|
||||
|
||||
fetch_sequence_data(lrel.nspname, lrel.relname, &last_value, &log_cnt, &is_called);
|
||||
|
||||
/* tablesync sets the sequences in non-transactional way */
|
||||
SetSequence(RelationGetRelid(rel), false, last_value, log_cnt, is_called);
|
||||
|
||||
logicalrep_rel_close(relmapentry, NoLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine the tablesync slot name.
|
||||
*
|
||||
@ -1260,10 +1350,21 @@ LogicalRepSyncTableStart(XLogRecPtr *origin_startpos)
|
||||
originname)));
|
||||
}
|
||||
|
||||
/* Now do the initial data copy */
|
||||
PushActiveSnapshot(GetTransactionSnapshot());
|
||||
copy_table(rel);
|
||||
PopActiveSnapshot();
|
||||
/* Do the right action depending on the relation kind. */
|
||||
if (get_rel_relkind(RelationGetRelid(rel)) == RELKIND_SEQUENCE)
|
||||
{
|
||||
/* Now do the initial sequence copy */
|
||||
PushActiveSnapshot(GetTransactionSnapshot());
|
||||
copy_sequence(rel);
|
||||
PopActiveSnapshot();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Now do the initial data copy */
|
||||
PushActiveSnapshot(GetTransactionSnapshot());
|
||||
copy_table(rel);
|
||||
PopActiveSnapshot();
|
||||
}
|
||||
|
||||
res = walrcv_exec(LogRepWorkerWalRcvConn, "COMMIT", 0, NULL);
|
||||
if (res->status != WALRCV_OK_COMMAND)
|
||||
|
Reference in New Issue
Block a user