PostgreSQL Source Code git master
pg_logicalinspect.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * pg_logicalinspect.c
4 * Functions to inspect contents of PostgreSQL logical snapshots
5 *
6 * Copyright (c) 2024-2025, PostgreSQL Global Development Group
7 *
8 * IDENTIFICATION
9 * contrib/pg_logicalinspect/pg_logicalinspect.c
10 *
11 *-------------------------------------------------------------------------
12 */
13#include "postgres.h"
14
15#include "funcapi.h"
17#include "utils/array.h"
18#include "utils/builtins.h"
19#include "utils/pg_lsn.h"
20
22
25
26/* Return the description of SnapBuildState */
27static const char *
29{
30 const char *stateDesc = "unknown state";
31
32 switch (state)
33 {
34 case SNAPBUILD_START:
35 stateDesc = "start";
36 break;
38 stateDesc = "building";
39 break;
41 stateDesc = "full";
42 break;
44 stateDesc = "consistent";
45 break;
46 }
47
48 return stateDesc;
49}
50
51/*
52 * Extract the LSN from the given serialized snapshot file name.
53 */
54static XLogRecPtr
56{
57 uint32 hi;
58 uint32 lo;
59 XLogRecPtr lsn;
60 char tmpfname[MAXPGPATH];
61
62 /*
63 * Extract the values to build the LSN.
64 *
65 * Note: Including ".snap" doesn't mean that sscanf() also does the format
66 * check including the suffix. The subsequent check validates if the given
67 * filename has the expected suffix.
68 */
69 if (sscanf(filename, "%X-%X.snap", &hi, &lo) != 2)
70 goto parse_error;
71
72 /*
73 * Bring back the extracted LSN to the snapshot file format and compare it
74 * to the given filename. This check strictly checks if the given filename
75 * follows the format of the snapshot filename.
76 */
77 sprintf(tmpfname, "%X-%X.snap", hi, lo);
78 if (strcmp(tmpfname, filename) != 0)
79 goto parse_error;
80
81 lsn = ((uint64) hi) << 32 | lo;
82
83 return lsn;
84
85parse_error:
87 errmsg("invalid snapshot file name \"%s\"", filename));
88
89 return InvalidXLogRecPtr; /* keep compiler quiet */
90}
91
92/*
93 * Retrieve the logical snapshot file metadata.
94 */
97{
98#define PG_GET_LOGICAL_SNAPSHOT_META_COLS 3
99 SnapBuildOnDisk ondisk;
100 HeapTuple tuple;
102 bool nulls[PG_GET_LOGICAL_SNAPSHOT_META_COLS] = {0};
103 TupleDesc tupdesc;
104 XLogRecPtr lsn;
105 int i = 0;
106 text *filename_t = PG_GETARG_TEXT_PP(0);
107
108 /* Build a tuple descriptor for our result type */
109 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
110 elog(ERROR, "return type must be a row type");
111
112 lsn = parse_snapshot_filename(text_to_cstring(filename_t));
113
114 /* Validate and restore the snapshot to 'ondisk' */
116
117 values[i++] = UInt32GetDatum(ondisk.magic);
118 values[i++] = Int64GetDatum((int64) ondisk.checksum);
119 values[i++] = UInt32GetDatum(ondisk.version);
120
122
123 tuple = heap_form_tuple(tupdesc, values, nulls);
124
126
127#undef PG_GET_LOGICAL_SNAPSHOT_META_COLS
128}
129
130Datum
132{
133#define PG_GET_LOGICAL_SNAPSHOT_INFO_COLS 14
134 SnapBuildOnDisk ondisk;
135 HeapTuple tuple;
137 bool nulls[PG_GET_LOGICAL_SNAPSHOT_INFO_COLS] = {0};
138 TupleDesc tupdesc;
139 XLogRecPtr lsn;
140 int i = 0;
141 text *filename_t = PG_GETARG_TEXT_PP(0);
142
143 /* Build a tuple descriptor for our result type */
144 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
145 elog(ERROR, "return type must be a row type");
146
147 lsn = parse_snapshot_filename(text_to_cstring(filename_t));
148
149 /* Validate and restore the snapshot to 'ondisk' */
151
162
164 if (ondisk.builder.committed.xcnt > 0)
165 {
166 Datum *arrayelems;
167
168 arrayelems = (Datum *) palloc(ondisk.builder.committed.xcnt * sizeof(Datum));
169
170 for (int j = 0; j < ondisk.builder.committed.xcnt; j++)
171 arrayelems[j] = TransactionIdGetDatum(ondisk.builder.committed.xip[j]);
172
174 ondisk.builder.committed.xcnt,
175 XIDOID));
176 }
177 else
178 nulls[i++] = true;
179
181 if (ondisk.builder.catchange.xcnt > 0)
182 {
183 Datum *arrayelems;
184
185 arrayelems = (Datum *) palloc(ondisk.builder.catchange.xcnt * sizeof(Datum));
186
187 for (int j = 0; j < ondisk.builder.catchange.xcnt; j++)
188 arrayelems[j] = TransactionIdGetDatum(ondisk.builder.catchange.xip[j]);
189
191 ondisk.builder.catchange.xcnt,
192 XIDOID));
193 }
194 else
195 nulls[i++] = true;
196
198
199 tuple = heap_form_tuple(tupdesc, values, nulls);
200
202
203#undef PG_GET_LOGICAL_SNAPSHOT_INFO_COLS
204}
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
Definition: arrayfuncs.c:3381
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define CStringGetTextDatum(s)
Definition: builtins.h:97
int64_t int64
Definition: c.h:499
uint64_t uint64
Definition: c.h:503
uint32_t uint32
Definition: c.h:502
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1807
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:276
@ TYPEFUNC_COMPOSITE
Definition: funcapi.h:149
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition: funcapi.h:230
Assert(PointerIsAligned(start, uint64))
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
int j
Definition: isn.c:75
int i
Definition: isn.c:74
void * palloc(Size size)
Definition: mcxt.c:1317
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
#define MAXPGPATH
static char * filename
Definition: pg_dumpall.c:124
#define PG_GET_LOGICAL_SNAPSHOT_META_COLS
Datum pg_get_logical_snapshot_info(PG_FUNCTION_ARGS)
PG_MODULE_MAGIC
Datum pg_get_logical_snapshot_meta(PG_FUNCTION_ARGS)
static const char * get_snapbuild_state_desc(SnapBuildState state)
#define PG_GET_LOGICAL_SNAPSHOT_INFO_COLS
static XLogRecPtr parse_snapshot_filename(const char *filename)
PG_FUNCTION_INFO_V1(pg_get_logical_snapshot_meta)
static Datum LSNGetDatum(XLogRecPtr X)
Definition: pg_lsn.h:28
#define sprintf
Definition: port.h:241
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
static Datum TransactionIdGetDatum(TransactionId X)
Definition: postgres.h:277
uintptr_t Datum
Definition: postgres.h:69
static Datum BoolGetDatum(bool X)
Definition: postgres.h:107
static Datum UInt32GetDatum(uint32 X)
Definition: postgres.h:237
bool SnapBuildRestoreSnapshot(SnapBuildOnDisk *ondisk, XLogRecPtr lsn, MemoryContext context, bool missing_ok)
Definition: snapbuild.c:1694
SnapBuildState
Definition: snapbuild.h:23
@ SNAPBUILD_START
Definition: snapbuild.h:27
@ SNAPBUILD_BUILDING_SNAPSHOT
Definition: snapbuild.h:33
@ SNAPBUILD_FULL_SNAPSHOT
Definition: snapbuild.h:43
@ SNAPBUILD_CONSISTENT
Definition: snapbuild.h:50
XLogRecPtr start_decoding_at
SnapBuildState state
TransactionId xmin
TransactionId initial_xmin_horizon
struct SnapBuild::@117 committed
TransactionId xmax
TransactionId * xip
XLogRecPtr two_phase_at
bool building_full_snapshot
TransactionId next_phase_at
XLogRecPtr last_serialized_snapshot
struct SnapBuild::@118 catchange
Definition: regguts.h:323
Definition: c.h:658
char * text_to_cstring(const text *t)
Definition: varlena.c:225
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28