logicalrep-partition-code-fixes.patch
application/octet-stream
Filename: logicalrep-partition-code-fixes.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| src/backend/replication/pgoutput/pgoutput.c | 59 | 62 |
diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c
index 5fbf2d4..c499410 100644
--- a/src/backend/replication/pgoutput/pgoutput.c
+++ b/src/backend/replication/pgoutput/pgoutput.c
@@ -299,14 +299,7 @@ maybe_send_schema(LogicalDecodingContext *ctx,
if (relentry->publish_as_relid != RelationGetRelid(relation))
{
Relation ancestor = RelationIdGetRelation(relentry->publish_as_relid);
- TupleDesc indesc = RelationGetDescr(relation);
- TupleDesc outdesc = RelationGetDescr(ancestor);
- MemoryContext oldctx;
-
- /* Map must live as long as the session does. */
- oldctx = MemoryContextSwitchTo(CacheMemoryContext);
- relentry->map = convert_tuples_by_name(indesc, outdesc);
- MemoryContextSwitchTo(oldctx);
+
send_relation_and_attrs(ancestor, ctx);
RelationClose(ancestor);
}
@@ -362,6 +355,9 @@ pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
PGOutputData *data = (PGOutputData *) ctx->output_plugin_private;
MemoryContext old;
RelationSyncEntry *relentry;
+ Relation ancestor = NULL;
+ HeapTuple oldtuple;
+ HeapTuple newtuple;
if (!is_publishable_relation(relation))
return;
@@ -392,67 +388,43 @@ pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
maybe_send_schema(ctx, relation, relentry);
+ /* Switch relation if publishing via ancestor. */
+ if (relentry->publish_as_relid != RelationGetRelid(relation))
+ {
+ Assert(relation->rd_rel->relispartition);
+ ancestor = RelationIdGetRelation(relentry->publish_as_relid);
+ relation = ancestor;
+ }
+
+ /* Set oldtuple/newtuple and convert to ancestor rowtype if necessary. */
+ oldtuple = change->data.tp.oldtuple ?
+ &change->data.tp.oldtuple->tuple : NULL;
+ if (oldtuple && relentry->map)
+ oldtuple = execute_attr_map_tuple(oldtuple, relentry->map);
+
+ newtuple = change->data.tp.newtuple ?
+ &change->data.tp.newtuple->tuple : NULL;
+ if (newtuple && relentry->map)
+ newtuple = execute_attr_map_tuple(newtuple, relentry->map);
+
/* Send the data */
switch (change->action)
{
case REORDER_BUFFER_CHANGE_INSERT:
- {
- HeapTuple tuple = &change->data.tp.newtuple->tuple;
-
- /* Switch relation if publishing via root. */
- if (relentry->publish_as_relid != RelationGetRelid(relation))
- {
- Assert(relation->rd_rel->relispartition);
- relation = RelationIdGetRelation(relentry->publish_as_relid);
- /* Convert tuple if needed. */
- if (relentry->map)
- tuple = execute_attr_map_tuple(tuple, relentry->map);
- }
+ OutputPluginPrepareWrite(ctx, true);
+ logicalrep_write_insert(ctx->out, relation, newtuple);
+ OutputPluginWrite(ctx, true);
+ break;
- OutputPluginPrepareWrite(ctx, true);
- logicalrep_write_insert(ctx->out, relation, tuple);
- OutputPluginWrite(ctx, true);
- break;
- }
case REORDER_BUFFER_CHANGE_UPDATE:
- {
- HeapTuple oldtuple = change->data.tp.oldtuple ?
- &change->data.tp.oldtuple->tuple : NULL;
- HeapTuple newtuple = &change->data.tp.newtuple->tuple;
-
- /* Switch relation if publishing via root. */
- if (relentry->publish_as_relid != RelationGetRelid(relation))
- {
- Assert(relation->rd_rel->relispartition);
- relation = RelationIdGetRelation(relentry->publish_as_relid);
- /* Convert tuples if needed. */
- if (relentry->map)
- {
- oldtuple = execute_attr_map_tuple(oldtuple, relentry->map);
- newtuple = execute_attr_map_tuple(newtuple, relentry->map);
- }
- }
+ OutputPluginPrepareWrite(ctx, true);
+ logicalrep_write_update(ctx->out, relation, oldtuple, newtuple);
+ OutputPluginWrite(ctx, true);
+ break;
- OutputPluginPrepareWrite(ctx, true);
- logicalrep_write_update(ctx->out, relation, oldtuple, newtuple);
- OutputPluginWrite(ctx, true);
- break;
- }
case REORDER_BUFFER_CHANGE_DELETE:
- if (change->data.tp.oldtuple)
+ if (oldtuple)
{
- HeapTuple oldtuple = &change->data.tp.oldtuple->tuple;
-
- /* Switch relation if publishing via root. */
- if (relentry->publish_as_relid != RelationGetRelid(relation))
- {
- Assert(relation->rd_rel->relispartition);
- relation = RelationIdGetRelation(relentry->publish_as_relid);
- /* Convert tuple if needed. */
- if (relentry->map)
- oldtuple = execute_attr_map_tuple(oldtuple, relentry->map);
- }
-
OutputPluginPrepareWrite(ctx, true);
logicalrep_write_delete(ctx->out, relation, oldtuple);
OutputPluginWrite(ctx, true);
@@ -460,10 +432,14 @@ pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
else
elog(DEBUG1, "didn't send DELETE change because of missing oldtuple");
break;
+
default:
Assert(false);
}
+ if (ancestor)
+ RelationClose(ancestor);
+
/* Cleanup */
MemoryContextSwitchTo(old);
MemoryContextReset(data->context);
@@ -635,8 +611,6 @@ static RelationSyncEntry *
get_rel_sync_entry(PGOutputData *data, Oid relid)
{
RelationSyncEntry *entry;
- bool am_partition = get_rel_relispartition(relid);
- char relkind = get_rel_relkind(relid);
bool found;
MemoryContext oldctx;
@@ -656,6 +630,9 @@ get_rel_sync_entry(PGOutputData *data, Oid relid)
List *pubids = GetRelationPublications(relid);
ListCell *lc;
Oid publish_as_relid = relid;
+ Relation relation = RelationIdGetRelation(relid);
+ bool am_partition = relation->rd_rel->relispartition;
+ char relkind = relation->rd_rel->relkind;
/* Reload publications if needed before use. */
if (!publications_valid)
@@ -745,7 +722,27 @@ get_rel_sync_entry(PGOutputData *data, Oid relid)
list_free(pubids);
entry->publish_as_relid = publish_as_relid;
+ /* Also set map while at it. */
+ if (publish_as_relid != relid)
+ {
+ Relation ancestor = RelationIdGetRelation(publish_as_relid);
+ TupleDesc indesc = RelationGetDescr(relation);
+ TupleDesc outdesc = RelationGetDescr(ancestor);
+ MemoryContext oldctx;
+
+ /*
+ * Map must live as long as the session does. TupleDescs must be
+ * copied before putting into the map, because they may not live
+ * as long as we want the map to live.
+ */
+ oldctx = MemoryContextSwitchTo(CacheMemoryContext);
+ entry->map = convert_tuples_by_name(CreateTupleDescCopy(indesc),
+ CreateTupleDescCopy(outdesc));
+ MemoryContextSwitchTo(oldctx);
+ RelationClose(ancestor);
+ }
entry->replicate_valid = true;
+ RelationClose(relation);
}
if (!found)