PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 .name = "pg_logicalinspect",
23 .version = PG_VERSION
24);
25
28
29/* Return the description of SnapBuildState */
30static const char *
32{
33 const char *stateDesc = "unknown state";
34
35 switch (state)
36 {
37 case SNAPBUILD_START:
38 stateDesc = "start";
39 break;
41 stateDesc = "building";
42 break;
44 stateDesc = "full";
45 break;
47 stateDesc = "consistent";
48 break;
49 }
50
51 return stateDesc;
52}
53
54/*
55 * Extract the LSN from the given serialized snapshot file name.
56 */
57static XLogRecPtr
59{
60 uint32 hi;
61 uint32 lo;
62 XLogRecPtr lsn;
63 char tmpfname[MAXPGPATH];
64
65 /*
66 * Extract the values to build the LSN.
67 *
68 * Note: Including ".snap" doesn't mean that sscanf() also does the format
69 * check including the suffix. The subsequent check validates if the given
70 * filename has the expected suffix.
71 */
72 if (sscanf(filename, "%X-%X.snap", &hi, &lo) != 2)
73 goto parse_error;
74
75 /*
76 * Bring back the extracted LSN to the snapshot file format and compare it
77 * to the given filename. This check strictly checks if the given filename
78 * follows the format of the snapshot filename.
79 */
80 sprintf(tmpfname, "%X-%X.snap", hi, lo);
81 if (strcmp(tmpfname, filename) != 0)
82 goto parse_error;
83
84 lsn = ((uint64) hi) << 32 | lo;
85
86 return lsn;
87
88parse_error:
90 errmsg("invalid snapshot file name \"%s\"", filename));
91
92 return InvalidXLogRecPtr; /* keep compiler quiet */
93}
94
95/*
96 * Retrieve the logical snapshot file metadata.
97 */
100{
101#define PG_GET_LOGICAL_SNAPSHOT_META_COLS 3
102 SnapBuildOnDisk ondisk;
103 HeapTuple tuple;
105 bool nulls[PG_GET_LOGICAL_SNAPSHOT_META_COLS] = {0};
106 TupleDesc tupdesc;
107 XLogRecPtr lsn;
108 int i = 0;
109 text *filename_t = PG_GETARG_TEXT_PP(0);
110
111 /* Build a tuple descriptor for our result type */
112 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
113 elog(ERROR, "return type must be a row type");
114
115 lsn = parse_snapshot_filename(text_to_cstring(filename_t));
116
117 /* Validate and restore the snapshot to 'ondisk' */
119
120 values[i++] = UInt32GetDatum(ondisk.magic);
121 values[i++] = Int64GetDatum((int64) ondisk.checksum);
122 values[i++] = UInt32GetDatum(ondisk.version);
123
125
126 tuple = heap_form_tuple(tupdesc, values, nulls);
127
129
130#undef PG_GET_LOGICAL_SNAPSHOT_META_COLS
131}
132
133Datum
135{
136#define PG_GET_LOGICAL_SNAPSHOT_INFO_COLS 14
137 SnapBuildOnDisk ondisk;
138 HeapTuple tuple;
140 bool nulls[PG_GET_LOGICAL_SNAPSHOT_INFO_COLS] = {0};
141 TupleDesc tupdesc;
142 XLogRecPtr lsn;
143 int i = 0;
144 text *filename_t = PG_GETARG_TEXT_PP(0);
145
146 /* Build a tuple descriptor for our result type */
147 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
148 elog(ERROR, "return type must be a row type");
149
150 lsn = parse_snapshot_filename(text_to_cstring(filename_t));
151
152 /* Validate and restore the snapshot to 'ondisk' */
154
165
167 if (ondisk.builder.committed.xcnt > 0)
168 {
169 Datum *arrayelems;
170
171 arrayelems = (Datum *) palloc(ondisk.builder.committed.xcnt * sizeof(Datum));
172
173 for (int j = 0; j < ondisk.builder.committed.xcnt; j++)
174 arrayelems[j] = TransactionIdGetDatum(ondisk.builder.committed.xip[j]);
175
177 ondisk.builder.committed.xcnt,
178 XIDOID));
179 }
180 else
181 nulls[i++] = true;
182
184 if (ondisk.builder.catchange.xcnt > 0)
185 {
186 Datum *arrayelems;
187
188 arrayelems = (Datum *) palloc(ondisk.builder.catchange.xcnt * sizeof(Datum));
189
190 for (int j = 0; j < ondisk.builder.catchange.xcnt; j++)
191 arrayelems[j] = TransactionIdGetDatum(ondisk.builder.catchange.xip[j]);
192
194 ondisk.builder.catchange.xcnt,
195 XIDOID));
196 }
197 else
198 nulls[i++] = true;
199
201
202 tuple = heap_form_tuple(tupdesc, values, nulls);
203
205
206#undef PG_GET_LOGICAL_SNAPSHOT_INFO_COLS
207}
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:1071
#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:78
int i
Definition: isn.c:77
void * palloc(Size size)
Definition: mcxt.c:1943
MemoryContext CurrentMemoryContext
Definition: mcxt.c:159
#define MAXPGPATH
static char * filename
Definition: pg_dumpall.c:123
#define PG_GET_LOGICAL_SNAPSHOT_META_COLS
Datum pg_get_logical_snapshot_info(PG_FUNCTION_ARGS)
PG_MODULE_MAGIC_EXT(.name="pg_logicalinspect",.version=PG_VERSION)
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:1734
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
const char * name
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28