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 2e2120b5 Fix create_graph failing when ag_catalog is not in 
search_path (#2505)
2e2120b5 is described below

commit 2e2120b5c116a1dd391d9c7331a2865a0b68255f
Author: Himmel <[email protected]>
AuthorDate: Tue Sep 15 04:02:16 2026 +0800

    Fix create_graph failing when ag_catalog is not in search_path (#2505)
    
    create_index_on_column() passed "graphid_ops" as an unqualified operator
    class name, so it was resolved against the caller's search_path. Whenever
    ag_catalog was not on the search_path, creating a label failed with
    
      ERROR:  operator class "graphid_ops" does not exist for access method 
"btree"
    
    even for a fully qualified call such as
    
      SELECT ag_catalog.create_graph('g');
    
    The error is misleading: the operator class does exist, it is simply not
    visible. This affected create_graph(), create_vlabel(), create_elabel(),
    the CSV loader, and label creation from a CREATE or MERGE clause at query
    time, since all of them reach create_label().
    
    The unqualified name arrived with the id column indexes in #2117, so this
    is a regression. Before that commit create_label() built no index and
    resolved no name through the search_path. Every other object referenced by
    the DDL that create_label() generates is already reached either by OID or
    by an ag_catalog qualified name, so qualifying this one restores the
    previous behaviour.
---
 regress/expected/catalog.out          | 52 +++++++++++++++++++++++++++++++++++
 regress/sql/catalog.sql               | 18 ++++++++++++
 src/backend/commands/label_commands.c |  3 +-
 3 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/regress/expected/catalog.out b/regress/expected/catalog.out
index a15fa469..7cf67cda 100644
--- a/regress/expected/catalog.out
+++ b/regress/expected/catalog.out
@@ -607,3 +607,55 @@ NOTICE:  graph "graph" has been dropped
  
 (1 row)
 
+--
+-- create_label() must not resolve graphid_ops through the search_path
+--
+-- Every AGE object is referenced with an ag_catalog qualified name here, so
+-- these statements have to work with ag_catalog off the search_path.
+--
+SET search_path TO public;
+SELECT ag_catalog.create_graph('graphid_ops_search_path');
+NOTICE:  graph "graphid_ops_search_path" has been created
+ create_graph 
+--------------
+ 
+(1 row)
+
+-- vertex labels index id, edge labels index start_id and end_id
+SELECT ag_catalog.create_vlabel('graphid_ops_search_path', 'v');
+NOTICE:  VLabel "v" has been created
+ create_vlabel 
+---------------
+ 
+(1 row)
+
+SELECT ag_catalog.create_elabel('graphid_ops_search_path', 'e');
+NOTICE:  ELabel "e" has been created
+ create_elabel 
+---------------
+ 
+(1 row)
+
+-- label creation at query time goes through the same path
+SELECT * FROM ag_catalog.cypher('graphid_ops_search_path',
+    $$CREATE (:query_time_v)-[:query_time_e]->(:query_time_v)$$)
+  AS (result ag_catalog.agtype);
+ result 
+--------
+(0 rows)
+
+SELECT ag_catalog.drop_graph('graphid_ops_search_path', true);
+NOTICE:  drop cascades to 6 other objects
+DETAIL:  drop cascades to table graphid_ops_search_path._ag_label_vertex
+drop cascades to table graphid_ops_search_path._ag_label_edge
+drop cascades to table graphid_ops_search_path.v
+drop cascades to table graphid_ops_search_path.e
+drop cascades to table graphid_ops_search_path.query_time_v
+drop cascades to table graphid_ops_search_path.query_time_e
+NOTICE:  graph "graphid_ops_search_path" has been dropped
+ drop_graph 
+------------
+ 
+(1 row)
+
+SET search_path TO ag_catalog;
diff --git a/regress/sql/catalog.sql b/regress/sql/catalog.sql
index bb72c349..87a8bf76 100644
--- a/regress/sql/catalog.sql
+++ b/regress/sql/catalog.sql
@@ -235,3 +235,21 @@ SELECT count(*) FROM ag_label;
 -- dropping the graphs
 SELECT drop_graph('issue_2245', true);
 SELECT drop_graph('graph', true);
+
+--
+-- create_label() must not resolve graphid_ops through the search_path
+--
+-- Every AGE object is referenced with an ag_catalog qualified name here, so
+-- these statements have to work with ag_catalog off the search_path.
+--
+SET search_path TO public;
+SELECT ag_catalog.create_graph('graphid_ops_search_path');
+-- vertex labels index id, edge labels index start_id and end_id
+SELECT ag_catalog.create_vlabel('graphid_ops_search_path', 'v');
+SELECT ag_catalog.create_elabel('graphid_ops_search_path', 'e');
+-- label creation at query time goes through the same path
+SELECT * FROM ag_catalog.cypher('graphid_ops_search_path',
+    $$CREATE (:query_time_v)-[:query_time_e]->(:query_time_v)$$)
+  AS (result ag_catalog.agtype);
+SELECT ag_catalog.drop_graph('graphid_ops_search_path', true);
+SET search_path TO ag_catalog;
diff --git a/src/backend/commands/label_commands.c 
b/src/backend/commands/label_commands.c
index bc8d63da..1560ae10 100644
--- a/src/backend/commands/label_commands.c
+++ b/src/backend/commands/label_commands.c
@@ -509,7 +509,8 @@ static void create_index_on_column(char *schema_name,
     index_col->expr = NULL;
     index_col->indexcolname = NULL;
     index_col->collation = NIL;
-    index_col->opclass = list_make1(makeString("graphid_ops"));
+    index_col->opclass = list_make2(makeString("ag_catalog"),
+                                    makeString("graphid_ops"));
     index_col->opclassopts = NIL;
     index_col->ordering = SORTBY_DEFAULT;
     index_col->nulls_ordering = SORTBY_NULLS_DEFAULT;

Reply via email to