]> granicus.if.org Git - postgresql/commitdiff
Expose control file data via SQL accessible functions.
authorJoe Conway <mail@joeconway.com>
Sat, 5 Mar 2016 19:10:19 +0000 (11:10 -0800)
committerJoe Conway <mail@joeconway.com>
Sat, 5 Mar 2016 19:10:19 +0000 (11:10 -0800)
Add four new SQL accessible functions: pg_control_system(),
pg_control_checkpoint(), pg_control_recovery(), and pg_control_init()
which expose a subset of the control file data.

Along the way move the code to read and validate the control file to
src/common, where it can be shared by the new backend functions
and the original pg_controldata frontend program.

Patch by me, significant input, testing, and review by Michael Paquier.

doc/src/sgml/func.sgml
src/backend/utils/misc/Makefile
src/backend/utils/misc/pg_controldata.c [new file with mode: 0644]
src/bin/pg_controldata/pg_controldata.c
src/common/Makefile
src/common/controldata_utils.c [new file with mode: 0644]
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h
src/include/common/controldata_utils.h [new file with mode: 0644]
src/include/utils/builtins.h
src/tools/msvc/Mkvcbuild.pm

index c0b94bc072867349a18cd106aaecabf69915ad0b..4b5ee8135f021fe5935f1a85f6290dca21d462c7 100644 (file)
@@ -16703,6 +16703,362 @@ SELECT collation for ('foo' COLLATE "de_DE");
     </tgroup>
    </table>
 
