Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
12c7f6d
Add Postgres 17, 18, 19 support
dimitri Jul 12, 2026
a9039c3
Fix compilation and test failures for Postgres 19
dimitri Jul 12, 2026
c61c1a5
Fix zero-warning policy: old-style function defs and vendored fallthr…
dimitri Jul 12, 2026
18bc94c
Fix pidfile race in service restart: atomic write + defensive retry
dimitri Jul 12, 2026
2197c60
Fix PG19 failover stall: use received_tli > 0 to filter wal receiver …
dimitri Jul 12, 2026
986f4bb
Fix PG19 failover stall: remove wrong PgStartTime→MyStartTimestamp shim
dimitri Jul 12, 2026
a9cd75e
Add debug_failover_pg19 diagnostic spec (excluded from CI schedule)
dimitri Jul 12, 2026
081ba90
tests: move Citus DROP TABLE out of teardown into an explicit test step
dimitri Jul 13, 2026
6852c3b
tests: fix Citus DROP TABLE race against metadata sync
dimitri Jul 13, 2026
a6f7ee7
tests: pgaftest summary, drop-node coverage, CI image caching, pg_aut…
dimitri Jul 13, 2026
c26497d
cleanup: remove accidentally staged run-test.sh and pycache files
dimitri Jul 13, 2026
2aa0702
ci: add PostgreSQL 18 and 19 to base image and job matrix
dimitri Jul 15, 2026
2c991af
fix: remove duplicate cli_node_init functions from rebase artifact
dimitri Jul 15, 2026
a814184
fix: suppress -Wold-style-definition warning in runprogram.h (PG19)
dimitri Jul 15, 2026
ba09a7b
ci: force-rebuild base image when Dockerfile.base changes in PR
dimitri Jul 15, 2026
01ac15d
ci: remove PG19 citus pgaftest jobs — no Citus release supports PG19 yet
dimitri Jul 15, 2026
807fb62
tests: fix race in test_004_002_writes_via_coordinator_to_worker2_fail
dimitri Jul 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 59 additions & 13 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ name: CI
#
# Job dependency graph:
#
# style_checker ──┐
# ├── (both must pass before any build job starts)
# ensure_base ───┘
# ├── build_run_images (PG 14-17 → pgaf:run-pgN; installcheck runs inside build stage)
# │ └── test_pgaftest (17 spec jobs)
# style_checker ──────┐
# check_base_changed ─┤
# ├── (all must pass before any build job starts)
# ensure_base ───────┘
# ├── build_run_images (PG 14-19 → pgaf:run-pgN; installcheck runs inside build stage)
# │ └── test_pgaftest (spec jobs)
# ├── build_pgaftest (pgaf:pgaftest, built from PG17)
# │ └── test_pgaftest (same)
# │ └── upgrade
# └── build_test_images (PG 14-17 → pg_auto_failover_test:pgN)
# └── build_test_images (PG 14-19 → pg_auto_failover_test:pgN)
# └── test_python (PG × suite matrix)

on:
Expand Down Expand Up @@ -52,14 +53,41 @@ jobs:
run: ci/banned.h.sh

# ---------------------------------------------------------------------------
# 2. Ensure base image — pull from ghcr.io or build+push on cache miss.
# Runs in parallel with style_checker; build jobs wait for both.
# Fast path (image exists): ~5 s manifest check.
# Slow path (first run / Dockerfile.base changed): ~20 min build.
# 2a. Detect whether Dockerfile.base changed in this PR/push so that
# ensure_base knows to force-rebuild rather than reuse the cached image.
# ---------------------------------------------------------------------------
check_base_changed:
name: Check if Dockerfile.base changed
runs-on: ubuntu-latest
outputs:
changed: ${{ steps.diff.outputs.changed }}
steps:
- uses: actions/checkout@v7.0.0
with:
fetch-depth: 0

- name: Detect Dockerfile.base change
id: diff
run: |
BASE_REF="${{ github.event.pull_request.base.sha || 'HEAD~1' }}"
if git diff --name-only "${BASE_REF}"...HEAD | grep -q '^Dockerfile\.base$'; then
echo "changed=true" >> "$GITHUB_OUTPUT"
else
echo "changed=false" >> "$GITHUB_OUTPUT"
fi

