Coverage Report

Created: 2026-11-12 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/backup/walsummaryfuncs.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * walsummaryfuncs.c
4
 *    SQL-callable functions for accessing WAL summary data.
5
 *
6
 * Portions Copyright (c) 2010-2026, PostgreSQL Global Development Group
7
 *
8
 * src/backend/backup/walsummaryfuncs.c
9
 *
10
 *-------------------------------------------------------------------------
11
 */
12
13
#include "postgres.h"
14
15
#include "access/htup_details.h"
16
#include "backup/walsummary.h"
17
#include "common/blkreftable.h"
18
#include "funcapi.h"
19
#include "miscadmin.h"
20
#include "postmaster/walsummarizer.h"
21
#include "utils/fmgrprotos.h"
22
#include "utils/pg_lsn.h"
23
#include "utils/tuplestore.h"
24
25
#define NUM_WS_ATTS     3
26
#define NUM_SUMMARY_ATTS  6
27
#define NUM_STATE_ATTS    4
28
0
#define MAX_BLOCKS_PER_CALL 256
29
30
/*
31
 * List the WAL summary files available in pg_wal/summaries.
32
 */
33
Datum
34
pg_available_wal_summaries(PG_FUNCTION_ARGS)
35
0
{
36
0
  ReturnSetInfo *rsi;
37
0
  List     *wslist;
38
0
  ListCell   *lc;
39
0
  Datum   values[NUM_WS_ATTS];
40
0
  bool    nulls[NUM_WS_ATTS];
41
42
0
  InitMaterializedSRF(fcinfo, 0);
43
0
  rsi = (ReturnSetInfo *) fcinfo->resultinfo;
44
45
0
  memset(nulls, 0, sizeof(nulls));
46
47
0
  wslist = GetWalSummaries(0, InvalidXLogRecPtr, InvalidXLogRecPtr);
48
0
  foreach(lc, wslist)
49
0
  {
50
0
    WalSummaryFile *ws = (WalSummaryFile *) lfirst(lc);
51
0
    HeapTuple tuple;
52
53
0
    CHECK_FOR_INTERRUPTS();
54
55
0
    values[0] = Int64GetDatum((int64) ws->tli);
56
0
    values[1] = LSNGetDatum(ws->start_lsn);
57
0
    values[2] = LSNGetDatum(ws->end_lsn);
58
59
0
    tuple = heap_form_tuple(rsi->setDesc, values, nulls);
60
0
    tuplestore_puttuple(rsi->setResult, tuple);
61
0
  }
62
63
0
  return (Datum) 0;
64
0
}
65
66
/*
67
 * List the contents of a WAL summary file identified by TLI, start LSN,
68
 * and end LSN.
69
 */
