@@ -891,6 +891,13 @@ DecodeMultiInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
891
891
892
892
xlrec = (xl_heap_multi_insert * ) XLogRecGetData (r );
893
893
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
+
894
901
/* only interested in our database */
895
902
XLogRecGetBlockTag (r , 0 , & rnode , NULL , NULL );
896
903
if (rnode .dbNode != ctx -> slot -> data .database )
@@ -901,8 +908,8 @@ DecodeMultiInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
901
908
return ;
902
909
903
910
/*
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.
906
913
*/
907
914
tupledata = XLogRecGetBlockData (r , 0 , & tuplelen );
908
915
Assert (tupledata != NULL );
@@ -914,6 +921,7 @@ DecodeMultiInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
914
921
xl_multi_insert_tuple * xlhdr ;
915
922
int datalen ;
916
923
ReorderBufferTupleBuf * tuple ;
924
+ HeapTupleHeader header ;
917
925
918
926
change = ReorderBufferGetChange (ctx -> reorder );
919
927
change -> action = REORDER_BUFFER_CHANGE_INSERT ;
@@ -925,43 +933,30 @@ DecodeMultiInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
925
933
data = ((char * ) xlhdr ) + SizeOfMultiInsertTuple ;
926
934
datalen = xlhdr -> datalen ;
927
935
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 );
941
938
942
- tuple = change -> data .tp .newtuple ;
943
- header = tuple -> tuple .t_data ;
939
+ tuple = change -> data .tp .newtuple ;
940
+ header = tuple -> tuple .t_data ;
944
941
945
- /* not a disk based tuple */
946
- ItemPointerSetInvalid (& tuple -> tuple .t_self );
942
+ /* not a disk based tuple */
943
+ ItemPointerSetInvalid (& tuple -> tuple .t_self );
947
944
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 ;
953
949
954
- tuple -> tuple .t_len = datalen + SizeofHeapTupleHeader ;
950
+ tuple -> tuple .t_len = datalen + SizeofHeapTupleHeader ;
955
951
956
- memset (header , 0 , SizeofHeapTupleHeader );
952
+ memset (header , 0 , SizeofHeapTupleHeader );
957
953
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 ;
965
960
966
961
/*
967
962
* Reset toast reassembly state only after the last row in the last
0 commit comments