+   <para>
+    The functions shown in <xref linkend="functions-controldata">
+    print information initialized during <command>initdb</>, such
+    as the catalog version. They also show information about write-ahead
+    logging and checkpoint processing. This information is cluster-wide,
+    and not specific to any one database. They provide most of the same
+    information, from the same source, as
+    <xref linkend="APP-PGCONTROLDATA">, although in a form better suited
+    to <acronym>SQL</acronym> functions.
+   </para>
+
+   <table id="functions-controldata">
+    <title>Control Data Functions</title>
+    <tgroup cols="3">
+     <thead>
+      <row><entry>Name</entry> <entry>Return Type</entry> <entry>Description</entry></row>
+     </thead>
+
+     <tbody>
+      <row>
+       <entry>
+        <indexterm><primary>pg_control_checkpoint</primary></indexterm>
+        <literal><function>pg_control_checkpoint()</function></literal>
+       </entry>
+       <entry><type>record</type></entry>
+       <entry>
+        Returns information about current checkpoint state.
+       </entry>
+      </row>
+
+      <row>
+       <entry>
+        <indexterm><primary>pg_control_system</primary></indexterm>
+        <literal><function>pg_control_system()</function></literal>
+       </entry>
+       <entry><type>record</type></entry>
+       <entry>
+        Returns information about current controldata file state.
+       </entry>
+      </row>
+
+      <row>
+       <entry>
+        <indexterm><primary>pg_control_init</primary></indexterm>
+        <literal><function>pg_control_init()</function></literal>
+       </entry>
+       <entry><type>record</type></entry>
+       <entry>
+        Returns information about cluster initialization state.
+       </entry>
+      </row>
+
+      <row>
+       <entry>
+        <indexterm><primary>pg_control_recovery</primary></indexterm>
+        <literal><function>pg_control_recovery()</function></literal>
+       </entry>
+       <entry><type>record</type></entry>
+       <entry>
+        Returns information about recovery state.
+       </entry>
+      </row>
+
+     </tbody>
+    </tgroup>
+   </table>
+
+   <para>
+    <function>pg_control_checkpoint</> returns a record, shown in
+    <xref linkend="functions-pg-control-checkpoint">
+   </para>
+
+   <table id="functions-pg-control-checkpoint">
+    <title><function>pg_control_checkpoint</> Columns</title>
+    <tgroup cols="2">
+     <thead>
+      <row>
+       <entry>Column Name</entry>
+       <entry>Data Type</entry>
+      </row>
+     </thead>
+
+     <tbody>
+
+      <row>
+       <entry>checkpoint_location</entry>
+       <entry><type>pg_lsn</type></entry>
+      </row>
+
+      <row>
+       <entry>prior_location</entry>
+       <entry><type>pg_lsn</type></entry>
+      </row>
+
+      <row>
+       <entry>redo_location</entry>
+       <entry><type>pg_lsn</type></entry>
+      </row>
+
+      <row>
+       <entry>redo_wal_file</entry>
+       <entry><type>text</type></entry>
+      </row>
+
+      <row>
+       <entry>timeline_id</entry>
+       <entry><type>integer</type></entry>
+      </row>
+
+      <row>
+       <entry>prev_timeline_id</entry>
+       <entry><type>integer</type></entry>
+      </row>
+
+      <row>
+       <entry>full_page_writes</entry>
+       <entry><type>boolean</type></entry>
+      </row>
+
+      <row>
+       <entry>next_xid</entry>
+       <entry><type>text</type></entry>
+      </row>
+
+      <row>
+       <entry>next_oid</entry>
+       <entry><type>oid</type></entry>
+      </row>
+
+      <row>
+       <entry>next_multixact_id</entry>
+       <entry><type>xid</type></entry>
+      </row>
+
+      <row>
+       <entry>next_multi_offset</entry>
+       <entry><type>xid</type></entry>
+      </row>
+
+      <row>
+       <entry>oldest_xid</entry>
+       <entry><type>xid</type></entry>
+      </row>
+
+      <row>
+       <entry>oldest_xid_dbid</entry>
+       <entry><type>oid</type></entry>
+      </row>
+
+      <row>
+       <entry>oldest_active_xid</entry>
+       <entry><type>xid</type></entry>
+      </row>
+
+      <row>
+       <entry>oldest_multi_xid</entry>
+       <entry><type>xid</type></entry>
+      </row>
+
+      <row>
+       <entry>oldest_multi_dbid</entry>
+       <entry><type>oid</type></entry>
+      </row>
+
+      <row>
+       <entry>oldest_commit_ts_xid</entry>
+       <entry><type>xid</type></entry>
+      </row>
+
+      <row>
+       <entry>newest_commit_ts_xid</entry>
+       <entry><type>xid</type></entry>
+      </row>
+
+      <row>
+       <entry>checkpoint_time</entry>
+       <entry><type>timestamp with time zone</type></entry>
+      </row>
+
+     </tbody>
+    </tgroup>
+   </table>
+
+   <para>
+    <function>pg_control_system</> returns a record, shown in
+    <xref linkend="functions-pg-control-system">
+   </para>
+
+   <table id="functions-pg-control-system">
+    <title><function>pg_control_system</> Columns</title>
+    <tgroup cols="2">
+     <thead>
+      <row>
+       <entry>Column Name</entry>
+       <entry>Data Type</entry>
+      </row>
+     </thead>
+
+     <tbody>
+
+      <row>
+       <entry>pg_control_version</entry>
+       <entry><type>integer</type></entry>
+      </row>
+
+      <row>
+       <entry>catalog_version_no</entry>
+       <entry><type>integer</type></entry>
+      </row>
+
+      <row>
+       <entry>system_identifier</entry>
+       <entry><type>bigint</type></entry>
+      </row>
+
+      <row>
+       <entry>pg_control_last_modified</entry>
+       <entry><type>timestamp with time zone</type></entry>
+      </row>
+
+     </tbody>
+    </tgroup>
+   </table>
+
+   <para>
+    <function>pg_control_init</> returns a record, shown in
+    <xref linkend="functions-pg-control-init">
+   </para>
+
+   <table id="functions-pg-control-init">
+    <title><function>pg_control_init</> Columns</title>
+    <tgroup cols="2">
+     <thead>
+      <row>
+       <entry>Column Name</entry>
+       <entry>Data Type</entry>
+      </row>
+     </thead>
+
+     <tbody>
+
+      <row>
+       <entry>max_data_alignment</entry>
+       <entry><type>integer</type></entry>
+      </row>
+
+      <row>
+       <entry>database_block_size</entry>
+       <entry><type>integer</type></entry>
+      </row>
+
+      <row>
+       <entry>blocks_per_segment</entry>
+       <entry><type>integer</type></entry>
+      </row>
+
+      <row>
+       <entry>wal_block_size</entry>
+       <entry><type>integer</type></entry>
+      </row>
+
+      <row>
+       <entry>bytes_per_wal_segment</entry>
+       <entry><type>integer</type></entry>
+      </row>
+
+      <row>
+       <entry>max_identifier_length</entry>
+       <entry><type>integer</type></entry>
+      </row>
+
+      <row>
+       <entry>max_index_columns</entry>
+       <entry><type>integer</type></entry>
+      </row>
+
+      <row>
+       <entry>max_toast_chunk_size</entry>
+       <entry><type>integer</type></entry>
+      </row>
+
+      <row>
+       <entry>large_object_chunk_size</entry>
+       <entry><type>integer</type></entry>
+      </row>
+
+      <row>
+       <entry>bigint_timestamps</entry>
+       <entry><type>boolean</type></entry>
+      </row>
+
+      <row>
+       <entry>float4_pass_by_value</entry>
+       <entry><type>boolean</type></entry>
+      </row>
+
+      <row>
+       <entry>float8_pass_by_value</entry>
+       <entry><type>boolean</type></entry>
+      </row>
+
+      <row>
+       <entry>data_page_checksum_version</entry>
+       <entry><type>integer</type></entry>
+      </row>
+
+     </tbody>
+    </tgroup>
+   </table>
+
+   <para>
+    <function>pg_control_recovery</> returns a record, shown in
+    <xref linkend="functions-pg-control-recovery">
+   </para>
+
+   <table id="functions-pg-control-recovery">
+    <title><function>pg_control_recovery</> Columns</title>
+    <tgroup cols="2">
+     <thead>
+      <row>
+       <entry>Column Name</entry>
+       <entry>Data Type</entry>
+      </row>
+     </thead>
+
+     <tbody>
+
+      <row>
+       <entry>min_recovery_end_location</entry>
+       <entry><type>pg_lsn</type></entry>
+      </row>
+
+      <row>
+       <entry>min_recovery_end_timeline</entry>
+       <entry><type>integer</type></entry>
+      </row>
+
+      <row>
+       <entry>backup_start_location</entry>
+       <entry><type>pg_lsn</type></entry>
+      </row>
+
+      <row>
+       <entry>backup_end_location</entry>
+       <entry><type>pg_lsn</type></entry>
+      </row>
+
+      <row>
+       <entry>end_of_backup_record_required</entry>
+       <entry><type>boolean</type></entry>
+      </row>
+
+     </tbody>
+    </tgroup>
+   </table>
+
   </sect1>
 
   <sect1 id="functions-admin">
index a0c82c174386e4bedd9fa7471e7fcc866207ac31..a5b487d0b64de0e169423e721d897b748fe3e2df 100644 (file)
@@ -14,7 +14,7 @@ include $(top_builddir)/src/Makefile.global
 
 override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS)
 
