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