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

Reply via email to