-OBJS = guc.o help_config.o pg_config.o pg_rusage.o \
+OBJS = guc.o help_config.o pg_config.o pg_controldata.o pg_rusage.o \
        ps_status.o rls.o sampling.o superuser.o timeout.o tzparser.o
 
 # This location might depend on the installation directories. Therefore
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
new file mode 100644 (file)
index 0000000..8552c07
--- /dev/null
@@ -0,0 +1,341 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_controldata.c
+ *
+ * Routines to expose the contents of the control data file via
+ * a set of SQL functions.
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *       src/backend/utils/misc/pg_controldata.c
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "funcapi.h"
+#include "miscadmin.h"
+#include "access/htup_details.h"
+#include "access/xlog_internal.h"
+#include "catalog/pg_control.h"
+#include "catalog/pg_type.h"
+#include "common/controldata_utils.h"
+#include "utils/builtins.h"
+#include "utils/pg_lsn.h"
+#include "utils/timestamp.h"
+
+Datum
+pg_control_system(PG_FUNCTION_ARGS)
+{
+       Datum                           values[4];
+       bool                            nulls[4];
+       TupleDesc                       tupdesc;
+       HeapTuple                       htup;
+       ControlFileData    *ControlFile;
+
+       /*
+        * Construct a tuple descriptor for the result row.  This must match this
+        * function's pg_proc entry!
+        */
+       tupdesc = CreateTemplateTupleDesc(4, false);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 1, "pg_control_version",
+                                          INT4OID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 2, "catalog_version_no",
+                                          INT4OID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 3, "system_identifier",
+                                          INT8OID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 4, "pg_control_last_modified",
+                                          TIMESTAMPTZOID, -1, 0);
+       tupdesc = BlessTupleDesc(tupdesc);
+
+       /* read the control file */
+       ControlFile = get_controlfile(DataDir, NULL);
+
+       values[0] = Int32GetDatum(ControlFile->pg_control_version);
+       nulls[0] = false;
+
+       values[1] = Int32GetDatum(ControlFile->catalog_version_no);
+       nulls[1] = false;
+
+       values[2] = Int64GetDatum(ControlFile->system_identifier);
+       nulls[2] = false;
+
+       values[3] = TimestampTzGetDatum(time_t_to_timestamptz(ControlFile->time));
+       nulls[3] = false;
+
+       htup = heap_form_tuple(tupdesc, values, nulls);
+
+       PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+}
+
+Datum
+pg_control_checkpoint(PG_FUNCTION_ARGS)
+{
+       Datum                           values[19];
+       bool                            nulls[19];
+       TupleDesc                       tupdesc;
+       HeapTuple                       htup;
+       ControlFileData    *ControlFile;
+       XLogSegNo                       segno;
+       char                            xlogfilename[MAXFNAMELEN];
+
+       /*
+        * Construct a tuple descriptor for the result row.  This must match this
+        * function's pg_proc entry!
+        */
+       tupdesc = CreateTemplateTupleDesc(19, false);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 1, "checkpoint_location",
+                                          LSNOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 2, "prior_location",
+                                          LSNOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 3, "redo_location",
+                                          LSNOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 4, "redo_wal_file",
+                                          TEXTOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 5, "timeline_id",
+                                          INT4OID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 6, "prev_timeline_id",
+                                          INT4OID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 7, "full_page_writes",
+                                          BOOLOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 8, "next_xid",
+                                          TEXTOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 9, "next_oid",
+                                          OIDOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 10, "next_multixact_id",
+                                          XIDOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 11, "next_multi_offset",
+                                          XIDOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 12, "oldest_xid",
+                                          XIDOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 13, "oldest_xid_dbid",
+                                          OIDOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 14, "oldest_active_xid",
+                                          XIDOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 15, "oldest_multi_xid",
+                                          XIDOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 16, "oldest_multi_dbid",
+                                          OIDOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 17, "oldest_commit_ts_xid",
+                                          XIDOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 18, "newest_commit_ts_xid",
+                                          XIDOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 19, "checkpoint_time",
+                                          TIMESTAMPTZOID, -1, 0);
+       tupdesc = BlessTupleDesc(tupdesc);
+
+       /* Read the control file. */
+       ControlFile = get_controlfile(DataDir, NULL);
+
+       /*
+        * Calculate name of the WAL file containing the latest checkpoint's REDO
+        * start point.
+        */
+       XLByteToSeg(ControlFile->checkPointCopy.redo, segno);
+       XLogFileName(xlogfilename, ControlFile->checkPointCopy.ThisTimeLineID, segno);
+
+       /* Populate the values and null arrays */
+       values[0] = LSNGetDatum(ControlFile->checkPoint);
+       nulls[0] = false;
+
+       values[1] = LSNGetDatum(ControlFile->prevCheckPoint);
+       nulls[1] = false;
+
+       values[2] = LSNGetDatum(ControlFile->checkPointCopy.redo);
+       nulls[2] = false;
+
+       values[3] = CStringGetTextDatum(xlogfilename);
+       nulls[3] = false;
+
+       values[4] = Int32GetDatum(ControlFile->checkPointCopy.ThisTimeLineID);
+       nulls[4] = false;
+
+       values[5] = Int32GetDatum(ControlFile->checkPointCopy.PrevTimeLineID);
+       nulls[5] = false;
+
+       values[6] = BoolGetDatum(ControlFile->checkPointCopy.fullPageWrites);
+       nulls[6] = false;
+
+       values[7] = CStringGetTextDatum(psprintf("%u:%u",
+                                                               ControlFile->checkPointCopy.nextXidEpoch,
+                                                               ControlFile->checkPointCopy.nextXid));
+       nulls[7] = false;
+
+       values[8] = ObjectIdGetDatum(ControlFile->checkPointCopy.nextOid);
+       nulls[8] = false;
+
+       values[9] = TransactionIdGetDatum(ControlFile->checkPointCopy.nextMulti);
+       nulls[9] = false;
+
+       values[10] = TransactionIdGetDatum(ControlFile->checkPointCopy.nextMultiOffset);
+       nulls[10] = false;
+
+       values[11] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestXid);
+       nulls[11] = false;
+
+       values[12] = ObjectIdGetDatum(ControlFile->checkPointCopy.oldestXidDB);
+       nulls[12] = false;
+
+       values[13] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestActiveXid);
+       nulls[13] = false;
+
+       values[14] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestMulti);
+       nulls[14] = false;
+
+       values[15] = ObjectIdGetDatum(ControlFile->checkPointCopy.oldestMultiDB);
+       nulls[15] = false;
+
+       values[16] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestCommitTsXid);
+       nulls[16] = false;
+
+       values[17] = TransactionIdGetDatum(ControlFile->checkPointCopy.newestCommitTsXid);
+       nulls[17] = false;
+
+       values[18] = TimestampTzGetDatum(
+                                       time_t_to_timestamptz(ControlFile->checkPointCopy.time));
+       nulls[18] = false;
+
+       htup = heap_form_tuple(tupdesc, values, nulls);
+
+       PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+}
+
+Datum
+pg_control_recovery(PG_FUNCTION_ARGS)
+{
+       Datum                           values[5];
+       bool                            nulls[5];
+       TupleDesc                       tupdesc;
+       HeapTuple                       htup;
+       ControlFileData    *ControlFile;
+
+       /*
+        * Construct a tuple descriptor for the result row.  This must match this
+        * function's pg_proc entry!
+        */
+       tupdesc = CreateTemplateTupleDesc(5, false);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 1, "min_recovery_end_location",
+                                          LSNOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 2, "min_recovery_end_timeline",
+                                          INT4OID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 3, "backup_start_location",
+                                          LSNOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 4, "backup_end_location",
+                                          LSNOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 5, "end_of_backup_record_required",
+                                          BOOLOID, -1, 0);
+       tupdesc = BlessTupleDesc(tupdesc);
+
+       /* read the control file */
+       ControlFile = get_controlfile(DataDir, NULL);
+
+       values[0] = LSNGetDatum(ControlFile->minRecoveryPoint);
+       nulls[0] = false;
+
+       values[1] = Int32GetDatum(ControlFile->minRecoveryPointTLI);
+       nulls[1] = false;
+
+       values[2] = LSNGetDatum(ControlFile->backupStartPoint);
+       nulls[2] = false;
+
+       values[3] = LSNGetDatum(ControlFile->backupEndPoint);
+       nulls[3] = false;
+
+       values[4] = BoolGetDatum(ControlFile->backupEndRequired);
+       nulls[4] = false;
+
+       htup = heap_form_tuple(tupdesc, values, nulls);
+
+       PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+}
+
+Datum
+pg_control_init(PG_FUNCTION_ARGS)
+{
+       Datum                           values[13];
+       bool                            nulls[13];
+       TupleDesc                       tupdesc;
+       HeapTuple                       htup;
+       ControlFileData    *ControlFile;
+
+       /*
+        * Construct a tuple descriptor for the result row.  This must match this
+        * function's pg_proc entry!
+        */
+       tupdesc = CreateTemplateTupleDesc(13, false);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 1, "max_data_alignment",
+                                          INT4OID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database_block_size",
+                                          INT4OID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 3, "blocks_per_segment",
+                                          INT4OID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 4, "wal_block_size",
+                                          INT4OID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 5, "bytes_per_wal_segment",
+                                          INT4OID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 6, "max_identifier_length",
+                                          INT4OID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 7, "max_index_columns",
+                                          INT4OID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 8, "max_toast_chunk_size",
+                                          INT4OID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 9, "large_object_chunk_size",
+                                          INT4OID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 10, "bigint_timestamps",
+                                          BOOLOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 11, "float4_pass_by_value",
+                                          BOOLOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 12, "float8_pass_by_value",
+                                          BOOLOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 13, "data_page_checksum_version",
+                                          INT4OID, -1, 0);
+       tupdesc = BlessTupleDesc(tupdesc);
+
+       /* read the control file */
+       ControlFile = get_controlfile(DataDir, NULL);
+
+       values[0] = Int32GetDatum(ControlFile->maxAlign);
+       nulls[0] = false;
+
+       values[1] = Int32GetDatum(ControlFile->blcksz);
+       nulls[1] = false;
+
+       values[2] = Int32GetDatum(ControlFile->relseg_size);
+       nulls[2] = false;
+
+       values[3] = Int32GetDatum(ControlFile->xlog_blcksz);
+       nulls[3] = false;
+
+       values[4] = Int32GetDatum(ControlFile->xlog_seg_size);
+       nulls[4] = false;
+
+       values[5] = Int32GetDatum(ControlFile->nameDataLen);
+       nulls[5] = false;
+
+       values[6] = Int32GetDatum(ControlFile->indexMaxKeys);
+       nulls[6] = false;
+
+       values[7] = Int32GetDatum(ControlFile->toast_max_chunk_size);
+       nulls[7] = false;
+
+       values[8] = Int32GetDatum(ControlFile->loblksize);
+       nulls[8] = false;
+
+       values[9] = BoolGetDatum(ControlFile->enableIntTimes);
+       nulls[9] = false;
+
+       values[10] = BoolGetDatum(ControlFile->float4ByVal);
+       nulls[10] = false;
+
+       values[11] = BoolGetDatum(ControlFile->float8ByVal);
+       nulls[11] = false;
+
+       values[12] = Int32GetDatum(ControlFile->data_checksum_version);
+       nulls[12] = false;
+
+       htup = heap_form_tuple(tupdesc, values, nulls);
+
+       PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+}
index 5dd2dbc5da5fe46b53dfd1269789d8338b0baae3..fdf7c7de9b66883f77dc229c8dc6894f17869239 100644 (file)
 
 #include "postgres.h"
 