# ---------------------------------------------------------------------------
# 2b. Ensure base image — pull from ghcr.io or build+push on cache miss.
# Runs in parallel with style_checker; build jobs wait for both.
# Fast path (image exists and Dockerfile.base unchanged): ~5 s check.
# Slow path (first run or Dockerfile.base changed): ~20 min build.
# ---------------------------------------------------------------------------
ensure_base:
name: Ensure base image
needs: check_base_changed
uses: ./.github/workflows/base-image.yml
with:
force_rebuild: ${{ needs.check_base_changed.outputs.changed == 'true' }}
permissions:
contents: read
packages: write
Expand All @@ -79,7 +107,7 @@ jobs:
strategy:
fail-fast: false
matrix:
PGVERSION: [14, 15, 16, 17]
PGVERSION: [14, 15, 16, 17, 18, 19]

steps:
- uses: actions/checkout@v7.0.0
Expand Down Expand Up @@ -188,7 +216,7 @@ jobs:
strategy:
fail-fast: false
matrix:
PGVERSION: [14, 15, 16, 17]
PGVERSION: [14, 15, 16, 17, 18, 19]

steps:
- uses: actions/checkout@v7.0.0
Expand Down Expand Up @@ -249,24 +277,34 @@ jobs:
- { PGVERSION: 15, schedule: quick }
- { PGVERSION: 16, schedule: quick }
- { PGVERSION: 17, schedule: quick }
- { PGVERSION: 18, schedule: quick }
- { PGVERSION: 19, schedule: quick }
# node: create_standby_with_pgdata, maintenance_and_drop, auth,
# monitor_disabled, replace_monitor, extension_update,
# debian_clusters, tablespaces
- { PGVERSION: 14, schedule: node }
- { PGVERSION: 15, schedule: node }
- { PGVERSION: 16, schedule: node }
- { PGVERSION: 17, schedule: node }
- { PGVERSION: 18, schedule: node }
- { PGVERSION: 19, schedule: node }
# ssl: enable_ssl, ssl_self_signed, ssl_cert
- { PGVERSION: 14, schedule: ssl }
- { PGVERSION: 15, schedule: ssl }
- { PGVERSION: 16, schedule: ssl }
- { PGVERSION: 17, schedule: ssl }
- { PGVERSION: 18, schedule: ssl }
- { PGVERSION: 19, schedule: ssl }
# slow schedules: PG17 only (FSM logic, not version-specific code paths)
- { PGVERSION: 17, schedule: multi-alternate }
- { PGVERSION: 17, schedule: multi-misc }
- { PGVERSION: 17, schedule: multi-async }
- { PGVERSION: 17, schedule: citus-1 }
- { PGVERSION: 17, schedule: citus-2 }
# citus on PG18 (supported); allow failure until officially validated
- { PGVERSION: 18, schedule: citus-1, continue-on-error: true }
- { PGVERSION: 18, schedule: citus-2, continue-on-error: true }
# PG19: no Citus release yet (CITUSTAG_19=none) — citus schedules omitted

steps:
- uses: actions/checkout@v7.0.0
Expand Down Expand Up @@ -379,11 +417,19 @@ jobs:
strategy:
fail-fast: false
matrix:
PGVERSION: [14, 15, 16, 17]
PGVERSION: [14, 15, 16, 17, 18, 19]
TEST: [multi, single, monitor, ssl, citus]
exclude:
# Citus does not support PG19 yet
- PGVERSION: 19
TEST: citus
include:
- PGVERSION: 14
TEST: tablespaces
# Allow citus failures on PG18 until officially validated
- PGVERSION: 18
TEST: citus
continue-on-error: true

steps:
- uses: actions/checkout@v7.0.0
Expand Down
16 changes: 13 additions & 3 deletions Dockerfile.base
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ RUN curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc \
| gpg --dearmor -o /usr/share/keyrings/pgdg-archive-keyring.gpg

RUN echo "deb [signed-by=/usr/share/keyrings/pgdg-archive-keyring.gpg] \
http://apt.postgresql.org/pub/repos/apt bookworm-pgdg main 14 15 16 17" \
http://apt.postgresql.org/pub/repos/apt bookworm-pgdg main 14 15 16 17 18 19" \
> /etc/apt/sources.list.d/pgdg.list

