Support building against PostgreSQL 19#2457
Conversation
03e1a51 to
feb7e47
Compare
There was a problem hiding this comment.
Pull request overview
Updates Apache AGE’s backend code to compile cleanly against PostgreSQL 19’s C API changes and aligns regression tests with PostgreSQL 19’s adjusted error text, while preserving runtime behavior (notably around scan options, tuple-slot flags, and index-insert conflict handling).
Changes:
- Adjusts numerous PostgreSQL API callsites (scan APIs, tuple slot initialization, DML tuple ops, index tuple insertion, DSM callbacks/LWLock tranche handling, ParseState usage).
- Adds headers that are no longer pulled in transitively by PostgreSQL 19’s leaner includes.
- Updates regression SQL/expected outputs for PostgreSQL 19 wording changes and makes one previously non-deterministic path query deterministic via
ORDER BY.
Reviewed changes
Copilot reviewed 23 out of 23 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| .github/workflows/installcheck.yaml | Increases checkout fetch depth for CI installcheck workflow. |
| regress/expected/cypher_call.out | Updates expected error output text to match PostgreSQL 19 diagnostics. |
| regress/expected/cypher_match.out | Updates expected output and reflects deterministic ordering change. |
| regress/expected/expr.out | Updates expected error output text to match PostgreSQL 19 diagnostics. |
| regress/expected/jsonb_operators.out | Updates expected error output text to match PostgreSQL 19 diagnostics. |
| regress/expected/subgraph.out | Updates expected error output text to match PostgreSQL 19 diagnostics. |
| regress/sql/cypher_match.sql | Adds ORDER BY p to stabilize previously non-deterministic path ordering. |
| src/backend/catalog/ag_label.c | Updates index/table scan calls for PostgreSQL 19 scan flags. |
| src/backend/commands/graph_commands.c | Adapts schema creation to new ParseState-based CreateSchemaCommand; updates tuple slot creation flags. |
| src/backend/executor/cypher_create.c | Updates tuple slot initialization to include new flags argument. |
| src/backend/executor/cypher_delete.c | Updates tuple slot init, heap_delete signature, and scan calls for PostgreSQL 19 API changes. |
| src/backend/executor/cypher_merge.c | Updates tuple slot initialization to include new flags argument. |
| src/backend/executor/cypher_set.c | Updates tuple slot init, table_tuple_update signature, ExecInsertIndexTuples flags mapping, and scan calls. |
| src/backend/executor/cypher_utils.c | Updates scan calls and ExecInsertIndexTuples call signature. |
| src/backend/parser/cypher_analyze.c | Updates post-parse-analyze hook signature to const-qualify JumbleState. |
| src/backend/parser/cypher_expr.c | Adds header needed for htup macros with PostgreSQL 19 headers. |
| src/backend/parser/cypher_keywords.c | Adds pg_type header for OID macros now needed explicitly. |
| src/backend/utils/adt/age_global_graph.c | Updates scan calls, DSM init callback signature, LWLock tranche API usage, and DSM segment API call signature. |
| src/backend/utils/adt/age_vle.c | Adds header needed for htup macros with PostgreSQL 19 headers. |
| src/backend/utils/adt/agtype.c | Adds missing headers; updates scan calls; replaces removed PointerIsValid; adjusts varlena access macros to pass pointers. |
| src/backend/utils/adt/agtype_ops.c | Adjusts varlena access macros to pass pointers. |
| src/backend/utils/adt/agtype_util.c | Replaces fallthrough comment with pg_fallthrough. |
| src/backend/utils/load/age_load.c | Updates ExecInsertIndexTuples call to new signature and preserves “no duplicate” behavior via flags. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| static void age_dsm_init_callback(void *ptr, void *arg) | ||
| { | ||
| GraphVersionState *state = (GraphVersionState *) ptr; | ||
|
|
||
| LWLockInitialize(&state->lock, |
|
Nice — diff is clean and CI's green on the
Otherwise the PG19 API adaptations look right to me. |
Note: A big thank you to Alexander Kukushkin <cyberdemn@gmail.com>
who's work helped to make this possible.
Adapt AGE to PostgreSQL 19's C API changes so the extension compiles
cleanly (verified with COPT=-Werror) and passes the full regression
suite against 19beta1. Each prototype change was matched to how AGE
actually uses the function rather than blindly appending arguments.
Access-method scans: table_beginscan() and index_beginscan() gained a
trailing uint32 flags. Pass SO_NONE (no special scan options);
table_beginscan() still ORs in SO_TYPE_SEQSCAN internally, so behavior is
unchanged. Add access/genam.h to the files that use index_*/IndexScanDesc
(previously reached only transitively through now-leaner PG headers).
Tuple-slot init: MakeTupleTableSlot() and ExecInitScanTupleSlot() gained a
uint16 flags. Pass 0. AGE's DML executors are CustomScanState nodes whose
input tuples are synthesized agtype rows, so -- like PostgreSQL's own
nodeCustom.c and nodeSubqueryscan.c -- 0 is correct. The
TTS_FLAG_OBEYS_NOT_NULL_CONSTRAINTS hint that heap seq/index scans pass
would be unsound here since these tuples are not guaranteed to obey a base
relation's NOT NULL constraints.
DML tuple ops: heap_delete() added a uint32 options argument and dropped
the trailing changingPart bool; table_tuple_update() added a uint32 options
argument. Pass 0 in both (AGE used changingPart=false and no special
options, so 0 preserves behavior).
ExecInsertIndexTuples() was reworked to
(resultRelInfo, estate, uint32 flags, slot, arbiterIndexes, specConflict)
with flags EIIT_IS_UPDATE / EIIT_NO_DUPE_ERROR / EIIT_ONLY_SUMMARIZING. The
old booleans map to flags: plain inserts (cypher_utils) use 0; SET uses
EIIT_ONLY_SUMMARIZING when update_indexes == TU_Summarizing. Importantly,
the bulk loader (age_load) previously passed noDupErr=true so it could
detect the conflict list and raise its own error; this maps to
EIIT_NO_DUPE_ERROR (not 0), preserving AGE's "Cannot insert duplicate
vertex id" message instead of surfacing the raw unique-constraint violation.
CreateSchemaCommand() replaced its const char *queryString parameter with a
ParseState *. Build one with make_parsestate(), set p_sourcetext to the
generated command string, and free_parsestate() afterward (mirroring
standard_ProcessUtility). The argument count is unchanged, so this mismatch
only warns under default flags -- another reason the build uses -Werror.
Shared-memory/locks: LWLockNewTrancheId() now takes the tranche name
directly and LWLockRegisterTranche() was removed; GetNamedDSMSegment() and
its init callback gained a void *arg. Update the graph-version DSM setup
accordingly, passing NULL for the unused callback argument.
Miscellaneous: add includes exposed by leaner PG19 headers (catalog/pg_type.h
for TEXTOID/CHAROID, <time.h> for CLOCK_REALTIME, utils/tuplesort.h and
utils/tuplestore.h, access/htup_details.h for GETSTRUCT/heap_form_tuple);
PointerIsValid() was removed (use != NULL); VARDATA()/VARSIZE() now require a
pointer, so wrap the Datum in DatumGetPointer(); replace the fall-through
comment with the pg_fallthrough macro; and const-qualify JumbleState * in the
post_parse_analyze hook signature.
Regression output: the only differences under PG19 are cosmetic and are
reflected in the expected files. PostgreSQL 19 reworded undefined
function/operator errors -- the "HINT: No function/operator matches the given
name and argument types" line became "DETAIL: No function/operator of that
name accepts...", and for a wholly unknown operator "DETAIL: There is no
operator of that name."; the ERROR lines themselves are unchanged. This
accounts for the expr, cypher_call, jsonb_operators and subgraph updates.
Separately, a divergent-path query in cypher_match returned the same four
paths in a different, non-deterministic order under PG19; add ORDER BY p to
make it deterministic (matching the project's practice of ordering
non-deterministic RETURN queries). The returned row multiset is unchanged --
it is purely a reordering, not a data difference.
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Alexander Kukushkin <cyberdemn@gmail.com>
modified: regress/expected/cypher_call.out
modified: regress/expected/cypher_match.out
modified: regress/expected/expr.out
modified: regress/expected/jsonb_operators.out
modified: regress/expected/subgraph.out
modified: regress/sql/cypher_match.sql
modified: src/backend/catalog/ag_label.c
modified: src/backend/commands/graph_commands.c
modified: src/backend/executor/cypher_create.c
modified: src/backend/executor/cypher_delete.c
modified: src/backend/executor/cypher_merge.c
modified: src/backend/executor/cypher_set.c
modified: src/backend/executor/cypher_utils.c
modified: src/backend/parser/cypher_analyze.c
modified: src/backend/parser/cypher_expr.c
modified: src/backend/parser/cypher_keywords.c
modified: src/backend/utils/adt/age_global_graph.c
modified: src/backend/utils/adt/age_vle.c
modified: src/backend/utils/adt/agtype.c
modified: src/backend/utils/adt/agtype_ops.c
modified: src/backend/utils/adt/agtype_util.c
modified: src/backend/utils/load/age_load.c
modified: .github/workflows/installcheck.yaml
Resolved conflicts: .github/workflows/installcheck.yaml
feb7e47 to
9f42230
Compare
Note: A big thank you to Alexander Kukushkin cyberdemn@gmail.com
who's work helped to make this possible.
Note: This is a beta branch for PostgreSQL 19. This PR is part of the work to get the PG19 branch up and running. Other items will follow.
Adapt AGE to PostgreSQL 19's C API changes so the extension compiles cleanly (verified with COPT=-Werror) and passes the full regression suite against 19beta1. Each prototype change was matched to how AGE actually uses the function rather than blindly appending arguments.
Access-method scans: table_beginscan() and index_beginscan() gained a trailing uint32 flags. Pass SO_NONE (no special scan options); table_beginscan() still ORs in SO_TYPE_SEQSCAN internally, so behavior is unchanged. Add access/genam.h to the files that use index_*/IndexScanDesc (previously reached only transitively through now-leaner PG headers).
Tuple-slot init: MakeTupleTableSlot() and ExecInitScanTupleSlot() gained a uint16 flags. Pass 0. AGE's DML executors are CustomScanState nodes whose input tuples are synthesized agtype rows, so -- like PostgreSQL's own nodeCustom.c and nodeSubqueryscan.c -- 0 is correct. The TTS_FLAG_OBEYS_NOT_NULL_CONSTRAINTS hint that heap seq/index scans pass would be unsound here since these tuples are not guaranteed to obey a base relation's NOT NULL constraints.
DML tuple ops: heap_delete() added a uint32 options argument and dropped the trailing changingPart bool; table_tuple_update() added a uint32 options argument. Pass 0 in both (AGE used changingPart=false and no special options, so 0 preserves behavior).
ExecInsertIndexTuples() was reworked to
(resultRelInfo, estate, uint32 flags, slot, arbiterIndexes, specConflict) with flags EIIT_IS_UPDATE / EIIT_NO_DUPE_ERROR / EIIT_ONLY_SUMMARIZING. The old booleans map to flags: plain inserts (cypher_utils) use 0; SET uses EIIT_ONLY_SUMMARIZING when update_indexes == TU_Summarizing. Importantly, the bulk loader (age_load) previously passed noDupErr=true so it could detect the conflict list and raise its own error; this maps to EIIT_NO_DUPE_ERROR (not 0), preserving AGE's "Cannot insert duplicate vertex id" message instead of surfacing the raw unique-constraint violation.
CreateSchemaCommand() replaced its const char *queryString parameter with a ParseState *. Build one with make_parsestate(), set p_sourcetext to the generated command string, and free_parsestate() afterward (mirroring standard_ProcessUtility). The argument count is unchanged, so this mismatch only warns under default flags -- another reason the build uses -Werror.
Shared-memory/locks: LWLockNewTrancheId() now takes the tranche name directly and LWLockRegisterTranche() was removed; GetNamedDSMSegment() and its init callback gained a void *arg. Update the graph-version DSM setup accordingly, passing NULL for the unused callback argument.
Miscellaneous: add includes exposed by leaner PG19 headers (catalog/pg_type.h for TEXTOID/CHAROID, <time.h> for CLOCK_REALTIME, utils/tuplesort.h and utils/tuplestore.h, access/htup_details.h for GETSTRUCT/heap_form_tuple); PointerIsValid() was removed (use != NULL); VARDATA()/VARSIZE() now require a pointer, so wrap the Datum in DatumGetPointer(); replace the fall-through comment with the pg_fallthrough macro; and const-qualify JumbleState * in the post_parse_analyze hook signature.
Regression output: the only differences under PG19 are cosmetic and are reflected in the expected files. PostgreSQL 19 reworded undefined function/operator errors -- the "HINT: No function/operator matches the given name and argument types" line became "DETAIL: No function/operator of that name accepts...", and for a wholly unknown operator "DETAIL: There is no operator of that name."; the ERROR lines themselves are unchanged. This accounts for the expr, cypher_call, jsonb_operators and subgraph updates. Separately, a divergent-path query in cypher_match returned the same four paths in a different, non-deterministic order under PG19; add ORDER BY p to make it deterministic (matching the project's practice of ordering non-deterministic RETURN queries). The returned row multiset is unchanged -- it is purely a reordering, not a data difference.
Co-authored-by: Copilot copilot@github.com
Co-authored-by: Alexander Kukushkin cyberdemn@gmail.com
modified: regress/expected/cypher_call.out
modified: regress/expected/cypher_match.out
modified: regress/expected/expr.out
modified: regress/expected/jsonb_operators.out
modified: regress/expected/subgraph.out
modified: regress/sql/cypher_match.sql
modified: src/backend/catalog/ag_label.c
modified: src/backend/commands/graph_commands.c
modified: src/backend/executor/cypher_create.c
modified: src/backend/executor/cypher_delete.c
modified: src/backend/executor/cypher_merge.c
modified: src/backend/executor/cypher_set.c
modified: src/backend/executor/cypher_utils.c
modified: src/backend/parser/cypher_analyze.c
modified: src/backend/parser/cypher_expr.c
modified: src/backend/parser/cypher_keywords.c
modified: src/backend/utils/adt/age_global_graph.c
modified: src/backend/utils/adt/age_vle.c
modified: src/backend/utils/adt/agtype.c
modified: src/backend/utils/adt/agtype_ops.c
modified: src/backend/utils/adt/agtype_util.c
modified: src/backend/utils/load/age_load.c