-#include <unistd.h>
 #include <time.h>
-#include <sys/stat.h>
-#include <fcntl.h>
 
 #include "access/xlog.h"
 #include "access/xlog_internal.h"
 #include "catalog/pg_control.h"
+#include "common/controldata_utils.h"
 #include "pg_getopt.h"
 
 
@@ -89,11 +87,8 @@ wal_level_str(WalLevel wal_level)
 int
 main(int argc, char *argv[])
 {
-       ControlFileData ControlFile;
-       int                     fd;
-       char            ControlFilePath[MAXPGPATH];
+       ControlFileData *ControlFile;
        char       *DataDir = NULL;
-       pg_crc32c       crc;
        time_t          time_tmp;
        char            pgctime_str[128];
        char            ckpttime_str[128];
@@ -161,34 +156,8 @@ main(int argc, char *argv[])
                exit(1);
        }
 
-       snprintf(ControlFilePath, MAXPGPATH, "%s/global/pg_control", DataDir);
-
-       if ((fd = open(ControlFilePath, O_RDONLY | PG_BINARY, 0)) == -1)
-       {
-               fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
-                               progname, ControlFilePath, strerror(errno));
-               exit(2);
-       }
-
-       if (read(fd, &ControlFile, sizeof(ControlFileData)) != sizeof(ControlFileData))
-       {
-               fprintf(stderr, _("%s: could not read file \"%s\": %s\n"),
-                               progname, ControlFilePath, strerror(errno));
-               exit(2);
-       }
-       close(fd);
-
-       /* Check the CRC. */
-       INIT_CRC32C(crc);
-       COMP_CRC32C(crc,
-                               (char *) &ControlFile,
-                               offsetof(ControlFileData, crc));
-       FIN_CRC32C(crc);
-
-       if (!EQ_CRC32C(crc, ControlFile.crc))
-               printf(_("WARNING: Calculated CRC checksum does not match value stored in file.\n"
-                                "Either the file is corrupt, or it has a different layout than this program\n"
-                                "is expecting.  The results below are untrustworthy.\n\n"));
+       /* get a copy of the control file */
+       ControlFile = get_controlfile(DataDir, progname);
 
        /*
         * This slightly-chintzy coding will work as long as the control file
@@ -199,10 +168,10 @@ main(int argc, char *argv[])
         * Use variable for format to suppress overly-anal-retentive gcc warning
         * about %c
         */
