1/*-------------------------------------------------------------------------
2 *
3 * pg_controldata.c
4 *
5 * Routines to expose the contents of the control data file via
6 * a set of SQL functions.
7 *
8 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
9 * Portions Copyright (c) 1994, Regents of the University of California
10 *
11 * IDENTIFICATION
12 * src/backend/utils/misc/pg_controldata.c
13 *-------------------------------------------------------------------------
14 */
15
16#include "postgres.h"
17
18#include "access/htup_details.h"
19#include "access/transam.h"
20#include "access/xlog_internal.h"
21#include "access/xlog.h"
22#include "catalog/pg_control.h"
23#include "catalog/pg_type.h"
24#include "common/controldata_utils.h"
25#include "funcapi.h"
26#include "miscadmin.h"
27#include "utils/builtins.h"
28#include "utils/pg_lsn.h"
29#include "utils/timestamp.h"
30
31Datum
32pg_control_system(PG_FUNCTION_ARGS)
33{
34 Datum values[4];
35 bool nulls[4];
36 TupleDesc tupdesc;
37 HeapTuple htup;
38 ControlFileData *ControlFile;
39 bool crc_ok;
40
41 /*
42 * Construct a tuple descriptor for the result row. This must match this
43 * function's pg_proc entry!
44 */
45 tupdesc = CreateTemplateTupleDesc(4);
46 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "pg_control_version",
47 INT4OID, -1, 0);
48 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "catalog_version_no",
49 INT4OID, -1, 0);
50 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "system_identifier",
51 INT8OID, -1, 0);
52 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "pg_control_last_modified",
53 TIMESTAMPTZOID, -1, 0);
54 tupdesc = BlessTupleDesc(tupdesc);
55
56 /* read the control file */
57 ControlFile = get_controlfile(DataDir, &crc_ok);
58 if (!crc_ok)
59 ereport(ERROR,
60 (errmsg("calculated CRC checksum does not match value stored in file")));
61
62 values[0] = Int32GetDatum(ControlFile->pg_control_version);
63 nulls[0] = false;
64
65 values[1] = Int32GetDatum(ControlFile->catalog_version_no);
66 nulls[1] = false;
67
68 values[2] = Int64GetDatum(ControlFile->system_identifier);
69 nulls[2] = false;
70
71 values[3] = TimestampTzGetDatum(time_t_to_timestamptz(ControlFile->time));
72 nulls[3] = false;
73
74 htup = heap_form_tuple(tupdesc, values, nulls);
75
76 PG_RETURN_DATUM(HeapTupleGetDatum(htup));
77}
78
79Datum
80pg_control_checkpoint(PG_FUNCTION_ARGS)
81{
82 Datum values[19];
83 bool nulls[19];
84 TupleDesc tupdesc;
85 HeapTuple htup;
86 ControlFileData *ControlFile;
87 XLogSegNo segno;
88 char xlogfilename[MAXFNAMELEN];
89 bool crc_ok;
90
91 /*
92 * Construct a tuple descriptor for the result row. This must match this
93 * function's pg_proc entry!
94 */
95 tupdesc = CreateTemplateTupleDesc(18);
96 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "checkpoint_lsn",
97 LSNOID, -1, 0);
98 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "redo_lsn",
99 LSNOID, -1, 0);
100 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "redo_wal_file",
101 TEXTOID, -1, 0);
102 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "timeline_id",
103 INT4OID, -1, 0);
104 TupleDescInitEntry(tupdesc, (AttrNumber) 5, "prev_timeline_id",
105 INT4OID, -1, 0);
106 TupleDescInitEntry(tupdesc, (AttrNumber) 6, "full_page_writes",
107 BOOLOID, -1, 0);
108 TupleDescInitEntry(tupdesc, (AttrNumber) 7, "next_xid",
109 TEXTOID, -1, 0);
110 TupleDescInitEntry(tupdesc, (AttrNumber) 8, "next_oid",
111 OIDOID, -1, 0);
112 TupleDescInitEntry(tupdesc, (AttrNumber) 9, "next_multixact_id",
113 XIDOID, -1, 0);
114 TupleDescInitEntry(tupdesc, (AttrNumber) 10, "next_multi_offset",
115 XIDOID, -1, 0);
116 TupleDescInitEntry(tupdesc, (AttrNumber) 11, "oldest_xid",
117 XIDOID, -1, 0);
118 TupleDescInitEntry(tupdesc, (AttrNumber) 12, "oldest_xid_dbid",
119 OIDOID, -1, 0);
120 TupleDescInitEntry(tupdesc, (AttrNumber) 13, "oldest_active_xid",
121 XIDOID, -1, 0);
122 TupleDescInitEntry(tupdesc, (AttrNumber) 14, "oldest_multi_xid",
123 XIDOID, -1, 0);
124 TupleDescInitEntry(tupdesc, (AttrNumber) 15, "oldest_multi_dbid",
125 OIDOID, -1, 0);
126 TupleDescInitEntry(tupdesc, (AttrNumber) 16, "oldest_commit_ts_xid",
127 XIDOID, -1, 0);
128 TupleDescInitEntry(tupdesc, (AttrNumber) 17, "newest_commit_ts_xid",
129 XIDOID, -1, 0);
130 TupleDescInitEntry(tupdesc, (AttrNumber) 18, "checkpoint_time",
131 TIMESTAMPTZOID, -1, 0);
132 tupdesc = BlessTupleDesc(tupdesc);
133
134 /* Read the control file. */
135 ControlFile = get_controlfile(DataDir, &crc_ok);
136 if (!crc_ok)
137 ereport(ERROR,
138 (errmsg("calculated CRC checksum does not match value stored in file")));
139
140 /*
141 * Calculate name of the WAL file containing the latest checkpoint's REDO
142 * start point.
143 */
144 XLByteToSeg(ControlFile->checkPointCopy.redo, segno, wal_segment_size);
145 XLogFileName(xlogfilename, ControlFile->checkPointCopy.ThisTimeLineID,
146 segno, wal_segment_size);
147
148 /* Populate the values and null arrays */
149 values[0] = LSNGetDatum(ControlFile->checkPoint);
150 nulls[0] = false;
151
152 values[1] = LSNGetDatum(ControlFile->checkPointCopy.redo);
153 nulls[1] = false;
154
155 values[2] = CStringGetTextDatum(xlogfilename);
156 nulls[2] = false;
157
158 values[3] = Int32GetDatum(ControlFile->checkPointCopy.ThisTimeLineID);
159 nulls[3] = false;
160
161 values[4] = Int32GetDatum(ControlFile->checkPointCopy.PrevTimeLineID);
162 nulls[4] = false;
163
164 values[5] = BoolGetDatum(ControlFile->checkPointCopy.fullPageWrites);
165 nulls[5] = false;
166
167 values[6] = CStringGetTextDatum(psprintf("%u:%u",
168 EpochFromFullTransactionId(ControlFile->checkPointCopy.nextFullXid),
169 XidFromFullTransactionId(ControlFile->checkPointCopy.nextFullXid)));
170 nulls[6] = false;
171
172 values[7] = ObjectIdGetDatum(ControlFile->checkPointCopy.nextOid);
173 nulls[7] = false;
174
175 values[8] = TransactionIdGetDatum(ControlFile->checkPointCopy.nextMulti);
176 nulls[8] = false;
177
178 values[9] = TransactionIdGetDatum(ControlFile->checkPointCopy.nextMultiOffset);
179 nulls[9] = false;
180
181 values[10] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestXid);
182 nulls[10] = false;
183
184 values[11] = ObjectIdGetDatum(ControlFile->checkPointCopy.oldestXidDB);
185 nulls[11] = false;
186
187 values[12] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestActiveXid);
188 nulls[12] = false;
189
190 values[13] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestMulti);
191 nulls[13] = false;
192
193 values[14] = ObjectIdGetDatum(ControlFile->checkPointCopy.oldestMultiDB);
194 nulls[14] = false;
195
196 values[15] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestCommitTsXid);
197 nulls[15] = false;
198
199 values[16] = TransactionIdGetDatum(ControlFile->checkPointCopy.newestCommitTsXid);
200 nulls[16] = false;
201
202 values[17] = TimestampTzGetDatum(
203 time_t_to_timestamptz(ControlFile->checkPointCopy.time));
204 nulls[17] = false;
205
206 htup = heap_form_tuple(tupdesc, values, nulls);
207
208 PG_RETURN_DATUM(HeapTupleGetDatum(htup));
209}
210
211Datum
212pg_control_recovery(PG_FUNCTION_ARGS)
213{
214 Datum values[5];
215 bool nulls[5];
216 TupleDesc tupdesc;
217 HeapTuple htup;
218 ControlFileData *ControlFile;
219 bool crc_ok;
220
221 /*
222 * Construct a tuple descriptor for the result row. This must match this
223 * function's pg_proc entry!
224 */
225 tupdesc = CreateTemplateTupleDesc(5);
226 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "min_recovery_end_lsn",
227 LSNOID, -1, 0);
228 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "min_recovery_end_timeline",
229 INT4OID, -1, 0);
230 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "backup_start_lsn",
231 LSNOID, -1, 0);
232 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "backup_end_lsn",
233 LSNOID, -1, 0);
234 TupleDescInitEntry(tupdesc, (AttrNumber) 5, "end_of_backup_record_required",
235 BOOLOID, -1, 0);
236 tupdesc = BlessTupleDesc(tupdesc);
237
238 /* read the control file */
239 ControlFile = get_controlfile(DataDir, &crc_ok);
240 if (!crc_ok)
241 ereport(ERROR,
242 (errmsg("calculated CRC checksum does not match value stored in file")));
243
244 values[0] = LSNGetDatum(ControlFile->minRecoveryPoint);
245 nulls[0] = false;
246
247 values[1] = Int32GetDatum(ControlFile->minRecoveryPointTLI);
248 nulls[1] = false;
249
250 values[2] = LSNGetDatum(ControlFile->backupStartPoint);
251 nulls[2] = false;
252
253 values[3] = LSNGetDatum(ControlFile->backupEndPoint);
254 nulls[3] = false;
255
256 values[4] = BoolGetDatum(ControlFile->backupEndRequired);
257 nulls[4] = false;
258
259 htup = heap_form_tuple(tupdesc, values, nulls);
260
261 PG_RETURN_DATUM(HeapTupleGetDatum(htup));
262}
263
264Datum
265pg_control_init(PG_FUNCTION_ARGS)
266{
267 Datum values[12];
268 bool nulls[12];
269 TupleDesc tupdesc;
270 HeapTuple htup;
271 ControlFileData *ControlFile;
272 bool crc_ok;
273
274 /*
275 * Construct a tuple descriptor for the result row. This must match this
276 * function's pg_proc entry!
277 */
278 tupdesc = CreateTemplateTupleDesc(12);
279 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "max_data_alignment",
280 INT4OID, -1, 0);
281 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database_block_size",
282 INT4OID, -1, 0);
283 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "blocks_per_segment",
284 INT4OID, -1, 0);
285 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "wal_block_size",
286 INT4OID, -1, 0);
287 TupleDescInitEntry(tupdesc, (AttrNumber) 5, "bytes_per_wal_segment",
288 INT4OID, -1, 0);
289 TupleDescInitEntry(tupdesc, (AttrNumber) 6, "max_identifier_length",
290 INT4OID, -1, 0);
291 TupleDescInitEntry(tupdesc, (AttrNumber) 7, "max_index_columns",
292 INT4OID, -1, 0);
293 TupleDescInitEntry(tupdesc, (AttrNumber) 8, "max_toast_chunk_size",
294 INT4OID, -1, 0);
295 TupleDescInitEntry(tupdesc, (AttrNumber) 9, "large_object_chunk_size",
296 INT4OID, -1, 0);
297 TupleDescInitEntry(tupdesc, (AttrNumber) 10, "float4_pass_by_value",
298 BOOLOID, -1, 0);
299 TupleDescInitEntry(tupdesc, (AttrNumber) 11, "float8_pass_by_value",
300 BOOLOID, -1, 0);
301 TupleDescInitEntry(tupdesc, (AttrNumber) 12, "data_page_checksum_version",
302 INT4OID, -1, 0);
303 tupdesc = BlessTupleDesc(tupdesc);
304
305 /* read the control file */
306 ControlFile = get_controlfile(DataDir, &crc_ok);
307 if (!crc_ok)
308 ereport(ERROR,
309 (errmsg("calculated CRC checksum does not match value stored in file")));
310
311 values[0] = Int32GetDatum(ControlFile->maxAlign);
312 nulls[0] = false;
313
314 values[1] = Int32GetDatum(ControlFile->blcksz);
315 nulls[1] = false;
316
317 values[2] = Int32GetDatum(ControlFile->relseg_size);
318 nulls[2] = false;
319
320 values[3] = Int32GetDatum(ControlFile->xlog_blcksz);
321 nulls[3] = false;
322
323 values[4] = Int32GetDatum(ControlFile->xlog_seg_size);
324 nulls[4] = false;
325
326 values[5] = Int32GetDatum(ControlFile->nameDataLen);
327 nulls[5] = false;
328
329 values[6] = Int32GetDatum(ControlFile->indexMaxKeys);
330 nulls[6] = false;
331
332 values[7] = Int32GetDatum(ControlFile->toast_max_chunk_size);
333 nulls[7] = false;
334
335 values[8] = Int32GetDatum(ControlFile->loblksize);
336 nulls[8] = false;
337
338 values[9] = BoolGetDatum(ControlFile->float4ByVal);
339 nulls[9] = false;
340
341 values[10] = BoolGetDatum(ControlFile->float8ByVal);
342 nulls[10] = false;
343
344 values[11] = Int32GetDatum(ControlFile->data_checksum_version);
345 nulls[11] = false;
346
347 htup = heap_form_tuple(tupdesc, values, nulls);
348
349 PG_RETURN_DATUM(HeapTupleGetDatum(htup));
350}
351