You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@age.apache.org by ak...@apache.org on 2022/12/12 21:06:32 UTC

[age] branch master updated: create complete graph function (#342)

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

ako 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 dc5895e  create complete graph function (#342)
dc5895e is described below

commit dc5895ed0b6215ac29e15e66686de41af80a1538
Author: Utkarsh Kansal <u_...@yahoo.com>
AuthorDate: Mon Dec 12 13:06:26 2022 -0800

    create complete graph function (#342)
    
    * create complete graph function
    
    * fix get_label_name
    
    * add regression tests
---
 Makefile                              |   3 +
 age--1.1.0.sql                        |  13 ++-
 regress/expected/graph_generation.out | 111 +++++++++++++++++++
 regress/sql/graph_generation.sql      |  47 ++++++++
 src/backend/catalog/ag_label.c        |  10 +-
 src/backend/commands/label_commands.c |   2 +-
 src/backend/utils/adt/agtype.c        |   2 +-
 src/backend/utils/cache/ag_cache.c    | 196 ++++++++++++++++++++++++++++++++
 src/backend/utils/graph_generation.c  | 203 ++++++++++++++++++++++++++++++++++
 src/backend/utils/load/age_load.c     |   2 +-
 src/include/catalog/ag_label.h        |   8 +-
 src/include/commands/graph_commands.h |  27 +++++
 src/include/commands/label_commands.h |   5 +
 src/include/utils/ag_cache.h          |   2 +
 src/include/utils/load/age_load.h     |   2 +
 15 files changed, 625 insertions(+), 8 deletions(-)

diff --git a/Makefile b/Makefile
index da84c31..e6024d6 100644
--- a/Makefile
+++ b/Makefile
@@ -63,6 +63,7 @@ OBJS = src/backend/age.o \
        src/backend/utils/adt/ag_float8_supp.o \
        src/backend/utils/adt/graphid.o \
        src/backend/utils/ag_func.o \
+       src/backend/utils/graph_generation.o \
        src/backend/utils/cache/ag_cache.o \
        src/backend/utils/load/ag_load_labels.o \
        src/backend/utils/load/ag_load_edges.o \
@@ -95,7 +96,9 @@ REGRESS = scan \
           age_load \
           index \
           analyze \
+          graph_generation \
           drop
+          
 
 srcdir=`pwd`
 
diff --git a/age--1.1.0.sql b/age--1.1.0.sql
index 6fe30ad..e2a5e83 100644
--- a/age--1.1.0.sql
+++ b/age--1.1.0.sql
@@ -47,7 +47,8 @@ CREATE TABLE ag_label (
   graph oid NOT NULL,
   id label_id,
   kind label_kind,
-  relation regclass NOT NULL
+  relation regclass NOT NULL,
+  seq_name name NOT NULL
 ) WITH (OIDS);
 
 CREATE UNIQUE INDEX ag_label_oid_index ON ag_label USING btree (oid);
@@ -62,6 +63,9 @@ USING btree (graph, id);
 
 CREATE UNIQUE INDEX ag_label_relation_index ON ag_label USING btree (relation);
 
+CREATE UNIQUE INDEX ag_label_seq_name_graph_index
+ON ag_label
+USING btree (seq_name, graph);
 --
 -- catalog lookup functions
 --
@@ -4157,6 +4161,13 @@ STABLE
 PARALLEL SAFE
 AS 'MODULE_PATHNAME';
 
+CREATE FUNCTION ag_catalog.create_complete_graph(graph_name name, nodes int, edge_label name, node_label name = NULL)
+RETURNS void
+LANGUAGE c
+CALLED ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
 CREATE FUNCTION ag_catalog.age_prepare_cypher(cstring, cstring)
 RETURNS boolean
 LANGUAGE c
diff --git a/regress/expected/graph_generation.out b/regress/expected/graph_generation.out
new file mode 100644
index 0000000..118ab6e
--- /dev/null
+++ b/regress/expected/graph_generation.out
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+LOAD 'age';
+SET search_path = ag_catalog;
+SELECT * FROM create_complete_graph('gp1',5,'edges','vertices');
+NOTICE:  graph "gp1" has been created
+NOTICE:  VLabel "vertices" has been created
+NOTICE:  ELabel "edges" has been created
+ create_complete_graph 
+-----------------------
+ 
+(1 row)
+
+SELECT COUNT(*) FROM gp1."edges";
+ count 
+-------
+    10
+(1 row)
+
+SELECT COUNT(*) FROM gp1."vertices";
+ count 
+-------
+     5
+(1 row)
+
+SELECT * FROM cypher('gp1', $$MATCH (a)-[e]->(b) RETURN e$$) as (n agtype);
+                                                             n                                                              
+----------------------------------------------------------------------------------------------------------------------------
+ {"id": 1125899906842625, "label": "edges", "end_id": 844424930131970, "start_id": 844424930131969, "properties": {}}::edge
+ {"id": 1125899906842629, "label": "edges", "end_id": 844424930131971, "start_id": 844424930131970, "properties": {}}::edge
+ {"id": 1125899906842626, "label": "edges", "end_id": 844424930131971, "start_id": 844424930131969, "properties": {}}::edge
+ {"id": 1125899906842630, "label": "edges", "end_id": 844424930131972, "start_id": 844424930131970, "properties": {}}::edge
+ {"id": 1125899906842627, "label": "edges", "end_id": 844424930131972, "start_id": 844424930131969, "properties": {}}::edge
+ {"id": 1125899906842632, "label": "edges", "end_id": 844424930131972, "start_id": 844424930131971, "properties": {}}::edge
+ {"id": 1125899906842631, "label": "edges", "end_id": 844424930131973, "start_id": 844424930131970, "properties": {}}::edge
+ {"id": 1125899906842634, "label": "edges", "end_id": 844424930131973, "start_id": 844424930131972, "properties": {}}::edge
+ {"id": 1125899906842633, "label": "edges", "end_id": 844424930131973, "start_id": 844424930131971, "properties": {}}::edge
+ {"id": 1125899906842628, "label": "edges", "end_id": 844424930131973, "start_id": 844424930131969, "properties": {}}::edge
+(10 rows)
+
+SELECT * FROM create_complete_graph('gp1',5,'edges','vertices');
+ create_complete_graph 
+-----------------------
+ 
+(1 row)
+
+SELECT COUNT(*) FROM gp1."edges";
+ count 
+-------
+    20
+(1 row)
+
+SELECT COUNT(*) FROM gp1."vertices";
+ count 
+-------
+    10
+(1 row)
+
+SELECT * FROM create_complete_graph('gp2',5,'edges');
+NOTICE:  graph "gp2" has been created
+NOTICE:  ELabel "edges" has been created
+ create_complete_graph 
+-----------------------
+ 
+(1 row)
+
+SELECT * FROM create_complete_graph('gp3',5, NULL);
+ERROR:  edge label can not be NULL
+SELECT * FROM create_complete_graph('gp4',NULL,NULL);
+ERROR:  number of nodes can not be NULL
+SELECT * FROM create_complete_graph(NULL,NULL,NULL);
+ERROR:  graph name can not be NULL
+SELECT drop_graph('gp1', true);
+NOTICE:  drop cascades to 4 other objects
+DETAIL:  drop cascades to table gp1._ag_label_vertex
+drop cascades to table gp1._ag_label_edge
+drop cascades to table gp1.vertices
+drop cascades to table gp1.edges
+NOTICE:  graph "gp1" has been dropped
+ drop_graph 
+------------
+ 
+(1 row)
+
+SELECT drop_graph('gp2', true);
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to table gp2._ag_label_vertex
+drop cascades to table gp2._ag_label_edge
+drop cascades to table gp2.edges
+NOTICE:  graph "gp2" has been dropped
+ drop_graph 
+------------
+ 
+(1 row)
+
diff --git a/regress/sql/graph_generation.sql b/regress/sql/graph_generation.sql
new file mode 100644
index 0000000..1ad90f5
--- /dev/null
+++ b/regress/sql/graph_generation.sql
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+LOAD 'age';
+
+SET search_path = ag_catalog;
+
+SELECT * FROM create_complete_graph('gp1',5,'edges','vertices');
+
+SELECT COUNT(*) FROM gp1."edges";
+SELECT COUNT(*) FROM gp1."vertices";
+
+SELECT * FROM cypher('gp1', $$MATCH (a)-[e]->(b) RETURN e$$) as (n agtype);
+
+SELECT * FROM create_complete_graph('gp1',5,'edges','vertices');
+
+SELECT COUNT(*) FROM gp1."edges";
+SELECT COUNT(*) FROM gp1."vertices";
+
+SELECT * FROM create_complete_graph('gp2',5,'edges');
+
+SELECT * FROM create_complete_graph('gp3',5, NULL);
+
+SELECT * FROM create_complete_graph('gp4',NULL,NULL);
+
+SELECT * FROM create_complete_graph(NULL,NULL,NULL);
+
+SELECT drop_graph('gp1', true);
+SELECT drop_graph('gp2', true);
+
diff --git a/src/backend/catalog/ag_label.c b/src/backend/catalog/ag_label.c
index 8001f53..cd8d0ba 100644
--- a/src/backend/catalog/ag_label.c
+++ b/src/backend/catalog/ag_label.c
@@ -44,11 +44,12 @@
 #include "utils/graphid.h"
 
 // INSERT INTO ag_catalog.ag_label
-// VALUES (label_name, label_graph, label_id, label_kind, label_relation)
+// VALUES (label_name, label_graph, label_id, label_kind, label_relation, seq_name)
 Oid insert_label(const char *label_name, Oid label_graph, int32 label_id,
-                 char label_kind, Oid label_relation)
+                 char label_kind, Oid label_relation, const char *seq_name)
 {
     NameData label_name_data;
+    NameData seq_name_data;
     Datum values[Natts_ag_label];
     bool nulls[Natts_ag_label];
     Relation ag_label;
@@ -65,6 +66,7 @@ Oid insert_label(const char *label_name, Oid label_graph, int32 label_id,
     AssertArg(label_kind == LABEL_KIND_VERTEX ||
               label_kind == LABEL_KIND_EDGE);
     AssertArg(OidIsValid(label_relation));
+    AssertArg(seq_name);
 
     namestrcpy(&label_name_data, label_name);
     values[Anum_ag_label_name - 1] = NameGetDatum(&label_name_data);
@@ -82,6 +84,10 @@ Oid insert_label(const char *label_name, Oid label_graph, int32 label_id,
     values[Anum_ag_label_relation - 1] = ObjectIdGetDatum(label_relation);
     nulls[Anum_ag_label_relation - 1] = false;
 
+    namestrcpy(&seq_name_data, seq_name);
+    values[Anum_ag_label_seq_name - 1] = NameGetDatum(&seq_name_data);
+    nulls[Anum_ag_label_seq_name - 1] = false;
+
     ag_label = heap_open(ag_label_relation_id(), RowExclusiveLock);
 
     tuple = heap_form_tuple(RelationGetDescr(ag_label), values, nulls);
diff --git a/src/backend/commands/label_commands.c b/src/backend/commands/label_commands.c
index 66b6818..02bf574 100644
--- a/src/backend/commands/label_commands.c
+++ b/src/backend/commands/label_commands.c
@@ -308,7 +308,7 @@ Oid create_label(char *graph_name, char *label_name, char label_type,
     label_id = get_new_label_id(graph_oid, nsp_id);
 
     label_oid = insert_label(label_name, graph_oid, label_id, label_type,
-                             relation_id);
+                             relation_id,seq_name);
 
     CommandCounterIncrement();
 
diff --git a/src/backend/utils/adt/agtype.c b/src/backend/utils/adt/agtype.c
index 908f388..6c1a500 100644
--- a/src/backend/utils/adt/agtype.c
+++ b/src/backend/utils/adt/agtype.c
@@ -4526,7 +4526,7 @@ static char *get_label_name(const char *graph_name, int64 graphid)
     tupdesc = RelationGetDescr(ag_label);
 
     /* bail if the number of columns differs */
-    if (tupdesc->natts != 5)
+    if (tupdesc->natts != 6)
         ereport(ERROR,
                 (errcode(ERRCODE_UNDEFINED_TABLE),
                  errmsg("Invalid number of attributes for ag_catalog.ag_label")));
diff --git a/src/backend/utils/cache/ag_cache.c b/src/backend/utils/cache/ag_cache.c
index ec34355..95e5d0d 100644
--- a/src/backend/utils/cache/ag_cache.c
+++ b/src/backend/utils/cache/ag_cache.c
@@ -87,6 +87,18 @@ typedef struct label_relation_cache_entry
     label_cache_data data;
 } label_relation_cache_entry;
 
+typedef struct label_seq_name_graph_cache_key
+{
+    NameData name;
+    Oid graph;
+} label_seq_name_graph_cache_key;
+
+typedef struct label_seq_name_graph_cache_entry
+{
+    label_seq_name_graph_cache_key key; // hash key
+    label_cache_data data;
+} label_seq_name_graph_cache_entry;
+
 // ag_graph.name
 static HTAB *graph_name_cache_hash = NULL;
 static ScanKeyData graph_name_scan_keys[1];
@@ -111,6 +123,10 @@ static ScanKeyData label_graph_id_scan_keys[2];
 static HTAB *label_relation_cache_hash = NULL;
 static ScanKeyData label_relation_scan_keys[1];
 
+// ag_label.seq_name, ag_label.graph
+static HTAB *label_seq_name_graph_cache_hash = NULL;
+static ScanKeyData label_seq_name_graph_scan_keys[2];
+
 // initialize all caches
 static void initialize_caches(void);
 
@@ -140,6 +156,7 @@ static void create_label_oid_cache(void);
 static void create_label_name_graph_cache(void);
 static void create_label_graph_id_cache(void);
 static void create_label_relation_cache(void);
+static void create_label_seq_name_graph_cache(void);
 static void invalidate_label_caches(Datum arg, Oid relid);
 static void invalidate_label_oid_cache(Oid relid);
 static void flush_label_oid_cache(void);
@@ -149,6 +166,9 @@ static void invalidate_label_graph_id_cache(Oid relid);
 static void flush_label_graph_id_cache(void);
 static void invalidate_label_relation_cache(Oid relid);
 static void flush_label_relation_cache(void);
+static void invalidate_label_seq_name_graph_cache(Oid relid);
+static void flush_label_seq_name_graph_cache(void);
+
 static label_cache_data *search_label_oid_cache_miss(Oid oid);
 static label_cache_data *search_label_name_graph_cache_miss(Name name,
                                                             Oid graph);
@@ -159,6 +179,12 @@ static label_cache_data *search_label_graph_id_cache_miss(Oid graph, int32 id);
 static void *label_graph_id_cache_hash_search(Oid graph, int32 id,
                                               HASHACTION action, bool *found);
 static label_cache_data *search_label_relation_cache_miss(Oid relation);
+static label_cache_data *search_label_seq_name_graph_cache_miss(Name name,
+                                                            Oid graph);
+static void *label_seq_name_graph_cache_hash_search(Name name, Oid graph,
+                                                HASHACTION action,
+                                                bool *found);
+
 static void fill_label_cache_data(label_cache_data *cache_data,
                                   HeapTuple tuple, TupleDesc tuple_desc);
 
@@ -486,6 +512,12 @@ static void initialize_label_caches(void)
     // ag_label.relation
     ag_cache_scan_key_init(&label_relation_scan_keys[0],
                            Anum_ag_label_relation, F_OIDEQ);
+    
+    // ag_label.seq_name, ag_label.graph
+    ag_cache_scan_key_init(&label_seq_name_graph_scan_keys[0], Anum_ag_label_seq_name,
+                           F_NAMEEQ);
+    ag_cache_scan_key_init(&label_seq_name_graph_scan_keys[1], Anum_ag_label_graph,
+                           F_OIDEQ);
 
     create_label_caches();
 
@@ -506,6 +538,8 @@ static void create_label_caches(void)
     create_label_name_graph_cache();
     create_label_graph_id_cache();
     create_label_relation_cache();
+    create_label_seq_name_graph_cache();
+
 }
 
 static void create_label_oid_cache(void)
@@ -578,9 +612,28 @@ static void create_label_relation_cache(void)
                                             &hash_ctl, HASH_ELEM | HASH_BLOBS);
 }
 
+static void create_label_seq_name_graph_cache(void)
+{
+    HASHCTL hash_ctl;
+
+    MemSet(&hash_ctl, 0, sizeof(hash_ctl));
+    hash_ctl.keysize = sizeof(label_seq_name_graph_cache_key);
+    hash_ctl.entrysize = sizeof(label_seq_name_graph_cache_entry);
+
+    /*
+     * Please see the comment of hash_create() for the nelem value 16 here.
+     * HASH_BLOBS flag is set because the key for this hash is fixed-size.
+     */
+    label_seq_name_graph_cache_hash = hash_create("ag_label (seq_name, graph) cache",
+                                              16, &hash_ctl,
+                                              HASH_ELEM | HASH_BLOBS);
+}
+
 static void invalidate_label_caches(Datum arg, Oid relid)
 {
     Assert(label_name_graph_cache_hash);
+    Assert(label_seq_name_graph_cache_hash);
+
 
     if (OidIsValid(relid))
     {
@@ -588,6 +641,7 @@ static void invalidate_label_caches(Datum arg, Oid relid)
         invalidate_label_name_graph_cache(relid);
         invalidate_label_graph_id_cache(relid);
         invalidate_label_relation_cache(relid);
+        invalidate_label_seq_name_graph_cache(relid);
     }
     else
     {
@@ -595,6 +649,7 @@ static void invalidate_label_caches(Datum arg, Oid relid)
         flush_label_name_graph_cache();
         flush_label_graph_id_cache();
         flush_label_relation_cache();
+        flush_label_seq_name_graph_cache();
     }
 }
 
@@ -802,6 +857,61 @@ static void flush_label_relation_cache(void)
     }
 }
 
