@@ -891,6 +891,13 @@ DecodeMultiInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
891891
892892 xlrec = (xl_heap_multi_insert * ) XLogRecGetData (r );
893893
894+ /*
895+ * Ignore insert records without new tuples. This happens when a
896+ * multi_insert is done on a catalog or on a non-persistent relation.
897+ */
898+ if (!(xlrec -> flags & XLH_INSERT_CONTAINS_NEW_TUPLE ))
899+ return ;
900+
894901 /* only interested in our database */
895902 XLogRecGetBlockTag (r , 0 , & rnode , NULL , NULL );
896903 if (rnode .dbNode != ctx -> slot -> data .database )
@@ -901,8 +908,8 @@ DecodeMultiInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
901908 return ;
902909
903910 /*
904- * As multi_insert is not used for catalogs yet, the block should always
905- * have data even if a full-page write of it is taken.
911+ * We know that this multi_insert isn't for a catalog, so the block should
912+ * always have data even if a full-page write of it is taken.
906913 */
907914 tupledata = XLogRecGetBlockData (r , 0 , & tuplelen );
908915 Assert (tupledata != NULL );
@@ -914,6 +921,7 @@ DecodeMultiInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
914921 xl_multi_insert_tuple * xlhdr ;
915922 int datalen ;
916923 ReorderBufferTupleBuf * tuple ;
924+ HeapTupleHeader header ;
917925
918926 change = ReorderBufferGetChange (ctx -> reorder );
919927 change -> action = REORDER_BUFFER_CHANGE_INSERT ;
@@ -925,43 +933,30 @@ DecodeMultiInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
925933 data = ((char * ) xlhdr ) + SizeOfMultiInsertTuple ;
926934 datalen = xlhdr -> datalen ;
927935
928- /*
929- * CONTAINS_NEW_TUPLE will always be set currently as multi_insert
930- * isn't used for catalogs, but better be future proof.
931- *
932- * We decode the tuple in pretty much the same way as DecodeXLogTuple,
933- * but since the layout is slightly different, we can't use it here.
934- */
935- if (xlrec -> flags & XLH_INSERT_CONTAINS_NEW_TUPLE )
936- {
937- HeapTupleHeader header ;
938-
939- change -> data .tp .newtuple =
940- ReorderBufferGetTupleBuf (ctx -> reorder , datalen );
936+ change -> data .tp .newtuple =
937+ ReorderBufferGetTupleBuf (ctx -> reorder , datalen );
941938
942- tuple = change -> data .tp .newtuple ;
943- header = tuple -> tuple .t_data ;
939+ tuple = change -> data .tp .newtuple ;
940+ header = tuple -> tuple .t_data ;
944941
945- /* not a disk based tuple */
946- ItemPointerSetInvalid (& tuple -> tuple .t_self );
942+ /* not a disk based tuple */
943+ ItemPointerSetInvalid (& tuple -> tuple .t_self );
947944
948- /*
949- * We can only figure this out after reassembling the
950- * transactions.
951- */
952- tuple -> tuple .t_tableOid = InvalidOid ;
945+ /*
946+ * We can only figure this out after reassembling the transactions.
947+ */
948+ tuple -> tuple .t_tableOid = InvalidOid ;
953949
954- tuple -> tuple .t_len = datalen + SizeofHeapTupleHeader ;
950+ tuple -> tuple .t_len = datalen + SizeofHeapTupleHeader ;
955951
956- memset (header , 0 , SizeofHeapTupleHeader );
952+ memset (header , 0 , SizeofHeapTupleHeader );
957953
958- memcpy ((char * ) tuple -> tuple .t_data + SizeofHeapTupleHeader ,
959- (char * ) data ,
960- datalen );
961- header -> t_infomask = xlhdr -> t_infomask ;
962- header -> t_infomask2 = xlhdr -> t_infomask2 ;
963- header -> t_hoff = xlhdr -> t_hoff ;
964- }
954+ memcpy ((char * ) tuple -> tuple .t_data + SizeofHeapTupleHeader ,
955+ (char * ) data ,
956+ datalen );
957+ header -> t_infomask = xlhdr -> t_infomask ;
958+ header -> t_infomask2 = xlhdr -> t_infomask2 ;
959+ header -> t_hoff = xlhdr -> t_hoff ;
965960
966961 /*
967962 * Reset toast reassembly state only after the last row in the last
0 commit comments