-       time_tmp = (time_t) ControlFile.time;
+       time_tmp = (time_t) ControlFile->time;
        strftime(pgctime_str, sizeof(pgctime_str), strftime_fmt,
                         localtime(&time_tmp));
-       time_tmp = (time_t) ControlFile.checkPointCopy.time;
+       time_tmp = (time_t) ControlFile->checkPointCopy.time;
        strftime(ckpttime_str, sizeof(ckpttime_str), strftime_fmt,
                         localtime(&time_tmp));
 
@@ -210,129 +179,124 @@ main(int argc, char *argv[])
         * Calculate name of the WAL file containing the latest checkpoint's REDO
         * start point.
         */
-       XLByteToSeg(ControlFile.checkPointCopy.redo, segno);
-       XLogFileName(xlogfilename, ControlFile.checkPointCopy.ThisTimeLineID, segno);
+       XLByteToSeg(ControlFile->checkPointCopy.redo, segno);
+       XLogFileName(xlogfilename, ControlFile->checkPointCopy.ThisTimeLineID, segno);
 
        /*
         * Format system_identifier separately to keep platform-dependent format
         * code out of the translatable message string.
         */
        snprintf(sysident_str, sizeof(sysident_str), UINT64_FORMAT,
-                        ControlFile.system_identifier);
+                        ControlFile->system_identifier);
 
        printf(_("pg_control version number:            %u\n"),
-                  ControlFile.pg_control_version);
-       if (ControlFile.pg_control_version % 65536 == 0 && ControlFile.pg_control_version / 65536 != 0)
-               printf(_("WARNING: possible byte ordering mismatch\n"
-                                "The byte ordering used to store the pg_control file might not match the one\n"
-                                "used by this program.  In that case the results below would be incorrect, and\n"
-                                "the PostgreSQL installation would be incompatible with this data directory.\n"));
+                  ControlFile->pg_control_version);
        printf(_("Catalog version number:               %u\n"),
-                  ControlFile.catalog_version_no);
+                  ControlFile->catalog_version_no);
        printf(_("Database system identifier:           %s\n"),
                   sysident_str);
        printf(_("Database cluster state:               %s\n"),
-                  dbState(ControlFile.state));
+                  dbState(ControlFile->state));
        printf(_("pg_control last modified:             %s\n"),
                   pgctime_str);
        printf(_("Latest checkpoint location:           %X/%X\n"),
-                  (uint32) (ControlFile.checkPoint >> 32),
-                  (uint32) ControlFile.checkPoint);
+                  (uint32) (ControlFile->checkPoint >> 32),
+                  (uint32) ControlFile->checkPoint);
        printf(_("Prior checkpoint location:            %X/%X\n"),
-                  (uint32) (ControlFile.prevCheckPoint >> 32),
-                  (uint32) ControlFile.prevCheckPoint);
+                  (uint32) (ControlFile->prevCheckPoint >> 32),
+                  (uint32) ControlFile->prevCheckPoint);
        printf(_("Latest checkpoint's REDO location:    %X/%X\n"),
-                  (uint32) (ControlFile.checkPointCopy.redo >> 32),
-                  (uint32) ControlFile.checkPointCopy.redo);
+                  (uint32) (ControlFile->checkPointCopy.redo >> 32),
+                  (uint32) ControlFile->checkPointCopy.redo);
        printf(_("Latest checkpoint's REDO WAL file:    %s\n"),
                   xlogfilename);
        printf(_("Latest checkpoint's TimeLineID:       %u\n"),
-                  ControlFile.checkPointCopy.ThisTimeLineID);
+                  ControlFile->checkPointCopy.ThisTimeLineID);
        printf(_("Latest checkpoint's PrevTimeLineID:   %u\n"),
-                  ControlFile.checkPointCopy.PrevTimeLineID);
+                  ControlFile->checkPointCopy.PrevTimeLineID);
        printf(_("Latest checkpoint's full_page_writes: %s\n"),
-                  ControlFile.checkPointCopy.fullPageWrites ? _("on") : _("off"));
+                  ControlFile->checkPointCopy.fullPageWrites ? _("on") : _("off"));
        printf(_("Latest checkpoint's NextXID:          %u:%u\n"),
-                  ControlFile.checkPointCopy.nextXidEpoch,
-                  ControlFile.checkPointCopy.nextXid);
+                  ControlFile->checkPointCopy.nextXidEpoch,
+                  ControlFile->checkPointCopy.nextXid);
        printf(_("Latest checkpoint's NextOID:          %u\n"),
-                  ControlFile.checkPointCopy.nextOid);
+                  ControlFile->checkPointCopy.nextOid);
        printf(_("Latest checkpoint's NextMultiXactId:  %u\n"),
-                  ControlFile.checkPointCopy.nextMulti);
+                  ControlFile->checkPointCopy.nextMulti);
        printf(_("Latest checkpoint's NextMultiOffset:  %u\n"),
-                  ControlFile.checkPointCopy.nextMultiOffset);
+                  ControlFile->checkPointCopy.nextMultiOffset);
        printf(_("Latest checkpoint's oldestXID:        %u\n"),
-                  ControlFile.checkPointCopy.oldestXid);
+                  ControlFile->checkPointCopy.oldestXid);
        printf(_("Latest checkpoint's oldestXID's DB:   %u\n"),
-                  ControlFile.checkPointCopy.oldestXidDB);
+                  ControlFile->checkPointCopy.oldestXidDB);
        printf(_("Latest checkpoint's oldestActiveXID:  %u\n"),
-                  ControlFile.checkPointCopy.oldestActiveXid);
+                  ControlFile->checkPointCopy.oldestActiveXid);
        printf(_("Latest checkpoint's oldestMultiXid:   %u\n"),
-                  ControlFile.checkPointCopy.oldestMulti);
+                  ControlFile->checkPointCopy.oldestMulti);
        printf(_("Latest checkpoint's oldestMulti's DB: %u\n"),
-                  ControlFile.checkPointCopy.oldestMultiDB);
+                  ControlFile->checkPointCopy.oldestMultiDB);
        printf(_("Latest checkpoint's oldestCommitTsXid:%u\n"),
-                  ControlFile.checkPointCopy.oldestCommitTsXid);
+                  ControlFile->checkPointCopy.oldestCommitTsXid);
        printf(_("Latest checkpoint's newestCommitTsXid:%u\n"),
-                  ControlFile.checkPointCopy.newestCommitTsXid);
+                  ControlFile->checkPointCopy.newestCommitTsXid);
        printf(_("Time of latest checkpoint:            %s\n"),
                   ckpttime_str);
        printf(_("Fake LSN counter for unlogged rels:   %X/%X\n"),
-                  (uint32) (ControlFile.unloggedLSN >> 32),
-                  (uint32) ControlFile.unloggedLSN);
+                  (uint32) (ControlFile->unloggedLSN >> 32),
+                  (uint32) ControlFile->unloggedLSN);
        printf(_("Minimum recovery ending location:     %X/%X\n"),
-                  (uint32) (ControlFile.minRecoveryPoint >> 32),
-                  (uint32) ControlFile.minRecoveryPoint);
+                  (uint32) (ControlFile->minRecoveryPoint >> 32),
+                  (uint32) ControlFile->minRecoveryPoint);
        printf(_("Min recovery ending loc's timeline:   %u\n"),
-                  ControlFile.minRecoveryPointTLI);
+                  ControlFile->minRecoveryPointTLI);
        printf(_("Backup start location:                %X/%X\n"),
-                  (uint32) (ControlFile.backupStartPoint >> 32),
-                  (uint32) ControlFile.backupStartPoint);
+                  (uint32) (ControlFile->backupStartPoint >> 32),
+                  (uint32) ControlFile->backupStartPoint);
        printf(_("Backup end location:                  %X/%X\n"),
-                  (uint32) (ControlFile.backupEndPoint >> 32),
-                  (uint32) ControlFile.backupEndPoint);
+                  (uint32) (ControlFile->backupEndPoint >> 32),
+                  (uint32) ControlFile->backupEndPoint);
        printf(_("End-of-backup record required:        %s\n"),
-                  ControlFile.backupEndRequired ? _("yes") : _("no"));
+                  ControlFile->backupEndRequired ? _("yes") : _("no"));
        printf(_("wal_level setting:                    %s\n"),
-                  wal_level_str(ControlFile.wal_level));
+                  wal_level_str(ControlFile->wal_level));
        printf(_("wal_log_hints setting:                %s\n"),
-                  ControlFile.wal_log_hints ? _("on") : _("off"));
+                  ControlFile->wal_log_hints ? _("on") : _("off"));
        printf(_("max_connections setting:              %d\n"),
-                  ControlFile.MaxConnections);
+                  ControlFile->MaxConnections);
        printf(_("max_worker_processes setting:         %d\n"),
-                  ControlFile.max_worker_processes);
+                  ControlFile->max_worker_processes);
        printf(_("max_prepared_xacts setting:           %d\n"),
-                  ControlFile.max_prepared_xacts);
+                  ControlFile->max_prepared_xacts);
        printf(_("max_locks_per_xact setting:           %d\n"),
-                  ControlFile.max_locks_per_xact);
+                  ControlFile->max_locks_per_xact);
        printf(_("track_commit_timestamp setting:       %s\n"),
-                  ControlFile.track_commit_timestamp ? _("on") : _("off"));
+                  ControlFile->track_commit_timestamp ? _("on") : _("off"));
        printf(_("Maximum data alignment:               %u\n"),
-                  ControlFile.maxAlign);
+                  ControlFile->maxAlign);
        /* we don't print floatFormat since can't say much useful about it */
        printf(_("Database block size:                  %u\n"),
-                  ControlFile.blcksz);
+                  ControlFile->blcksz);
        printf(_("Blocks per segment of large relation: %u\n"),
-                  ControlFile.relseg_size);
+                  ControlFile->relseg_size);
        printf(_("WAL block size:                       %u\n"),
-                  ControlFile.xlog_blcksz);
+                  ControlFile->xlog_blcksz);
        printf(_("Bytes per WAL segment:                %u\n"),
-                  ControlFile.xlog_seg_size);
+                  ControlFile->xlog_seg_size);
        printf(_("Maximum length of identifiers:        %u\n"),
-                  ControlFile.nameDataLen);
+                  ControlFile->nameDataLen);
        printf(_("Maximum columns in an index:          %u\n"),
-                  ControlFile.indexMaxKeys);
+                  ControlFile->indexMaxKeys);
        printf(_("Maximum size of a TOAST chunk:        %u\n"),
-                  ControlFile.toast_max_chunk_size);
+                  ControlFile->toast_max_chunk_size);
        printf(_("Size of a large-object chunk:         %u\n"),
-                  ControlFile.loblksize);
+                  ControlFile->loblksize);
        printf(_("Date/time type storage:               %s\n"),
-                  (ControlFile.enableIntTimes ? _("64-bit integers") : _("floating-point numbers")));
+                  (ControlFile->enableIntTimes ? _("64-bit integers") : _("floating-point numbers")));
        printf(_("Float4 argument passing:              %s\n"),
-                  (ControlFile.float4ByVal ? _("by value") : _("by reference")));
+                  (ControlFile->float4ByVal ? _("by value") : _("by reference")));
        printf(_("Float8 argument passing:              %s\n"),
-                  (ControlFile.float8ByVal ? _("by value") : _("by reference")));
+                  (ControlFile->float8ByVal ? _("by value") : _("by reference")));
        printf(_("Data page checksum version:           %u\n"),
-                  ControlFile.data_checksum_version);
+                  ControlFile->data_checksum_version);
        return 0;
 }