+static void invalidate_label_seq_name_graph_cache(Oid relid)
+{
+    HASH_SEQ_STATUS hash_seq;
+
+    hash_seq_init(&hash_seq, label_seq_name_graph_cache_hash);
+    for (;;)
+    {
+        label_seq_name_graph_cache_entry *entry;
+        void *removed;
+
+        entry = hash_seq_search(&hash_seq);
+        if (!entry)
+            break;
+
+        if (entry->data.relation != relid)
+            continue;
+
+        removed = hash_search(label_seq_name_graph_cache_hash, &entry->key,
+                              HASH_REMOVE, NULL);
+        hash_seq_term(&hash_seq);
+
+        if (!removed)
+        {
+            ereport(ERROR,
+                    (errmsg_internal("label (seq_name, graph) cache corrupted")));
+        }
+
+        break;
+    }
+}
+
+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 (;;)
+    {
+        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")));
+        }
+    }
+}
+
 label_cache_data *search_label_oid_cache(Oid oid)
 {
     label_cache_data *entry;
@@ -1080,6 +1190,88 @@ static label_cache_data *search_label_relation_cache_miss(Oid relation)
     return entry;
 }
 
+label_cache_data *search_label_seq_name_graph_cache(const char *name, Oid graph)
+{
+    NameData name_key;
+    label_seq_name_graph_cache_entry *entry;
+
+    AssertArg(name);
+    AssertArg(OidIsValid(graph));
+
+    initialize_caches();
+
+    namestrcpy(&name_key, name);
+    entry = label_seq_name_graph_cache_hash_search(&name_key, graph, HASH_FIND,
+                                               NULL);
+    if (entry)
+        return &entry->data;
+
+    return search_label_seq_name_graph_cache_miss(&name_key, graph);
+}
+
+static label_cache_data *search_label_seq_name_graph_cache_miss(Name name,
+                                                            Oid graph)
+{
+    ScanKeyData scan_keys[2];
+    Relation ag_label;
+    SysScanDesc scan_desc;
+    HeapTuple tuple;
+    bool found;
+    label_seq_name_graph_cache_entry *entry;
+
+    memcpy(scan_keys, label_seq_name_graph_scan_keys,
+           sizeof(label_seq_name_graph_scan_keys));
+    scan_keys[0].sk_argument = NameGetDatum(name);
+    scan_keys[1].sk_argument = ObjectIdGetDatum(graph);
+
+    /*
+     * Calling heap_open() might call AcceptInvalidationMessage() and that
+     * might invalidate the label caches. This is OK because this function is
+     * called when the desired entry is not in the cache.
+     */
+    ag_label = heap_open(ag_label_relation_id(), AccessShareLock);
+    scan_desc = systable_beginscan(ag_label, ag_label_seq_name_graph_index_id(),
+                                   true, NULL, 2, scan_keys);
+
+    /*
+     * don't need to loop over scan_desc because ag_label_seq_name_graph_index is
+     * UNIQUE
+     */
+    tuple = systable_getnext(scan_desc);
+    if (!HeapTupleIsValid(tuple))
+    {
+        systable_endscan(scan_desc);
+        heap_close(ag_label, AccessShareLock);
+
+        return NULL;
+    }
+
+    // get a new entry
+    entry = label_seq_name_graph_cache_hash_search(name, graph, HASH_ENTER,
+                                               &found);
+    Assert(!found); // no concurrent update on label_seq_name_graph_cache_hash
+
+    // fill the new entry with the retrieved tuple
+    fill_label_cache_data(&entry->data, tuple, RelationGetDescr(ag_label));
+
+    systable_endscan(scan_desc);
+    heap_close(ag_label, AccessShareLock);
+
+    return &entry->data;
+}
+
+static void *label_seq_name_graph_cache_hash_search(Name name, Oid graph,
+                                                HASHACTION action, bool *found)
+{
+    label_seq_name_graph_cache_key key;
+
+    // initialize the hash key for label_seq_name_graph_cache_hash
+    namecpy(&key.name, name);
+    key.graph = graph;
+
+    return hash_search(label_seq_name_graph_cache_hash, &key, action, found);
+}
+
 static void fill_label_cache_data(label_cache_data *cache_data,
                                   HeapTuple tuple, TupleDesc tuple_desc)
 {
@@ -1110,4 +1302,8 @@ static void fill_label_cache_data(label_cache_data *cache_data,
     value = heap_getattr(tuple, Anum_ag_label_relation, tuple_desc, &is_null);
     Assert(!is_null);
     cache_data->relation = DatumGetObjectId(value);
+    // ag_label.seq_name
+    value = heap_getattr(tuple, Anum_ag_label_seq_name, tuple_desc, &is_null);
+    Assert(!is_null);
+    namecpy(&cache_data->seq_name, DatumGetName(value));
 }
diff --git a/src/backend/utils/graph_generation.c b/src/backend/utils/graph_generation.c
new file mode 100644
index 0000000..49da5f8
--- /dev/null
+++ b/src/backend/utils/graph_generation.c
@@ -0,0 +1,203 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "postgres.h"
+
+#include "access/xact.h"
+#include "access/genam.h"
+#include "access/heapam.h"
+#include "catalog/dependency.h"
+#include "catalog/objectaddress.h"
+#include "commands/defrem.h"
+#include "commands/schemacmds.h"
+#include "commands/tablecmds.h"
+#include "fmgr.h"
+#include "miscadmin.h"
+#include "nodes/makefuncs.h"
+#include "nodes/nodes.h"
+#include "nodes/parsenodes.h"
+#include "nodes/pg_list.h"
+#include "nodes/value.h"
+#include "parser/parser.h"
+#include "utils/fmgroids.h"
+#include "utils/relcache.h"
+#include "utils/rel.h"
+
+#include "catalog/ag_graph.h"
+#include "catalog/ag_label.h"
+#include "commands/label_commands.h"
+#include "utils/graphid.h"
+#include "commands/graph_commands.h"
+#include "utils/load/age_load.h"
+#include "utils/load/ag_load_edges.h"
+#include "utils/load/ag_load_labels.h"
+
+
+PG_FUNCTION_INFO_V1(create_complete_graph);
+
+/*
+* SELECT * FROM ag_catalog.create_complete_graph('graph_name',no_of_nodes, 'edge_label', 'node_label'=NULL);
+*/
+
+Datum create_complete_graph(PG_FUNCTION_ARGS)
+{   
+    Oid graph_id;
+    Name graph_name;
+
+    int64 no_vertices;
+    int64 i,j,vid = 1, eid, start_vid, end_vid;
+
+    Name vtx_label_name = NULL;
+    Name edge_label_name;
+    int32 vtx_label_id;
+    int32 edge_label_id;
+
+    agtype *props = NULL;
+    graphid object_graph_id;
+    graphid start_vertex_graph_id;
+    graphid end_vertex_graph_id;
+
+    Oid vtx_seq_id;
+    Oid edge_seq_id;
+
+    char* graph_name_str;
+    char* vtx_name_str;
+    char* edge_name_str;
+
+    graph_cache_data *graph_cache;
+    label_cache_data *vertex_cache;
+    label_cache_data *edge_cache;
+
+    Oid nsp_id;
+    Name vtx_seq_name;
+    char *vtx_seq_name_str;
+
+    Name edge_seq_name;
+    char *edge_seq_name_str;
+
+    int64 lid; 
+
+    if (PG_ARGISNULL(0))
+    {
+        ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                        errmsg("graph name can not be NULL")));
+    }
+
+    if (PG_ARGISNULL(1))
+    {
+        ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                errmsg("number of nodes can not be NULL")));
+    }
+    
+    if (PG_ARGISNULL(2))
+    {
+        ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                errmsg("edge label can not be NULL")));
+    }
+
+
+    graph_name = PG_GETARG_NAME(0);
+    no_vertices = (int64) PG_GETARG_INT64(1);
+    edge_label_name = PG_GETARG_NAME(2);
+    namestrcpy(vtx_label_name, AG_DEFAULT_LABEL_VERTEX);
+
+    graph_name_str = NameStr(*graph_name);
+    vtx_name_str = AG_DEFAULT_LABEL_VERTEX;
+    edge_name_str = NameStr(*edge_label_name);
+
+
+    if (!graph_exists(graph_name_str))
+    {
+        DirectFunctionCall1(create_graph, CStringGetDatum(graph_name));
+
+    }
+
+    graph_id = get_graph_oid(graph_name_str);
+
+    
+    
+    if (!PG_ARGISNULL(3))
+    {
+        vtx_label_name = PG_GETARG_NAME(3);
+        vtx_name_str = NameStr(*vtx_label_name);
+        // Check if label with the input name already exists
+        if (!label_exists(vtx_name_str, graph_id))
+        {
+            DirectFunctionCall2(create_vlabel, CStringGetDatum(graph_name), CStringGetDatum(vtx_label_name));
+        }
+    }
+
+    if (!label_exists(edge_name_str, graph_id))
+    {
+        DirectFunctionCall2(create_elabel, CStringGetDatum(graph_name), CStringGetDatum(edge_label_name));   
+    }
+
+    vtx_label_id = get_label_id(vtx_name_str, graph_id);
+    edge_label_id = get_label_id(edge_name_str, graph_id);
+
+    graph_cache = search_graph_name_cache(graph_name_str);
+    vertex_cache = search_label_name_graph_cache(vtx_name_str,graph_id);
+    edge_cache = search_label_name_graph_cache(edge_name_str,graph_id);
+
+    nsp_id = graph_cache->namespace;
+    vtx_seq_name = &(vertex_cache->seq_name);
+    vtx_seq_name_str = NameStr(*vtx_seq_name);
+
+    edge_seq_name = &(edge_cache->seq_name);
+    edge_seq_name_str = NameStr(*edge_seq_name);
+
+    vtx_seq_id = get_relname_relid(vtx_seq_name_str, nsp_id);
+    edge_seq_id = get_relname_relid(edge_seq_name_str, nsp_id);
+
+    /* Creating vertices*/
+    for (i=(int64)1;i<=no_vertices;i++)
+    {   
+        vid = nextval_internal(vtx_seq_id, true);
+        object_graph_id = make_graphid(vtx_label_id, vid);
+        props = create_empty_agtype();
+        insert_vertex_simple(graph_id,vtx_name_str,object_graph_id,props);
+    }
+
+    lid = vid;
+    
+    /* Creating edges*/
+    for (i = 1;i<=no_vertices-1;i++)
+    {   
+        start_vid = lid-no_vertices+i;
+        for(j=i+1;j<=no_vertices;j++)
+        {  
+            end_vid = lid-no_vertices+j;
+            eid = nextval_internal(edge_seq_id, true);
+            object_graph_id = make_graphid(edge_label_id, eid);
+
+            start_vertex_graph_id = make_graphid(vtx_label_id, start_vid);
+            end_vertex_graph_id = make_graphid(vtx_label_id, end_vid);
+
+            props = create_empty_agtype();
+
+            insert_edge_simple(graph_id, edge_name_str,
+                            object_graph_id, start_vertex_graph_id,
+                            end_vertex_graph_id, props);
+            
+        }
+    }
+
+    PG_RETURN_VOID();
+}
+
diff --git a/src/backend/utils/load/age_load.c b/src/backend/utils/load/age_load.c
index b80e950..cbdf158 100644
--- a/src/backend/utils/load/age_load.c
+++ b/src/backend/utils/load/age_load.c
@@ -58,7 +58,7 @@
 #include "utils/load/ag_load_labels.h"
 #include "utils/load/ag_load_edges.h"
 
