Skip to content

Drop PG16 support - #8757

Merged
ibrahim halatci (ihalatci) merged 8 commits into
mainfrom
ihalatci-drop-pg16-support
Sep 1, 2026
Merged

ibrahim halatci (ihalatci) merged 8 commits into
mainfrom
ihalatci-drop-pg16-support

Conversation

@ihalatci

Copy link
Copy Markdown
Contributor

PR 1 of 2 for #8750 — drops PostgreSQL 16 support. Supported set becomes PG17 + PG18.

This mirrors the PG15 drop (62a919066): PR 1 covers build plumbing, source, and CI; PR 2 covers test output / helper cleanup.

⚠️ Merge ordering

This PR depends on citusdata/the-process#240, which removes PG16 from the test image definitions.

image_suffix is temporarily pinned to the dev images from that PR (-dev-ef6cc68) in a separate, clearly labelled commit. Once CI is green here, the-process#240 is merged and the release images are published, that commit gets replaced with the new stable -v<sha> suffix and this PR moves out of draft.

What changed

Build plumbing

  • configure.ac / configure — PG16 no longer accepted; configure now fails with Citus is not compatible with the detected PostgreSQL version 16.
  • src/include/pg_version_constants.h — dropped PG_VERSION_16
  • .gitattributes — dropped the ruleutils_16.c entry

Files

  • Deleted src/backend/distributed/deparser/ruleutils_16.c (9235 lines)
  • Renamed pg_get_object_address_16_17_18.cpg_get_object_address_17_18.c

Sources

  • src/include/pg_version_compat.h — 480 → 437 lines; the pre-PG17 compat half is gone
  • 52 PG_VERSION_17 guard blocks removed across 19 files, plus the now-dead hasPseudoconstantQuals helper and the PG16 makeStringConst fallback

Deprecated GUC
citus.enable_outer_joins_with_pseudoconstant_quals_pre_pg17 is left defined but inert rather than removed, so existing configs don't fail to start. It now carries a deprecation description and a check hook that warns whenever it is set from any non-default source (session SET, ALTER SYSTEM, ALTER DATABASE/ROLE ... SET, postgresql.conf):

WARNING:  citus.enable_outer_joins_with_pseudoconstant_quals_pre_pg17 is deprecated and has no effect

A clean install that never touches the GUC stays silent, and a value persisted across a restart does not produce per-backend log spam. Removal is tracked in #8751 for 15.1.

CI / devcontainer

  • build_and_test.yml — dropped the pg16_version param and every matrix entry that used it; upgrade_pg_versions17.10-18.4; test-pg-upgrade reduced to just 17→18
  • flaky_test_debugging.ymlvars.pg16_versionvars.pg17_version
  • .devcontainer/Dockerfile — removed the pg16 build stage
  • .github/actions/setup_cassert_pg/action.yml — doc-string example updated

Verification

Check Result
Build against PG 17.10 ✅ clean, zero warnings
Build against PG 18.4 ✅ clean, zero warnings
Configure against PG 16.14 ✅ correctly rejected
GUC warning behaviour (set / reset / ALTER SYSTEM / restart) ✅ as described above
banned.h.sh, check_gucs_are_alphabetically_sorted.sh, editorconfig.sh ✅ pass

Follow-ups (deliberately not in this PR)

  • PR 2 — test output and helper cleanup, incl. removing the three GUC SET/RESET pairs in pg17.sql that would otherwise pull the new warning into expected output
  • #8754test-citus-upgrade is missing PG18
  • #8755 — dead pre-PG16 shims in sql/udfs/

