@@ -176,24 +176,29 @@ ReadNextXLogRecord(XLogReaderState *xlogreader)
176176}
177177
178178/*
179- * Get a single WAL record info.
179+ * Output values that make up a row describing caller's WAL record.
180+ *
181+ * This function leaks memory. Caller may need to use its own custom memory
182+ * context.
183+ *
184+ * Keep this in sync with GetWALBlockInfo.
180185 */
181186static void
182187GetWALRecordInfo (XLogReaderState * record ,Datum * values ,
183188bool * nulls ,uint32 ncols )
184189{
185- const char * id ;
190+ const char * record_type ;
186191RmgrData desc ;
187192uint32 fpi_len = 0 ;
188193StringInfoData rec_desc ;
189194StringInfoData rec_blk_ref ;
190195int i = 0 ;
191196
192197desc = GetRmgr (XLogRecGetRmid (record ));
193- id = desc .rm_identify (XLogRecGetInfo (record ));
198+ record_type = desc .rm_identify (XLogRecGetInfo (record ));
194199
195- if (id == NULL )
196- id = psprintf ("UNKNOWN (%x)" ,XLogRecGetInfo (record )& ~XLR_INFO_MASK );
200+ if (record_type == NULL )
201+ record_type = psprintf ("UNKNOWN (%x)" ,XLogRecGetInfo (record )& ~XLR_INFO_MASK );
197202
198203initStringInfo (& rec_desc );
199204desc .rm_desc (& rec_desc ,record );
@@ -209,7 +214,7 @@ GetWALRecordInfo(XLogReaderState *record, Datum *values,
209214values [i ++ ]= LSNGetDatum (XLogRecGetPrev (record ));
210215values [i ++ ]= TransactionIdGetDatum (XLogRecGetXid (record ));
211216values [i ++ ]= CStringGetTextDatum (desc .rm_name );
212- values [i ++ ]= CStringGetTextDatum (id );
217+ values [i ++ ]= CStringGetTextDatum (record_type );
213218values [i ++ ]= UInt32GetDatum (XLogRecGetTotalLen (record ));
214219values [i ++ ]= UInt32GetDatum (XLogRecGetDataLen (record ));
215220values [i ++ ]= UInt32GetDatum (fpi_len );
@@ -229,24 +234,48 @@ GetWALRecordInfo(XLogReaderState *record, Datum *values,
229234
230235
231236/*
232- * Store a set of block information from a single record (FPI and block
233- * information).
237+ * Output one or more rows in rsinfo tuple store, each describing a single
238+ * block reference from caller's WAL record. (Should only be called with
239+ * records that have block references.)
240+ *
241+ * This function leaks memory. Caller may need to use its own custom memory
242+ * context.
243+ *
244+ * Keep this in sync with GetWALRecordInfo.
234245 */
235246static void
236247GetWALBlockInfo (FunctionCallInfo fcinfo ,XLogReaderState * record )
237248{
238- #define PG_GET_WAL_BLOCK_INFO_COLS 11
249+ #define PG_GET_WAL_BLOCK_INFO_COLS 20
239250int block_id ;
240251ReturnSetInfo * rsinfo = (ReturnSetInfo * )fcinfo -> resultinfo ;
252+ RmgrData desc ;
253+ const char * record_type ;
254+ StringInfoData rec_desc ;
255+
256+ Assert (XLogRecHasAnyBlockRefs (record ));
257+
258+ desc = GetRmgr (XLogRecGetRmid (record ));
259+ record_type = desc .rm_identify (XLogRecGetInfo (record ));
260+
261+ if (record_type == NULL )
262+ record_type = psprintf ("UNKNOWN (%x)" ,
263+ XLogRecGetInfo (record )& ~XLR_INFO_MASK );
264+
265+ initStringInfo (& rec_desc );
266+ desc .rm_desc (& rec_desc ,record );
241267
242268for (block_id = 0 ;block_id <=XLogRecMaxBlockId (record );block_id ++ )
243269{
244270DecodedBkpBlock * blk ;
245271BlockNumber blkno ;
246272RelFileLocator rnode ;
247- ForkNumber fork ;
273+ ForkNumber forknum ;
248274Datum values [PG_GET_WAL_BLOCK_INFO_COLS ]= {0 };
249275bool nulls [PG_GET_WAL_BLOCK_INFO_COLS ]= {0 };
276+ uint32 block_data_len = 0 ,
277+ block_fpi_len = 0 ;
278+ ArrayType * block_fpi_info = NULL ;
250279int i = 0 ;
251280
252281if (!XLogRecHasBlockRef (record ,block_id ))
@@ -255,99 +284,117 @@ GetWALBlockInfo(FunctionCallInfo fcinfo, XLogReaderState *record)
255284blk = XLogRecGetBlock (record ,block_id );
256285
257286(void )XLogRecGetBlockTagExtended (record ,block_id ,
258- & rnode ,& fork ,& blkno ,NULL );
287+ & rnode ,& forknum ,& blkno ,NULL );
259288
289+ /* Save block_data_len */
290+ if (blk -> has_data )
291+ block_data_len = blk -> data_len ;
292+
293+ if (blk -> has_image )
294+ {
295+ /* Block reference has an FPI, so prepare relevant output */
296+ int bitcnt ;
297+ int cnt = 0 ;
298+ Datum * flags ;
299+
300+ /* Save block_fpi_len */
301+ block_fpi_len = blk -> bimg_len ;
302+
303+ /* Construct and save block_fpi_info */
304+ bitcnt = pg_popcount ((const char * )& blk -> bimg_info ,
305+ sizeof (uint8 ));
306+ flags = (Datum * )palloc0 (sizeof (Datum )* bitcnt );
307+ if ((blk -> bimg_info & BKPIMAGE_HAS_HOLE )!= 0 )
308+ flags [cnt ++ ]= CStringGetTextDatum ("HAS_HOLE" );
309+ if (blk -> apply_image )
310+ flags [cnt ++ ]= CStringGetTextDatum ("APPLY" );
311+ if ((blk -> bimg_info & BKPIMAGE_COMPRESS_PGLZ )!= 0 )
312+ flags [cnt ++ ]= CStringGetTextDatum ("COMPRESS_PGLZ" );
313+ if ((blk -> bimg_info & BKPIMAGE_COMPRESS_LZ4 )!= 0 )
314+ flags [cnt ++ ]= CStringGetTextDatum ("COMPRESS_LZ4" );
315+ if ((blk -> bimg_info & BKPIMAGE_COMPRESS_ZSTD )!= 0 )
316+ flags [cnt ++ ]= CStringGetTextDatum ("COMPRESS_ZSTD" );
317+
318+ Assert (cnt <=bitcnt );
319+ block_fpi_info = construct_array_builtin (flags ,cnt ,TEXTOID );
320+ }
321+
322+ /* start_lsn, end_lsn, prev_lsn, and blockid outputs */
260323values [i ++ ]= LSNGetDatum (record -> ReadRecPtr );
324+ values [i ++ ]= LSNGetDatum (record -> EndRecPtr );
325+ values [i ++ ]= LSNGetDatum (XLogRecGetPrev (record ));
261326values [i ++ ]= Int16GetDatum (block_id );
327+
328+ /* relfile and block related outputs */
262329values [i ++ ]= ObjectIdGetDatum (blk -> rlocator .spcOid );
263330values [i ++ ]= ObjectIdGetDatum (blk -> rlocator .dbOid );
264331values [i ++ ]= ObjectIdGetDatum (blk -> rlocator .relNumber );
332+ values [i ++ ]= Int16GetDatum (forknum );
265333values [i ++ ]= Int64GetDatum ((int64 )blkno );
266334
267- if (fork >=0 && fork <=MAX_FORKNUM )
268- values [i ++ ]= CStringGetTextDatum (forkNames [fork ]);
335+ /* xid, resource_manager, and record_type outputs */
336+ values [i ++ ]= TransactionIdGetDatum (XLogRecGetXid (record ));
337+ values [i ++ ]= CStringGetTextDatum (desc .rm_name );
338+ values [i ++ ]= CStringGetTextDatum (record_type );
339+
340+ /*
341+ * record_length, main_data_length, block_data_len, and
342+ * block_fpi_length outputs
343+ */
344+ values [i ++ ]= UInt32GetDatum (XLogRecGetTotalLen (record ));
345+ values [i ++ ]= UInt32GetDatum (XLogRecGetDataLen (record ));
346+ values [i ++ ]= UInt32GetDatum (block_data_len );
347+ values [i ++ ]= UInt32GetDatum (block_fpi_len );
348+
349+ /* block_fpi_info (text array) output */
350+ if (block_fpi_info )
351+ values [i ++ ]= PointerGetDatum (block_fpi_info );
269352else
270- ereport (ERROR ,
271- (errcode (ERRCODE_INTERNAL_ERROR ),
272- errmsg_internal ("invalid fork number: %u" ,fork )));
353+ nulls [i ++ ]= true;
273354
274- /* Block data */
355+ /* description output (describes WAL record) */
356+ if (rec_desc .len > 0 )
357+ values [i ++ ]= CStringGetTextDatum (rec_desc .data );
358+ else
359+ nulls [i ++ ]= true;
360+
361+ /* block_data output */
275362if (blk -> has_data )
276363{
277- bytea * raw_data ;
364+ bytea * block_data ;
278365
279- /* Initialize bytea buffer to copy the data to */
280- raw_data = (bytea * )palloc (blk -> data_len + VARHDRSZ );
281- SET_VARSIZE (raw_data ,blk -> data_len + VARHDRSZ );
282-
283- /* Copy the data */
284- memcpy (VARDATA (raw_data ),blk -> data ,blk -> data_len );
285- values [i ++ ]= PointerGetDatum (raw_data );
366+ block_data = (bytea * )palloc (block_data_len + VARHDRSZ );
367+ SET_VARSIZE (block_data ,block_data_len + VARHDRSZ );
368+ memcpy (VARDATA (block_data ),blk -> data ,block_data_len );
369+ values [i ++ ]= PointerGetDatum (block_data );
286370}
287371else
288- {
289- /* No data, so set this field to NULL */
290372nulls [i ++ ]= true;
291- }
292373
374+ /* block_fpi_data output */
293375if (blk -> has_image )
294376{
295377PGAlignedBlock buf ;
296378Page page ;
297- bytea * raw_page ;
298- int bitcnt ;
299- int cnt = 0 ;
300- Datum * flags ;
301- ArrayType * a ;
379+ bytea * block_fpi_data ;
302380
303381page = (Page )buf .data ;
304-
305- /* Full page image exists, so let's save it */
306382if (!RestoreBlockImage (record ,block_id ,page ))
307383ereport (ERROR ,
308384(errcode (ERRCODE_INTERNAL_ERROR ),
309385errmsg_internal ("%s" ,record -> errormsg_buf )));
310386
311- /* Initialize bytea buffer to copy the FPI to */
312- raw_page = (bytea * )palloc (BLCKSZ + VARHDRSZ );
313- SET_VARSIZE (raw_page ,BLCKSZ + VARHDRSZ );
314-
315- /* Take a verbatim copy of the FPI */
316- memcpy (VARDATA (raw_page ),page ,BLCKSZ );
317-
318- values [i ++ ]= PointerGetDatum (raw_page );
319- values [i ++ ]= UInt32GetDatum (blk -> bimg_len );
320-
321- /* FPI flags */
322- bitcnt = pg_popcount ((const char * )& blk -> bimg_info ,
323- sizeof (uint8 ));
324- /* Build set of raw flags */
325- flags = (Datum * )palloc0 (sizeof (Datum )* bitcnt );
326-
327- if ((blk -> bimg_info & BKPIMAGE_HAS_HOLE )!= 0 )
328- flags [cnt ++ ]= CStringGetTextDatum ("HAS_HOLE" );
329- if (blk -> apply_image )
330- flags [cnt ++ ]= CStringGetTextDatum ("APPLY" );
331- if ((blk -> bimg_info & BKPIMAGE_COMPRESS_PGLZ )!= 0 )
332- flags [cnt ++ ]= CStringGetTextDatum ("COMPRESS_PGLZ" );
333- if ((blk -> bimg_info & BKPIMAGE_COMPRESS_LZ4 )!= 0 )
334- flags [cnt ++ ]= CStringGetTextDatum ("COMPRESS_LZ4" );
335- if ((blk -> bimg_info & BKPIMAGE_COMPRESS_ZSTD )!= 0 )
336- flags [cnt ++ ]= CStringGetTextDatum ("COMPRESS_ZSTD" );
337-
338- Assert (cnt <=bitcnt );
339- a = construct_array_builtin (flags ,cnt ,TEXTOID );
340- values [i ++ ]= PointerGetDatum (a );
387+ block_fpi_data = (bytea * )palloc (BLCKSZ + VARHDRSZ );
388+ SET_VARSIZE (block_fpi_data ,BLCKSZ + VARHDRSZ );
389+ memcpy (VARDATA (block_fpi_data ),page ,BLCKSZ );
390+ values [i ++ ]= PointerGetDatum (block_fpi_data );
341391}
342392else
343- {
344- /* No full page image, so store NULLs for all its fields */
345- memset (& nulls [i ], true,3 * sizeof (bool ));
346- i += 3 ;
347- }
393+ nulls [i ++ ]= true;
348394
349395Assert (i == PG_GET_WAL_BLOCK_INFO_COLS );
350396
397+ /* Store a tuple for this block reference */
351398tuplestore_putvalues (rsinfo -> setResult ,rsinfo -> setDesc ,
352399values ,nulls );
353400}
@@ -356,11 +403,7 @@ GetWALBlockInfo(FunctionCallInfo fcinfo, XLogReaderState *record)
356403}
357404
358405/*
359- * Get information about all the blocks saved in WAL records between start
360- * and end LSNs. This produces information about the full page images with
361- * their relation information, and the data saved in each block associated
362- * to a record. Decompression is applied to the full page images, if
363- * necessary.
406+ * Get WAL record info, unnested by block reference
364407 */
365408Datum
366409pg_get_wal_block_info (PG_FUNCTION_ARGS )
@@ -484,7 +527,7 @@ ValidateInputLSNs(XLogRecPtr start_lsn, XLogRecPtr *end_lsn)
484527}
485528
486529/*
487- * Get infoand data of all WAL records between start LSN and end LSN.
530+ * Get info of all WAL records between start LSN and end LSN.
488531 */
489532static void
490533GetWALRecordsInfo (FunctionCallInfo fcinfo ,XLogRecPtr start_lsn ,
@@ -536,7 +579,7 @@ GetWALRecordsInfo(FunctionCallInfo fcinfo, XLogRecPtr start_lsn,
536579}
537580
538581/*
539- * Get infoand data of all WAL records between start LSN and end LSN.
582+ * Get info of all WAL records between start LSN and end LSN.
540583 */
541584Datum
542585pg_get_wal_records_info (PG_FUNCTION_ARGS )