On 12/23/2015 04:37 PM, Michael Paquier wrote: > On Thu, Dec 24, 2015 at 2:08 AM, Joe Conway <m...@joeconway.com> wrote: >> 2) Change the pg_controldata to be a bunch of separate functions as >> suggested by Josh Berkus rather than one SRF. > > This looks like a plan, thanks!
As discussed, a completely revamped and split off pg_controldata patch. Below are the details for those interested. Comments please. Joe =============== What this patch does: --------------- 1) Change NextXID output format from "%u/%u" to "%u:%u" (see recent hackers thread) 2) Refactor bin/pg_controldata (there should be no visible change to pg_controldata output) 3) Adds new functions, more or less in line with previous discussions: * pg_checkpoint_state() * pg_controldata_state() * pg_recovery_state() * pg_init_state() =============== Missing (TODO once agreement on the above is reached): --------------- a) documentation b) catversion bump c) regression tests =============== New function detail and sample output: --------------- postgres=# \x Expanded display is on. postgres=# \df pg_*_state List of functions -[ RECORD 1 ]-------+---------------------------------------------- Schema | pg_catalog Name | pg_checkpoint_state Result data type | record Argument data types | OUT checkpoint_location pg_lsn, | OUT prior_location pg_lsn, | OUT redo_location pg_lsn, | OUT redo_wal_file text, | OUT timeline_id integer, | OUT prev_timeline_id integer, | OUT full_page_writes boolean, | OUT next_xid text, | OUT next_oid oid, | OUT next_multixact_id xid, | OUT next_multi_offset xid, | OUT oldest_xid xid, | OUT oldest_xid_dbid oid, | OUT oldest_active_xid xid, | OUT oldest_multi_xid xid, | OUT oldest_multi_dbid oid, | OUT oldest_commit_ts_xid xid, | OUT newest_commit_ts_xid xid, | OUT checkpoint_time timestamp with time zone Type | normal -[ RECORD 2 ]-------+---------------------------------------------- Schema | pg_catalog Name | pg_controldata_state Result data type | record Argument data types | OUT pg_control_version integer, | OUT catalog_version_no integer, | OUT system_identifier bigint, | OUT pg_control_last_modified | timestamp with time zone Type | normal -[ RECORD 3 ]-------+---------------------------------------------- Schema | pg_catalog Name | pg_init_state Result data type | record Argument data types | OUT max_data_alignment integer, | OUT database_block_size integer, | OUT blocks_per_segment integer, | OUT wal_block_size integer, | OUT bytes_per_wal_segment integer, | OUT max_identifier_length integer, | OUT max_index_columns integer, | OUT max_toast_chunk_size integer, | OUT large_object_chunk_size integer, | OUT bigint_timestamps boolean, | OUT float4_pass_by_value boolean, | OUT float8_pass_by_value boolean, | OUT data_page_checksum_version integer Type | normal -[ RECORD 4 ]-------+---------------------------------------------- Schema | pg_catalog Name | pg_recovery_state Result data type | record Argument data types | OUT min_recovery_end_location pg_lsn, | OUT min_recovery_end_timeline integer, | OUT backup_start_location pg_lsn, | OUT backup_end_location pg_lsn, | OUT end_of_backup_record_required boolean Type | normal postgres=# select * from pg_controldata_state(); -[ RECORD 1 ]------------+----------------------- pg_control_version | 942 catalog_version_no | 201511071 system_identifier | 6233852631805477166 pg_control_last_modified | 2015-12-29 15:32:09-08 postgres=# select * from pg_checkpoint_state(); -[ RECORD 1 ]--------+------------------------- checkpoint_location | 0/14E8C38 prior_location | 0/14D6340 redo_location | 0/14E8C38 redo_wal_file | 000000010000000000000001 timeline_id | 1 prev_timeline_id | 1 full_page_writes | t next_xid | 0:574 next_oid | 12407 next_multixact_id | 1 next_multi_offset | 0 oldest_xid | 565 oldest_xid_dbid | 1 oldest_active_xid | 0 oldest_multi_xid | 1 oldest_multi_dbid | 1 oldest_commit_ts_xid | 0 newest_commit_ts_xid | 0 checkpoint_time | 2015-12-29 15:32:02-08 postgres=# select * from pg_recovery_state(); -[ RECORD 1 ]-----------------+---- min_recovery_end_location | 0/0 min_recovery_end_timeline | 0 backup_start_location | 0/0 backup_end_location | 0/0 end_of_backup_record_required | f postgres=# select * from pg_init_state(); -[ RECORD 1 ]--------------+--------- max_data_alignment | 8 database_block_size | 8192 blocks_per_segment | 131072 wal_block_size | 8192 bytes_per_wal_segment | 16777216 max_identifier_length | 64 max_index_columns | 32 max_toast_chunk_size | 1996 large_object_chunk_size | 2048 bigint_timestamps | t float4_pass_by_value | t float8_pass_by_value | t data_page_checksum_version | 0 -- Crunchy Data - http://crunchydata.com PostgreSQL Support for Secure Enterprises Consulting, Training, & Open Source Development
diff --git a/src/backend/utils/misc/Makefile b/src/backend/utils/misc/Makefile index 7889101..80b139e 100644 *** a/src/backend/utils/misc/Makefile --- b/src/backend/utils/misc/Makefile *************** include $(top_builddir)/src/Makefile.glo *** 14,21 **** override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS) ! OBJS = guc.o help_config.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 # we can't subsitute it into pg_config.h. --- 14,21 ---- override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS) ! OBJS = guc.o help_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 # we can't subsitute it into pg_config.h. diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c index ...fd00ec7 . *** a/src/backend/utils/misc/pg_controldata.c --- b/src/backend/utils/misc/pg_controldata.c *************** *** 0 **** --- 1,358 ---- + /*------------------------------------------------------------------------- + * + * pg_controldata.c + * Expose select pg_controldata output, except via SQL functions + * + * Portions Copyright (c) 1996-2015, 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" + + extern controldata *ControlData; + + Datum + pg_controldata_state(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); + + if (ControlFile->pg_control_version % 65536 == 0 && + ControlFile->pg_control_version / 65536 != 0) + elog(ERROR, _("byte ordering mismatch")); + + 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_checkpoint_state(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); + + /* Make sure it is valid. */ + if (ControlFile->pg_control_version % 65536 == 0 && + ControlFile->pg_control_version / 65536 != 0) + elog(ERROR, _("byte ordering mismatch")); + + /* + * 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_recovery_state(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); + + if (ControlFile->pg_control_version % 65536 == 0 && + ControlFile->pg_control_version / 65536 != 0) + elog(ERROR, _("byte ordering mismatch")); + + 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_init_state(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); + + if (ControlFile->pg_control_version % 65536 == 0 && + ControlFile->pg_control_version / 65536 != 0) + elog(ERROR, _("byte ordering mismatch")); + + 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)); + } diff --git a/src/bin/pg_controldata/pg_controldata.c b/src/bin/pg_controldata/pg_controldata.c index e7e072f..75ed71b 100644 *** a/src/bin/pg_controldata/pg_controldata.c --- b/src/bin/pg_controldata/pg_controldata.c *************** *** 26,31 **** --- 26,32 ---- #include "access/xlog.h" #include "access/xlog_internal.h" #include "catalog/pg_control.h" + #include "common/controldata_utils.h" #include "pg_getopt.h" *************** usage(const char *progname) *** 45,108 **** } ! static const char * ! dbState(DBState state) ! { ! switch (state) ! { ! case DB_STARTUP: ! return _("starting up"); ! case DB_SHUTDOWNED: ! return _("shut down"); ! case DB_SHUTDOWNED_IN_RECOVERY: ! return _("shut down in recovery"); ! case DB_SHUTDOWNING: ! return _("shutting down"); ! case DB_IN_CRASH_RECOVERY: ! return _("in crash recovery"); ! case DB_IN_ARCHIVE_RECOVERY: ! return _("in archive recovery"); ! case DB_IN_PRODUCTION: ! return _("in production"); ! } ! return _("unrecognized status code"); ! } ! ! static const char * ! wal_level_str(WalLevel wal_level) ! { ! switch (wal_level) ! { ! case WAL_LEVEL_MINIMAL: ! return "minimal"; ! case WAL_LEVEL_ARCHIVE: ! return "archive"; ! case WAL_LEVEL_HOT_STANDBY: ! return "hot_standby"; ! case WAL_LEVEL_LOGICAL: ! return "logical"; ! } ! return _("unrecognized wal_level"); ! } ! ! int main(int argc, char *argv[]) { ! ControlFileData ControlFile; ! int fd; ! char ControlFilePath[MAXPGPATH]; ! char *DataDir = NULL; ! pg_crc32c crc; ! time_t time_tmp; ! char pgctime_str[128]; ! char ckpttime_str[128]; ! char sysident_str[32]; ! const char *strftime_fmt = "%c"; ! const char *progname; ! XLogSegNo segno; ! char xlogfilename[MAXFNAMELEN]; ! int c; set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_controldata")); --- 46,62 ---- } ! #define CONTROLDATANAME_LEN 39 ! #define CONTROLDATANAME_FMT "%-39s%s\n" int main(int argc, char *argv[]) { ! char *DataDir = NULL; ! controldata *ControlData; ! size_t ControlData_len; ! char ControlDataName[CONTROLDATANAME_LEN + 1]; ! const char *progname; ! int c, i; set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_controldata")); *************** main(int argc, char *argv[]) *** 161,338 **** 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")); - - /* - * This slightly-chintzy coding will work as long as the control file - * timestamps are within the range of time_t; that should be the case in - * all foreseeable circumstances, so we don't bother importing the - * backend's timezone library into pg_controldata. - * - * Use variable for format to suppress overly-anal-retentive gcc warning - * about %c - */ - time_tmp = (time_t) ControlFile.time; - strftime(pgctime_str, sizeof(pgctime_str), strftime_fmt, - localtime(&time_tmp)); - time_tmp = (time_t) ControlFile.checkPointCopy.time; - strftime(ckpttime_str, sizeof(ckpttime_str), strftime_fmt, - localtime(&time_tmp)); - - /* - * 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); - - /* - * 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); - 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")); - printf(_("Catalog version number: %u\n"), - ControlFile.catalog_version_no); - printf(_("Database system identifier: %s\n"), - sysident_str); - printf(_("Database cluster state: %s\n"), - 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); - printf(_("Prior checkpoint location: %X/%X\n"), - (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); - printf(_("Latest checkpoint's REDO WAL file: %s\n"), - xlogfilename); - printf(_("Latest checkpoint's TimeLineID: %u\n"), - ControlFile.checkPointCopy.ThisTimeLineID); - printf(_("Latest checkpoint's PrevTimeLineID: %u\n"), - ControlFile.checkPointCopy.PrevTimeLineID); - printf(_("Latest checkpoint's full_page_writes: %s\n"), - ControlFile.checkPointCopy.fullPageWrites ? _("on") : _("off")); - printf(_("Latest checkpoint's NextXID: %u/%u\n"), - ControlFile.checkPointCopy.nextXidEpoch, - ControlFile.checkPointCopy.nextXid); - printf(_("Latest checkpoint's NextOID: %u\n"), - ControlFile.checkPointCopy.nextOid); - printf(_("Latest checkpoint's NextMultiXactId: %u\n"), - ControlFile.checkPointCopy.nextMulti); - printf(_("Latest checkpoint's NextMultiOffset: %u\n"), - ControlFile.checkPointCopy.nextMultiOffset); - printf(_("Latest checkpoint's oldestXID: %u\n"), - ControlFile.checkPointCopy.oldestXid); - printf(_("Latest checkpoint's oldestXID's DB: %u\n"), - ControlFile.checkPointCopy.oldestXidDB); - printf(_("Latest checkpoint's oldestActiveXID: %u\n"), - ControlFile.checkPointCopy.oldestActiveXid); - printf(_("Latest checkpoint's oldestMultiXid: %u\n"), - ControlFile.checkPointCopy.oldestMulti); - printf(_("Latest checkpoint's oldestMulti's DB: %u\n"), - ControlFile.checkPointCopy.oldestMultiDB); - printf(_("Latest checkpoint's oldestCommitTsXid:%u\n"), - ControlFile.checkPointCopy.oldestCommitTsXid); - printf(_("Latest checkpoint's newestCommitTsXid:%u\n"), - 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); - printf(_("Minimum recovery ending location: %X/%X\n"), - (uint32) (ControlFile.minRecoveryPoint >> 32), - (uint32) ControlFile.minRecoveryPoint); - printf(_("Min recovery ending loc's timeline: %u\n"), - ControlFile.minRecoveryPointTLI); - printf(_("Backup start location: %X/%X\n"), - (uint32) (ControlFile.backupStartPoint >> 32), - (uint32) ControlFile.backupStartPoint); - printf(_("Backup end location: %X/%X\n"), - (uint32) (ControlFile.backupEndPoint >> 32), - (uint32) ControlFile.backupEndPoint); - printf(_("End-of-backup record required: %s\n"), - ControlFile.backupEndRequired ? _("yes") : _("no")); - printf(_("wal_level setting: %s\n"), - wal_level_str(ControlFile.wal_level)); - printf(_("wal_log_hints setting: %s\n"), - ControlFile.wal_log_hints ? _("on") : _("off")); - printf(_("max_connections setting: %d\n"), - ControlFile.MaxConnections); - printf(_("max_worker_processes setting: %d\n"), - ControlFile.max_worker_processes); - printf(_("max_prepared_xacts setting: %d\n"), - ControlFile.max_prepared_xacts); - printf(_("max_locks_per_xact setting: %d\n"), - ControlFile.max_locks_per_xact); - printf(_("track_commit_timestamp setting: %s\n"), - ControlFile.track_commit_timestamp ? _("on") : _("off")); - printf(_("Maximum data alignment: %u\n"), - ControlFile.maxAlign); - /* we don't print floatFormat since can't say much useful about it */ - printf(_("Database block size: %u\n"), - ControlFile.blcksz); - printf(_("Blocks per segment of large relation: %u\n"), - ControlFile.relseg_size); - printf(_("WAL block size: %u\n"), - ControlFile.xlog_blcksz); - printf(_("Bytes per WAL segment: %u\n"), - ControlFile.xlog_seg_size); - printf(_("Maximum length of identifiers: %u\n"), - ControlFile.nameDataLen); - printf(_("Maximum columns in an index: %u\n"), - ControlFile.indexMaxKeys); - printf(_("Maximum size of a TOAST chunk: %u\n"), - ControlFile.toast_max_chunk_size); - printf(_("Size of a large-object chunk: %u\n"), - ControlFile.loblksize); - printf(_("Date/time type storage: %s\n"), - (ControlFile.enableIntTimes ? _("64-bit integers") : _("floating-point numbers"))); - printf(_("Float4 argument passing: %s\n"), - (ControlFile.float4ByVal ? _("by value") : _("by reference"))); - printf(_("Float8 argument passing: %s\n"), - (ControlFile.float8ByVal ? _("by value") : _("by reference"))); - printf(_("Data page checksum version: %u\n"), - ControlFile.data_checksum_version); return 0; } --- 115,128 ---- exit(1); } ! ControlData = get_controldata(DataDir, progname, &ControlData_len); ! for (i = 0; i < ControlData_len; i++) { ! memset(ControlDataName, ' ', CONTROLDATANAME_LEN); ! snprintf (ControlDataName, CONTROLDATANAME_LEN, ! "%s:", ControlData[i].name); ! printf(CONTROLDATANAME_FMT, ControlDataName, ControlData[i].setting); } return 0; } diff --git a/src/bin/pg_resetxlog/pg_resetxlog.c b/src/bin/pg_resetxlog/pg_resetxlog.c index f675c92..642ec54 100644 *** a/src/bin/pg_resetxlog/pg_resetxlog.c --- b/src/bin/pg_resetxlog/pg_resetxlog.c *************** PrintControlValues(bool guessed) *** 646,652 **** ControlFile.checkPointCopy.ThisTimeLineID); printf(_("Latest checkpoint's full_page_writes: %s\n"), ControlFile.checkPointCopy.fullPageWrites ? _("on") : _("off")); ! printf(_("Latest checkpoint's NextXID: %u/%u\n"), ControlFile.checkPointCopy.nextXidEpoch, ControlFile.checkPointCopy.nextXid); printf(_("Latest checkpoint's NextOID: %u\n"), --- 646,652 ---- ControlFile.checkPointCopy.ThisTimeLineID); printf(_("Latest checkpoint's full_page_writes: %s\n"), ControlFile.checkPointCopy.fullPageWrites ? _("on") : _("off")); ! printf(_("Latest checkpoint's NextXID: %u:%u\n"), ControlFile.checkPointCopy.nextXidEpoch, ControlFile.checkPointCopy.nextXid); printf(_("Latest checkpoint's NextOID: %u\n"), diff --git a/src/common/Makefile b/src/common/Makefile index c47445e..5d04a6b 100644 *** a/src/common/Makefile --- b/src/common/Makefile *************** include $(top_builddir)/src/Makefile.glo *** 23,30 **** override CPPFLAGS := -DFRONTEND $(CPPFLAGS) LIBS += $(PTHREAD_LIBS) ! OBJS_COMMON = 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 --- 23,30 ---- override CPPFLAGS := -DFRONTEND $(CPPFLAGS) LIBS += $(PTHREAD_LIBS) ! OBJS_COMMON = 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 index ...f7b12c8 . *** a/src/common/controldata_utils.c --- b/src/common/controldata_utils.c *************** *** 0 **** --- 1,378 ---- + /*------------------------------------------------------------------------- + * + * controldata_utils.c + * Common code for pg_controldata output + * + * + * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/common/controldata_utils.c + * + *------------------------------------------------------------------------- + */ + + #include "postgres.h" + + #include <unistd.h> + #include <time.h> + #include <sys/stat.h> + #include <fcntl.h> + + #include "miscadmin.h" + #include "access/xlog.h" + #include "access/xlog_internal.h" + #include "catalog/pg_control.h" + #include "catalog/pg_type.h" + #include "common/controldata_utils.h" + #include "port/pg_crc32c.h" + #include "utils/builtins.h" + + #ifndef FRONTEND + /* NOTE: caller must provide gettext call around str */ + #define log_error(str, param1, param2) \ + elog(ERROR, str, param1, param2) + #else + #define log_error(str, param1, param2) \ + do { \ + char *buf = psprintf("%%s: %s", str); \ + fprintf(stderr, buf, progname, param1, param2); \ + exit(2); \ + } while (0) + #endif + + static const char *dbState(DBState state); + static const char *wal_level_str(WalLevel wal_level); + + static const char *const ControlDataNames[] = + { + gettext_noop("pg_control version number"), + gettext_noop("Catalog version number"), + gettext_noop("Database system identifier"), + gettext_noop("Database cluster state"), + gettext_noop("pg_control last modified"), + gettext_noop("Latest checkpoint location"), + gettext_noop("Prior checkpoint location"), + gettext_noop("Latest checkpoint's REDO location"), + gettext_noop("Latest checkpoint's REDO WAL file"), + gettext_noop("Latest checkpoint's TimeLineID"), + gettext_noop("Latest checkpoint's PrevTimeLineID"), + gettext_noop("Latest checkpoint's full_page_writes"), + gettext_noop("Latest checkpoint's NextXID"), + gettext_noop("Latest checkpoint's NextOID"), + gettext_noop("Latest checkpoint's NextMultiXactId"), + gettext_noop("Latest checkpoint's NextMultiOffset"), + gettext_noop("Latest checkpoint's oldestXID"), + gettext_noop("Latest checkpoint's oldestXID's DB"), + gettext_noop("Latest checkpoint's oldestActiveXID"), + gettext_noop("Latest checkpoint's oldestMultiXid"), + gettext_noop("Latest checkpoint's oldestMulti's DB"), + gettext_noop("Latest checkpoint's oldestCommitTsXid"), + gettext_noop("Latest checkpoint's newestCommitTsXid"), + gettext_noop("Time of latest checkpoint"), + gettext_noop("Fake LSN counter for unlogged rels"), + gettext_noop("Minimum recovery ending location"), + gettext_noop("Min recovery ending loc's timeline"), + gettext_noop("Backup start location"), + gettext_noop("Backup end location"), + gettext_noop("End-of-backup record required"), + gettext_noop("wal_level setting"), + gettext_noop("wal_log_hints setting"), + gettext_noop("max_connections setting"), + gettext_noop("max_worker_processes setting"), + gettext_noop("max_prepared_xacts setting"), + gettext_noop("max_locks_per_xact setting"), + gettext_noop("track_commit_timestamp setting"), + gettext_noop("Maximum data alignment"), + gettext_noop("Database block size"), + gettext_noop("Blocks per segment of large relation"), + gettext_noop("WAL block size"), + gettext_noop("Bytes per WAL segment"), + gettext_noop("Maximum length of identifiers"), + gettext_noop("Maximum columns in an index"), + gettext_noop("Maximum size of a TOAST chunk"), + gettext_noop("Size of a large-object chunk"), + gettext_noop("Date/time type storage"), + gettext_noop("Float4 argument passing"), + gettext_noop("Float8 argument passing"), + gettext_noop("Data page checksum version"), + NULL + }; + + static size_t + ControlDataNames_len(void) + { + size_t i = 0; + + while (ControlDataNames[i]) + i++; + + return i; + } + + + static const char * + dbState(DBState state) + { + switch (state) + { + case DB_STARTUP: + return _("starting up"); + case DB_SHUTDOWNED: + return _("shut down"); + case DB_SHUTDOWNED_IN_RECOVERY: + return _("shut down in recovery"); + case DB_SHUTDOWNING: + return _("shutting down"); + case DB_IN_CRASH_RECOVERY: + return _("in crash recovery"); + case DB_IN_ARCHIVE_RECOVERY: + return _("in archive recovery"); + case DB_IN_PRODUCTION: + return _("in production"); + } + return _("unrecognized status code"); + } + + static const char * + wal_level_str(WalLevel wal_level) + { + switch (wal_level) + { + case WAL_LEVEL_MINIMAL: + return "minimal"; + case WAL_LEVEL_ARCHIVE: + return "archive"; + case WAL_LEVEL_HOT_STANDBY: + return "hot_standby"; + case WAL_LEVEL_LOGICAL: + return "logical"; + } + return _("unrecognized wal_level"); + } + + + 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 + + return ControlFile; + } + + controldata * + get_controldata(char *DataDir, const char *progname, + size_t *controldata_len) + { + ControlFileData *ControlFile; + controldata *ControlData; + time_t time_tmp; + char pgctime_str[128]; + char ckpttime_str[128]; + char sysident_str[32]; + const char *strftime_fmt = "%c"; + XLogSegNo segno; + char xlogfilename[MAXFNAMELEN]; + int i; + int idx = 0; + + *controldata_len = ControlDataNames_len(); + ControlData = palloc(*controldata_len * sizeof(controldata)); + + /* + * initialize controldata names + * + * These better be in sync with the settings manually + * defined below. + */ + for (i = 0; i < *controldata_len; i++) + ControlData[i].name = pstrdup(_(ControlDataNames[i])); + + /* get a copy of the control file */ + ControlFile = get_controlfile(DataDir, progname); + + /* + * This slightly-chintzy coding will work as long as the control file + * timestamps are within the range of time_t; that should be the case in + * all foreseeable circumstances, so we don't bother importing the + * backend's timezone library. + * + * Use variable for format to suppress overly-anal-retentive gcc warning + * about %c + */ + time_tmp = (time_t) ControlFile->time; + strftime(pgctime_str, sizeof(pgctime_str), strftime_fmt, + localtime(&time_tmp)); + time_tmp = (time_t) ControlFile->checkPointCopy.time; + strftime(ckpttime_str, sizeof(ckpttime_str), strftime_fmt, + localtime(&time_tmp)); + + /* + * 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); + + /* + * 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); + + 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 + + ControlData[idx++].setting = psprintf("%u", + ControlFile->pg_control_version); + ControlData[idx++].setting = psprintf("%u", + ControlFile->catalog_version_no); + ControlData[idx++].setting = psprintf("%s", + sysident_str); + ControlData[idx++].setting = psprintf("%s", + dbState(ControlFile->state)); + ControlData[idx++].setting = psprintf("%s", + pgctime_str); + ControlData[idx++].setting = psprintf("%X/%X", + (uint32) (ControlFile->checkPoint >> 32), + (uint32) ControlFile->checkPoint); + ControlData[idx++].setting = psprintf("%X/%X", + (uint32) (ControlFile->prevCheckPoint >> 32), + (uint32) ControlFile->prevCheckPoint); + ControlData[idx++].setting = psprintf("%X/%X", + (uint32) (ControlFile->checkPointCopy.redo >> 32), + (uint32) ControlFile->checkPointCopy.redo); + ControlData[idx++].setting = psprintf("%s", xlogfilename); + ControlData[idx++].setting = psprintf("%u", + ControlFile->checkPointCopy.ThisTimeLineID); + ControlData[idx++].setting = psprintf("%u", + ControlFile->checkPointCopy.PrevTimeLineID); + ControlData[idx++].setting = psprintf("%s", + ControlFile->checkPointCopy.fullPageWrites ? _("on") : _("off")); + ControlData[idx++].setting = psprintf("%u:%u", + ControlFile->checkPointCopy.nextXidEpoch, + ControlFile->checkPointCopy.nextXid); + ControlData[idx++].setting = psprintf("%u", + ControlFile->checkPointCopy.nextOid); + ControlData[idx++].setting = psprintf("%u", + ControlFile->checkPointCopy.nextMulti); + ControlData[idx++].setting = psprintf("%u", + ControlFile->checkPointCopy.nextMultiOffset); + ControlData[idx++].setting = psprintf("%u", + ControlFile->checkPointCopy.oldestXid); + ControlData[idx++].setting = psprintf("%u", + ControlFile->checkPointCopy.oldestXidDB); + ControlData[idx++].setting = psprintf("%u", + ControlFile->checkPointCopy.oldestActiveXid); + ControlData[idx++].setting = psprintf("%u", + ControlFile->checkPointCopy.oldestMulti); + ControlData[idx++].setting = psprintf("%u", + ControlFile->checkPointCopy.oldestMultiDB); + ControlData[idx++].setting = psprintf("%u", + ControlFile->checkPointCopy.oldestCommitTsXid); + ControlData[idx++].setting = psprintf("%u", + ControlFile->checkPointCopy.newestCommitTsXid); + ControlData[idx++].setting = psprintf("%s", ckpttime_str); + ControlData[idx++].setting = psprintf("%X/%X", + (uint32) (ControlFile->unloggedLSN >> 32), + (uint32) ControlFile->unloggedLSN); + ControlData[idx++].setting = psprintf("%X/%X", + (uint32) (ControlFile->minRecoveryPoint >> 32), + (uint32) ControlFile->minRecoveryPoint); + ControlData[idx++].setting = psprintf("%u", + ControlFile->minRecoveryPointTLI); + ControlData[idx++].setting = psprintf("%X/%X", + (uint32) (ControlFile->backupStartPoint >> 32), + (uint32) ControlFile->backupStartPoint); + ControlData[idx++].setting = psprintf("%X/%X", + (uint32) (ControlFile->backupEndPoint >> 32), + (uint32) ControlFile->backupEndPoint); + ControlData[idx++].setting = psprintf("%s", + ControlFile->backupEndRequired ? _("yes") : _("no")); + ControlData[idx++].setting = psprintf("%s", + wal_level_str(ControlFile->wal_level)); + ControlData[idx++].setting = psprintf("%s", + ControlFile->wal_log_hints ? _("on") : _("off")); + ControlData[idx++].setting = psprintf("%d", + ControlFile->MaxConnections); + ControlData[idx++].setting = psprintf("%d", + ControlFile->max_worker_processes); + ControlData[idx++].setting = psprintf("%d", + ControlFile->max_prepared_xacts); + ControlData[idx++].setting = psprintf("%d", + ControlFile->max_locks_per_xact); + ControlData[idx++].setting = psprintf("%s", + ControlFile->track_commit_timestamp ? _("on") : _("off")); + ControlData[idx++].setting = psprintf("%u", + ControlFile->maxAlign); + ControlData[idx++].setting = psprintf("%u", + ControlFile->blcksz); + ControlData[idx++].setting = psprintf("%u", + ControlFile->relseg_size); + ControlData[idx++].setting = psprintf("%u", + ControlFile->xlog_blcksz); + ControlData[idx++].setting = psprintf("%u", + ControlFile->xlog_seg_size); + ControlData[idx++].setting = psprintf("%u", + ControlFile->nameDataLen); + ControlData[idx++].setting = psprintf("%u", + ControlFile->indexMaxKeys); + ControlData[idx++].setting = psprintf("%u", + ControlFile->toast_max_chunk_size); + ControlData[idx++].setting = psprintf("%u", + ControlFile->loblksize); + ControlData[idx++].setting = psprintf("%s", + (ControlFile->enableIntTimes ? + _("64-bit integers") : _("floating-point numbers"))); + ControlData[idx++].setting = psprintf("%s", + (ControlFile->float4ByVal ? _("by value") : _("by reference"))); + ControlData[idx++].setting = psprintf("%s", + (ControlFile->float8ByVal ? _("by value") : _("by reference"))); + ControlData[idx++].setting = psprintf("%u", + ControlFile->data_checksum_version); + + return ControlData; + } diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index d8640db..6923136 100644 *** a/src/include/catalog/pg_proc.h --- b/src/include/catalog/pg_proc.h *************** DESCR("get an individual replication ori *** 5337,5342 **** --- 5337,5355 ---- DATA(insert OID = 6014 ( pg_show_replication_origin_status PGNSP PGUID 12 1 100 0 0 f f f f f t v r 0 0 2249 "" "{26,25,3220,3220}" "{o,o,o,o}" "{local_id, external_id, remote_lsn, local_lsn}" _null_ _null_ pg_show_replication_origin_status _null_ _null_ _null_ )); DESCR("get progress for all replication origins"); + /* pg_controldata related functions */ + DATA(insert OID = 3331 ( pg_controldata_state 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_controldata_state _null_ _null_ _null_ )); + DESCR("pg_controldata general state information as a function"); + + DATA(insert OID = 3332 ( pg_checkpoint_state 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_checkpoint_state _null_ _null_ _null_ )); + DESCR("pg_controldata checkpoint state information as a function"); + + DATA(insert OID = 3333 ( pg_recovery_state 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_recovery_state _null_ _null_ _null_ )); + DESCR("pg_controldata recovery state information as a function"); + + DATA(insert OID = 3334 ( pg_init_state 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_init_state _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 index ...70989ef . *** a/src/include/common/controldata_utils.h --- b/src/include/common/controldata_utils.h *************** *** 0 **** --- 1,23 ---- + /* + * controldata_utils.h + * Common code for pg_controldata output + * + * Portions Copyright (c) 1996-2015, 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 + + typedef struct controldata + { + char *name; + char *setting; + } controldata; + + extern ControlFileData *get_controlfile(char *DataDir, const char *progname); + extern controldata *get_controldata(char *DataDir, const char *progname, + size_t *controldata_len); + + #endif /* COMMON_CONTROLDATA_UTILS_H */ diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index e610bf3..f977279 100644 *** a/src/include/utils/builtins.h --- b/src/include/utils/builtins.h *************** extern Datum set_config_by_name(PG_FUNCT *** 1123,1128 **** --- 1123,1134 ---- extern Datum show_all_settings(PG_FUNCTION_ARGS); extern Datum show_all_file_settings(PG_FUNCTION_ARGS); + /* pg_controldata.c */ + extern Datum pg_controldata_state(PG_FUNCTION_ARGS); + extern Datum pg_checkpoint_state(PG_FUNCTION_ARGS); + extern Datum pg_recovery_state(PG_FUNCTION_ARGS); + extern Datum pg_init_state(PG_FUNCTION_ARGS); + /* rls.c */ extern Datum row_security_active(PG_FUNCTION_ARGS); extern Datum row_security_active_name(PG_FUNCTION_ARGS);
signature.asc
Description: OpenPGP digital signature