Skip to content

Commit 704c852

Browse files
committed
Support building against PostgreSQL 19
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
1 parent 9088e01 commit 704c852

22 files changed

Lines changed: 172 additions & 141 deletions

‎regress/expected/cypher_call.out‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ SELECT * FROM cypher('cypher_call', $$CALL ag_catalog.add_agtype(1,2)$$) as (sqr
8080
ERROR: function ag_catalog.add_agtype(agtype, agtype) does not exist
8181
LINE 2: ...cypher('cypher_call', $$CALL ag_catalog.add_agtype(1,2)$$) a...
8282
^
83-
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
8483
/* CALL YIELD WHERE, should fail */
8584
SELECT * FROM cypher('cypher_call', $$CALL sqrt(64) YIELD sqrt WHERE sqrt > 1$$) as (sqrt agtype);
8685
ERROR: Cannot use standalone CALL with WHERE
@@ -287,12 +286,11 @@ SELECT * FROM cypher('cypher_call', $$ CALL ag_catalog.myfunc() YIELD myfunc RET
287286
ERROR: function ag_catalog.myfunc() does not exist
288287
LINE 1: ...T * FROM cypher('cypher_call', $$ CALL ag_catalog.myfunc() Y...
289288
^
290-
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
289+
DETAIL: No function of that name accepts the given number of arguments.
291290
SELECT * FROM cypher('cypher_call', $$ CALL ag_catalog.myfunz(25) YIELD myfunc RETURN myfunc $$) as (result agtype);
292291
ERROR: function ag_catalog.myfunz(agtype) does not exist
293292
LINE 1: ...OM cypher('cypher_call', $$ CALL ag_catalog.myfunz(25) YIELD...
294293
^
295-
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
296294
DROP FUNCTION myfunc;
297295
DROP SCHEMA call_stmt_test CASCADE;
298296
NOTICE: drop cascades to function call_stmt_test.add_agtype(agtype,agtype)

‎regress/expected/cypher_match.out‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -333,13 +333,14 @@ SELECT * FROM cypher('cypher_match', $$
333333
MATCH ()<-[]-(n:v2)-[]->()
334334
MATCH p=(n)-[]->()
335335
RETURN p
336+
ORDER BY p
336337
$$) AS (i agtype);
337338
i
338339
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
339-
[{"id": 1688849860263938, "label": "v2", "properties": {"id": "middle"}}::vertex, {"id": 1970324836974594, "label": "e2", "end_id": 1688849860263937, "start_id": 1688849860263938, "properties": {}}::edge, {"id": 1688849860263937, "label": "v2", "properties": {"id": "initial"}}::vertex]::path
340340
[{"id": 1688849860263938, "label": "v2", "properties": {"id": "middle"}}::vertex, {"id": 1970324836974593, "label": "e2", "end_id": 1688849860263939, "start_id": 1688849860263938, "properties": {}}::edge, {"id": 1688849860263939, "label": "v2", "properties": {"id": "end"}}::vertex]::path
341-
[{"id": 1688849860263938, "label": "v2", "properties": {"id": "middle"}}::vertex, {"id": 1970324836974594, "label": "e2", "end_id": 1688849860263937, "start_id": 1688849860263938, "properties": {}}::edge, {"id": 1688849860263937, "label": "v2", "properties": {"id": "initial"}}::vertex]::path
342341
[{"id": 1688849860263938, "label": "v2", "properties": {"id": "middle"}}::vertex, {"id": 1970324836974593, "label": "e2", "end_id": 1688849860263939, "start_id": 1688849860263938, "properties": {}}::edge, {"id": 1688849860263939, "label": "v2", "properties": {"id": "end"}}::vertex]::path
342+
[{"id": 1688849860263938, "label": "v2", "properties": {"id": "middle"}}::vertex, {"id": 1970324836974594, "label": "e2", "end_id": 1688849860263937, "start_id": 1688849860263938, "properties": {}}::edge, {"id": 1688849860263937, "label": "v2", "properties": {"id": "initial"}}::vertex]::path
343+
[{"id": 1688849860263938, "label": "v2", "properties": {"id": "middle"}}::vertex, {"id": 1970324836974594, "label": "e2", "end_id": 1688849860263937, "start_id": 1688849860263938, "properties": {}}::edge, {"id": 1688849860263937, "label": "v2", "properties": {"id": "initial"}}::vertex]::path
343344
(4 rows)
344345

345346
SELECT * FROM cypher('cypher_match', $$
@@ -1494,14 +1495,14 @@ AS (u agtype);
14941495
ERROR: function ag_catalog.age_isempty(agtype, agtype, agtype) does not exist
14951496
LINE 2: $$MATCH (u:for_pred) WHERE isEmpty(1,2,3) RETURN properties...
14961497
^
1497-
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
1498+
DETAIL: No function of that name accepts the given number of arguments.
14981499
SELECT * FROM cypher('for_isEmpty',
14991500
$$MATCH (u:for_pred) WHERE isEmpty() RETURN properties(u) $$)
15001501
AS (u agtype);
15011502
ERROR: function ag_catalog.age_isempty() does not exist
15021503
LINE 2: $$MATCH (u:for_pred) WHERE isEmpty() RETURN properties(u) $...
15031504
^
1504-
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
1505+
DETAIL: No function of that name accepts the given number of arguments.
15051506
-- clean up
15061507
SELECT drop_graph('for_isEmpty', true);
15071508
NOTICE: drop cascades to 3 other objects

0 commit comments

Comments
 (0)