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