-static agtype* create_empty_agtype(void)
+agtype* create_empty_agtype(void)
 {
     agtype_in_state result;
 
diff --git a/src/include/catalog/ag_label.h b/src/include/catalog/ag_label.h
index d925b8d..f60a038 100644
--- a/src/include/catalog/ag_label.h
+++ b/src/include/catalog/ag_label.h
@@ -49,8 +49,10 @@
 #define Anum_ag_label_id 3
 #define Anum_ag_label_kind 4
 #define Anum_ag_label_relation 5
+#define Anum_ag_label_seq_name 6
 
-#define Natts_ag_label 5
+
+#define Natts_ag_label 6
 
 #define ag_label_relation_id() ag_relation_id("ag_label", "table")
 #define ag_label_oid_index_id() ag_relation_id("ag_label_oid_index", "index")
@@ -60,6 +62,8 @@
     ag_relation_id("ag_label_graph_id_index", "index")
 #define ag_label_relation_index_id() \
     ag_relation_id("ag_label_relation_index", "index")
+#define ag_label_seq_name_graph_index_id() \
+    ag_relation_id("ag_label_seq_name_graph_index", "index")
 
 #define LABEL_ID_SEQ_NAME "_label_id_seq"
 
@@ -67,7 +71,7 @@
 #define LABEL_KIND_EDGE 'e'
 
 Oid insert_label(const char *label_name, Oid label_graph, int32 label_id,
-                 char label_kind, Oid label_relation);
+                 char label_kind, Oid label_relation, const char *seq_name);
 void delete_label(Oid relation);
 
 Oid get_label_oid(const char *label_name, Oid label_graph);
