diff --git a/doc/xml/release.xml b/doc/xml/release.xml
index ad31a71e7..aca44e5d3 100644
--- a/doc/xml/release.xml
+++ b/doc/xml/release.xml
@@ -57,6 +57,10 @@
Remove redundant documentation from interface files and clarify ambiguous function names.
+
+ Add WAL info to interface.
+
+
Move WAL path prefix logic into walPath()
.
diff --git a/src/postgres/interface.c b/src/postgres/interface.c
index 3e0c449d3..35353a21c 100644
--- a/src/postgres/interface.c
+++ b/src/postgres/interface.c
@@ -43,6 +43,12 @@ really old storage with 512-byte sectors. This is true across all versions of P
#define PG_CONTROL_SIZE ((unsigned int)(8 * 1024))
#define PG_CONTROL_DATA_SIZE ((unsigned int)(512))
+/***********************************************************************************************************************************
+WAL header size. It doesn't seem worth tracking the exact size of the WAL header across versions of PostgreSQL so just set it to
+something far larger needed but <= the minimum read size on just about any system.
+***********************************************************************************************************************************/
+#define PG_WAL_HEADER_SIZE ((unsigned int)(512))
+
/***********************************************************************************************************************************
PostgreSQL interface definitions
@@ -61,9 +67,19 @@ typedef struct PgInterface
// Convert pg_control to a common data structure
PgControl (*control)(const Buffer *);
+ // Does the WAL header match this version of PostgreSQL?
+ bool (*walIs)(const Buffer *);
+
+ // Convert WAL header to a common data structure
+ PgWal (*wal)(const Buffer *);
+
#ifdef DEBUG
+
// Create pg_control for testing
void (*controlTest)(PgControl, Buffer *);
+
+ // Create WAL header for testing
+ void (*walTest)(PgWal, Buffer *);
#endif
} PgInterface;
@@ -75,8 +91,12 @@ static const PgInterface pgInterface[] =
.controlIs = pgInterfaceControlIs110,
.control = pgInterfaceControl110,
+ .walIs = pgInterfaceWalIs110,
+ .wal = pgInterfaceWal110,
+
#ifdef DEBUG
.controlTest = pgInterfaceControlTest110,
+ .walTest = pgInterfaceWalTest110,
#endif
},
{
@@ -85,8 +105,12 @@ static const PgInterface pgInterface[] =
.controlIs = pgInterfaceControlIs100,
.control = pgInterfaceControl100,
+ .walIs = pgInterfaceWalIs100,
+ .wal = pgInterfaceWal100,
+
#ifdef DEBUG
.controlTest = pgInterfaceControlTest100,
+ .walTest = pgInterfaceWalTest100,
#endif
},
{
@@ -95,8 +119,12 @@ static const PgInterface pgInterface[] =
.controlIs = pgInterfaceControlIs096,
.control = pgInterfaceControl096,
+ .walIs = pgInterfaceWalIs096,
+ .wal = pgInterfaceWal096,
+
#ifdef DEBUG
.controlTest = pgInterfaceControlTest096,
+ .walTest = pgInterfaceWalTest096,
#endif
},
{
@@ -105,8 +133,12 @@ static const PgInterface pgInterface[] =
.controlIs = pgInterfaceControlIs095,
.control = pgInterfaceControl095,
+ .walIs = pgInterfaceWalIs095,
+ .wal = pgInterfaceWal095,
+
#ifdef DEBUG
.controlTest = pgInterfaceControlTest095,
+ .walTest = pgInterfaceWalTest095,
#endif
},
{
@@ -115,8 +147,12 @@ static const PgInterface pgInterface[] =
.controlIs = pgInterfaceControlIs094,
.control = pgInterfaceControl094,
+ .walIs = pgInterfaceWalIs094,
+ .wal = pgInterfaceWal094,
+
#ifdef DEBUG
.controlTest = pgInterfaceControlTest094,
+ .walTest = pgInterfaceWalTest094,
#endif
},
{
@@ -125,8 +161,12 @@ static const PgInterface pgInterface[] =
.controlIs = pgInterfaceControlIs093,
.control = pgInterfaceControl093,
+ .walIs = pgInterfaceWalIs093,
+ .wal = pgInterfaceWal093,
+
#ifdef DEBUG
.controlTest = pgInterfaceControlTest093,
+ .walTest = pgInterfaceWalTest093,
#endif
},
{
@@ -135,8 +175,12 @@ static const PgInterface pgInterface[] =
.controlIs = pgInterfaceControlIs092,
.control = pgInterfaceControl092,
+ .walIs = pgInterfaceWalIs092,
+ .wal = pgInterfaceWal092,
+
#ifdef DEBUG
.controlTest = pgInterfaceControlTest092,
+ .walTest = pgInterfaceWalTest092,
#endif
},
{
@@ -145,8 +189,12 @@ static const PgInterface pgInterface[] =
.controlIs = pgInterfaceControlIs091,
.control = pgInterfaceControl091,
+ .walIs = pgInterfaceWalIs091,
+ .wal = pgInterfaceWal091,
+
#ifdef DEBUG
.controlTest = pgInterfaceControlTest091,
+ .walTest = pgInterfaceWalTest091,
#endif
},
{
@@ -155,8 +203,12 @@ static const PgInterface pgInterface[] =
.controlIs = pgInterfaceControlIs090,
.control = pgInterfaceControl090,
+ .walIs = pgInterfaceWalIs090,
+ .wal = pgInterfaceWal090,
+
#ifdef DEBUG
.controlTest = pgInterfaceControlTest090,
+ .walTest = pgInterfaceWalTest090,
#endif
},
{
@@ -165,8 +217,12 @@ static const PgInterface pgInterface[] =
.controlIs = pgInterfaceControlIs084,
.control = pgInterfaceControl084,
+ .walIs = pgInterfaceWalIs084,
+ .wal = pgInterfaceWal084,
+
#ifdef DEBUG
.controlTest = pgInterfaceControlTest084,
+ .walTest = pgInterfaceWalTest084,
#endif
},
{
@@ -175,8 +231,12 @@ static const PgInterface pgInterface[] =
.controlIs = pgInterfaceControlIs083,
.control = pgInterfaceControl083,
+ .walIs = pgInterfaceWalIs083,
+ .wal = pgInterfaceWal083,
+
#ifdef DEBUG
.controlTest = pgInterfaceControlTest083,
+ .walTest = pgInterfaceWalTest083,
#endif
},
};
@@ -275,6 +335,89 @@ pgControlFromFile(const String *pgPath)
FUNCTION_LOG_RETURN(PG_CONTROL, result);
}
+/***********************************************************************************************************************************
+These WAL header fields are common to all versions of PostgreSQL, so we can use them to generate error messages when the WAL magic
+cannot be found.
+***********************************************************************************************************************************/
+typedef struct PgWalCommon
+{
+ uint16_t magic;
+ uint16_t flag;
+} PgWalCommon;
+
+#define PG_WAL_LONG_HEADER 0x0002
+
+/***********************************************************************************************************************************
+Get info from WAL header
+***********************************************************************************************************************************/
+PgWal
+pgWalFromBuffer(const Buffer *walBuffer)
+{
+ FUNCTION_LOG_BEGIN(logLevelTrace);
+ FUNCTION_LOG_PARAM(BUFFER, walBuffer);
+ FUNCTION_LOG_END();
+
+ ASSERT(walBuffer != NULL);
+
+ // Check that this is a long format WAL header
+ if (!(((PgWalCommon *)bufPtr(walBuffer))->flag & PG_WAL_LONG_HEADER))
+ THROW_FMT(FormatError, "first page header in WAL file is expected to be in long format");
+
+ // Search for the version of PostgreSQL that uses this WAL magic
+ const PgInterface *interface = NULL;
+
+ for (unsigned int interfaceIdx = 0; interfaceIdx < sizeof(pgInterface) / sizeof(PgInterface); interfaceIdx++)
+ {
+ if (pgInterface[interfaceIdx].walIs(walBuffer))
+ {
+ interface = &pgInterface[interfaceIdx];
+ break;
+ }
+ }
+
+ // If the version was not found then error with the magic that was found
+ if (interface == NULL)
+ {
+ THROW_FMT(
+ VersionNotSupportedError,
+ "unexpected WAL magic %u\n"
+ "HINT: is this version of PostgreSQL supported?",
+ ((PgWalCommon *)bufPtr(walBuffer))->magic);
+ }
+
+ // Get info from the control file
+ PgWal result = interface->wal(walBuffer);
+ result.version = interface->version;
+
+ FUNCTION_LOG_RETURN(PG_WAL, result);
+}
+
+/***********************************************************************************************************************************
+Get info from a WAL segment
+***********************************************************************************************************************************/
+PgWal
+pgWalFromFile(const String *walFile)
+{
+ FUNCTION_LOG_BEGIN(logLevelDebug);
+ FUNCTION_LOG_PARAM(STRING, walFile);
+ FUNCTION_LOG_END();
+
+ ASSERT(walFile != NULL);
+
+ PgWal result = {0};
+
+ MEM_CONTEXT_TEMP_BEGIN()
+ {
+ // Read WAL segment header
+ Buffer *walBuffer = storageGetP(storageNewReadNP(storageLocal(), walFile), .exactSize = PG_WAL_HEADER_SIZE);
+
+ result = pgWalFromBuffer(walBuffer);
+ }
+ MEM_CONTEXT_TEMP_END();
+
+ FUNCTION_LOG_RETURN(PG_WAL, result);
+}
+
/***********************************************************************************************************************************
Create pg_control for testing
***********************************************************************************************************************************/
@@ -318,6 +461,38 @@ pgControlTestToBuffer(PgControl pgControl)
FUNCTION_TEST_RETURN(result);
}
+void
+pgWalTestToBuffer(PgWal pgWal, Buffer *walBuffer)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(PG_WAL, pgWal);
+ FUNCTION_TEST_PARAM(BUFFER, walBuffer);
+ FUNCTION_TEST_END();
+
+ ASSERT(walBuffer != NULL);
+
+ // Find the interface for the version of PostgreSQL
+ const PgInterface *interface = NULL;
+
+ for (unsigned int interfaceIdx = 0; interfaceIdx < sizeof(pgInterface) / sizeof(PgInterface); interfaceIdx++)
+ {
+ if (pgInterface[interfaceIdx].version == pgWal.version)
+ {
+ interface = &pgInterface[interfaceIdx];
+ break;
+ }
+ }
+
+ // If the version was not found then error
+ if (interface == NULL)
+ THROW_FMT(AssertError, "invalid version %u", pgWal.version);
+
+ // Generate pg_control
+ interface->walTest(pgWal, walBuffer);
+
+ FUNCTION_TEST_RETURN_VOID();
+}
+
#endif
/***********************************************************************************************************************************
@@ -387,3 +562,9 @@ pgControlToLog(const PgControl *pgControl)
"{version: %u, systemId: %" PRIu64 ", walSegmentSize: %u, pageChecksum: %s}", pgControl->version, pgControl->systemId,
pgControl->walSegmentSize, cvtBoolToConstZ(pgControl->pageChecksum));
}
+
+String *
+pgWalToLog(const PgWal *pgWal)
+{
+ return strNewFmt("{version: %u, systemId: %" PRIu64 "}", pgWal->version, pgWal->systemId);
+}
diff --git a/src/postgres/interface.h b/src/postgres/interface.h
index 542de01e6..273ad8ef6 100644
--- a/src/postgres/interface.h
+++ b/src/postgres/interface.h
@@ -33,6 +33,15 @@ typedef struct PgControl
bool pageChecksum;
} PgControl;
+/***********************************************************************************************************************************
+PostgreSQL WAL Info
+***********************************************************************************************************************************/
+typedef struct PgWal
+{
+ unsigned int version;
+ uint64_t systemId;
+} PgWal;
+
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
@@ -41,21 +50,31 @@ PgControl pgControlFromBuffer(const Buffer *controlFile);
unsigned int pgVersionFromStr(const String *version);
String *pgVersionToStr(unsigned int version);
+PgWal pgWalFromFile(const String *walFile);
+PgWal pgWalFromBuffer(const Buffer *walBuffer);
+
/***********************************************************************************************************************************
Test Functions
***********************************************************************************************************************************/
#ifdef DEBUG
Buffer *pgControlTestToBuffer(PgControl pgControl);
+ void pgWalTestToBuffer(PgWal pgWal, Buffer *walBuffer);
#endif
/***********************************************************************************************************************************
Macros for function logging
***********************************************************************************************************************************/
String *pgControlToLog(const PgControl *pgControl);
+String *pgWalToLog(const PgWal *pgWal);
#define FUNCTION_LOG_PG_CONTROL_TYPE \
PgControl
#define FUNCTION_LOG_PG_CONTROL_FORMAT(value, buffer, bufferSize) \
FUNCTION_LOG_STRING_OBJECT_FORMAT(&value, pgControlToLog, buffer, bufferSize)
+#define FUNCTION_LOG_PG_WAL_TYPE \
+ PgWal
+#define FUNCTION_LOG_PG_WAL_FORMAT(value, buffer, bufferSize) \
+ FUNCTION_LOG_STRING_OBJECT_FORMAT(&value, pgWalToLog, buffer, bufferSize)
+
#endif
diff --git a/src/postgres/interface/v083.auto.c b/src/postgres/interface/v083.auto.c
index cbdeff4d1..9ce2d9171 100644
--- a/src/postgres/interface/v083.auto.c
+++ b/src/postgres/interface/v083.auto.c
@@ -6,6 +6,7 @@ PostgreSQL 8.3 Types
Types from src/include/c.h
***********************************************************************************************************************************/
typedef int64_t int64;
+typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
@@ -201,3 +202,35 @@ typedef struct ControlFileData
/* CRC of all above ... MUST BE LAST! */
pg_crc32 crc;
} ControlFileData;
+
+/***********************************************************************************************************************************
+Types from src/include/access/xlog_internal.h
+***********************************************************************************************************************************/
+/*
+ * Each page of XLOG file has a header like this:
+ */
+#define XLOG_PAGE_MAGIC 0xD062 /* can be used as WAL version indicator */
+
+typedef struct XLogPageHeaderData
+{
+ uint16 xlp_magic; /* magic value for correctness checks */
+ uint16 xlp_info; /* flag bits, see below */
+ TimeLineID xlp_tli; /* TimeLineID of first record on page */
+ XLogRecPtr xlp_pageaddr; /* XLOG address of this page */
+} XLogPageHeaderData;
+
+/*
+ * When the XLP_LONG_HEADER flag is set, we store additional fields in the
+ * page header. (This is ordinarily done just in the first page of an
+ * XLOG file.) The additional fields serve to identify the file accurately.
+ */
+typedef struct XLogLongPageHeaderData
+{
+ XLogPageHeaderData std; /* standard header fields */
+ uint64 xlp_sysid; /* system identifier from pg_control */
+ uint32 xlp_seg_size; /* just as a cross-check */
+ uint32 xlp_xlog_blcksz; /* just as a cross-check */
+} XLogLongPageHeaderData;
+
+/* This flag indicates a "long" page header */
+#define XLP_LONG_HEADER 0x0002
diff --git a/src/postgres/interface/v083.c b/src/postgres/interface/v083.c
index 290c06014..a0ca82f5e 100644
--- a/src/postgres/interface/v083.c
+++ b/src/postgres/interface/v083.c
@@ -49,6 +49,37 @@ pgInterfaceControl083(const Buffer *controlFile)
FUNCTION_LOG_RETURN(PG_CONTROL, result);
}
+/**********************************************************************************************************************************/
+bool
+pgInterfaceWalIs083(const Buffer *walFile)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(BUFFER, controlFile);
+ FUNCTION_TEST_END();
+
+ ASSERT(walFile != NULL);
+
+ FUNCTION_TEST_RETURN(((XLogPageHeaderData *)bufPtr(walFile))->xlp_magic == XLOG_PAGE_MAGIC);
+}
+
+/**********************************************************************************************************************************/
+PgWal
+pgInterfaceWal083(const Buffer *walFile)
+{
+ FUNCTION_LOG_BEGIN(logLevelTrace);
+ FUNCTION_LOG_PARAM(BUFFER, walFile);
+ FUNCTION_LOG_END();
+
+ ASSERT(walFile != NULL);
+ ASSERT(pgInterfaceWalIs083(walFile));
+
+ PgWal result = {0};
+
+ result.systemId = ((XLogLongPageHeaderData *)bufPtr(walFile))->xlp_sysid;
+
+ FUNCTION_LOG_RETURN(PG_WAL, result);
+}
+
#ifdef DEBUG
/**********************************************************************************************************************************/
@@ -71,4 +102,20 @@ pgInterfaceControlTest083(PgControl pgControl, Buffer *buffer)
FUNCTION_TEST_RETURN_VOID();
}
+/**********************************************************************************************************************************/
+void
+pgInterfaceWalTest083(PgWal pgWal, Buffer *buffer)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(PG_WAL, pgWal);
+ FUNCTION_TEST_END();
+
+ XLogLongPageHeaderData *walData = (XLogLongPageHeaderData *)bufPtr(buffer);
+
+ walData->std.xlp_magic = XLOG_PAGE_MAGIC;
+ walData->xlp_sysid = pgWal.systemId;
+
+ FUNCTION_TEST_RETURN_VOID();
+}
+
#endif
diff --git a/src/postgres/interface/v083.h b/src/postgres/interface/v083.h
index 471987eaf..fe5d7806c 100644
--- a/src/postgres/interface/v083.h
+++ b/src/postgres/interface/v083.h
@@ -11,12 +11,15 @@ Functions
***********************************************************************************************************************************/
bool pgInterfaceControlIs083(const Buffer *controlFile);
PgControl pgInterfaceControl083(const Buffer *controlFile);
+bool pgInterfaceWalIs083(const Buffer *walFile);
+PgWal pgInterfaceWal083(const Buffer *controlFile);
/***********************************************************************************************************************************
Test Functions
***********************************************************************************************************************************/
#ifdef DEBUG
void pgInterfaceControlTest083(PgControl pgControl, Buffer *buffer);
+ void pgInterfaceWalTest083(PgWal pgWal, Buffer *buffer);
#endif
#endif
diff --git a/src/postgres/interface/v084.auto.c b/src/postgres/interface/v084.auto.c
index 0471b55f2..8f8eccbaf 100644
--- a/src/postgres/interface/v084.auto.c
+++ b/src/postgres/interface/v084.auto.c
@@ -6,6 +6,7 @@ PostgreSQL 8.4 Types
Types from src/include/c.h
***********************************************************************************************************************************/
typedef int64_t int64;
+typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
@@ -206,3 +207,35 @@ typedef struct ControlFileData
/* CRC of all above ... MUST BE LAST! */
pg_crc32 crc;
} ControlFileData;
+
+/***********************************************************************************************************************************
+Types from src/include/access/xlog_internal.h
+***********************************************************************************************************************************/
+/*
+ * Each page of XLOG file has a header like this:
+ */
+#define XLOG_PAGE_MAGIC 0xD063 /* can be used as WAL version indicator */
+
+typedef struct XLogPageHeaderData
+{
+ uint16 xlp_magic; /* magic value for correctness checks */
+ uint16 xlp_info; /* flag bits, see below */
+ TimeLineID xlp_tli; /* TimeLineID of first record on page */
+ XLogRecPtr xlp_pageaddr; /* XLOG address of this page */
+} XLogPageHeaderData;
+
+/*
+ * When the XLP_LONG_HEADER flag is set, we store additional fields in the
+ * page header. (This is ordinarily done just in the first page of an
+ * XLOG file.) The additional fields serve to identify the file accurately.
+ */
+typedef struct XLogLongPageHeaderData
+{
+ XLogPageHeaderData std; /* standard header fields */
+ uint64 xlp_sysid; /* system identifier from pg_control */
+ uint32 xlp_seg_size; /* just as a cross-check */
+ uint32 xlp_xlog_blcksz; /* just as a cross-check */
+} XLogLongPageHeaderData;
+
+/* This flag indicates a "long" page header */
+#define XLP_LONG_HEADER 0x0002
diff --git a/src/postgres/interface/v084.c b/src/postgres/interface/v084.c
index 17c55aac9..2cca4a5f3 100644
--- a/src/postgres/interface/v084.c
+++ b/src/postgres/interface/v084.c
@@ -49,6 +49,37 @@ pgInterfaceControl084(const Buffer *controlFile)
FUNCTION_LOG_RETURN(PG_CONTROL, result);
}
+/**********************************************************************************************************************************/
+bool
+pgInterfaceWalIs084(const Buffer *walFile)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(BUFFER, controlFile);
+ FUNCTION_TEST_END();
+
+ ASSERT(walFile != NULL);
+
+ FUNCTION_TEST_RETURN(((XLogPageHeaderData *)bufPtr(walFile))->xlp_magic == XLOG_PAGE_MAGIC);
+}
+
+/**********************************************************************************************************************************/
+PgWal
+pgInterfaceWal084(const Buffer *walFile)
+{
+ FUNCTION_LOG_BEGIN(logLevelTrace);
+ FUNCTION_LOG_PARAM(BUFFER, walFile);
+ FUNCTION_LOG_END();
+
+ ASSERT(walFile != NULL);
+ ASSERT(pgInterfaceWalIs084(walFile));
+
+ PgWal result = {0};
+
+ result.systemId = ((XLogLongPageHeaderData *)bufPtr(walFile))->xlp_sysid;
+
+ FUNCTION_LOG_RETURN(PG_WAL, result);
+}
+
#ifdef DEBUG
/**********************************************************************************************************************************/
@@ -71,4 +102,20 @@ pgInterfaceControlTest084(PgControl pgControl, Buffer *buffer)
FUNCTION_TEST_RETURN_VOID();
}
+/**********************************************************************************************************************************/
+void
+pgInterfaceWalTest084(PgWal pgWal, Buffer *buffer)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(PG_WAL, pgWal);
+ FUNCTION_TEST_END();
+
+ XLogLongPageHeaderData *walData = (XLogLongPageHeaderData *)bufPtr(buffer);
+
+ walData->std.xlp_magic = XLOG_PAGE_MAGIC;
+ walData->xlp_sysid = pgWal.systemId;
+
+ FUNCTION_TEST_RETURN_VOID();
+}
+
#endif
diff --git a/src/postgres/interface/v084.h b/src/postgres/interface/v084.h
index 24b0c78dc..ceab85176 100644
--- a/src/postgres/interface/v084.h
+++ b/src/postgres/interface/v084.h
@@ -11,12 +11,15 @@ Functions
***********************************************************************************************************************************/
bool pgInterfaceControlIs084(const Buffer *controlFile);
PgControl pgInterfaceControl084(const Buffer *controlFile);
+bool pgInterfaceWalIs084(const Buffer *walFile);
+PgWal pgInterfaceWal084(const Buffer *controlFile);
/***********************************************************************************************************************************
Test Functions
***********************************************************************************************************************************/
#ifdef DEBUG
void pgInterfaceControlTest084(PgControl pgControl, Buffer *buffer);
+ void pgInterfaceWalTest084(PgWal pgWal, Buffer *buffer);
#endif
#endif
diff --git a/src/postgres/interface/v090.auto.c b/src/postgres/interface/v090.auto.c
index ef66c7f78..7eb6d38b4 100644
--- a/src/postgres/interface/v090.auto.c
+++ b/src/postgres/interface/v090.auto.c
@@ -6,6 +6,7 @@ PostgreSQL 9.0 Types
Types from src/include/c.h
***********************************************************************************************************************************/
typedef int64_t int64;
+typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
@@ -250,3 +251,35 @@ typedef struct ControlFileData
/* CRC of all above ... MUST BE LAST! */
pg_crc32 crc;
} ControlFileData;
+
+/***********************************************************************************************************************************
+Types from src/include/access/xlog_internal.h
+***********************************************************************************************************************************/
+/*
+ * Each page of XLOG file has a header like this:
+ */
+#define XLOG_PAGE_MAGIC 0xD064 /* can be used as WAL version indicator */
+
+typedef struct XLogPageHeaderData
+{
+ uint16 xlp_magic; /* magic value for correctness checks */
+ uint16 xlp_info; /* flag bits, see below */
+ TimeLineID xlp_tli; /* TimeLineID of first record on page */
+ XLogRecPtr xlp_pageaddr; /* XLOG address of this page */
+} XLogPageHeaderData;
+
+/*
+ * When the XLP_LONG_HEADER flag is set, we store additional fields in the
+ * page header. (This is ordinarily done just in the first page of an
+ * XLOG file.) The additional fields serve to identify the file accurately.
+ */
+typedef struct XLogLongPageHeaderData
+{
+ XLogPageHeaderData std; /* standard header fields */
+ uint64 xlp_sysid; /* system identifier from pg_control */
+ uint32 xlp_seg_size; /* just as a cross-check */
+ uint32 xlp_xlog_blcksz; /* just as a cross-check */
+} XLogLongPageHeaderData;
+
+/* This flag indicates a "long" page header */
+#define XLP_LONG_HEADER 0x0002
diff --git a/src/postgres/interface/v090.c b/src/postgres/interface/v090.c
index 7ccdef515..162511625 100644
--- a/src/postgres/interface/v090.c
+++ b/src/postgres/interface/v090.c
@@ -49,6 +49,37 @@ pgInterfaceControl090(const Buffer *controlFile)
FUNCTION_LOG_RETURN(PG_CONTROL, result);
}
+/**********************************************************************************************************************************/
+bool
+pgInterfaceWalIs090(const Buffer *walFile)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(BUFFER, controlFile);
+ FUNCTION_TEST_END();
+
+ ASSERT(walFile != NULL);
+
+ FUNCTION_TEST_RETURN(((XLogPageHeaderData *)bufPtr(walFile))->xlp_magic == XLOG_PAGE_MAGIC);
+}
+
+/**********************************************************************************************************************************/
+PgWal
+pgInterfaceWal090(const Buffer *walFile)
+{
+ FUNCTION_LOG_BEGIN(logLevelTrace);
+ FUNCTION_LOG_PARAM(BUFFER, walFile);
+ FUNCTION_LOG_END();
+
+ ASSERT(walFile != NULL);
+ ASSERT(pgInterfaceWalIs090(walFile));
+
+ PgWal result = {0};
+
+ result.systemId = ((XLogLongPageHeaderData *)bufPtr(walFile))->xlp_sysid;
+
+ FUNCTION_LOG_RETURN(PG_WAL, result);
+}
+
#ifdef DEBUG
/**********************************************************************************************************************************/
@@ -71,4 +102,20 @@ pgInterfaceControlTest090(PgControl pgControl, Buffer *buffer)
FUNCTION_TEST_RETURN_VOID();
}
+/**********************************************************************************************************************************/
+void
+pgInterfaceWalTest090(PgWal pgWal, Buffer *buffer)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(PG_WAL, pgWal);
+ FUNCTION_TEST_END();
+
+ XLogLongPageHeaderData *walData = (XLogLongPageHeaderData *)bufPtr(buffer);
+
+ walData->std.xlp_magic = XLOG_PAGE_MAGIC;
+ walData->xlp_sysid = pgWal.systemId;
+
+ FUNCTION_TEST_RETURN_VOID();
+}
+
#endif
diff --git a/src/postgres/interface/v090.h b/src/postgres/interface/v090.h
index 1105daf88..dd6c350a3 100644
--- a/src/postgres/interface/v090.h
+++ b/src/postgres/interface/v090.h
@@ -11,12 +11,15 @@ Functions
***********************************************************************************************************************************/
bool pgInterfaceControlIs090(const Buffer *controlFile);
PgControl pgInterfaceControl090(const Buffer *controlFile);
+bool pgInterfaceWalIs090(const Buffer *walFile);
+PgWal pgInterfaceWal090(const Buffer *controlFile);
/***********************************************************************************************************************************
Test Functions
***********************************************************************************************************************************/
#ifdef DEBUG
void pgInterfaceControlTest090(PgControl pgControl, Buffer *buffer);
+ void pgInterfaceWalTest090(PgWal pgWal, Buffer *buffer);
#endif
#endif
diff --git a/src/postgres/interface/v091.auto.c b/src/postgres/interface/v091.auto.c
index 5929de710..2051fbf72 100644
--- a/src/postgres/interface/v091.auto.c
+++ b/src/postgres/interface/v091.auto.c
@@ -6,6 +6,7 @@ PostgreSQL 9.1 Types
Types from src/include/c.h
***********************************************************************************************************************************/
typedef int64_t int64;
+typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
@@ -250,3 +251,35 @@ typedef struct ControlFileData
/* CRC of all above ... MUST BE LAST! */
pg_crc32 crc;
} ControlFileData;
+
+/***********************************************************************************************************************************
+Types from src/include/access/xlog_internal.h
+***********************************************************************************************************************************/
+/*
+ * Each page of XLOG file has a header like this:
+ */
+#define XLOG_PAGE_MAGIC 0xD066 /* can be used as WAL version indicator */
+
+typedef struct XLogPageHeaderData
+{
+ uint16 xlp_magic; /* magic value for correctness checks */
+ uint16 xlp_info; /* flag bits, see below */
+ TimeLineID xlp_tli; /* TimeLineID of first record on page */
+ XLogRecPtr xlp_pageaddr; /* XLOG address of this page */
+} XLogPageHeaderData;
+
+/*
+ * When the XLP_LONG_HEADER flag is set, we store additional fields in the
+ * page header. (This is ordinarily done just in the first page of an
+ * XLOG file.) The additional fields serve to identify the file accurately.
+ */
+typedef struct XLogLongPageHeaderData
+{
+ XLogPageHeaderData std; /* standard header fields */
+ uint64 xlp_sysid; /* system identifier from pg_control */
+ uint32 xlp_seg_size; /* just as a cross-check */
+ uint32 xlp_xlog_blcksz; /* just as a cross-check */
+} XLogLongPageHeaderData;
+
+/* This flag indicates a "long" page header */
+#define XLP_LONG_HEADER 0x0002
diff --git a/src/postgres/interface/v091.c b/src/postgres/interface/v091.c
index ec1214692..2abb0f6c1 100644
--- a/src/postgres/interface/v091.c
+++ b/src/postgres/interface/v091.c
@@ -49,6 +49,37 @@ pgInterfaceControl091(const Buffer *controlFile)
FUNCTION_LOG_RETURN(PG_CONTROL, result);
}
+/**********************************************************************************************************************************/
+bool
+pgInterfaceWalIs091(const Buffer *walFile)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(BUFFER, controlFile);
+ FUNCTION_TEST_END();
+
+ ASSERT(walFile != NULL);
+
+ FUNCTION_TEST_RETURN(((XLogPageHeaderData *)bufPtr(walFile))->xlp_magic == XLOG_PAGE_MAGIC);
+}
+
+/**********************************************************************************************************************************/
+PgWal
+pgInterfaceWal091(const Buffer *walFile)
+{
+ FUNCTION_LOG_BEGIN(logLevelTrace);
+ FUNCTION_LOG_PARAM(BUFFER, walFile);
+ FUNCTION_LOG_END();
+
+ ASSERT(walFile != NULL);
+ ASSERT(pgInterfaceWalIs091(walFile));
+
+ PgWal result = {0};
+
+ result.systemId = ((XLogLongPageHeaderData *)bufPtr(walFile))->xlp_sysid;
+
+ FUNCTION_LOG_RETURN(PG_WAL, result);
+}
+
#ifdef DEBUG
/**********************************************************************************************************************************/
@@ -71,4 +102,20 @@ pgInterfaceControlTest091(PgControl pgControl, Buffer *buffer)
FUNCTION_TEST_RETURN_VOID();
}
+/**********************************************************************************************************************************/
+void
+pgInterfaceWalTest091(PgWal pgWal, Buffer *buffer)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(PG_WAL, pgWal);
+ FUNCTION_TEST_END();
+
+ XLogLongPageHeaderData *walData = (XLogLongPageHeaderData *)bufPtr(buffer);
+
+ walData->std.xlp_magic = XLOG_PAGE_MAGIC;
+ walData->xlp_sysid = pgWal.systemId;
+
+ FUNCTION_TEST_RETURN_VOID();
+}
+
#endif
diff --git a/src/postgres/interface/v091.h b/src/postgres/interface/v091.h
index 906e436de..add914ddc 100644
--- a/src/postgres/interface/v091.h
+++ b/src/postgres/interface/v091.h
@@ -11,12 +11,15 @@ Functions
***********************************************************************************************************************************/
bool pgInterfaceControlIs091(const Buffer *controlFile);
PgControl pgInterfaceControl091(const Buffer *controlFile);
+bool pgInterfaceWalIs091(const Buffer *walFile);
+PgWal pgInterfaceWal091(const Buffer *controlFile);
/***********************************************************************************************************************************
Test Functions
***********************************************************************************************************************************/
#ifdef DEBUG
void pgInterfaceControlTest091(PgControl pgControl, Buffer *buffer);
+ void pgInterfaceWalTest091(PgWal pgWal, Buffer *buffer);
#endif
#endif
diff --git a/src/postgres/interface/v092.auto.c b/src/postgres/interface/v092.auto.c
index 913fb38c4..e06e6d631 100644
--- a/src/postgres/interface/v092.auto.c
+++ b/src/postgres/interface/v092.auto.c
@@ -6,6 +6,7 @@ PostgreSQL 9.2 Types
Types from src/include/c.h
***********************************************************************************************************************************/
typedef int64_t int64;
+typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
@@ -265,3 +266,35 @@ typedef struct ControlFileData
/* CRC of all above ... MUST BE LAST! */
pg_crc32 crc;
} ControlFileData;
+
+/***********************************************************************************************************************************
+Types from src/include/access/xlog_internal.h
+***********************************************************************************************************************************/
+/*
+ * Each page of XLOG file has a header like this:
+ */
+#define XLOG_PAGE_MAGIC 0xD071 /* can be used as WAL version indicator */
+
+typedef struct XLogPageHeaderData
+{
+ uint16 xlp_magic; /* magic value for correctness checks */
+ uint16 xlp_info; /* flag bits, see below */
+ TimeLineID xlp_tli; /* TimeLineID of first record on page */
+ XLogRecPtr xlp_pageaddr; /* XLOG address of this page */
+} XLogPageHeaderData;
+
+/*
+ * When the XLP_LONG_HEADER flag is set, we store additional fields in the
+ * page header. (This is ordinarily done just in the first page of an
+ * XLOG file.) The additional fields serve to identify the file accurately.
+ */
+typedef struct XLogLongPageHeaderData
+{
+ XLogPageHeaderData std; /* standard header fields */
+ uint64 xlp_sysid; /* system identifier from pg_control */
+ uint32 xlp_seg_size; /* just as a cross-check */
+ uint32 xlp_xlog_blcksz; /* just as a cross-check */
+} XLogLongPageHeaderData;
+
+/* This flag indicates a "long" page header */
+#define XLP_LONG_HEADER 0x0002
diff --git a/src/postgres/interface/v092.c b/src/postgres/interface/v092.c
index e350f6f61..9e57ac452 100644
--- a/src/postgres/interface/v092.c
+++ b/src/postgres/interface/v092.c
@@ -49,6 +49,37 @@ pgInterfaceControl092(const Buffer *controlFile)
FUNCTION_LOG_RETURN(PG_CONTROL, result);
}
+/**********************************************************************************************************************************/
+bool
+pgInterfaceWalIs092(const Buffer *walFile)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(BUFFER, controlFile);
+ FUNCTION_TEST_END();
+
+ ASSERT(walFile != NULL);
+
+ FUNCTION_TEST_RETURN(((XLogPageHeaderData *)bufPtr(walFile))->xlp_magic == XLOG_PAGE_MAGIC);
+}
+
+/**********************************************************************************************************************************/
+PgWal
+pgInterfaceWal092(const Buffer *walFile)
+{
+ FUNCTION_LOG_BEGIN(logLevelTrace);
+ FUNCTION_LOG_PARAM(BUFFER, walFile);
+ FUNCTION_LOG_END();
+
+ ASSERT(walFile != NULL);
+ ASSERT(pgInterfaceWalIs092(walFile));
+
+ PgWal result = {0};
+
+ result.systemId = ((XLogLongPageHeaderData *)bufPtr(walFile))->xlp_sysid;
+
+ FUNCTION_LOG_RETURN(PG_WAL, result);
+}
+
#ifdef DEBUG
/**********************************************************************************************************************************/
@@ -71,4 +102,20 @@ pgInterfaceControlTest092(PgControl pgControl, Buffer *buffer)
FUNCTION_TEST_RETURN_VOID();
}
+/**********************************************************************************************************************************/
+void
+pgInterfaceWalTest092(PgWal pgWal, Buffer *buffer)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(PG_WAL, pgWal);
+ FUNCTION_TEST_END();
+
+ XLogLongPageHeaderData *walData = (XLogLongPageHeaderData *)bufPtr(buffer);
+
+ walData->std.xlp_magic = XLOG_PAGE_MAGIC;
+ walData->xlp_sysid = pgWal.systemId;
+
+ FUNCTION_TEST_RETURN_VOID();
+}
+
#endif
diff --git a/src/postgres/interface/v092.h b/src/postgres/interface/v092.h
index fc6a00848..63aad6f4a 100644
--- a/src/postgres/interface/v092.h
+++ b/src/postgres/interface/v092.h
@@ -11,12 +11,15 @@ Functions
***********************************************************************************************************************************/
bool pgInterfaceControlIs092(const Buffer *controlFile);
PgControl pgInterfaceControl092(const Buffer *controlFile);
+bool pgInterfaceWalIs092(const Buffer *walFile);
+PgWal pgInterfaceWal092(const Buffer *controlFile);
/***********************************************************************************************************************************
Test Functions
***********************************************************************************************************************************/
#ifdef DEBUG
void pgInterfaceControlTest092(PgControl pgControl, Buffer *buffer);
+ void pgInterfaceWalTest092(PgWal pgWal, Buffer *buffer);
#endif
#endif
diff --git a/src/postgres/interface/v093.auto.c b/src/postgres/interface/v093.auto.c
index 924c9ff4f..fb5a4841f 100644
--- a/src/postgres/interface/v093.auto.c
+++ b/src/postgres/interface/v093.auto.c
@@ -6,6 +6,7 @@ PostgreSQL 9.3 Types
Types from src/include/c.h
***********************************************************************************************************************************/
typedef int64_t int64;
+typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
@@ -260,3 +261,46 @@ typedef struct ControlFileData
/* CRC of all above ... MUST BE LAST! */
pg_crc32 crc;
} ControlFileData;
+
+/***********************************************************************************************************************************
+Types from src/include/access/xlog_internal.h
+***********************************************************************************************************************************/
+/*
+ * Each page of XLOG file has a header like this:
+ */
+#define XLOG_PAGE_MAGIC 0xD075 /* can be used as WAL version indicator */
+
+typedef struct XLogPageHeaderData
+{
+ uint16 xlp_magic; /* magic value for correctness checks */
+ uint16 xlp_info; /* flag bits, see below */
+ TimeLineID xlp_tli; /* TimeLineID of first record on page */
+ XLogRecPtr xlp_pageaddr; /* XLOG address of this page */
+
+ /*
+ * When there is not enough space on current page for whole record, we
+ * continue on the next page. xlp_rem_len is the number of bytes
+ * remaining from a previous page.
+ *
+ * Note that xl_rem_len includes backup-block data; that is, it tracks
+ * xl_tot_len not xl_len in the initial header. Also note that the
+ * continuation data isn't necessarily aligned.
+ */
+ uint32 xlp_rem_len; /* total len of remaining data for record */
+} XLogPageHeaderData;
+
+/*
+ * When the XLP_LONG_HEADER flag is set, we store additional fields in the
+ * page header. (This is ordinarily done just in the first page of an
+ * XLOG file.) The additional fields serve to identify the file accurately.
+ */
+typedef struct XLogLongPageHeaderData
+{
+ XLogPageHeaderData std; /* standard header fields */
+ uint64 xlp_sysid; /* system identifier from pg_control */
+ uint32 xlp_seg_size; /* just as a cross-check */
+ uint32 xlp_xlog_blcksz; /* just as a cross-check */
+} XLogLongPageHeaderData;
+
+/* This flag indicates a "long" page header */
+#define XLP_LONG_HEADER 0x0002
diff --git a/src/postgres/interface/v093.c b/src/postgres/interface/v093.c
index c72619178..34b6aca08 100644
--- a/src/postgres/interface/v093.c
+++ b/src/postgres/interface/v093.c
@@ -51,6 +51,37 @@ pgInterfaceControl093(const Buffer *controlFile)
FUNCTION_LOG_RETURN(PG_CONTROL, result);
}
+/**********************************************************************************************************************************/
+bool
+pgInterfaceWalIs093(const Buffer *walFile)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(BUFFER, controlFile);
+ FUNCTION_TEST_END();
+
+ ASSERT(walFile != NULL);
+
+ FUNCTION_TEST_RETURN(((XLogPageHeaderData *)bufPtr(walFile))->xlp_magic == XLOG_PAGE_MAGIC);
+}
+
+/**********************************************************************************************************************************/
+PgWal
+pgInterfaceWal093(const Buffer *walFile)
+{
+ FUNCTION_LOG_BEGIN(logLevelTrace);
+ FUNCTION_LOG_PARAM(BUFFER, walFile);
+ FUNCTION_LOG_END();
+
+ ASSERT(walFile != NULL);
+ ASSERT(pgInterfaceWalIs093(walFile));
+
+ PgWal result = {0};
+
+ result.systemId = ((XLogLongPageHeaderData *)bufPtr(walFile))->xlp_sysid;
+
+ FUNCTION_LOG_RETURN(PG_WAL, result);
+}
+
#ifdef DEBUG
/**********************************************************************************************************************************/
@@ -75,4 +106,20 @@ pgInterfaceControlTest093(PgControl pgControl, Buffer *buffer)
FUNCTION_TEST_RETURN_VOID();
}
+/**********************************************************************************************************************************/
+void
+pgInterfaceWalTest093(PgWal pgWal, Buffer *buffer)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(PG_WAL, pgWal);
+ FUNCTION_TEST_END();
+
+ XLogLongPageHeaderData *walData = (XLogLongPageHeaderData *)bufPtr(buffer);
+
+ walData->std.xlp_magic = XLOG_PAGE_MAGIC;
+ walData->xlp_sysid = pgWal.systemId;
+
+ FUNCTION_TEST_RETURN_VOID();
+}
+
#endif
diff --git a/src/postgres/interface/v093.h b/src/postgres/interface/v093.h
index 8a6443545..b4d7bcce6 100644
--- a/src/postgres/interface/v093.h
+++ b/src/postgres/interface/v093.h
@@ -11,12 +11,15 @@ Functions
***********************************************************************************************************************************/
bool pgInterfaceControlIs093(const Buffer *controlFile);
PgControl pgInterfaceControl093(const Buffer *controlFile);
+bool pgInterfaceWalIs093(const Buffer *walFile);
+PgWal pgInterfaceWal093(const Buffer *controlFile);
/***********************************************************************************************************************************
Test Functions
***********************************************************************************************************************************/
#ifdef DEBUG
void pgInterfaceControlTest093(PgControl pgControl, Buffer *buffer);
+ void pgInterfaceWalTest093(PgWal pgWal, Buffer *buffer);
#endif
#endif
diff --git a/src/postgres/interface/v094.auto.c b/src/postgres/interface/v094.auto.c
index a50905df1..159575207 100644
--- a/src/postgres/interface/v094.auto.c
+++ b/src/postgres/interface/v094.auto.c
@@ -6,6 +6,7 @@ PostgreSQL 9.4 Types
Types from src/include/c.h
***********************************************************************************************************************************/
typedef int64_t int64;
+typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
@@ -263,3 +264,46 @@ typedef struct ControlFileData
/* CRC of all above ... MUST BE LAST! */
pg_crc32 crc;
} ControlFileData;
+
+/***********************************************************************************************************************************
+Types from src/include/access/xlog_internal.h
+***********************************************************************************************************************************/
+/*
+ * Each page of XLOG file has a header like this:
+ */
+#define XLOG_PAGE_MAGIC 0xD07E /* can be used as WAL version indicator */
+
+typedef struct XLogPageHeaderData
+{
+ uint16 xlp_magic; /* magic value for correctness checks */
+ uint16 xlp_info; /* flag bits, see below */
+ TimeLineID xlp_tli; /* TimeLineID of first record on page */
+ XLogRecPtr xlp_pageaddr; /* XLOG address of this page */
+
+ /*
+ * When there is not enough space on current page for whole record, we
+ * continue on the next page. xlp_rem_len is the number of bytes
+ * remaining from a previous page.
+ *
+ * Note that xl_rem_len includes backup-block data; that is, it tracks
+ * xl_tot_len not xl_len in the initial header. Also note that the
+ * continuation data isn't necessarily aligned.
+ */
+ uint32 xlp_rem_len; /* total len of remaining data for record */
+} XLogPageHeaderData;
+
+/*
+ * When the XLP_LONG_HEADER flag is set, we store additional fields in the
+ * page header. (This is ordinarily done just in the first page of an
+ * XLOG file.) The additional fields serve to identify the file accurately.
+ */
+typedef struct XLogLongPageHeaderData
+{
+ XLogPageHeaderData std; /* standard header fields */
+ uint64 xlp_sysid; /* system identifier from pg_control */
+ uint32 xlp_seg_size; /* just as a cross-check */
+ uint32 xlp_xlog_blcksz; /* just as a cross-check */
+} XLogLongPageHeaderData;
+
+/* This flag indicates a "long" page header */
+#define XLP_LONG_HEADER 0x0002
diff --git a/src/postgres/interface/v094.c b/src/postgres/interface/v094.c
index a510f0748..fc65ab740 100644
--- a/src/postgres/interface/v094.c
+++ b/src/postgres/interface/v094.c
@@ -51,6 +51,37 @@ pgInterfaceControl094(const Buffer *controlFile)
FUNCTION_LOG_RETURN(PG_CONTROL, result);
}
+/**********************************************************************************************************************************/
+bool
+pgInterfaceWalIs094(const Buffer *walFile)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(BUFFER, controlFile);
+ FUNCTION_TEST_END();
+
+ ASSERT(walFile != NULL);
+
+ FUNCTION_TEST_RETURN(((XLogPageHeaderData *)bufPtr(walFile))->xlp_magic == XLOG_PAGE_MAGIC);
+}
+
+/**********************************************************************************************************************************/
+PgWal
+pgInterfaceWal094(const Buffer *walFile)
+{
+ FUNCTION_LOG_BEGIN(logLevelTrace);
+ FUNCTION_LOG_PARAM(BUFFER, walFile);
+ FUNCTION_LOG_END();
+
+ ASSERT(walFile != NULL);
+ ASSERT(pgInterfaceWalIs094(walFile));
+
+ PgWal result = {0};
+
+ result.systemId = ((XLogLongPageHeaderData *)bufPtr(walFile))->xlp_sysid;
+
+ FUNCTION_LOG_RETURN(PG_WAL, result);
+}
+
#ifdef DEBUG
/**********************************************************************************************************************************/
@@ -75,4 +106,20 @@ pgInterfaceControlTest094(PgControl pgControl, Buffer *buffer)
FUNCTION_TEST_RETURN_VOID();
}
+/**********************************************************************************************************************************/
+void
+pgInterfaceWalTest094(PgWal pgWal, Buffer *buffer)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(PG_WAL, pgWal);
+ FUNCTION_TEST_END();
+
+ XLogLongPageHeaderData *walData = (XLogLongPageHeaderData *)bufPtr(buffer);
+
+ walData->std.xlp_magic = XLOG_PAGE_MAGIC;
+ walData->xlp_sysid = pgWal.systemId;
+
+ FUNCTION_TEST_RETURN_VOID();
+}
+
#endif
diff --git a/src/postgres/interface/v094.h b/src/postgres/interface/v094.h
index f5645879c..055f9d460 100644
--- a/src/postgres/interface/v094.h
+++ b/src/postgres/interface/v094.h
@@ -11,12 +11,15 @@ Functions
***********************************************************************************************************************************/
bool pgInterfaceControlIs094(const Buffer *controlFile);
PgControl pgInterfaceControl094(const Buffer *controlFile);
+bool pgInterfaceWalIs094(const Buffer *walFile);
+PgWal pgInterfaceWal094(const Buffer *controlFile);
/***********************************************************************************************************************************
Test Functions
***********************************************************************************************************************************/
#ifdef DEBUG
void pgInterfaceControlTest094(PgControl pgControl, Buffer *buffer);
+ void pgInterfaceWalTest094(PgWal pgWal, Buffer *buffer);
#endif
#endif
diff --git a/src/postgres/interface/v095.auto.c b/src/postgres/interface/v095.auto.c
index 0ca268ce6..935ffbe1a 100644
--- a/src/postgres/interface/v095.auto.c
+++ b/src/postgres/interface/v095.auto.c
@@ -6,6 +6,7 @@ PostgreSQL 9.5 Types
Types from src/include/c.h
***********************************************************************************************************************************/
typedef int64_t int64;
+typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
@@ -268,3 +269,46 @@ typedef struct ControlFileData
/* CRC of all above ... MUST BE LAST! */
pg_crc32c crc;
} ControlFileData;
+
+/***********************************************************************************************************************************
+Types from src/include/access/xlog_internal.h
+***********************************************************************************************************************************/
+/*
+ * Each page of XLOG file has a header like this:
+ */
+#define XLOG_PAGE_MAGIC 0xD087 /* can be used as WAL version indicator */
+
+typedef struct XLogPageHeaderData
+{
+ uint16 xlp_magic; /* magic value for correctness checks */
+ uint16 xlp_info; /* flag bits, see below */
+ TimeLineID xlp_tli; /* TimeLineID of first record on page */
+ XLogRecPtr xlp_pageaddr; /* XLOG address of this page */
+
+ /*
+ * When there is not enough space on current page for whole record, we
+ * continue on the next page. xlp_rem_len is the number of bytes
+ * remaining from a previous page.
+ *
+ * Note that xl_rem_len includes backup-block data; that is, it tracks
+ * xl_tot_len not xl_len in the initial header. Also note that the
+ * continuation data isn't necessarily aligned.
+ */
+ uint32 xlp_rem_len; /* total len of remaining data for record */
+} XLogPageHeaderData;
+
+/*
+ * When the XLP_LONG_HEADER flag is set, we store additional fields in the
+ * page header. (This is ordinarily done just in the first page of an
+ * XLOG file.) The additional fields serve to identify the file accurately.
+ */
+typedef struct XLogLongPageHeaderData
+{
+ XLogPageHeaderData std; /* standard header fields */
+ uint64 xlp_sysid; /* system identifier from pg_control */
+ uint32 xlp_seg_size; /* just as a cross-check */
+ uint32 xlp_xlog_blcksz; /* just as a cross-check */
+} XLogLongPageHeaderData;
+
+/* This flag indicates a "long" page header */
+#define XLP_LONG_HEADER 0x0002
diff --git a/src/postgres/interface/v095.c b/src/postgres/interface/v095.c
index 558b60f25..341907dcc 100644
--- a/src/postgres/interface/v095.c
+++ b/src/postgres/interface/v095.c
@@ -51,6 +51,37 @@ pgInterfaceControl095(const Buffer *controlFile)
FUNCTION_LOG_RETURN(PG_CONTROL, result);
}
+/**********************************************************************************************************************************/
+bool
+pgInterfaceWalIs095(const Buffer *walFile)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(BUFFER, controlFile);
+ FUNCTION_TEST_END();
+
+ ASSERT(walFile != NULL);
+
+ FUNCTION_TEST_RETURN(((XLogPageHeaderData *)bufPtr(walFile))->xlp_magic == XLOG_PAGE_MAGIC);
+}
+
+/**********************************************************************************************************************************/
+PgWal
+pgInterfaceWal095(const Buffer *walFile)
+{
+ FUNCTION_LOG_BEGIN(logLevelTrace);
+ FUNCTION_LOG_PARAM(BUFFER, walFile);
+ FUNCTION_LOG_END();
+
+ ASSERT(walFile != NULL);
+ ASSERT(pgInterfaceWalIs095(walFile));
+
+ PgWal result = {0};
+
+ result.systemId = ((XLogLongPageHeaderData *)bufPtr(walFile))->xlp_sysid;
+
+ FUNCTION_LOG_RETURN(PG_WAL, result);
+}
+
#ifdef DEBUG
/**********************************************************************************************************************************/
@@ -75,4 +106,20 @@ pgInterfaceControlTest095(PgControl pgControl, Buffer *buffer)
FUNCTION_TEST_RETURN_VOID();
}
+/**********************************************************************************************************************************/
+void
+pgInterfaceWalTest095(PgWal pgWal, Buffer *buffer)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(PG_WAL, pgWal);
+ FUNCTION_TEST_END();
+
+ XLogLongPageHeaderData *walData = (XLogLongPageHeaderData *)bufPtr(buffer);
+
+ walData->std.xlp_magic = XLOG_PAGE_MAGIC;
+ walData->xlp_sysid = pgWal.systemId;
+
+ FUNCTION_TEST_RETURN_VOID();
+}
+
#endif
diff --git a/src/postgres/interface/v095.h b/src/postgres/interface/v095.h
index 6d9006028..e1a610c07 100644
--- a/src/postgres/interface/v095.h
+++ b/src/postgres/interface/v095.h
@@ -11,12 +11,15 @@ Functions
***********************************************************************************************************************************/
bool pgInterfaceControlIs095(const Buffer *controlFile);
PgControl pgInterfaceControl095(const Buffer *controlFile);
+bool pgInterfaceWalIs095(const Buffer *walFile);
+PgWal pgInterfaceWal095(const Buffer *controlFile);
/***********************************************************************************************************************************
Test Functions
***********************************************************************************************************************************/
#ifdef DEBUG
void pgInterfaceControlTest095(PgControl pgControl, Buffer *buffer);
+ void pgInterfaceWalTest095(PgWal pgWal, Buffer *buffer);
#endif
#endif
diff --git a/src/postgres/interface/v096.auto.c b/src/postgres/interface/v096.auto.c
index 2439e8145..0b93cf87d 100644
--- a/src/postgres/interface/v096.auto.c
+++ b/src/postgres/interface/v096.auto.c
@@ -6,6 +6,7 @@ PostgreSQL 9.6 Types
Types from src/include/c.h
***********************************************************************************************************************************/
typedef int64_t int64;
+typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
@@ -268,3 +269,46 @@ typedef struct ControlFileData
/* CRC of all above ... MUST BE LAST! */
pg_crc32c crc;
} ControlFileData;
+
+/***********************************************************************************************************************************
+Types from src/include/access/xlog_internal.h
+***********************************************************************************************************************************/
+/*
+ * Each page of XLOG file has a header like this:
+ */
+#define XLOG_PAGE_MAGIC 0xD093 /* can be used as WAL version indicator */
+
+typedef struct XLogPageHeaderData
+{
+ uint16 xlp_magic; /* magic value for correctness checks */
+ uint16 xlp_info; /* flag bits, see below */
+ TimeLineID xlp_tli; /* TimeLineID of first record on page */
+ XLogRecPtr xlp_pageaddr; /* XLOG address of this page */
+
+ /*
+ * When there is not enough space on current page for whole record, we
+ * continue on the next page. xlp_rem_len is the number of bytes
+ * remaining from a previous page.
+ *
+ * Note that xl_rem_len includes backup-block data; that is, it tracks
+ * xl_tot_len not xl_len in the initial header. Also note that the
+ * continuation data isn't necessarily aligned.
+ */
+ uint32 xlp_rem_len; /* total len of remaining data for record */
+} XLogPageHeaderData;
+
+/*
+ * When the XLP_LONG_HEADER flag is set, we store additional fields in the
+ * page header. (This is ordinarily done just in the first page of an
+ * XLOG file.) The additional fields serve to identify the file accurately.
+ */
+typedef struct XLogLongPageHeaderData
+{
+ XLogPageHeaderData std; /* standard header fields */
+ uint64 xlp_sysid; /* system identifier from pg_control */
+ uint32 xlp_seg_size; /* just as a cross-check */
+ uint32 xlp_xlog_blcksz; /* just as a cross-check */
+} XLogLongPageHeaderData;
+
+/* This flag indicates a "long" page header */
+#define XLP_LONG_HEADER 0x0002
diff --git a/src/postgres/interface/v096.c b/src/postgres/interface/v096.c
index 06dc342d5..9d6365deb 100644
--- a/src/postgres/interface/v096.c
+++ b/src/postgres/interface/v096.c
@@ -51,6 +51,37 @@ pgInterfaceControl096(const Buffer *controlFile)
FUNCTION_LOG_RETURN(PG_CONTROL, result);
}
+/**********************************************************************************************************************************/
+bool
+pgInterfaceWalIs096(const Buffer *walFile)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(BUFFER, controlFile);
+ FUNCTION_TEST_END();
+
+ ASSERT(walFile != NULL);
+
+ FUNCTION_TEST_RETURN(((XLogPageHeaderData *)bufPtr(walFile))->xlp_magic == XLOG_PAGE_MAGIC);
+}
+
+/**********************************************************************************************************************************/
+PgWal
+pgInterfaceWal096(const Buffer *walFile)
+{
+ FUNCTION_LOG_BEGIN(logLevelTrace);
+ FUNCTION_LOG_PARAM(BUFFER, walFile);
+ FUNCTION_LOG_END();
+
+ ASSERT(walFile != NULL);
+ ASSERT(pgInterfaceWalIs096(walFile));
+
+ PgWal result = {0};
+
+ result.systemId = ((XLogLongPageHeaderData *)bufPtr(walFile))->xlp_sysid;
+
+ FUNCTION_LOG_RETURN(PG_WAL, result);
+}
+
#ifdef DEBUG
/**********************************************************************************************************************************/
@@ -75,4 +106,20 @@ pgInterfaceControlTest096(PgControl pgControl, Buffer *buffer)
FUNCTION_TEST_RETURN_VOID();
}
+/**********************************************************************************************************************************/
+void
+pgInterfaceWalTest096(PgWal pgWal, Buffer *buffer)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(PG_WAL, pgWal);
+ FUNCTION_TEST_END();
+
+ XLogLongPageHeaderData *walData = (XLogLongPageHeaderData *)bufPtr(buffer);
+
+ walData->std.xlp_magic = XLOG_PAGE_MAGIC;
+ walData->xlp_sysid = pgWal.systemId;
+
+ FUNCTION_TEST_RETURN_VOID();
+}
+
#endif
diff --git a/src/postgres/interface/v096.h b/src/postgres/interface/v096.h
index 15724969a..77d079aef 100644
--- a/src/postgres/interface/v096.h
+++ b/src/postgres/interface/v096.h
@@ -11,12 +11,15 @@ Functions
***********************************************************************************************************************************/
bool pgInterfaceControlIs096(const Buffer *controlFile);
PgControl pgInterfaceControl096(const Buffer *controlFile);
+bool pgInterfaceWalIs096(const Buffer *walFile);
+PgWal pgInterfaceWal096(const Buffer *controlFile);
/***********************************************************************************************************************************
Test Functions
***********************************************************************************************************************************/
#ifdef DEBUG
void pgInterfaceControlTest096(PgControl pgControl, Buffer *buffer);
+ void pgInterfaceWalTest096(PgWal pgWal, Buffer *buffer);
#endif
#endif
diff --git a/src/postgres/interface/v100.auto.c b/src/postgres/interface/v100.auto.c
index 9202e5637..07308ee46 100644
--- a/src/postgres/interface/v100.auto.c
+++ b/src/postgres/interface/v100.auto.c
@@ -6,6 +6,7 @@ PostgreSQL 10 Types
Types from src/include/c.h
***********************************************************************************************************************************/
typedef int64_t int64;
+typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
@@ -271,3 +272,46 @@ typedef struct ControlFileData
/* CRC of all above ... MUST BE LAST! */
pg_crc32c crc;
} ControlFileData;
+
+/***********************************************************************************************************************************
+Types from src/include/access/xlog_internal.h
+***********************************************************************************************************************************/
+/*
+ * Each page of XLOG file has a header like this:
+ */
+#define XLOG_PAGE_MAGIC 0xD097 /* can be used as WAL version indicator */
+
+typedef struct XLogPageHeaderData
+{
+ uint16 xlp_magic; /* magic value for correctness checks */
+ uint16 xlp_info; /* flag bits, see below */
+ TimeLineID xlp_tli; /* TimeLineID of first record on page */
+ XLogRecPtr xlp_pageaddr; /* XLOG address of this page */
+
+ /*
+ * When there is not enough space on current page for whole record, we
+ * continue on the next page. xlp_rem_len is the number of bytes
+ * remaining from a previous page.
+ *
+ * Note that xl_rem_len includes backup-block data; that is, it tracks
+ * xl_tot_len not xl_len in the initial header. Also note that the
+ * continuation data isn't necessarily aligned.
+ */
+ uint32 xlp_rem_len; /* total len of remaining data for record */
+} XLogPageHeaderData;
+
+/*
+ * When the XLP_LONG_HEADER flag is set, we store additional fields in the
+ * page header. (This is ordinarily done just in the first page of an
+ * XLOG file.) The additional fields serve to identify the file accurately.
+ */
+typedef struct XLogLongPageHeaderData
+{
+ XLogPageHeaderData std; /* standard header fields */
+ uint64 xlp_sysid; /* system identifier from pg_control */
+ uint32 xlp_seg_size; /* just as a cross-check */
+ uint32 xlp_xlog_blcksz; /* just as a cross-check */
+} XLogLongPageHeaderData;
+
+/* This flag indicates a "long" page header */
+#define XLP_LONG_HEADER 0x0002
diff --git a/src/postgres/interface/v100.c b/src/postgres/interface/v100.c
index dd7fb6c86..8aefbe5e7 100644
--- a/src/postgres/interface/v100.c
+++ b/src/postgres/interface/v100.c
@@ -51,6 +51,37 @@ pgInterfaceControl100(const Buffer *controlFile)
FUNCTION_LOG_RETURN(PG_CONTROL, result);
}
+/**********************************************************************************************************************************/
+bool
+pgInterfaceWalIs100(const Buffer *walFile)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(BUFFER, controlFile);
+ FUNCTION_TEST_END();
+
+ ASSERT(walFile != NULL);
+
+ FUNCTION_TEST_RETURN(((XLogPageHeaderData *)bufPtr(walFile))->xlp_magic == XLOG_PAGE_MAGIC);
+}
+
+/**********************************************************************************************************************************/
+PgWal
+pgInterfaceWal100(const Buffer *walFile)
+{
+ FUNCTION_LOG_BEGIN(logLevelTrace);
+ FUNCTION_LOG_PARAM(BUFFER, walFile);
+ FUNCTION_LOG_END();
+
+ ASSERT(walFile != NULL);
+ ASSERT(pgInterfaceWalIs100(walFile));
+
+ PgWal result = {0};
+
+ result.systemId = ((XLogLongPageHeaderData *)bufPtr(walFile))->xlp_sysid;
+
+ FUNCTION_LOG_RETURN(PG_WAL, result);
+}
+
#ifdef DEBUG
/**********************************************************************************************************************************/
@@ -75,4 +106,20 @@ pgInterfaceControlTest100(PgControl pgControl, Buffer *buffer)
FUNCTION_TEST_RETURN_VOID();
}
+/**********************************************************************************************************************************/
+void
+pgInterfaceWalTest100(PgWal pgWal, Buffer *buffer)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(PG_WAL, pgWal);
+ FUNCTION_TEST_END();
+
+ XLogLongPageHeaderData *walData = (XLogLongPageHeaderData *)bufPtr(buffer);
+
+ walData->std.xlp_magic = XLOG_PAGE_MAGIC;
+ walData->xlp_sysid = pgWal.systemId;
+
+ FUNCTION_TEST_RETURN_VOID();
+}
+
#endif
diff --git a/src/postgres/interface/v100.h b/src/postgres/interface/v100.h
index 3de945d8a..ab458ed7e 100644
--- a/src/postgres/interface/v100.h
+++ b/src/postgres/interface/v100.h
@@ -11,12 +11,15 @@ Functions
***********************************************************************************************************************************/
bool pgInterfaceControlIs100(const Buffer *controlFile);
PgControl pgInterfaceControl100(const Buffer *controlFile);
+bool pgInterfaceWalIs100(const Buffer *walFile);
+PgWal pgInterfaceWal100(const Buffer *controlFile);
/***********************************************************************************************************************************
Test Functions
***********************************************************************************************************************************/
#ifdef DEBUG
void pgInterfaceControlTest100(PgControl pgControl, Buffer *buffer);
+ void pgInterfaceWalTest100(PgWal pgWal, Buffer *buffer);
#endif
#endif
diff --git a/src/postgres/interface/v110.auto.c b/src/postgres/interface/v110.auto.c
index e48fd6d62..ace681cff 100644
--- a/src/postgres/interface/v110.auto.c
+++ b/src/postgres/interface/v110.auto.c
@@ -6,6 +6,7 @@ PostgreSQL 11 Types
Types from src/include/c.h
***********************************************************************************************************************************/
typedef int64_t int64;
+typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
@@ -270,3 +271,46 @@ typedef struct ControlFileData
/* CRC of all above ... MUST BE LAST! */
pg_crc32c crc;
} ControlFileData;
+
+/***********************************************************************************************************************************
+Types from src/include/access/xlog_internal.h
+***********************************************************************************************************************************/
+/*
+ * Each page of XLOG file has a header like this:
+ */
+#define XLOG_PAGE_MAGIC 0xD098 /* can be used as WAL version indicator */
+
+typedef struct XLogPageHeaderData
+{
+ uint16 xlp_magic; /* magic value for correctness checks */
+ uint16 xlp_info; /* flag bits, see below */
+ TimeLineID xlp_tli; /* TimeLineID of first record on page */
+ XLogRecPtr xlp_pageaddr; /* XLOG address of this page */
+
+ /*
+ * When there is not enough space on current page for whole record, we
+ * continue on the next page. xlp_rem_len is the number of bytes
+ * remaining from a previous page.
+ *
+ * Note that xl_rem_len includes backup-block data; that is, it tracks
+ * xl_tot_len not xl_len in the initial header. Also note that the
+ * continuation data isn't necessarily aligned.
+ */
+ uint32 xlp_rem_len; /* total len of remaining data for record */
+} XLogPageHeaderData;
+
+/*
+ * When the XLP_LONG_HEADER flag is set, we store additional fields in the
+ * page header. (This is ordinarily done just in the first page of an
+ * XLOG file.) The additional fields serve to identify the file accurately.
+ */
+typedef struct XLogLongPageHeaderData
+{
+ XLogPageHeaderData std; /* standard header fields */
+ uint64 xlp_sysid; /* system identifier from pg_control */
+ uint32 xlp_seg_size; /* just as a cross-check */
+ uint32 xlp_xlog_blcksz; /* just as a cross-check */
+} XLogLongPageHeaderData;
+
+/* This flag indicates a "long" page header */
+#define XLP_LONG_HEADER 0x0002
diff --git a/src/postgres/interface/v110.c b/src/postgres/interface/v110.c
index ba47d1265..6f7e58d4b 100644
--- a/src/postgres/interface/v110.c
+++ b/src/postgres/interface/v110.c
@@ -51,6 +51,37 @@ pgInterfaceControl110(const Buffer *controlFile)
FUNCTION_LOG_RETURN(PG_CONTROL, result);
}
+/**********************************************************************************************************************************/
+bool
+pgInterfaceWalIs110(const Buffer *walFile)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(BUFFER, controlFile);
+ FUNCTION_TEST_END();
+
+ ASSERT(walFile != NULL);
+
+ FUNCTION_TEST_RETURN(((XLogPageHeaderData *)bufPtr(walFile))->xlp_magic == XLOG_PAGE_MAGIC);
+}
+
+/**********************************************************************************************************************************/
+PgWal
+pgInterfaceWal110(const Buffer *walFile)
+{
+ FUNCTION_LOG_BEGIN(logLevelTrace);
+ FUNCTION_LOG_PARAM(BUFFER, walFile);
+ FUNCTION_LOG_END();
+
+ ASSERT(walFile != NULL);
+ ASSERT(pgInterfaceWalIs110(walFile));
+
+ PgWal result = {0};
+
+ result.systemId = ((XLogLongPageHeaderData *)bufPtr(walFile))->xlp_sysid;
+
+ FUNCTION_LOG_RETURN(PG_WAL, result);
+}
+
#ifdef DEBUG
/**********************************************************************************************************************************/
@@ -75,4 +106,20 @@ pgInterfaceControlTest110(PgControl pgControl, Buffer *buffer)
FUNCTION_TEST_RETURN_VOID();
}
+/**********************************************************************************************************************************/
+void
+pgInterfaceWalTest110(PgWal pgWal, Buffer *buffer)
+{
+ FUNCTION_TEST_BEGIN();
+ FUNCTION_TEST_PARAM(PG_WAL, pgWal);
+ FUNCTION_TEST_END();
+
+ XLogLongPageHeaderData *walData = (XLogLongPageHeaderData *)bufPtr(buffer);
+
+ walData->std.xlp_magic = XLOG_PAGE_MAGIC;
+ walData->xlp_sysid = pgWal.systemId;
+
+ FUNCTION_TEST_RETURN_VOID();
+}
+
#endif
diff --git a/src/postgres/interface/v110.h b/src/postgres/interface/v110.h
index 5272f4b79..2beb07680 100644
--- a/src/postgres/interface/v110.h
+++ b/src/postgres/interface/v110.h
@@ -11,12 +11,15 @@ Functions
***********************************************************************************************************************************/
bool pgInterfaceControlIs110(const Buffer *controlFile);
PgControl pgInterfaceControl110(const Buffer *controlFile);
+bool pgInterfaceWalIs110(const Buffer *walFile);
+PgWal pgInterfaceWal110(const Buffer *controlFile);
/***********************************************************************************************************************************
Test Functions
***********************************************************************************************************************************/
#ifdef DEBUG
void pgInterfaceControlTest110(PgControl pgControl, Buffer *buffer);
+ void pgInterfaceWalTest110(PgWal pgWal, Buffer *buffer);
#endif
#endif
diff --git a/test/define.yaml b/test/define.yaml
index 70f86979c..117fe01e0 100644
--- a/test/define.yaml
+++ b/test/define.yaml
@@ -330,7 +330,7 @@ unit:
test:
# ----------------------------------------------------------------------------------------------------------------------------
- name: interface
- total: 3
+ total: 5
coverage:
postgres/interface: full
diff --git a/test/src/module/postgres/interfaceTest.c b/test/src/module/postgres/interfaceTest.c
index 11a741741..ff1ea5165 100644
--- a/test/src/module/postgres/interfaceTest.c
+++ b/test/src/module/postgres/interfaceTest.c
@@ -89,6 +89,50 @@ testRun(void)
TEST_RESULT_INT(info.version, PG_VERSION_83, " check version");
}
+ // *****************************************************************************************************************************
+ if (testBegin("pgWalFromBuffer() and pgWalFromFile()"))
+ {
+ String *walFile = strNewFmt("%s/0000000F0000000F0000000F", testPath());
+
+ // Create a bogus control file, initially not in long format)
+ // --------------------------------------------------------------------------------------------------------------------------
+ Buffer *result = bufNew((size_t)16 * 1024 * 1024);
+ memset(bufPtr(result), 0, bufSize(result));
+ bufUsedSet(result, bufSize(result));
+ ((PgWalCommon *)bufPtr(result))->magic = 777;
+
+ TEST_ERROR(pgWalFromBuffer(result), FormatError, "first page header in WAL file is expected to be in long format");
+
+ // Add the long flag so that the version will now error
+ // --------------------------------------------------------------------------------------------------------------------------
+ ((PgWalCommon *)bufPtr(result))->flag = PG_WAL_LONG_HEADER;
+
+ TEST_ERROR(
+ pgWalFromBuffer(result), VersionNotSupportedError,
+ "unexpected WAL magic 777\n"
+ "HINT: is this version of PostgreSQL supported?");
+
+ //--------------------------------------------------------------------------------------------------------------------------
+ TEST_ERROR(pgWalTestToBuffer((PgWal){.version = 0}, result), AssertError, "invalid version 0");
+
+ //--------------------------------------------------------------------------------------------------------------------------
+ pgWalTestToBuffer((PgWal){.version = PG_VERSION_11, .systemId = 0xECAFECAF}, result);
+ storagePutNP(storageNewWriteNP(storageTest, walFile), result);
+
+ PgWal info = {0};
+ TEST_ASSIGN(info, pgWalFromFile(walFile), "get wal info v11");
+ TEST_RESULT_INT(info.systemId, 0xECAFECAF, " check system id");
+ TEST_RESULT_INT(info.version, PG_VERSION_11, " check version");
+
+ //--------------------------------------------------------------------------------------------------------------------------
+ pgWalTestToBuffer((PgWal){.version = PG_VERSION_83, .systemId = 0xEAEAEAEA}, result);
+ storagePutNP(storageNewWriteNP(storageTest, walFile), result);
+
+ TEST_ASSIGN(info, pgWalFromFile(walFile), "get wal info v8.3");
+ TEST_RESULT_INT(info.systemId, 0xEAEAEAEA, " check system id");
+ TEST_RESULT_INT(info.version, PG_VERSION_83, " check version");
+ }
+
// *****************************************************************************************************************************
if (testBegin("pgControlToLog()"))
{
@@ -105,5 +149,20 @@ testRun(void)
"{version: 110000, systemId: 1030522662895, walSegmentSize: 16777216, pageChecksum: true}", "check log");
}
+
+ // *****************************************************************************************************************************
+ if (testBegin("pgWalToLog()"))
+ {
+ PgWal pgWal =
+ {
+ .version = PG_VERSION_10,
+ .systemId = 0xFEFEFEFEFE
+ };
+
+ TEST_RESULT_STR(
+ strPtr(pgWalToLog(&pgWal)),
+ "{version: 100000, systemId: 1095199817470}", "check log");
+ }
+
FUNCTION_HARNESS_RESULT_VOID();
}