# PostgreSQL version support matrix `pg_turbovec` supports PostgreSQL **13, 14, 15, 16, 17, 18** (and **19beta1**, experimentally). CI builds the latest patch of each major on every push (`cargo pgrx init --download`), so the "Tested patch" column below is the floor at the time of writing, not a pin. The test count (**445 passed / 8 ignored**, uniform across every native leg as of v2.10.2) is the same on all majors — the per-major notes below record only the C-ABI shape differences the extension shims, not test-count differences. | Version | Status | Tests | Notes | |---|---|---|---| | 13.x | ✅ Supported | 445 passed / 8 ignored | `aminsert` 7-arg shape; no `amsummarizing` / `amadjustmembers` fields. | | 14.x | ✅ Supported | 445 passed / 8 ignored | `aminsert` gained `indexUnchanged`; no `amsummarizing` field. | | 15.x | ✅ Supported | 445 passed / 8 ignored | Same shape as 14. | | 16.x | ✅ Supported | 445 passed / 8 ignored | Reference platform during development. | | 17.x | ✅ Supported | 445 passed / 8 ignored | Benchmark platform. | | 18.x | ✅ Supported | 445 passed / 8 ignored | `relopt_parse_elt` gained `isset_offset`. CI-validated every push (`.github/workflows/test.yml` matrix leg `test (18)`). | | 19.0beta1 | ✅ **Experimental** (beta PG) | CI matrix leg | pgrx 0.19.1 floor. PG19 deltas handled: `LockBuffer`'s `mode` param became `BufferLockMode::Type` (u32) — shimmed via `relfile::lock_buffer_mode`; `rd_locator.relNumber` same as pg16+. PG19 is upstream BETA — re-validate at RC/GA before production use. | > Test counts and patch versions above are the exact numbers CI > installs and reports as of the most recent green run > (`gh run view` on `.github/workflows/test.yml`'s `test` job, one > leg per `pg` matrix entry). `cargo pgrx init --pgN download` > always fetches the latest point release for major `N` at run > time, so these patch versions drift upward on their own — re-run > `bash scripts/drift-check.sh` and check the latest CI log rather > than trusting this table blindly. The one ignored test > (`src/index/ivf.rs`, `ivf_batch_speedup`) is a perf-only timing > comparison, not a correctness gate; it's `#[ignore]`d deliberately > on every PG version, not a skip specific to any one of them. > The out-of-core IVF build (v1.12.0+) uses PG's `BufFile` temp-file > API, whose signatures differ across majors (`BufFileReadExact` is > PG16+; `BufFileWrite`'s pointer type changed). v1.15.1 added > `scripts/compile-matrix.sh` (a `cargo check` across every `pgNN` > feature, wired into the pre-push hook) so version-specific C-API > breaks are caught before tagging — a v1.12.0–v1.15.0 regression > that broke the pg13/14/15/18 build legs slipped through because > local dev was pg16-only. ## How tests are run As of v1.3.0 (Phase Q), the `experimental_index_am` and `relfile_storage` Cargo features are gone; the only build knob is `pg`: ```bash cargo pgrx test pg --no-default-features \ --features "pg pg_test" ``` (Or simply `cargo pgrx test pg` if you're happy with the default feature set, which already enables `pg16`.) For each supported version, the test suite drives every type (`vector`, `halfvec`, `sparsevec`, `bitvec`), every distance operator (`<->`, `<#>`, `<=>`, `<+>`, `<~>`, `<%>`), the index access method opclasses, and aminsert / ambulkdelete via VACUUM. ## Why each gate exists ### `(*routine).amsummarizing` — `cfg = pg16+` The `IndexAmRoutine` struct gained an `amsummarizing: bool` field in PG 16 to drive BRIN's summarising-index codepath. Earlier versions don't know about it. ```rust #[cfg(any(feature = "pg16", feature = "pg17", feature = "pg18"))] { (*routine).amsummarizing = false; } ``` ### `(*routine).amadjustmembers` — `cfg = pg14+` `amadjustmembers` is the op-family-adjust-members callback added in PG 14 (`be08e10b41fd`). pg13 doesn't have the field. ```rust #[cfg(not(feature = "pg13"))] { (*routine).amadjustmembers = None; } ``` ### `aminsert` callback — split for `pg13` PG 14 added an `indexUnchanged: bool` parameter to `aminsert` for HOT-chain elision (`9dc718bdf2b1`). pg13's signature is one argument shorter. We expose two thin C-ABI wrappers selecting on the feature flag and a shared `aminsert_impl` Rust function: ```rust #[cfg(not(feature = "pg13"))] #[pgrx::pg_guard] pub(crate) unsafe extern "C-unwind" fn aminsert( index_relation: pg_sys::Relation, values: *mut pg_sys::Datum, isnull: *mut bool, heap_tid: pg_sys::ItemPointer, _heap_relation: pg_sys::Relation, _check_unique: pg_sys::IndexUniqueCheck::Type, _index_unchanged: bool, // <-- added in PG 14 _index_info: *mut pg_sys::IndexInfo, ) -> bool { aminsert_impl(index_relation, values, isnull, heap_tid) } ``` ### `relopt_parse_elt::isset_offset` — `cfg = pg18` PG 18 added `isset_offset: i32` to `relopt_parse_elt` so callers can distinguish "explicitly set to default" from "never set". We don't track that distinction; `-1` ("unused") works on every field. ```rust pg_sys::relopt_parse_elt { optname: c"bit_width".as_ptr(), opttype: pg_sys::relopt_type::RELOPT_TYPE_INT, offset: std::mem::offset_of!(TurbovecRelopts, bit_width) as i32, #[cfg(feature = "pg18")] isset_offset: -1, }, ``` ## Gotcha: `pgrx::pg_guard` reserves `_inner` The `#[pgrx::pg_guard]` macro expands to a wrapper plus a private helper named `_inner`. If you split a callback into a public C-ABI wrapper and an inner Rust impl, **don't name the inner helper `_inner`** — it collides with the macro's generated symbol. We use `_impl` instead. Surface that any new callback you split follows the same convention. ## Adding a future PG version 1. Add `pgN = ["pgrx/pgN", "pgrx-tests/pgN"]` to `[features]` in `Cargo.toml`. 2. Run `cargo pgrx test pgN`. 3. Compile errors will point at any new fields in `IndexAmRoutine`, callback shape changes, or relopt struct drift. Add `#[cfg(feature = "pgN")]` (or `#[cfg(not(feature = "pgM"))]` for "all versions <= M") gates to `src/index/`. 4. Re-run the full matrix to make sure no previous version was broken. 5. Update this file's table and the `CHANGELOG.md` entry. ## PostgreSQL 19 Not supported yet — PG19 is still in upstream beta (`REL_19_BETA1`) and the pinned `pgrx = "=0.17.0"` dependency has no `pg19` feature. for the blocker detail, the C-API delta found so far, and the recommended timeline (wait for PG19 RC1+, then treat the pgrx upgrade + port as its own dedicated piece of work).