diff --git a/doc/xml/release/2025/2.55.0.xml b/doc/xml/release/2025/2.55.0.xml index 19a0be42c..6ef54d0a8 100644 --- a/doc/xml/release/2025/2.55.0.xml +++ b/doc/xml/release/2025/2.55.0.xml @@ -92,6 +92,17 @@

Add support for S3/GCS requester pays.

+ + + + + + + + +

PostgreSQL 18 experimental support.

+
+ diff --git a/src/build/postgres/postgres.yaml b/src/build/postgres/postgres.yaml index ecc981da8..38b0d6c2b 100644 --- a/src/build/postgres/postgres.yaml +++ b/src/build/postgres/postgres.yaml @@ -15,3 +15,5 @@ version: - 15 - 16 - 17 + - 18: + release: false diff --git a/src/postgres/interface/version.vendor.h b/src/postgres/interface/version.vendor.h index bb5b21952..81412cf65 100644 --- a/src/postgres/interface/version.vendor.h +++ b/src/postgres/interface/version.vendor.h @@ -154,6 +154,19 @@ Types from src/include/catalog/catversion.h // --------------------------------------------------------------------------------------------------------------------------------- #if PG_VERSION > PG_VERSION_MAX +#elif PG_VERSION >= PG_VERSION_18 + +/* + * We could use anything we wanted for version numbers, but I recommend + * following the "YYYYMMDDN" style often used for DNS zone serial numbers. + * YYYYMMDD are the date of the change, and N is the number of the change + * on that day. (Hopefully we'll never commit ten independent sets of + * catalog changes on the same day...) + */ + +/* yyyymmddN */ +#define CATALOG_VERSION_NO 202504091 + #elif PG_VERSION >= PG_VERSION_17 /* @@ -316,6 +329,11 @@ Types from src/include/catalog/pg_control.h // --------------------------------------------------------------------------------------------------------------------------------- #if PG_VERSION > PG_VERSION_MAX +#elif PG_VERSION >= PG_VERSION_18 + +/* Version identifier for this pg_control format */ +#define PG_CONTROL_VERSION 1800 + #elif PG_VERSION >= PG_VERSION_17 /* Version identifier for this pg_control format */ @@ -590,6 +608,148 @@ typedef enum DBState // --------------------------------------------------------------------------------------------------------------------------------- #if PG_VERSION > PG_VERSION_MAX +#elif PG_VERSION >= PG_VERSION_18 + +/* + * Contents of pg_control. + */ +typedef struct ControlFileData +{ + /* + * Unique system identifier --- to ensure we match up xlog files with the + * installation that produced them. + */ + uint64 system_identifier; + + /* + * Version identifier information. Keep these fields at the same offset, + * especially pg_control_version; they won't be real useful if they move + * around. (For historical reasons they must be 8 bytes into the file + * rather than immediately at the front.) + * + * pg_control_version identifies the format of pg_control itself. + * catalog_version_no identifies the format of the system catalogs. + * + * There are additional version identifiers in individual files; for + * example, WAL logs contain per-page magic numbers that can serve as + * version cues for the WAL log. + */ + uint32 pg_control_version; /* PG_CONTROL_VERSION */ + uint32 catalog_version_no; /* see catversion.h */ + + /* + * System status data + */ + DBState state; /* see enum above */ + pg_time_t time; /* time stamp of last pg_control update */ + XLogRecPtr checkPoint; /* last check point record ptr */ + + CheckPoint checkPointCopy; /* copy of last check point record */ + + XLogRecPtr unloggedLSN; /* current fake LSN value, for unlogged rels */ + + /* + * These two values determine the minimum point we must recover up to + * before starting up: + * + * minRecoveryPoint is updated to the latest replayed LSN whenever we + * flush a data change during archive recovery. That guards against + * starting archive recovery, aborting it, and restarting with an earlier + * stop location. If we've already flushed data changes from WAL record X + * to disk, we mustn't start up until we reach X again. Zero when not + * doing archive recovery. + * + * backupStartPoint is the redo pointer of the backup start checkpoint, if + * we are recovering from an online backup and haven't reached the end of + * backup yet. It is reset to zero when the end of backup is reached, and + * we mustn't start up before that. A boolean would suffice otherwise, but + * we use the redo pointer as a cross-check when we see an end-of-backup + * record, to make sure the end-of-backup record corresponds the base + * backup we're recovering from. + * + * backupEndPoint is the backup end location, if we are recovering from an + * online backup which was taken from the standby and haven't reached the + * end of backup yet. It is initialized to the minimum recovery point in + * pg_control which was backed up last. It is reset to zero when the end + * of backup is reached, and we mustn't start up before that. + * + * If backupEndRequired is true, we know for sure that we're restoring + * from a backup, and must see a backup-end record before we can safely + * start up. + */ + XLogRecPtr minRecoveryPoint; + TimeLineID minRecoveryPointTLI; + XLogRecPtr backupStartPoint; + XLogRecPtr backupEndPoint; + bool backupEndRequired; + + /* + * Parameter settings that determine if the WAL can be used for archival + * or hot standby. + */ + int wal_level; + bool wal_log_hints; + int MaxConnections; + int max_worker_processes; + int max_wal_senders; + int max_prepared_xacts; + int max_locks_per_xact; + bool track_commit_timestamp; + + /* + * This data is used to check for hardware-architecture compatibility of + * the database and the backend executable. We need not check endianness + * explicitly, since the pg_control version will surely look wrong to a + * machine of different endianness, but we do need to worry about MAXALIGN + * and floating-point format. (Note: storage layout nominally also + * depends on SHORTALIGN and INTALIGN, but in practice these are the same + * on all architectures of interest.) + * + * Testing just one double value is not a very bulletproof test for + * floating-point compatibility, but it will catch most cases. + */ + uint32 maxAlign; /* alignment requirement for tuples */ + double floatFormat; /* constant 1234567.0 */ +#define FLOATFORMAT_VALUE 1234567.0 + + /* + * This data is used to make sure that configuration of this database is + * compatible with the backend executable. + */ + uint32 blcksz; /* data block size for this DB */ + uint32 relseg_size; /* blocks per segment of large relation */ + + uint32 xlog_blcksz; /* block size within WAL files */ + uint32 xlog_seg_size; /* size of each WAL segment */ + + uint32 nameDataLen; /* catalog name field width */ + uint32 indexMaxKeys; /* max number of columns in an index */ + + uint32 toast_max_chunk_size; /* chunk size in TOAST tables */ + uint32 loblksize; /* chunk size in pg_largeobject */ + + bool float8ByVal; /* float8, int8, etc pass-by-value? */ + + /* Are data pages protected by checksums? Zero if no checksum version */ + uint32 data_checksum_version; + + /* + * True if the default signedness of char is "signed" on a platform where + * the cluster is initialized. + */ + bool default_char_signedness; + + /* + * Random nonce, used in authentication requests that need to proceed + * based on values that are cluster-unique, like a SASL exchange that + * failed at an early stage. + */ + char mock_authentication_nonce[MOCK_AUTH_NONCE_LEN]; + + /* CRC of all above ... MUST BE LAST! */ + pg_crc32c crc; +} ControlFileData; + #elif PG_VERSION >= PG_VERSION_15 /* @@ -1572,6 +1732,10 @@ Types from src/include/access/xlog_internal.h // --------------------------------------------------------------------------------------------------------------------------------- #if PG_VERSION > PG_VERSION_MAX +#elif PG_VERSION >= PG_VERSION_18 + +#define XLOG_PAGE_MAGIC 0xD118 /* can be used as WAL version indicator */ + #elif PG_VERSION >= PG_VERSION_17 #define XLOG_PAGE_MAGIC 0xD116 /* can be used as WAL version indicator */ diff --git a/src/postgres/version.auto.h b/src/postgres/version.auto.h index 986048010..60bc7397e 100644 --- a/src/postgres/version.auto.h +++ b/src/postgres/version.auto.h @@ -19,8 +19,9 @@ PostgreSQL version constants #define PG_VERSION_15 150000 #define PG_VERSION_16 160000 #define PG_VERSION_17 170000 +#define PG_VERSION_18 180000 -#define PG_VERSION_MAX PG_VERSION_17 +#define PG_VERSION_MAX PG_VERSION_18 /*********************************************************************************************************************************** PostgreSQL version string constants for use in error messages @@ -35,5 +36,6 @@ PostgreSQL version string constants for use in error messages #define PG_VERSION_15_Z "15" #define PG_VERSION_16_Z "16" #define PG_VERSION_17_Z "17" +#define PG_VERSION_18_Z "18" #endif diff --git a/test/container.yaml b/test/container.yaml index ad6461d50..a94090f69 100644 --- a/test/container.yaml +++ b/test/container.yaml @@ -12,16 +12,19 @@ # - docker login -u pgbackrest # - DATE=YYYYMMDDX;VM=X;ARCH=X;BASE=pgbackrest/test:${VM?}-base-${ARCH?};docker tag ${BASE?} ${BASE?}-${DATE?} && docker push ${BASE?}-${DATE?} # ********************************************************************************************************************************** -20250228A: +20250413A: ppc64le: - u22: 28fa02cb370bbdacadf984afb215d3973ed5ab3e + u22: a07ecf5a76b633c1c0c54ba4a836ed4c19f710b6 s390x: - u22: f3e108dd7f808f6b0e82eadcfd72f585a7632530 + u22: 535e05dc96aa24dd93b8801ed213c13d9d7a0ee4 + x86_64: + u22: 3a2bd0b5842fd97cf4f67ecc990816efc78cb799 + +20250228A: x86_64: d11: 01e6970744c2b2529a14832e92cb861c7da94308 f41: ce870455184e991e0efd90176da1412f0f3f72a2 rh8: 4d141c845abfbdbf402ba447cf2bd2e4357c8a63 u20: 862159b4d2169a4752b106639ca0f47c1ebb1f86 - u22: df6cb8401b0e8d55d856e0ec1a9387a5884a2b63 diff --git a/test/lib/pgBackRestTest/Common/ContainerTest.pm b/test/lib/pgBackRestTest/Common/ContainerTest.pm index 88cca3d9e..8c6252aba 100644 --- a/test/lib/pgBackRestTest/Common/ContainerTest.pm +++ b/test/lib/pgBackRestTest/Common/ContainerTest.pm @@ -497,13 +497,17 @@ sub containerBuild $strScript .= " echo \"deb http://apt.postgresql.org/pub/repos/apt/ \$(lsb_release -s -c)-pgdg main" . "\" >> /etc/apt/sources.list.d/pgdg.list && \\\n" . + ($strOS eq VM_U22 ? + " echo \"deb http://apt.postgresql.org/pub/repos/apt/ \$(lsb_release -s -c)-pgdg-snapshot main" . + " 18\" >> /etc/apt/sources.list.d/pgdg.list && \\\n" : '') . " wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && \\\n" . " apt-get update && \\\n"; } $strScript .= - " apt-get install -y --no-install-recommends postgresql-common libpq-dev && \\\n" . - " sed -i 's/^\\#create\\_main\\_cluster.*\$/create\\_main\\_cluster \\= false/' " . + " apt-get install -y --no-install-recommends" . + ($strOS eq VM_U22 ? " -t \$(lsb_release -s -c)-pgdg-snapshot" : '') . " postgresql-common libpq-dev && \\\n" . + " sed -i 's/^\\#create\\_main\\_cluster.*\$/create\\_main\\_cluster \\= false/' " . "/etc/postgresql-common/createcluster.conf"; } @@ -518,8 +522,10 @@ sub containerBuild } else { - $strScript .= " apt-get install -y --no-install-recommends"; - } + $strScript .= + " apt-get install -y --no-install-recommends" . + ($strOS eq VM_U22 ? " -t \$(lsb_release -s -c)-pgdg-snapshot" : ''); + } # Construct list of databases to install foreach my $strDbVersion (@{$oOS->{&VM_DB}}) diff --git a/test/lib/pgBackRestTest/Common/DbVersion.pm b/test/lib/pgBackRestTest/Common/DbVersion.pm index db70baced..c994c1ddc 100644 --- a/test/lib/pgBackRestTest/Common/DbVersion.pm +++ b/test/lib/pgBackRestTest/Common/DbVersion.pm @@ -35,6 +35,8 @@ use constant PG_VERSION_16 => '16'; push @EXPORT, qw(PG_VERSION_16); use constant PG_VERSION_17 => '17'; push @EXPORT, qw(PG_VERSION_17); +use constant PG_VERSION_18 => '18'; + push @EXPORT, qw(PG_VERSION_18); #################################################################################################################################### # versionSupport @@ -47,7 +49,7 @@ sub versionSupport my ($strOperation) = logDebugParam(__PACKAGE__ . '->versionSupport'); my @strySupportVersion = (PG_VERSION_95, PG_VERSION_96, PG_VERSION_10, PG_VERSION_11, PG_VERSION_12, PG_VERSION_13, - PG_VERSION_14, PG_VERSION_15, PG_VERSION_16, PG_VERSION_17); + PG_VERSION_14, PG_VERSION_15, PG_VERSION_16, PG_VERSION_17, PG_VERSION_18); # Return from function and log return values if any return logDebugReturn diff --git a/test/lib/pgBackRestTest/Common/VmTest.pm b/test/lib/pgBackRestTest/Common/VmTest.pm index 89eeddbc1..22bd1e7d5 100644 --- a/test/lib/pgBackRestTest/Common/VmTest.pm +++ b/test/lib/pgBackRestTest/Common/VmTest.pm @@ -245,6 +245,7 @@ my $oyVm = PG_VERSION_15, PG_VERSION_16, PG_VERSION_17, + PG_VERSION_18, ], &VM_DB_TEST => @@ -253,6 +254,7 @@ my $oyVm = PG_VERSION_11, PG_VERSION_12, PG_VERSION_17, + PG_VERSION_18, ], }, }; diff --git a/test/src/common/harnessPostgres.c b/test/src/common/harnessPostgres.c index 7955cac01..a6bff3f6d 100644 --- a/test/src/common/harnessPostgres.c +++ b/test/src/common/harnessPostgres.c @@ -55,6 +55,10 @@ uint32_t hrnPgInterfaceCatalogVersion170(void); void hrnPgInterfaceControl170(unsigned int controlVersion, unsigned int crc, PgControl pgControl, unsigned char *buffer); void hrnPgInterfaceWal170(unsigned int magic, PgWal pgWal, unsigned char *buffer); +uint32_t hrnPgInterfaceCatalogVersion180(void); +void hrnPgInterfaceControl180(unsigned int controlVersion, unsigned int crc, PgControl pgControl, unsigned char *buffer); +void hrnPgInterfaceWal180(unsigned int magic, PgWal pgWal, unsigned char *buffer); + typedef struct HrnPgInterface { // Version of PostgreSQL supported by this interface @@ -72,6 +76,13 @@ typedef struct HrnPgInterface static const HrnPgInterface hrnPgInterface[] = { + { + .version = PG_VERSION_18, + + .catalogVersion = hrnPgInterfaceCatalogVersion180, + .control = hrnPgInterfaceControl180, + .wal = hrnPgInterfaceWal180, + }, { .version = PG_VERSION_17, diff --git a/test/src/common/harnessPostgres.h b/test/src/common/harnessPostgres.h index 271665cb3..198a3401c 100644 --- a/test/src/common/harnessPostgres.h +++ b/test/src/common/harnessPostgres.h @@ -44,6 +44,8 @@ System id constants by version #define HRN_PG_SYSTEMID_16_Z "10000000000000160000" #define HRN_PG_SYSTEMID_17 (10000000000000000000ULL + (uint64_t)PG_VERSION_17) #define HRN_PG_SYSTEMID_17_Z "10000000000000170000" +#define HRN_PG_SYSTEMID_18 (10000000000000000000ULL + (uint64_t)PG_VERSION_18) +#define HRN_PG_SYSTEMID_18_Z "10000000000000180000" /*********************************************************************************************************************************** Put a control file to storage diff --git a/test/src/common/harnessPostgres/harness180.c b/test/src/common/harnessPostgres/harness180.c new file mode 100644 index 000000000..4f6ac895e --- /dev/null +++ b/test/src/common/harnessPostgres/harness180.c @@ -0,0 +1,15 @@ +/*********************************************************************************************************************************** +Harness for PostgreSQL Interface (see PG_VERSION for version) +***********************************************************************************************************************************/ +#include "build.auto.h" + +#define PG_VERSION PG_VERSION_18 + +#include "common/harnessPostgres/harnessVersion.intern.h" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-prototypes" + +HRN_PG_INTERFACE(180); + +#pragma GCC diagnostic pop diff --git a/test/src/module/integration/allTest.c b/test/src/module/integration/allTest.c index bca4ff54c..4a36a332b 100644 --- a/test/src/module/integration/allTest.c +++ b/test/src/module/integration/allTest.c @@ -29,6 +29,7 @@ static HrnHostTestDefine testMatrix[] = {.pg = "15", .repo = "pg2", .tls = 0, .stg = "azure", .enc = 1, .cmp = "none", .rt = 2, .bnd = 1, .bi = 1}, {.pg = "16", .repo = "repo", .tls = 0, .stg = "sftp", .enc = 0, .cmp = "zst", .rt = 1, .bnd = 1, .bi = 1}, {.pg = "17", .repo = "repo", .tls = 0, .stg = "posix", .enc = 0, .cmp = "none", .rt = 1, .bnd = 0, .bi = 0}, + {.pg = "18", .repo = "repo", .tls = 0, .stg = "posix", .enc = 0, .cmp = "none", .rt = 1, .bnd = 0, .bi = 0}, // {uncrustify_on} }; diff --git a/test/src/module/postgres/interfaceTest.c b/test/src/module/postgres/interfaceTest.c index 2a7bc7ecd..76f3714f6 100644 --- a/test/src/module/postgres/interfaceTest.c +++ b/test/src/module/postgres/interfaceTest.c @@ -140,7 +140,7 @@ testRun(void) pgControlFromFile(storageTest, NULL), FormatError, "wal segment size is 47 but must be a power of two between 1048576 and 1073741824 inclusive"); - HRN_PG_CONTROL_PUT(storageTest, PG_VERSION_17, .walSegmentSize = (unsigned int)2 * 1024 * 1024 * 1024); + HRN_PG_CONTROL_PUT(storageTest, PG_VERSION_18, .walSegmentSize = (unsigned int)2 * 1024 * 1024 * 1024); TEST_ERROR( pgControlFromFile(storageTest, NULL), FormatError, @@ -225,13 +225,13 @@ testRun(void) TEST_RESULT_UINT(info.pageSize, pgPageSize16, "check page size"); HRN_PG_CONTROL_PUT( - storageTest, PG_VERSION_17, .systemId = 0xEFEFEFEFEF, .catalogVersion = hrnPgCatalogVersion(PG_VERSION_17), + storageTest, PG_VERSION_18, .systemId = 0xEFEFEFEFEF, .catalogVersion = hrnPgCatalogVersion(PG_VERSION_18), .checkpoint = 0xAABBAABBEEFFEEFF, .timeline = 88, .pageSize = pgPageSize32); TEST_ASSIGN(info, pgControlFromFile(storageTest, NULL), "get control info"); TEST_RESULT_UINT(info.systemId, 0xEFEFEFEFEF, "check system id"); - TEST_RESULT_UINT(info.version, PG_VERSION_17, "check version"); - TEST_RESULT_UINT(info.catalogVersion, 202406281, "check catalog version"); + TEST_RESULT_UINT(info.version, PG_VERSION_18, "check version"); + TEST_RESULT_UINT(info.catalogVersion, 202504091, "check catalog version"); TEST_RESULT_UINT(info.checkpoint, 0xAABBAABBEEFFEEFF, "check checkpoint"); TEST_RESULT_UINT(info.timeline, 88, "check timeline"); TEST_RESULT_UINT(info.pageSize, pgPageSize32, "check page size");