70
Datum
71
pg_wal_summary_contents(PG_FUNCTION_ARGS)
72
0
{
73
0
  ReturnSetInfo *rsi;
74
0
  Datum   values[NUM_SUMMARY_ATTS];
75
0
  bool    nulls[NUM_SUMMARY_ATTS];
76
0
  WalSummaryFile ws;
77
0
  WalSummaryIO io;
78
0
  BlockRefTableReader *reader;
79
0
  int64   raw_tli;
80
0
  RelFileLocator rlocator;
81
0
  ForkNumber  forknum;
82
0
  BlockNumber limit_block;
83
84
0
  InitMaterializedSRF(fcinfo, 0);
85
0
  rsi = (ReturnSetInfo *) fcinfo->resultinfo;
86
0
  memset(nulls, 0, sizeof(nulls));
87
88
  /*
89
   * Since the timeline could at least in theory be more than 2^31, and
90
   * since we don't have unsigned types at the SQL level, it is passed as a
91
   * 64-bit integer. Test whether it's out of range.
92
   */
93
0
  raw_tli = PG_GETARG_INT64(0);
94
0
  if (raw_tli < 1 || raw_tli > PG_INT32_MAX)
95
0
    ereport(ERROR,
96
0
        errcode(ERRCODE_INVALID_PARAMETER_VALUE),
97
0
        errmsg("invalid timeline %" PRId64, raw_tli));
98
99
  /* Prepare to read the specified WAL summary file. */
100
0
  ws.tli = (TimeLineID) raw_tli;
101
0
  ws.start_lsn = PG_GETARG_LSN(1);
102
0
  ws.end_lsn = PG_GETARG_LSN(2);
103
0
  io.filepos = 0;
104
0
  io.file = OpenWalSummaryFile(&ws, false);
105
0
  reader = CreateBlockRefTableReader(ReadWalSummary, &io,
106
0
                     FilePathName(io.file),
107
0
                     ReportWalSummaryError, NULL);
108
109
  /* Loop over relation forks. */
110
0
  while (BlockRefTableReaderNextRelation(reader, &rlocator, &forknum,
111
0
                       &limit_block))
112
0
  {
113
0
    BlockNumber blocks[MAX_BLOCKS_PER_CALL];
114
0
    HeapTuple tuple;
115
116
0
    CHECK_FOR_INTERRUPTS();
117
118
0
    values[0] = ObjectIdGetDatum(rlocator.relNumber);
119
0
    values[1] = ObjectIdGetDatum(rlocator.spcOid);
120
0
    values[2] = ObjectIdGetDatum(rlocator.dbOid);
121
0
    values[3] = Int16GetDatum((int16) forknum);
122
123
    /*
124
     * If the limit block is not InvalidBlockNumber, emit an extra row
125
     * with that block number and limit_block = true.
126
     *
127
     * There is no point in doing this when the limit_block is
128
     * InvalidBlockNumber, because no block with that number or any higher
129
     * number can ever exist.
130
     */
131
0
    if (BlockNumberIsValid(limit_block))
132
0
    {
133
0
      values[4] = Int64GetDatum((int64) limit_block);
134
0
      values[5] = BoolGetDatum(true);
135
136
0
      tuple = heap_form_tuple(rsi->setDesc, values, nulls);
137
0
      tuplestore_puttuple(rsi->setResult, tuple);
138
0
    }
139
140
    /* Loop over blocks within the current relation fork. */
141
0
    while (1)
142
0
    {
143
0
      unsigned  nblocks;
144
0
      unsigned  i;
145
146
0
      CHECK_FOR_INTERRUPTS();
147
148
0
      nblocks = BlockRefTableReaderGetBlocks(reader, blocks,
149
0
                           MAX_BLOCKS_PER_CALL);
150
0
      if (nblocks == 0)
151
0
        break;
152
153
      /*
154
       * For each block that we specifically know to have been modified,
155
       * emit a row with that block number and limit_block = false.
156
       */
157
0
      values[5] = BoolGetDatum(false);
158
0
      for (i = 0; i < nblocks; ++i)
159
0
      {
160
0
        values[4] = Int64GetDatum((int64) blocks[i]);
161
162
0
        tuple = heap_form_tuple(rsi->setDesc, values, nulls);
163
0
        tuplestore_puttuple(rsi->setResult, tuple);
164
0
      }
165
0
    }
166
0
  }
167
168
  /* Cleanup */
169
0
  DestroyBlockRefTableReader(reader);
170
0
  FileClose(io.file);
171
172
0
  return (Datum) 0;
173
0
}
174
175
/*
176
 * Returns information about the state of the WAL summarizer process.
177
 */
178
Datum
179
pg_get_wal_summarizer_state(PG_FUNCTION_ARGS)
180
0
{
181
0
  Datum   values[NUM_STATE_ATTS];
182
0
  bool    nulls[NUM_STATE_ATTS];
183
0
  TimeLineID  summarized_tli;
184
0
  XLogRecPtr  summarized_lsn;
185
0
  XLogRecPtr  pending_lsn;
186
0
  int     summarizer_pid;
187
0
  TupleDesc tupdesc;
188
0
  HeapTuple htup;
189
190
0
  GetWalSummarizerState(&summarized_tli, &summarized_lsn, &pending_lsn,
191
0
              &summarizer_pid);
192
193
0
  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
194
0
    elog(ERROR, "return type must be a row type");
195
196
0
  memset(nulls, 0, sizeof(nulls));
197
198
0
  values[0] = Int64GetDatum((int64) summarized_tli);
199
0
  values[1] = LSNGetDatum(summarized_lsn);
200
0
  values[2] = LSNGetDatum(pending_lsn);
201
202
0
  if (summarizer_pid < 0)
203
0
    nulls[3] = true;
204
0
  else
205
0
    values[3] = Int32GetDatum(summarizer_pid);
206
207
0
  htup = heap_form_tuple(tupdesc, values, nulls);
208
209
0
  PG_RETURN_DATUM(HeapTupleGetDatum(htup));
210
0
}