# Don't create a default cluster on install (we create them explicitly in tests)
Expand All @@ -91,6 +91,8 @@ RUN apt-get update \
postgresql-15 postgresql-server-dev-15 \
postgresql-16 postgresql-server-dev-16 \
postgresql-17 postgresql-server-dev-17 \
postgresql-18 postgresql-server-dev-18 \
postgresql-19 postgresql-server-dev-19 \
&& rm -rf /var/lib/apt/lists/*

# ---------------------------------------------------------------------------
Expand All @@ -104,13 +106,17 @@ ARG CITUSTAG_14=v12.1.5
ARG CITUSTAG_15=v12.1.5
ARG CITUSTAG_16=v13.2.0
ARG CITUSTAG_17=v13.2.0
ARG CITUSTAG_18=v14.1.0
ARG CITUSTAG_19=none

RUN set -e; \
for pair in \
"14:${CITUSTAG_14}" \
"15:${CITUSTAG_15}" \
"16:${CITUSTAG_16}" \
"17:${CITUSTAG_17}"; \
"17:${CITUSTAG_17}" \
"18:${CITUSTAG_18}" \
"19:${CITUSTAG_19}"; \
do \
PG="${pair%%:*}"; \
TAG="${pair#*:}"; \
Expand Down Expand Up @@ -140,8 +146,12 @@ ARG CITUSTAG_14
ARG CITUSTAG_15
ARG CITUSTAG_16
ARG CITUSTAG_17
ARG CITUSTAG_18
ARG CITUSTAG_19

LABEL org.pgaf.citustag.14="${CITUSTAG_14}" \
org.pgaf.citustag.15="${CITUSTAG_15}" \
org.pgaf.citustag.16="${CITUSTAG_16}" \
org.pgaf.citustag.17="${CITUSTAG_17}"
org.pgaf.citustag.17="${CITUSTAG_17}" \
org.pgaf.citustag.18="${CITUSTAG_18}" \
org.pgaf.citustag.19="${CITUSTAG_19}"
4 changes: 2 additions & 2 deletions Makefile.docker
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ $(VERSION_FILE):
@echo "#define GIT_VERSION \"$(GIT_VERSION)\"" > $@

# Supported PostgreSQL versions:
PGVERSIONS = 14 15 16 17
PGVERSIONS = 14 15 16 17 18 19

# Default version:
PGVERSION ?= 17
PGVERSION ?= 19

# Base image that provides all Postgres versions + Citus builds.
# Override locally after building the base image under a different tag.
Expand Down
4 changes: 2 additions & 2 deletions src/bin/common/Makefile.common
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ COMMON_INCLUDES += -I$(LIB_DIR)/parson/

CC = $(shell $(PG_CONFIG) --cc)

DEFAULT_CFLAGS = -std=c99 -D_GNU_SOURCE -g
DEFAULT_CFLAGS = -D_GNU_SOURCE -g
DEFAULT_CFLAGS += -I $(shell $(PG_CONFIG) --includedir)
DEFAULT_CFLAGS += -I $(shell $(PG_CONFIG) --includedir-server)
DEFAULT_CFLAGS += -I $(shell $(PG_CONFIG) --pkgincludedir)/internal
Expand Down Expand Up @@ -109,7 +109,7 @@ endif

# Shared rules for vendored libs
lib-snprintf.o: $(PG_SNPRINTF)
$(CC) $(CFLAGS) -c -MMD -MP -MF$(DEPDIR)/lib-snprintf.Po -MT$@ \
$(CC) $(CFLAGS) -Wno-implicit-fallthrough -c -MMD -MP -MF$(DEPDIR)/lib-snprintf.Po -MT$@ \
-o $@ $(LIB_DIR)/pg/snprintf.c

lib-strerror.o: $(PG_SNPRINTF)
Expand Down
12 changes: 11 additions & 1 deletion src/bin/common/pgctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -2350,12 +2350,22 @@ prepare_recovery_settings(const char *pgdata,
primaryNode->host,
primaryNode->port);

/*
* PG17 introduced synchronized_standby_slots for logical slot
* failover; pg_sync_replication_slots() requires primary_conninfo
* to include a dbname keyword. Pass it when available.
*/
const char *dbname =
IS_EMPTY_STRING_BUFFER(replicationSource->dbname)
? NULL
: replicationSource->dbname;

