fix(postgres): accept full_page_writes off on Amazon Aurora PostgreSQL only
maven / build (push) Successful in 6m14s
build / maven (push) Successful in 6m14s

Generation qualification refused every Amazon Aurora PostgreSQL server:
Aurora always reports full_page_writes = off and has no parameter to change
it, because its storage layer does not write torn pages.

The settings query now also returns
to_regprocedure('aurora_version()') IS NOT NULL (true on Aurora, false on
stock PostgreSQL, never an error). full_page_writes = off is accepted only
when that is true. Stock PostgreSQL must still report it on, and fsync on,
synchronous_commit on or remote_apply and every other check are unchanged
on both. The refusal text now says full-page writes are not required on
Aurora.

Tests run on a real postgres:17 engine whose settings are really changed;
only Aurora is simulated, by creating a function named aurora_version() in
the test database.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
james.maesandClaude Fable 5.2 committed 2026-11-09 20:25:55 -06:00
1 parent 1dc265647d
commit cfbf0744f9
4 files changed
+168 -11

No files matched your search

@@ -52,13 +52,24 @@ final class PostgresGenerationDatabase implements AutoCloseable
** Starts only this suite's loopback container with durable settings.
***************************************************************************/
PostgresGenerationDatabase()
{
this(true);
}
/***************************************************************************
** Pinned durability settings come from the server command line, which no
** ALTER SYSTEM can override. An unpinned engine starts with the same values
** (the PostgreSQL defaults) and lets a test weaken them through system().
***************************************************************************/
PostgresGenerationDatabase(boolean pinned)
{
// pgjdbc announces the JVM zone as the session TimeZone; qualification requires UTC.
previousZone = java.util.TimeZone.getDefault();
java.util.TimeZone.setDefault(java.util.TimeZone.getTimeZone("UTC"));
container = new GenericContainer<>(IMAGE)
.withEnv("POSTGRES_PASSWORD", rootPassword).withEnv("POSTGRES_DB", "bootstrap")
.withCommand("postgres", "-c", "fsync=on", "-c", "synchronous_commit=on", "-c", "full_page_writes=on", "-c", "max_connections=60")
.withCommand(pinned ? new String[] { "postgres", "-c", "fsync=on", "-c", "synchronous_commit=on", "-c", "full_page_writes=on", "-c", "max_connections=60" }
: new String[] { "postgres", "-c", "max_connections=60" })
.withExposedPorts(5432)
.withCreateContainerCmdModifier(command -> command.getHostConfig().withMemory(768L * 1024 * 1024).withNanoCPUs(2_000_000_000L)
.withPortBindings(FixtureEndpoint.publishedBinding(5432)))
@@ -143,6 +154,38 @@ final class PostgresGenerationDatabase implements AutoCloseable
}
}
/***************************************************************************
** Change one reloadable server setting of an unpinned engine (ALTER SYSTEM and
** a configuration reload), then wait until a new session actually reports it.
** Fixed fixture names and values only, never application input.
***************************************************************************/
void system(String name, String value) throws Exception
{
ConnectionManager.closeConnectionProviders();
try(var connection = DriverManager.getConnection(server + "bootstrap" + OPTIONS, "postgres", rootPassword); var statement = connection.createStatement())
{
statement.execute("ALTER SYSTEM SET " + name + " = '" + value + "'");
statement.execute("SELECT pg_reload_conf()");
}
long deadline = System.nanoTime() + java.time.Duration.ofSeconds(30).toNanos();
while(true)
{
try(var connection = DriverManager.getConnection(server + "bootstrap" + OPTIONS, "postgres", rootPassword); var statement = connection.createStatement();
var row = statement.executeQuery("SELECT current_setting('" + name + "')"))
{
if(row.next() && value.equals(row.getString(1)))
{
return;
}
}
if(System.nanoTime() >= deadline)
{
throw new IllegalStateException("PostgreSQL fixture did not apply " + name);
}
Thread.sleep(100);
}
}
/***************************************************************************
** Cold server restart retains only this container's data layer (committed
** data must survive; Docker may publish a different loopback port).