ihalatci-msft and others added 2 commits August 12, 2026 20:52
Makes PG17 the minimum supported PostgreSQL version, so the supported set
becomes PG17 and PG18. This is the first of two PRs; a follow-up will clean
up test outputs and helpers (see #8750).

- configure/configure.ac: reject PG16
- remove PG_VERSION_16 and the pre-PG17 half of pg_version_compat.h
- delete ruleutils_16.c and rename pg_get_object_address_16_17_18.c
- strip PG_VERSION_17 version guards that are now always true/dead
- CI: drop the pg16 matrix entries, devcontainer stage and 16->17/16->18
  pg-upgrade jobs; pg-upgrade now only covers 17->18

citus.enable_outer_joins_with_pseudoconstant_quals_pre_pg17 only ever
applied to PG16. It is kept defined-but-inert so existing configurations
keep loading, and now raises a deprecation warning when set explicitly.
It is scheduled for removal in 15.1 (see #8751).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7b92da71-e0c2-4baf-b47d-c81ec58da88b
Temporary pin to the dev images built by citusdata/the-process#240.
Revert to the stable -v<sha> suffix once that PR merges and the release
images are published.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7b92da71-e0c2-4baf-b47d-c81ec58da88b
@codecov

codecov Bot commented Aug 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 57.14286% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.73%. Comparing base (ca8e66a) to head (2bc0eaf).

❌ Your patch check has failed because the patch coverage (57.14%) is below the target coverage (75.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #8757   +/-   ##
=======================================
  Coverage   88.72%   88.73%           
=======================================
  Files         289      289           
  Lines       65073    64992   -81     
  Branches     8203     8200    -3     
=======================================
- Hits        57739    57673   -66     
+ Misses       4967     4953   -14     
+ Partials     2367     2366    -1     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

ihalatci-msft and others added 2 commits August 12, 2026 21:40
Addresses the two real CI failures on the PG16 drop.

check-style: restore the blank line that citus-style requires between a
variable declaration and a following comment block (merge_planner.c,
citus_depended_object.c), and collapse the four blank lines left behind by
the removed pre-PG17 helper in recursive_planning.c down to two.

pg17: the three citus.enable_outer_joins_with_pseudoconstant_quals_pre_pg17
SET/RESET pairs now emit the new deprecation warning, which is not in the
expected output. The GUC was already inert on PG17, so each "wrong result
pre-pg17" query was a verbatim duplicate of the query immediately above it
and the comment was no longer true. Remove the whole scaffold (SET, comment,
duplicate query, RESET) rather than only silencing the warning.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7b92da71-e0c2-4baf-b47d-c81ec58da88b
Removing the PG_VERSION_16 guards left three declaration/assignment
splits that only existed so the value could be set inside an #if block,
and made pg_version_constants.h unused in extension.c.

- merge_planner.c: inline the initializers in GetMergeJoinTree and
  GetMergeJoinCondition
- citus_depended_object.c: inline the mergeJoinCondition initializer
- extension.c: drop the now-unused pg_version_constants.h include

Verified locally by running the full check-style job: all 7 mutating
ci/*.sh scripts produce no diff, all 7 validators exit 0, and uncrustify
leaves the changed files byte-identical.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7b92da71-e0c2-4baf-b47d-c81ec58da88b

@onurctirtir Onur Tirtir (onurctirtir) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have any alternative test outputs we can drop while dropping support for PG < 17?

@ihalatci

Copy link
Copy Markdown
Contributor Author

Do we have any alternative test outputs we can drop while dropping support for PG < 17?

yes, in #8764 as a follow after this PR merges

…pport

# Conflicts:
#	.github/workflows/build_and_test.yml
#	configure
#	configure.ac
the-process #240 has merged as 609733ff2, so the release images are now
published and the temporary dev pin is no longer needed. This supersedes
the earlier "TEMP: point CI at the-process dev images" commit; since this
PR is squash-merged, that commit does not reach main and only the final
value here matters.

Verified every tag referenced through image_suffix exists at -v609733f:
extbuilder, exttester and failtester for 17.10/18.4/19beta3,
stylechecker:0.8.33, pgupgradetester:17.10-18.4-19beta3, and
citusupgradetester:17.10 (the only version that job's matrix uses).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7b92da71-e0c2-4baf-b47d-c81ec58da88b
@ihalatci
ibrahim halatci (ihalatci) merged commit d22e10d into main Sep 1, 2026
284 of 286 checks passed
@ihalatci
ibrahim halatci (ihalatci) deleted the ihalatci-drop-pg16-support branch September 1, 2026 11:06
ibrahim halatci (ihalatci) pushed a commit that referenced this pull request Sep 1, 2026
Should have been part of #8757

This commit deletes some redundant alternative test outputs which were
created for PG16, and collapses the now-always-true `server_version_ge_17`
gates. Since the minimum supported version is PG17, `server_version_ge_17`
is always true, so the `\else` branches guarded by it were dead code.

Also:
- removes the dead `15_16` arm from the `version_category` CASE in
  merge_unsupported
- removes an always-true `PG_MAJOR_VERSION >= 16` branch in common.py
- fixes a stale `#endif` comment in ruleutils_18.c which claimed the
  band was `>= 17 && < 18` while the `#if` actually guards `>= 18 && < 19`

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7b92da71-e0c2-4baf-b47d-c81ec58da88b
ibrahim halatci (ihalatci) added a commit that referenced this pull request Sep 1, 2026
Part 2 of 2 for [#8750](#8750).

Stacked on [#8757](#8757) —
**this PR targets that branch, not `main`.** Please merge
[#8757](#8757) first.

Mirrors the equivalent PG14 cleanup commit
[`529b303b6`](529b303b6) that
followed the PG15 drop.

## What this does

Now that PG17 is the minimum supported version, `server_version_ge_17`
is always true. This removes the resulting dead code.

### Deleted 6 dead alternative expected outputs (-4000 lines)
| File | Why it is dead |
|---|---|
| `expected/pg17_0.out` | PG16-only "cannot push down this subquery"
errors |
| `expected/pg17_json_0.out` | pure truncation after `\q` |
| `expected/subquery_in_where_0.out` | contains the PG16
pseudoconstant-quals ERROR |
| `expected/grant_on_table_propagation_0.out` | prints `f` for
`server_version_ge_17` |
| `expected/merge_unsupported_0.out` | `version_category` = `15_16` |
| `expected/multi_alter_table_add_constraints_1.out` | the `ge_17` block
produced no output |

### Collapsed 8 `server_version_ge_17` gates
`merge_unsupported`, `grant_on_table_propagation`,
`multi_alter_table_add_constraints`, `multi_mx_create_table`,
`multi_mx_hide_shard_names`, `multi_schema_support`, `pg15`, `pg17`,
`pg17_json` — `.sql` and `.out` edited in lockstep.

### Other
- `merge_unsupported`: dropped the dead `WHEN ... IN (15, 16) THEN
'15_16'` arm (the 17/18 arms stay)
- `citus_tests/common.py`: removed an always-true `if PG_MAJOR_VERSION
>= 16:`
- `ruleutils_18.c`: fixed a stale `#endif` comment that said `>= 17 && <
18` while the `#if` guards `>= 18 && < 19`

## Deliberately NOT changed
- `sql/pg16.sql` / `expected/pg16.out` — ungated feature test, same as
`pg15.sql` was kept after the PG15 drop
- `multi_test_helpers.sql` `pg_ge_16_options` — catalog introspection
(`attname = 'daticurules'`), not a version gate
- `expected/multi_mx_hide_shard_names_0.out` and `expected/pg18_0.out` —
still-live alternatives (plan shape / `<18` branch)

## Verification
- All 14 `ci/*.sh` style scripts pass; `black` / `isort` / `flake8`
clean
- Clean build against PG17.10, zero warnings
- All 10 affected regression tests pass locally: `subquery_in_where`,
`pg15`, `pg17`, `pg17_json`, `merge_unsupported`,
`grant_on_table_propagation`, `multi_alter_table_add_constraints`,
`multi_schema_support`, `multi_mx_create_table`,
`multi_mx_hide_shard_names`

---------

Co-authored-by: Ibrahim Halatci <ihalatci@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7b92da71-e0c2-4baf-b47d-c81ec58da88b
@ihalatci ibrahim halatci (ihalatci) linked an issue Sep 1, 2026 that may be closed by this pull request
ibrahim halatci (ihalatci) added a commit that referenced this pull request Sep 2, 2026
DESCRIPTION: Quote EXTRACT fields and support latest PostgreSQL minors

Fixes #8803.

## Changes

- quote EXTRACT field identifiers in the copied PG17 and PG18 ruleutils
implementations; `ruleutils_19.c` already carries the equivalent fix
from #8753;
- run one discriminating, repeat-safe regression across supported
PostgreSQL versions from the N-1-excluded create-Citus schedule; PG19
retains its dedicated #8753 coverage;
- bump CI coverage from 17.10 / 18.4 to 17.11 / 18.6;
- forward-port the already-landed release-14 fallout for the new
PostgreSQL security minors, including `output_plugin_libraries` handling
and modern psql COPY behavior;
- add PG18 to the `test-citus-upgrade` matrix.

### PG18 citus upgrade coverage

`citusupgradetester` is built and published for PG18
(`CITUS_UPGRADE_VERSIONS_18=v14.2.0`), but the matrix listed only PG17,
so that image was built and never exercised. This adds it, matching the
convention on `release-14.0`, which lists every supported major except
the newest.

PG19 stays out deliberately. The image compiles released Citus from
source, and no released Citus supports PG19 yet, which is why
the-process filters it out of `CITUS_UPGRADE_PG_VERSIONS`. PG19 upgrade
paths are still covered by `test-pg-upgrade`, whose matrix already
includes 17→18, 18→19, and 17→19.

## Cross-repo dependency

The test images are built by
[the-process#244](citusdata/the-process#244),
stacked above
[the-process#240](citusdata/the-process#240).
Both have merged, along with #8757 and #8764, so this PR is last in that
sequence and now pins the released `-vdba9cbb` suffix.

## Validation

- `-Werror` builds: PostgreSQL 17.11, 18.6, and 19beta3
- shared `extract_deparse`: 8/8 repetitions on each of PostgreSQL 17.11,
18.6, and 19beta3
- focused PG17, PG18, and PG19 version regressions
- focused `split_output_plugin_denied` regression on PG18.6
- `citus_indent --check`
- SQL snapshot and test-schedule checks
- `pg_regress_multi.pl` syntax check
- all 13 image tags referenced by the workflow resolved against GHCR at
the `-vdba9cbb` suffix before pinning

## Known limitation carried over from the release branches

The `output_plugin_libraries` preflight splits the GUC on commas, so a
plugin name containing a comma inside a quoted element (`"a,b"`) is not
parsed the way PostgreSQL's `SplitGUCList` would parse it. This is
unreachable for the name `citus` and matches what already shipped on
release-14.0, release-13.2, and release-12.1.

---------

Co-authored-by: Ibrahim Halatci <ihalatci@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ihalatci <10450368+ihalatci@users.noreply.github.com>
Co-authored-by: ihalatci <ihalatci@users.noreply.github.com>
Copilot-Session: 7c6370b2-06fd-4491-bf92-ecb811d34518
ibrahim halatci (ihalatci) added a commit that referenced this pull request Sep 8, 2026
## Problem

Branch protection today enumerates every individual CI leg as a required
status
check. Almost all of those names embed the Postgres major, e.g.
`Test Citus / PG18 - check-multi`. That makes the required-check list a
function
of each branch's PG matrix, so it can never be homogeneous across `main`
and the
release branches, and it silently rots whenever the matrix changes.

Two concrete symptoms:

- `release-14.0` had **no protection at all** until it was added
manually this
  week. Nothing detects that state.
- `Drop PG16 support (#8757)` just invalidated every `PG16 - *` required
context
on `main`. Required checks that no longer exist are simply never
reported, so
  the gap is invisible rather than loud.

Counts as of today: `main` 111 required contexts, `release-13.2` 89,
`release-12.1` 108 — all different, all hand-maintained.

## Change

Adds one aggregate gate job per workflow whose **name is constant** and
does not
mention any Postgres version:

| Job | Display name | Workflow |
|---|---|---|
| `ci-gate` | `CI` | `build_and_test.yml` |
| `packaging-gate` | `Packaging` | `packaging-test-pipelines.yml` |

Each gate is `if: always()`, `needs:` the blocking jobs, and fails if
any of them
reports `failure`, `cancelled`, or `skipped`. Branch protection can then
require
just `CI` + `Packaging` and never be touched again when the matrix
moves.

This is additive only — no existing line is modified, and no job's
behavior
changes. +54 lines total.

### Gated (blocking)

`build_and_test.yml`: `params`, `check-sql-snapshots`, `check-style`,
`build`,
`test-citus`, `test-citus-failure`, `test-citus-cdc`,
`test-arbitrary-configs`,
`test-pg-upgrade`, `test-citus-upgrade`.

`packaging-test-pipelines.yml`: `get_postgres_versions_from_file`,
`rpm_build_tests`, `deb_build_tests`.

### Not gated (advisory — still run, still visible)

`test-flakyness-pre`, `test-flakyness`, `ch_benchmark`,
`tpcc_benchmark`,
`prepare_parallelization_matrix_32`, and the N-1 suites. These are
deliberately
non-blocking.

## Notes for reviewers

- Every job in `needs` is unconditional, which is what makes treating
`skipped`
as a failure safe. The conditional jobs (benchmarks, flakyness) are
exactly the
ones left out. **If a conditional job is ever added to `needs`, that
logic must
  be revisited.**
- Trade-off: if a job is deleted from the workflow, the gate goes green
without
it. A `CODEOWNERS` entry for `/.github/workflows/` is the intended
mitigation
  and will follow separately.
- The required-check list must be derived from a **pull request**, not a
push:
  `license/cla`, `get_postgres_versions_from_file` and all 21
  `deb_build_tests`/`rpm_build_tests` legs only run on `pull_request`.

## Rollout

1. This PR — confirm `CI` and `Packaging` appear and go green.
2. Backport to `release-14.0` and `release-13.2` (job IDs are identical
to
   `main`, so it applies verbatim).
3. Add repository rulesets covering `main` + maintained release
branches, using
numeric ref patterns so future branches such as `release-15.0` are
protected
   automatically instead of starting out unprotected.
4. Run rulesets in `evaluate`, then switch to `active` and retire the
   per-branch classic protections.

`release-12.1` keeps its existing classic protection and is
intentionally out of
scope here.

Backporting to `release-13.2` will newly enforce `check-style` there,
since that
branch currently requires only `check-sql-snapshots` among the generic
checks.
That is an intended homogenization, called out here so it is not a
surprise.

Co-authored-by: Ibrahim Halatci <ihalatci@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: efb25be2-5642-4485-ad0c-fe162a1e4410
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Drop PG16 support

3 participants