This is an automated email from the ASF dual-hosted git repository.

mtaha pushed a commit to branch PG17
in repository https://gitbox.apache.org/repos/asf/age.git

commit afcc7091ef350d1d534e6d33297ca2c70b32cd2d
Author: John Gemignani <[email protected]>
AuthorDate: Wed Nov 19 13:45:44 2025 -0800

    Fix issue 2245 - Creating more than 41 vlabels causes crash in drop_graph 
(#2248)
    
    Fixed issue 2245 - Creating more than 41 vlabels causes drop_grapth to fail
    with "label (relation) cache corrupted" and crashing out on the following
    command.
    
    This was due to corruption of the label_relation_cache during the 
HASH_DELETE
    process.
    
    As the issue was with a cache flush routine, it was necessary to fix them
    all. Here is the list of the flush functions that were fixed -
    
        static void flush_graph_name_cache(void)
        static void flush_graph_namespace_cache(void)
        static void flush_label_name_graph_cache(void)
        static void flush_label_graph_oid_cache(void)
        static void flush_label_relation_cache(void)
        static void flush_label_seq_name_graph_cache(void)
    
    Added regression tests.
    
    modified:   regress/expected/catalog.out
    modified:   regress/sql/catalog.sql
    modified:   src/backend/utils/cache/ag_cache.c
---
 regress/expected/catalog.out       | 141 +++++++++++++++++++++++++++++-
 regress/sql/catalog.sql            |  42 ++++++++-
 src/backend/utils/cache/ag_cache.c | 174 +++++++++++++------------------------
 3 files changed, 241 insertions(+), 116 deletions(-)

diff --git a/regress/expected/catalog.out b/regress/expected/catalog.out
index d06a0ce6..a15fa469 100644
--- a/regress/expected/catalog.out
+++ b/regress/expected/catalog.out
@@ -457,7 +457,146 @@ NOTICE:  graph does not exist
 (1 row)
 
 DROP FUNCTION raise_notice(TEXT);
--- dropping the graph
+--
+-- Fix issue 2245 - Creating more than 41 vlabels causes drop_graph to fail 
with
+--  label (relation) cache corrupted
+--
+-- this result will change if another graph was created prior to this point.
+SELECT count(*) FROM ag_label;
+ count 
+-------
+     2
+(1 row)
+
+SELECT * FROM create_graph('issue_2245');
+NOTICE:  graph "issue_2245" has been created
+ create_graph 
+--------------
+ 
+(1 row)
+
+SELECT * FROM cypher('issue_2245', $$
+  CREATE (a1:Part1 {part_num: '123'}), (a2:Part2 {part_num: '345'}), (a3:Part3 
{part_num: '456'}),
+         (a4:Part4 {part_num: '789'}), (a5:Part5 {part_num: '123'}), (a6:Part6 
{part_num: '345'}),
+         (a7:Part7 {part_num: '456'}), (a8:Part8 {part_num: '789'}), (a9:Part9 
{part_num: '123'}),
+         (a10:Part10 {part_num: '345'}), (a11:Part11 {part_num: '456'}), 
(a12:Part12 {part_num: '789'}),
+         (a13:Part13 {part_num: '123'}), (a14:Part14 {part_num: '345'}), 
(a15:Part15 {part_num: '456'}),
+         (a16:Part16 {part_num: '789'}), (a17:Part17 {part_num: '123'}), 
(a18:Part18 {part_num: '345'}),
+         (a19:Part19 {part_num: '456'}), (a20:Part20 {part_num: '789'}), 
(a21:Part21 {part_num: '123'}),
+         (a22:Part22 {part_num: '345'}), (a23:Part23 {part_num: '456'}), 
(a24:Part24 {part_num: '789'}),
+         (a25:Part25 {part_num: '123'}), (a26:Part26 {part_num: '345'}), 
(a27:Part27 {part_num: '456'}),
+         (a28:Part28 {part_num: '789'}), (a29:Part29 {part_num: '789'}), 
(a30:Part30 {part_num: '123'}),
+         (a31:Part31 {part_num: '345'}), (a32:Part32 {part_num: '456'}), 
(a33:Part33 {part_num: '789'}),
+         (a34:Part34 {part_num: '123'}), (a35:Part35 {part_num: '345'}), 
(a36:Part36 {part_num: '456'}),
+         (a37:Part37 {part_num: '789'}), (a38:Part38 {part_num: '123'}), 
(a39:Part39 {part_num: '345'}),
+         (a40:Part40 {part_num: '456'}), (a41:Part41 {part_num: '789'}), 
(a42:Part42 {part_num: '345'}),
+         (a43:Part43 {part_num: '456'}), (a44:Part44 {part_num: '789'}), 
(a45:Part45 {part_num: '456'}),
+         (a46:Part46 {part_num: '789'}), (a47:Part47 {part_num: '456'}), 
(a48:Part48 {part_num: '789'}),
+         (a49:Part49 {part_num: '789'}), (a50:Part50 {part_num: '456'}), 
(a51:Part51 {part_num: '789'})
+  $$) AS (result agtype);
+ result 
+--------
+(0 rows)
+
+SELECT count(*) FROM ag_label;
+ count 
+-------
+    55
+(1 row)
+
+SELECT drop_graph('issue_2245', true);
+NOTICE:  drop cascades to 53 other objects
+DETAIL:  drop cascades to table issue_2245._ag_label_vertex
+drop cascades to table issue_2245._ag_label_edge
+drop cascades to table issue_2245."Part1"
+drop cascades to table issue_2245."Part2"
+drop cascades to table issue_2245."Part3"
+drop cascades to table issue_2245."Part4"
+drop cascades to table issue_2245."Part5"
+drop cascades to table issue_2245."Part6"
+drop cascades to table issue_2245."Part7"
+drop cascades to table issue_2245."Part8"
+drop cascades to table issue_2245."Part9"
+drop cascades to table issue_2245."Part10"
+drop cascades to table issue_2245."Part11"
+drop cascades to table issue_2245."Part12"
+drop cascades to table issue_2245."Part13"
+drop cascades to table issue_2245."Part14"
+drop cascades to table issue_2245."Part15"
+drop cascades to table issue_2245."Part16"
+drop cascades to table issue_2245."Part17"
+drop cascades to table issue_2245."Part18"
+drop cascades to table issue_2245."Part19"
+drop cascades to table issue_2245."Part20"
+drop cascades to table issue_2245."Part21"
+drop cascades to table issue_2245."Part22"
+drop cascades to table issue_2245."Part23"
+drop cascades to table issue_2245."Part24"
+drop cascades to table issue_2245."Part25"
+drop cascades to table issue_2245."Part26"
+drop cascades to table issue_2245."Part27"
+drop cascades to table issue_2245."Part28"
+drop cascades to table issue_2245."Part29"
+drop cascades to table issue_2245."Part30"
+drop cascades to table issue_2245."Part31"
+drop cascades to table issue_2245."Part32"
+drop cascades to table issue_2245."Part33"
+drop cascades to table issue_2245."Part34"
+drop cascades to table issue_2245."Part35"
+drop cascades to table issue_2245."Part36"
+drop cascades to table issue_2245."Part37"
+drop cascades to table issue_2245."Part38"
+drop cascades to table issue_2245."Part39"
+drop cascades to table issue_2245."Part40"
+drop cascades to table issue_2245."Part41"
+drop cascades to table issue_2245."Part42"
+drop cascades to table issue_2245."Part43"
+drop cascades to table issue_2245."Part44"
+drop cascades to table issue_2245."Part45"
+drop cascades to table issue_2245."Part46"
+drop cascades to table issue_2245."Part47"
+drop cascades to table issue_2245."Part48"
+drop cascades to table issue_2245."Part49"
+drop cascades to table issue_2245."Part50"
+drop cascades to table issue_2245."Part51"
+NOTICE:  graph "issue_2245" has been dropped
+ drop_graph 
+------------
+ 
+(1 row)
+
+-- this result should be the same as the one before the create_graph
+SELECT count(*) FROM ag_label;
+ count 
+-------
+     2
+(1 row)
+
+-- create the graph again
+SELECT * FROM create_graph('issue_2245');
+NOTICE:  graph "issue_2245" has been created
+ create_graph 
+--------------
+ 
+(1 row)
+
+SELECT count(*) FROM ag_label;
+ count 
+-------
+     4
+(1 row)
+
+-- dropping the graphs
+SELECT drop_graph('issue_2245', true);
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table issue_2245._ag_label_vertex
+drop cascades to table issue_2245._ag_label_edge
+NOTICE:  graph "issue_2245" has been dropped
+ drop_graph 
+------------
+ 
+(1 row)
+
 SELECT drop_graph('graph', true);
 NOTICE:  drop cascades to 2 other objects
 DETAIL:  drop cascades to table graph._ag_label_vertex
diff --git a/regress/sql/catalog.sql b/regress/sql/catalog.sql
index 85fc4e8a..bb72c349 100644
--- a/regress/sql/catalog.sql
+++ b/regress/sql/catalog.sql
@@ -193,5 +193,45 @@ SELECT raise_notice('graph1');
 
 DROP FUNCTION raise_notice(TEXT);
 
--- dropping the graph
+--
+-- Fix issue 2245 - Creating more than 41 vlabels causes drop_graph to fail 
with
+--  label (relation) cache corrupted
+--
+
+-- this result will change if another graph was created prior to this point.
+SELECT count(*) FROM ag_label;
+
+SELECT * FROM create_graph('issue_2245');
+SELECT * FROM cypher('issue_2245', $$
+  CREATE (a1:Part1 {part_num: '123'}), (a2:Part2 {part_num: '345'}), (a3:Part3 
{part_num: '456'}),
+         (a4:Part4 {part_num: '789'}), (a5:Part5 {part_num: '123'}), (a6:Part6 
{part_num: '345'}),
+         (a7:Part7 {part_num: '456'}), (a8:Part8 {part_num: '789'}), (a9:Part9 
{part_num: '123'}),
+         (a10:Part10 {part_num: '345'}), (a11:Part11 {part_num: '456'}), 
(a12:Part12 {part_num: '789'}),
+         (a13:Part13 {part_num: '123'}), (a14:Part14 {part_num: '345'}), 
(a15:Part15 {part_num: '456'}),
+         (a16:Part16 {part_num: '789'}), (a17:Part17 {part_num: '123'}), 
(a18:Part18 {part_num: '345'}),
+         (a19:Part19 {part_num: '456'}), (a20:Part20 {part_num: '789'}), 
(a21:Part21 {part_num: '123'}),
+         (a22:Part22 {part_num: '345'}), (a23:Part23 {part_num: '456'}), 
(a24:Part24 {part_num: '789'}),
+         (a25:Part25 {part_num: '123'}), (a26:Part26 {part_num: '345'}), 
(a27:Part27 {part_num: '456'}),
+         (a28:Part28 {part_num: '789'}), (a29:Part29 {part_num: '789'}), 
(a30:Part30 {part_num: '123'}),
+         (a31:Part31 {part_num: '345'}), (a32:Part32 {part_num: '456'}), 
(a33:Part33 {part_num: '789'}),
+         (a34:Part34 {part_num: '123'}), (a35:Part35 {part_num: '345'}), 
(a36:Part36 {part_num: '456'}),
+         (a37:Part37 {part_num: '789'}), (a38:Part38 {part_num: '123'}), 
(a39:Part39 {part_num: '345'}),
+         (a40:Part40 {part_num: '456'}), (a41:Part41 {part_num: '789'}), 
(a42:Part42 {part_num: '345'}),
+         (a43:Part43 {part_num: '456'}), (a44:Part44 {part_num: '789'}), 
(a45:Part45 {part_num: '456'}),
+         (a46:Part46 {part_num: '789'}), (a47:Part47 {part_num: '456'}), 
(a48:Part48 {part_num: '789'}),
+         (a49:Part49 {part_num: '789'}), (a50:Part50 {part_num: '456'}), 
(a51:Part51 {part_num: '789'})
+  $$) AS (result agtype);
+
+SELECT count(*) FROM ag_label;
+SELECT drop_graph('issue_2245', true);
+
+-- this result should be the same as the one before the create_graph
+SELECT count(*) FROM ag_label;
+
+-- create the graph again
+SELECT * FROM create_graph('issue_2245');
+SELECT count(*) FROM ag_label;
+
+-- dropping the graphs
+SELECT drop_graph('issue_2245', true);
 SELECT drop_graph('graph', true);
diff --git a/src/backend/utils/cache/ag_cache.c 
b/src/backend/utils/cache/ag_cache.c
index e3c4d079..493ffcfa 100644
--- a/src/backend/utils/cache/ag_cache.c
+++ b/src/backend/utils/cache/ag_cache.c
@@ -286,52 +286,34 @@ static void invalidate_graph_caches(Datum arg, int 
cache_id, uint32 hash_value)
 
 static void flush_graph_name_cache(void)
 {
-    HASH_SEQ_STATUS hash_seq;
-
-    hash_seq_init(&hash_seq, graph_name_cache_hash);
-    for (;;)
+    /*
+     * If the graph_name_cache exists, destroy it. This will avoid any
+     * potential corruption issues.
+     */
+    if (graph_name_cache_hash)
     {
-        graph_name_cache_entry *entry;
-        void *removed;
-
-        entry = hash_seq_search(&hash_seq);
-        if (!entry)
-        {
-            break;
-        }
-        removed = hash_search(graph_name_cache_hash, &entry->name, HASH_REMOVE,
-                              NULL);
-        if (!removed)
-        {
-            ereport(ERROR, (errmsg_internal("graph (name) cache corrupted")));
-        }
+        hash_destroy(graph_name_cache_hash);
+        graph_name_cache_hash = NULL;
     }
+
+    /* recreate the graph_name_cache */
+    create_graph_name_cache();
 }
 
 static void flush_graph_namespace_cache(void)
 {
-    HASH_SEQ_STATUS hash_seq;
-
-    hash_seq_init(&hash_seq, graph_namespace_cache_hash);
-    for (;;)
+    /*
+     * If the graph_namespace_cache exists, destroy it. This will avoid any
+     * potential corruption issues.
+     */
+    if (graph_namespace_cache_hash)
     {
-        graph_namespace_cache_entry *entry;
-        void *removed;
-
-        entry = hash_seq_search(&hash_seq);
-        if (!entry)
-        {
-            break;
-        }
-
-        removed = hash_search(graph_namespace_cache_hash, &entry->namespace,
-                              HASH_REMOVE, NULL);
-        if (!removed)
-        {
-            ereport(ERROR,
-                    (errmsg_internal("graph (namespace) cache corrupted")));
-        }
+        hash_destroy(graph_namespace_cache_hash);
+        graph_namespace_cache_hash = NULL;
     }
+
+    /* recreate the graph_namespace_cache */
+    create_graph_namespace_cache();
 }
 
 graph_cache_data *search_graph_name_cache(const char *name)
@@ -664,27 +646,18 @@ static void invalidate_label_name_graph_cache(Oid relid)
 
 static void flush_label_name_graph_cache(void)
 {
-    HASH_SEQ_STATUS hash_seq;
-
-    hash_seq_init(&hash_seq, label_name_graph_cache_hash);
-    for (;;)
+    /*
+     * If the label_name_graph_cache exists, destroy it. This will avoid any
+     * potential corruption issues.
+     */
+    if (label_name_graph_cache_hash)
     {
-        label_name_graph_cache_entry *entry;
-        void *removed;
-
-        entry = hash_seq_search(&hash_seq);
-        if (!entry)
-        {
-            break;
-        }
-        removed = hash_search(label_name_graph_cache_hash, &entry->key,
-                              HASH_REMOVE, NULL);
-        if (!removed)
-        {
-            ereport(ERROR,
-                    (errmsg_internal("label (name, graph) cache corrupted")));
-        }
+        hash_destroy(label_name_graph_cache_hash);
+        label_name_graph_cache_hash = NULL;
     }
+
+    /* recreate the label_name_graph_cache */
+    create_label_name_graph_cache();
 }
 
 static void invalidate_label_graph_oid_cache(Oid relid)
@@ -722,27 +695,18 @@ static void invalidate_label_graph_oid_cache(Oid relid)
 
 static void flush_label_graph_oid_cache(void)
 {
-    HASH_SEQ_STATUS hash_seq;
-
-    hash_seq_init(&hash_seq, label_graph_oid_cache_hash);
-    for (;;)
+    /*
+     * If the label_graph_oid_cache exists, destroy it. This will avoid any
+     * potential corruption issues.
+     */
+    if (label_graph_oid_cache_hash)
     {
-        label_graph_oid_cache_entry *entry;
-        void *removed;
-
-        entry = hash_seq_search(&hash_seq);
-        if (!entry)
-        {
-            break;
-        }
-        removed = hash_search(label_graph_oid_cache_hash, &entry->key,
-                              HASH_REMOVE, NULL);
-        if (!removed)
-        {
-            ereport(ERROR,
-                    (errmsg_internal("label (graph, id) cache corrupted")));
-        }
+        hash_destroy(label_graph_oid_cache_hash);
+        label_graph_oid_cache_hash = NULL;
     }
+
+    /* recreate the label_graph_oid_cache */
+    create_label_graph_oid_cache();
 }
 
 static void invalidate_label_relation_cache(Oid relid)
@@ -765,27 +729,18 @@ static void invalidate_label_relation_cache(Oid relid)
 
 static void flush_label_relation_cache(void)
 {
-    HASH_SEQ_STATUS hash_seq;
-
-    hash_seq_init(&hash_seq, label_relation_cache_hash);
-    for (;;)
+    /*
+     * If the label_relation_cache exists, destroy it. This will avoid any
+     * potential corruption issues.
+     */
+    if (label_relation_cache_hash)
     {
-        label_relation_cache_entry *entry;
-        void *removed;
-
-        entry = hash_seq_search(&hash_seq);
-        if (!entry)
-        {
-            break;
-        }
-        removed = hash_search(label_relation_cache_hash, &entry->relation,
-                              HASH_REMOVE, NULL);
-        if (!removed)
-        {
-            ereport(ERROR,
-                    (errmsg_internal("label (relation) cache corrupted")));
-        }
+        hash_destroy(label_relation_cache_hash);
+        label_relation_cache_hash = NULL;
     }
+
+    /* recreate the label_relation_cache */
+    create_label_relation_cache();
 }
 
 static void invalidate_label_seq_name_graph_cache(Oid relid)
@@ -823,27 +778,18 @@ static void invalidate_label_seq_name_graph_cache(Oid 
relid)
 
 static void flush_label_seq_name_graph_cache(void)
 {
-    HASH_SEQ_STATUS hash_seq;
-
-    hash_seq_init(&hash_seq, label_seq_name_graph_cache_hash);
-    for (;;)
+    /*
+     * If the label_seq_name_graph_cache exists, destroy it. This will
+     * avoid any potential corruption issues by deleting entries.
+     */
+    if (label_seq_name_graph_cache_hash)
     {
-        label_seq_name_graph_cache_entry *entry;
-        void *removed;
-
-        entry = hash_seq_search(&hash_seq);
-        if (!entry)
-        {
-            break;
-        }
-        removed = hash_search(label_seq_name_graph_cache_hash, &entry->key,
-                              HASH_REMOVE, NULL);
-        if (!removed)
-        {
-            ereport(ERROR,
-                    (errmsg_internal("label (seq_name, graph) cache 
corrupted")));
-        }
+        hash_destroy(label_seq_name_graph_cache_hash);
+        label_seq_name_graph_cache_hash = NULL;
     }
+
+    /* recreate the label_seq_name_graph_cache */
+    create_label_seq_name_graph_cache();
 }
 
 label_cache_data *search_label_name_graph_cache(const char *name, Oid graph)

Reply via email to