index bde4fc2597568901818805ccd689299578211a9a..f7a4a4d099a21dc5eb69a61a73b29d232792c7cf 100644 (file)
@@ -36,8 +36,8 @@ override CPPFLAGS += -DVAL_LDFLAGS_EX="\"$(LDFLAGS_EX)\""
 override CPPFLAGS += -DVAL_LDFLAGS_SL="\"$(LDFLAGS_SL)\""
 override CPPFLAGS += -DVAL_LIBS="\"$(LIBS)\""
 
-OBJS_COMMON = config_info.o exec.o pg_lzcompress.o pgfnames.o psprintf.o \
-       relpath.o rmtree.o string.o username.o wait_error.o
+OBJS_COMMON = config_info.o controldata_utils.o exec.o pg_lzcompress.o \
+       pgfnames.o psprintf.o relpath.o rmtree.o string.o username.o wait_error.o
 
 OBJS_FRONTEND = $(OBJS_COMMON) fe_memutils.o restricted_token.o
 
diff --git a/src/common/controldata_utils.c b/src/common/controldata_utils.c
new file mode 100644 (file)
index 0000000..b6d0a12
--- /dev/null
@@ -0,0 +1,100 @@
+/*-------------------------------------------------------------------------
+ *
+ * controldata_utils.c
+ *             Common code for control data file output.
+ *
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *       src/common/controldata_utils.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "catalog/pg_control.h"
+#include "common/controldata_utils.h"
+#include "port/pg_crc32c.h"
+
+#ifndef FRONTEND
+/* NOTE: caller must provide gettext call around the format string */
+#define log_error(...) \
+       elog(ERROR, __VA_ARGS__)
+#else
+#define log_error(...) \
+       do { \
+                       char *buf = psprintf(__VA_ARGS__); \
+                       fprintf(stderr, "%s: %s\n", progname, buf); \
+                       exit(2); \
+       } while (0)
+#endif
+
+/*
+ * get_controlfile(char *DataDir, const char *progname)
+ *
+ * Get controlfile values. The caller is responsible
+ * for pfreeing the result.
+ */
+ControlFileData *
+get_controlfile(char *DataDir, const char *progname)
+{
+       ControlFileData    *ControlFile;
+       int                                     fd;
+       char                            ControlFilePath[MAXPGPATH];
+       pg_crc32c                       crc;
+
+       ControlFile = palloc(sizeof(ControlFileData));
+       snprintf(ControlFilePath, MAXPGPATH, "%s/global/pg_control", DataDir);
+
+       if ((fd = open(ControlFilePath, O_RDONLY | PG_BINARY, 0)) == -1)
+               log_error(_("could not open file \"%s\" for reading: %s"),
+                                 ControlFilePath, strerror(errno));
+
+       if (read(fd, ControlFile, sizeof(ControlFileData)) != sizeof(ControlFileData))
+               log_error(_("could not read file \"%s\": %s"),
+                                 ControlFilePath, strerror(errno));
+
+       close(fd);
+
+       /* Check the CRC. */
+       INIT_CRC32C(crc);
+       COMP_CRC32C(crc,
+                          (char *) ControlFile,
+                          offsetof(ControlFileData, crc));
+       FIN_CRC32C(crc);
+
+       if (!EQ_CRC32C(crc, ControlFile->crc))
+#ifndef FRONTEND
+               elog(ERROR, _("calculated CRC checksum does not match value stored in file"));
+#else
+               printf(_("WARNING: Calculated CRC checksum does not match value stored in file.\n"
+                                "Either the file is corrupt, or it has a different layout than this program\n"
+                                "is expecting.  The results below are untrustworthy.\n\n"));
+#endif
+
+       /* Make sure the control file is valid byte order. */
+       if (ControlFile->pg_control_version % 65536 == 0 &&
+               ControlFile->pg_control_version / 65536 != 0)
+#ifndef FRONTEND
+               elog(ERROR, _("byte ordering mismatch"));
+#else
+               printf(_("WARNING: possible byte ordering mismatch\n"
+                                "The byte ordering used to store the pg_control file might not match the one\n"
+                                "used by this program.  In that case the results below would be incorrect, and\n"
+                                "the PostgreSQL installation would be incompatible with this data directory.\n"));
+#endif
+
+       return ControlFile;
+}
index 2f57524fcb25e68ea98342f8107f0ad29050407c..16cd304f1b71696568e1500e433cce7103154892 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     201603021
+#define CATALOG_VERSION_NO     201603051
 
 #endif
