mirror of
https://github.com/postgres/postgres.git
synced 2025-09-02 04:21:28 +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:
@@ -15,6 +15,7 @@
|
||||
#include "access/tupconvert.h"
|
||||
#include "catalog/partition.h"
|
||||
#include "catalog/pg_publication.h"
|
||||
#include "catalog/pg_publication_namespace.h"
|
||||
#include "catalog/pg_publication_rel.h"
|
||||
#include "commands/defrem.h"
|
||||
#include "executor/executor.h"
|
||||
@@ -53,6 +54,10 @@ static void pgoutput_message(LogicalDecodingContext *ctx,
|
||||
ReorderBufferTXN *txn, XLogRecPtr message_lsn,
|
||||
bool transactional, const char *prefix,
|
||||
Size sz, const char *message);
|
||||
static void pgoutput_sequence(LogicalDecodingContext *ctx,
|
||||
ReorderBufferTXN *txn, XLogRecPtr sequence_lsn,
|
||||
Relation relation, bool transactional,
|
||||
int64 last_value, int64 log_cnt, bool is_called);
|
||||
static bool pgoutput_origin_filter(LogicalDecodingContext *ctx,
|
||||
RepOriginId origin_id);
|
||||
static void pgoutput_begin_prepare_txn(LogicalDecodingContext *ctx,
|
||||
@@ -208,6 +213,7 @@ _PG_output_plugin_init(OutputPluginCallbacks *cb)
|
||||
cb->change_cb = pgoutput_change;
|
||||
cb->truncate_cb = pgoutput_truncate;
|
||||
cb->message_cb = pgoutput_message;
|
||||
cb->sequence_cb = pgoutput_sequence;
|
||||
cb->commit_cb = pgoutput_commit_txn;
|
||||
|
||||
cb->begin_prepare_cb = pgoutput_begin_prepare_txn;
|
||||
@@ -224,6 +230,7 @@ _PG_output_plugin_init(OutputPluginCallbacks *cb)
|
||||
cb->stream_commit_cb = pgoutput_stream_commit;
|
||||
cb->stream_change_cb = pgoutput_change;
|
||||
cb->stream_message_cb = pgoutput_message;
|
||||
cb->stream_sequence_cb = pgoutput_sequence;
|
||||
cb->stream_truncate_cb = pgoutput_truncate;
|
||||
/* transaction streaming - two-phase commit */
|
||||
cb->stream_prepare_cb = pgoutput_stream_prepare_txn;
|
||||
@@ -237,6 +244,7 @@ parse_output_parameters(List *options, PGOutputData *data)
|
||||
bool publication_names_given = false;
|
||||
bool binary_option_given = false;
|
||||
bool messages_option_given = false;
|
||||
bool sequences_option_given = false;
|
||||
bool streaming_given = false;
|
||||
bool two_phase_option_given = false;
|
||||
|
||||
@@ -244,6 +252,7 @@ parse_output_parameters(List *options, PGOutputData *data)
|
||||
data->streaming = false;
|
||||
data->messages = false;
|
||||
data->two_phase = false;
|
||||
data->sequences = true;
|
||||
|
||||
foreach(lc, options)
|
||||
{
|
||||
@@ -312,6 +321,16 @@ parse_output_parameters(List *options, PGOutputData *data)
|
||||
|
||||
data->messages = defGetBoolean(defel);
|
||||
}
|
||||
else if (strcmp(defel->defname, "sequences") == 0)
|
||||
{
|
||||
if (sequences_option_given)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("conflicting or redundant options")));
|
||||
sequences_option_given = true;
|
||||
|
||||
data->sequences = defGetBoolean(defel);
|
||||
}
|
||||
else if (strcmp(defel->defname, "streaming") == 0)
|
||||
{
|
||||
if (streaming_given)
|
||||
@@ -1440,6 +1459,51 @@ pgoutput_message(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
|
||||
OutputPluginWrite(ctx, true);
|
||||
}
|
||||
|
||||
static void
|
||||
pgoutput_sequence(LogicalDecodingContext *ctx,
|
||||
ReorderBufferTXN *txn, XLogRecPtr sequence_lsn,
|
||||
Relation relation, bool transactional,
|
||||
int64 last_value, int64 log_cnt, bool is_called)
|
||||
{
|
||||
PGOutputData *data = (PGOutputData *) ctx->output_plugin_private;
|
||||
TransactionId xid = InvalidTransactionId;
|
||||
RelationSyncEntry *relentry;
|
||||
|
||||
if (!data->sequences)
|
||||
return;
|
||||
|
||||
if (!is_publishable_relation(relation))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Remember the xid for the message in streaming mode. See
|
||||
* pgoutput_change.
|
||||
*/
|
||||
if (in_streaming)
|
||||
xid = txn->xid;
|
||||
|
||||
relentry = get_rel_sync_entry(data, relation);
|
||||
|
||||
/*
|
||||
* First check the sequence filter.
|
||||
*
|
||||
* We handle just REORDER_BUFFER_CHANGE_SEQUENCE here.
|
||||
*/
|
||||
if (!relentry->pubactions.pubsequence)
|
||||
return;
|
||||
|
||||
OutputPluginPrepareWrite(ctx, true);
|
||||
logicalrep_write_sequence(ctx->out,
|
||||
relation,
|
||||
xid,
|
||||
sequence_lsn,
|
||||
transactional,
|
||||
last_value,
|
||||
log_cnt,
|
||||
is_called);
|
||||
OutputPluginWrite(ctx, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Currently we always forward.
|
||||
*/
|
||||
@@ -1725,7 +1789,8 @@ get_rel_sync_entry(PGOutputData *data, Relation relation)
|
||||
entry->schema_sent = false;
|
||||
entry->streamed_txns = NIL;
|
||||
entry->pubactions.pubinsert = entry->pubactions.pubupdate =
|
||||
entry->pubactions.pubdelete = entry->pubactions.pubtruncate = false;
|
||||
entry->pubactions.pubdelete = entry->pubactions.pubtruncate =
|
||||
entry->pubactions.pubsequence = false;
|
||||
entry->new_slot = NULL;
|
||||
entry->old_slot = NULL;
|
||||
memset(entry->exprstate, 0, sizeof(entry->exprstate));
|
||||
@@ -1739,13 +1804,13 @@ get_rel_sync_entry(PGOutputData *data, Relation relation)
|
||||
{
|
||||
Oid schemaId = get_rel_namespace(relid);
|
||||
List *pubids = GetRelationPublications(relid);
|
||||
|
||||
char objectType = pub_get_object_type_for_relkind(get_rel_relkind(relid));
|
||||
/*
|
||||
* We don't acquire a lock on the namespace system table as we build
|
||||
* the cache entry using a historic snapshot and all the later changes
|
||||
* are absorbed while decoding WAL.
|
||||
*/
|
||||
List *schemaPubids = GetSchemaPublications(schemaId);
|
||||
List *schemaPubids = GetSchemaPublications(schemaId, objectType);
|
||||
ListCell *lc;
|
||||
Oid publish_as_relid = relid;
|
||||
int publish_ancestor_level = 0;
|
||||
@@ -1780,6 +1845,7 @@ get_rel_sync_entry(PGOutputData *data, Relation relation)
|
||||
entry->pubactions.pubupdate = false;
|
||||
entry->pubactions.pubdelete = false;
|
||||
entry->pubactions.pubtruncate = false;
|
||||
entry->pubactions.pubsequence = false;
|
||||
|
||||
/*
|
||||
* Tuple slots cleanups. (Will be rebuilt later if needed).
|
||||
@@ -1826,9 +1892,11 @@ get_rel_sync_entry(PGOutputData *data, Relation relation)
|
||||
|
||||
/*
|
||||
* If this is a FOR ALL TABLES publication, pick the partition root
|
||||
* and set the ancestor level accordingly.
|
||||
* and set the ancestor level accordingly. If this is a FOR ALL
|
||||
* SEQUENCES publication, we publish it too but we don't need to
|
||||
* pick the partition root etc.
|
||||
*/
|
||||
if (pub->alltables)
|
||||
if (pub->alltables || pub->allsequences)
|
||||
{
|
||||
publish = true;
|
||||
if (pub->pubviaroot && am_partition)
|
||||
@@ -1889,6 +1957,7 @@ get_rel_sync_entry(PGOutputData *data, Relation relation)
|
||||
entry->pubactions.pubupdate |= pub->pubactions.pubupdate;
|
||||
entry->pubactions.pubdelete |= pub->pubactions.pubdelete;
|
||||
entry->pubactions.pubtruncate |= pub->pubactions.pubtruncate;
|
||||
entry->pubactions.pubsequence |= pub->pubactions.pubsequence;
|
||||
|
||||
/*
|
||||
* We want to publish the changes as the top-most ancestor
|
||||
|
Reference in New Issue
Block a user