diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c index 5c206c4c294..f70b2f32055 100644 --- a/src/backend/access/heap/rewriteheap.c +++ b/src/backend/access/heap/rewriteheap.c @@ -658,12 +658,11 @@ raw_heap_insert(RewriteState state, HeapTuple tup) options |= HEAP_INSERT_SKIP_WAL; /* - * The new relfilenode's relcache entrye doesn't have the necessary - * information to determine whether a relation should emit data for - * logical decoding. Force it to off if necessary. + * While rewriting the heap for VACUUM FULL / CLUSTER, make sure data + * for the TOAST table are not logically decoded. The main heap is + * WAL-logged as XLOG FPI records, which are not logically decoded. */ - if (!RelationIsLogicallyLogged(state->rs_old_rel)) - options |= HEAP_INSERT_NO_LOGICAL; + options |= HEAP_INSERT_NO_LOGICAL; heaptup = toast_insert_or_update(state->rs_new_rel, tup, NULL, options); diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c index 09a334232e1..45742636999 100644 --- a/src/backend/replication/logical/decode.c +++ b/src/backend/replication/logical/decode.c @@ -607,12 +607,21 @@ DecodeAbort(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid, static void DecodeInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) { + Size datalen; + Size tuplelen; XLogRecord *r = &buf->record; xl_heap_insert *xlrec; ReorderBufferChange *change; xlrec = (xl_heap_insert *) buf->record_data; + /* + * Ignore insert records without new tuples (this does happen when + * raw_heap_insert marks the TOAST record as HEAP_INSERT_NO_LOGICAL). + */ + if (!(xlrec->flags & XLOG_HEAP_CONTAINS_NEW_TUPLE)) + return; + /* only interested in our database */ if (xlrec->target.node.dbNode != ctx->slot->data.database) return; @@ -621,19 +630,16 @@ DecodeInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) change->action = REORDER_BUFFER_CHANGE_INSERT; memcpy(&change->data.tp.relnode, &xlrec->target.node, sizeof(RelFileNode)); - if (xlrec->flags & XLOG_HEAP_CONTAINS_NEW_TUPLE) - { - Size datalen = r->xl_len - SizeOfHeapInsert; - Size tuplelen = datalen - SizeOfHeapHeader; + datalen = r->xl_len - SizeOfHeapInsert; + tuplelen = datalen - SizeOfHeapHeader; - Assert(r->xl_len > (SizeOfHeapInsert + SizeOfHeapHeader)); + Assert(r->xl_len > (SizeOfHeapInsert + SizeOfHeapHeader)); - change->data.tp.newtuple = - ReorderBufferGetTupleBuf(ctx->reorder, tuplelen); + change->data.tp.newtuple = + ReorderBufferGetTupleBuf(ctx->reorder, tuplelen); - DecodeXLogTuple((char *) xlrec + SizeOfHeapInsert, - datalen, change->data.tp.newtuple); - } + DecodeXLogTuple((char *) xlrec + SizeOfHeapInsert, + datalen, change->data.tp.newtuple); change->data.tp.clear_toast_afterwards = true;