if (!prepare_primary_conninfo(primaryConnInfo,
MAXCONNINFO,
primaryNode->host,
primaryNode->port,
replicationSource->userName,
NULL, /* no database */
dbname,
replicationSource->password,
replicationSource->applicationName,
replicationSource->sslOptions,
Expand Down
2 changes: 1 addition & 1 deletion src/bin/common/pgsetup.c
Original file line number Diff line number Diff line change
Expand Up @@ -1588,7 +1588,7 @@ pmStatusToString(PostmasterStatus pm_status)
* environment variable, or from our default hard-coded value of 5432.
*/
int
pgsetup_get_pgport()
pgsetup_get_pgport(void)
{
char pgport_env[NAMEDATALEN];
int pgport = 0;
Expand Down
5 changes: 4 additions & 1 deletion src/bin/common/pgsql.c
Original file line number Diff line number Diff line change
Expand Up @@ -2616,7 +2616,10 @@ pgsql_get_postgres_metadata(PGSQL *pgsql,
" end as current_lsn,"
" pg_control_version, catalog_version_no, system_identifier,"
" case when pg_is_in_recovery()"
" then (select received_tli from pg_stat_wal_receiver)"
" then coalesce("
" (select received_tli from pg_stat_wal_receiver"
" where received_tli > 0),"
" (select timeline_id from pg_control_checkpoint()))"
" else (select timeline_id from pg_control_checkpoint()) "
" end as timeline_id "
" from (values(1)) as dummy"
Expand Down
1 change: 1 addition & 0 deletions src/bin/common/pgsql.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ typedef struct ReplicationSource
{
NodeAddress primaryNode;
char userName[NAMEDATALEN];
char dbname[NAMEDATALEN]; /* database name for primary_conninfo (PG17+) */
char slotName[MAXCONNINFO];
char password[MAXCONNINFO];
char maximumBackupRate[MAXIMUM_BACKUP_RATE_LEN];
Expand Down
2 changes: 1 addition & 1 deletion src/bin/common/pidfile.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ get_service_pidfile(const char *pidfile,
* pidfile.
*/
static void
remove_service_pidfile_atexit()
remove_service_pidfile_atexit(void)
{
(void) remove_pidfile(service_pidfile);
}
Expand Down
18 changes: 13 additions & 5 deletions src/bin/common/signals.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,10 @@ unblock_signals(sigset_t *orig_mask)
* catch_reload receives the SIGHUP signal.
*/
void
catch_reload(int sig)
catch_reload(SIGNAL_ARGS)
{
int sig = postgres_signal_arg;

asked_to_reload = 1;
pqsignal(sig, catch_reload);
}
Expand All @@ -130,8 +132,10 @@ catch_reload(int sig)
* catch_int receives the SIGINT signal.
*/
void
catch_int(int sig)
catch_int(SIGNAL_ARGS)
{
int sig = postgres_signal_arg;

asked_to_stop_fast = 1;
pqsignal(sig, catch_int);
}
Expand All @@ -141,8 +145,10 @@ catch_int(int sig)
* catch_stop receives SIGTERM signal.
*/
void
catch_term(int sig)
catch_term(SIGNAL_ARGS)
{
int sig = postgres_signal_arg;

asked_to_stop = 1;
pqsignal(sig, catch_term);
}
Expand All @@ -152,8 +158,10 @@ catch_term(int sig)
* catch_quit receives the SIGQUIT signal.
*/
void
catch_quit(int sig)
catch_quit(SIGNAL_ARGS)
{
int sig = postgres_signal_arg;

/* default signal handler disposition is to core dump, we don't */
asked_to_quit = 1;
pqsignal(sig, catch_quit);
Expand All @@ -164,7 +172,7 @@ catch_quit(int sig)
* quit_and_exit exit(EXIT_CODE_QUIT) upon receiving the SIGQUIT signal.
*/
void
catch_quit_and_exit(int sig)
catch_quit_and_exit(SIGNAL_ARGS)
{
/* default signal handler disposition is to core dump, we don't */
exit(EXIT_CODE_QUIT);
Expand Down
11 changes: 6 additions & 5 deletions src/bin/common/signals.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include <inttypes.h>
#include <signal.h>
#include "postgres_fe.h" /* SIGNAL_ARGS, pqsigfunc */

/* This flag controls termination of the main loop. */
extern volatile sig_atomic_t asked_to_stop; /* SIGTERM */
Expand All @@ -25,11 +26,11 @@ extern volatile sig_atomic_t asked_to_quit; /* SIGQUIT */
void set_signal_handlers(bool exitOnQuit);
bool block_signals(sigset_t *mask, sigset_t *orig_mask);
void unblock_signals(sigset_t *orig_mask);
void catch_reload(int sig);
void catch_int(int sig);
void catch_term(int sig);
void catch_quit(int sig);
void catch_quit_and_exit(int sig);
void catch_reload(SIGNAL_ARGS);
void catch_int(SIGNAL_ARGS);
void catch_term(SIGNAL_ARGS);
void catch_quit(SIGNAL_ARGS);
void catch_quit_and_exit(SIGNAL_ARGS);

int get_current_signal(int defaultSignal);
int pick_stronger_signal(int sig1, int sig2);
Expand Down
2 changes: 1 addition & 1 deletion src/bin/lib/subcommands.c/runprogram.h
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ free_program(Program *prog)
* and stdout and exits with the exit code EXIT_CODE_INTERNAL_ERROR.
*/
static void
exit_internal_error()
exit_internal_error(void)
{
fprintf(stdout, "%s\n", strerror(errno));
fprintf(stderr, "%s\n", strerror(errno));
Expand Down
Loading