index aec6c4ca9044304ee132375000300a5c9adad64e..cbbb8835c463b06526789c4e7b88bf30c3c5bd0f 100644 (file)
@@ -5225,6 +5225,19 @@ DESCR("row security for current context active on table by table name");
 DATA(insert OID = 3400 ( pg_config PGNSP PGUID 12 1 23 0 0 f f f f t t i r 0 0 2249 "" "{25,25}" "{o,o}" "{name,setting}" _null_ _null_ pg_config _null_ _null_ _null_ ));
 DESCR("pg_config binary as a function");
 
+/* pg_controldata related functions */
+DATA(insert OID = 3441 ( pg_control_system PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 2249 "" "{23,23,20,1184}" "{o,o,o,o}" "{pg_control_version,catalog_version_no,system_identifier,pg_control_last_modified}" _null_ _null_ pg_control_system _null_ _null_ _null_ ));
+DESCR("pg_controldata general state information as a function");
+
+DATA(insert OID = 3442 ( pg_control_checkpoint PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 2249 "" "{3220,3220,3220,25,23,23,16,25,26,28,28,28,26,28,28,26,28,28,1184}" "{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{checkpoint_location,prior_location,redo_location,redo_wal_file,timeline_id,prev_timeline_id,full_page_writes,next_xid,next_oid,next_multixact_id,next_multi_offset,oldest_xid,oldest_xid_dbid,oldest_active_xid,oldest_multi_xid,oldest_multi_dbid,oldest_commit_ts_xid,newest_commit_ts_xid,checkpoint_time}" _null_ _null_ pg_control_checkpoint _null_ _null_ _null_ ));
+DESCR("pg_controldata checkpoint state information as a function");
+
+DATA(insert OID = 3443 ( pg_control_recovery PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 2249 "" "{3220,23,3220,3220,16}" "{o,o,o,o,o}" "{min_recovery_end_location,min_recovery_end_timeline,backup_start_location,backup_end_location,end_of_backup_record_required}" _null_ _null_ pg_control_recovery _null_ _null_ _null_ ));
+DESCR("pg_controldata recovery state information as a function");
+
+DATA(insert OID = 3444 ( pg_control_init PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 2249 "" "{23,23,23,23,23,23,23,23,23,16,16,16,23}" "{o,o,o,o,o,o,o,o,o,o,o,o,o}" "{max_data_alignment,database_block_size,blocks_per_segment,wal_block_size,bytes_per_wal_segment,max_identifier_length,max_index_columns,max_toast_chunk_size,large_object_chunk_size,bigint_timestamps,float4_pass_by_value,float8_pass_by_value,data_page_checksum_version}" _null_ _null_ pg_control_init _null_ _null_ _null_ ));
+DESCR("pg_controldata init state information as a function");
+
 /*
  * Symbolic values for provolatile column: these indicate whether the result
  * of a function is dependent *only* on the values of its explicit arguments,
diff --git a/src/include/common/controldata_utils.h b/src/include/common/controldata_utils.h
new file mode 100644 (file)
index 0000000..1a09765
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * controldata_utils.h
+ *             Common code for pg_controldata output
+ *
+ *     Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ *     Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *     src/include/common/controldata_utils.h
+ */
+#ifndef COMMON_CONTROLDATA_UTILS_H
+#define COMMON_CONTROLDATA_UTILS_H
+
+extern ControlFileData *get_controlfile(char *DataDir, const char *progname);
+
+#endif   /* COMMON_CONTROLDATA_UTILS_H */
index 7ec93c95c7c116064beeebbba381c7414edc8acd..115f8afb45b61a5f9ae4cb6684f9b45c6d22e9bf 100644 (file)
@@ -1151,6 +1151,12 @@ extern Datum show_all_file_settings(PG_FUNCTION_ARGS);
 /* pg_config.c */
 extern Datum pg_config(PG_FUNCTION_ARGS);
 
+/* pg_controldata.c */
+extern Datum pg_control_checkpoint(PG_FUNCTION_ARGS);
+extern Datum pg_control_system(PG_FUNCTION_ARGS);
+extern Datum pg_control_init(PG_FUNCTION_ARGS);
+extern Datum pg_control_recovery(PG_FUNCTION_ARGS);
+
 /* rls.c */
 extern Datum row_security_active(PG_FUNCTION_ARGS);
 extern Datum row_security_active_name(PG_FUNCTION_ARGS);
index e4fb44e63985f121f76ad00e12d0d7a858fed207..949077a797f9bb378aa2321eb5799aa655ebc8a3 100644 (file)
@@ -106,8 +106,8 @@ sub mkvcbuild
        }
 
        our @pgcommonallfiles = qw(
-         config_info.c exec.c pg_lzcompress.c pgfnames.c psprintf.c
-         relpath.c rmtree.c string.c username.c wait_error.c);
+         config_info.c controldata_utils.c exec.c pg_lzcompress.c pgfnames.c
+         psprintf.c relpath.c rmtree.c string.c username.c wait_error.c);
 
        our @pgcommonfrontendfiles = (
                @pgcommonallfiles, qw(fe_memutils.c