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