Expose control file data via SQL accessible functions.
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.
This commit is contained in:
parent
d34794f7d5
commit
dc7d70ea05
|
@ -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">
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
|
@ -18,14 +18,12 @@
|
|||
|
||||
#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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -53,6 +53,6 @@
|
|||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 201603021
|
||||
#define CATALOG_VERSION_NO 201603051
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue