This is an automated email from the ASF dual-hosted git repository.
MuhammadTahaNaveed pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/age.git
The following commit(s) were added to refs/heads/master by this push:
new 8c7e44fd Fix MERGE edges on 32-bit builds: keep path_entry ids as
graphids (#2602)
8c7e44fd is described below
commit 8c7e44fd2a525dedfd3d4e8168921442eb4fce2f
Author: Eric Laquer <[email protected]>
AuthorDate: Wed Nov 4 14:29:20 2026 -0600
Fix MERGE edges on 32-bit builds: keep path_entry ids as graphids (#2602)
path_entry's id, start_id and end_id are graphid fields, but merge_vertex
and merge_edge stored Datums in them and read them back as Datums, while
prebuild_path stores real graphids for vertices bound by an earlier clause.
On a 64-bit build the two are the same bits. With SIZEOF_DATUM=4 (the
32-bit support added in #2286, used by PGlite's wasm32 build) a graphid
Datum is a pointer, so a MERGE of an edge onto bound vertices -- for
example
MERGE (a:N {k:'x'}) MERGE (b:N {k:'y'}) MERGE (a)-[:E]->(b)
MATCH (a:N {k:'x'}), (b:N {k:'y'}) MERGE (a)-[:E]->(b)
wrote the edge with start_id and end_id read from whatever the graphid,
taken as an address, pointed to (0 in practice): the row is stored but no
MATCH walks it, and a second MERGE of the same edge stores a duplicate.
Convert with GRAPHID_GET_DATUM / DATUM_GET_GRAPHID where path_entry meets
a Datum, guarding a NULL id. On 64-bit builds these are identity casts, so
behaviour there is unchanged.
Found running the same Cypher workload on PostgreSQL 17 (64-bit) and in
PGlite 0.4.6 (wasm32): 606 of 617 statements agreed before, 617 after.
---
src/backend/executor/cypher_merge.c | 28 +++++++++++++++++++---------
1 file changed, 19 insertions(+), 9 deletions(-)
diff --git a/src/backend/executor/cypher_merge.c
b/src/backend/executor/cypher_merge.c
index cbd86644..c1c4b765 100644
--- a/src/backend/executor/cypher_merge.c
+++ b/src/backend/executor/cypher_merge.c
@@ -34,6 +34,13 @@
*
* Note: This structure is only useful for paths when stored in a dynamic
* array.
+ *
+ * Note: id, start_id and end_id hold graphid values, never Datums. They are
+ * converted with GRAPHID_GET_DATUM/DATUM_GET_GRAPHID where they meet a
+ * Datum. On a 64-bit build the two are the same bits, but with
+ * SIZEOF_DATUM=4 a graphid Datum is a pointer, and storing it here (or
+ * reading a graphid stored here as a Datum) writes edges with
+ * start_id/end_id from whatever that address holds.
*/
typedef struct path_entry
{
@@ -1270,8 +1277,9 @@ static Datum merge_vertex(cypher_merge_custom_scan_state
*css,
path_array != NULL &&
path_array[path_index] != NULL)
{
- id = path_array[path_index]->id;
isNull = path_array[path_index]->id_isNull;
+ id = isNull ? (Datum) 0 :
+ GRAPHID_GET_DATUM(path_array[path_index]->id);
}
/*
* Otherwise, we need to retrieve the vertex normally and store its
@@ -1285,7 +1293,8 @@ static Datum merge_vertex(cypher_merge_custom_scan_state
*css,
if (path_array != NULL && path_array[path_index] != NULL)
{
/* store it */
- path_array[path_index]->id = id;
+ path_array[path_index]->id = isNull ? 0 :
+ DATUM_GET_GRAPHID(id);
path_array[path_index]->id_isNull = isNull;
}
}
@@ -1422,7 +1431,7 @@ static Datum merge_vertex(cypher_merge_custom_scan_state
*css,
else if (path_array != NULL && path_array[path_index] != NULL)
{
/* retrieve the id of the vertex */
- id = path_array[path_index]->id;
+ id = GRAPHID_GET_DATUM(path_array[path_index]->id);
/*
* Add the Datum to the list of entities for creating the path variable
@@ -1606,10 +1615,11 @@ static void merge_edge(cypher_merge_custom_scan_state
*css,
path_array != NULL &&
path_array[path_index] != NULL)
{
- id = path_array[path_index]->id;
isNull = path_array[path_index]->id_isNull;
- start_id = path_array[path_index]->start_id;
- end_id = path_array[path_index]->end_id;
+ id = isNull ? (Datum) 0 :
+ GRAPHID_GET_DATUM(path_array[path_index]->id);
+ start_id = GRAPHID_GET_DATUM(path_array[path_index]->start_id);
+ end_id = GRAPHID_GET_DATUM(path_array[path_index]->end_id);
}
/*
* Otherwise, we need to get the edge's ID and store its unique values if
@@ -1623,10 +1633,10 @@ static void merge_edge(cypher_merge_custom_scan_state
*css,
if (path_array != NULL && path_array[path_index] != NULL)
{
/* store it */
- path_array[path_index]->id = id;
+ path_array[path_index]->id = isNull ? 0 : DATUM_GET_GRAPHID(id);
path_array[path_index]->id_isNull = isNull;
- path_array[path_index]->start_id = start_id;
- path_array[path_index]->end_id = end_id;
+ path_array[path_index]->start_id = DATUM_GET_GRAPHID(start_id);
+ path_array[path_index]->end_id = DATUM_GET_GRAPHID(end_id);
}
}
else