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,