diff --git a/src/include/commands/graph_commands.h b/src/include/commands/graph_commands.h
new file mode 100644
index 0000000..6e1bbb9
--- /dev/null
+++ b/src/include/commands/graph_commands.h
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef AG_GRAPH_COMMANDS_H
+#define AG_GRAPH_COMMANDS_H
+
+#include "postgres.h"
+
+Datum create_graph(PG_FUNCTION_ARGS);
+
+#endif
\ No newline at end of file
diff --git a/src/include/commands/label_commands.h b/src/include/commands/label_commands.h
index ad1041c..711a564 100644
--- a/src/include/commands/label_commands.h
+++ b/src/include/commands/label_commands.h
@@ -54,6 +54,11 @@
 #define IS_AG_DEFAULT_LABEL(x) \
     (IS_DEFAULT_LABEL_EDGE(x) || IS_DEFAULT_LABEL_VERTEX(x))
 
+
+Datum create_vlabel(PG_FUNCTION_ARGS);
+
+Datum create_elabel(PG_FUNCTION_ARGS);
+
 Oid create_label(char *graph_name, char *label_name, char label_type,
                  List *parents);
 
diff --git a/src/include/utils/ag_cache.h b/src/include/utils/ag_cache.h
index deb50ef..a368c26 100644
--- a/src/include/utils/ag_cache.h
+++ b/src/include/utils/ag_cache.h
@@ -39,6 +39,7 @@ typedef struct label_cache_data
     int32 id;
     char kind;
     Oid relation;
+    NameData seq_name;
 } label_cache_data;
 
 // callers of these functions must not modify the returned struct
@@ -48,5 +49,6 @@ label_cache_data *search_label_oid_cache(Oid oid);
 label_cache_data *search_label_name_graph_cache(const char *name, Oid graph);
 label_cache_data *search_label_graph_id_cache(Oid graph, int32 id);
 label_cache_data *search_label_relation_cache(Oid relation);
+label_cache_data *search_label_seq_name_graph_cache(const char *name, Oid graph);
 
 #endif
diff --git a/src/include/utils/load/age_load.h b/src/include/utils/load/age_load.h
index 8424fb4..49eff48 100644
--- a/src/include/utils/load/age_load.h
+++ b/src/include/utils/load/age_load.h
@@ -57,6 +57,8 @@
 #ifndef AGE_ENTITY_CREATOR_H
 #define AGE_ENTITY_CREATOR_H
 
+agtype* create_empty_agtype(void);
+
 agtype* create_agtype_from_list(char **header, char **fields,
                                 size_t fields_len, int64 vertex_id);
 agtype* create_agtype_from_list_i(char **header, char **fields,