This is an automated email from the ASF dual-hosted git repository.
zainabsaad 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 8288aa54 Add the command graph_stats and improve VLE messaging for
load (#1750)
8288aa54 is described below
commit 8288aa5435fdfda619c45d5aa1570b05915a8e9a
Author: John Gemignani <[email protected]>
AuthorDate: Tue Apr 16 15:33:14 2024 -0700
Add the command graph_stats and improve VLE messaging for load (#1750)
Added the command graph_stats. This command will force a reload of
the specified graph. This is done to generate current statistics
and dump any warning messages about the graph generated during a
the load.
Cleaned up some messaging from the VLE load process for duplicate
vertices and edges.
Added regression tests.
---
age--1.5.0--y.y.y.sql | 8 ++
regress/expected/age_global_graph.out | 154 +++++++++++++++++++++++++++-
regress/sql/age_global_graph.sql | 34 ++++++
sql/agtype_typecast.sql | 7 ++
src/backend/utils/adt/age_global_graph.c | 171 ++++++++++++++++++++++++++-----
5 files changed, 348 insertions(+), 26 deletions(-)
diff --git a/age--1.5.0--y.y.y.sql b/age--1.5.0--y.y.y.sql
index 0239d439..ef6a7727 100644
--- a/age--1.5.0--y.y.y.sql
+++ b/age--1.5.0--y.y.y.sql
@@ -98,3 +98,11 @@ RETURNS NULL ON NULL INPUT
PARALLEL SAFE
AS 'MODULE_PATHNAME';
+-- this is a new function for graph statistics
+CREATE FUNCTION ag_catalog.age_graph_stats(agtype)
+ RETURNS agtype
+ LANGUAGE c
+ STABLE
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
diff --git a/regress/expected/age_global_graph.out
b/regress/expected/age_global_graph.out
index 73377b31..f2d9b059 100644
--- a/regress/expected/age_global_graph.out
+++ b/regress/expected/age_global_graph.out
@@ -216,12 +216,164 @@ SELECT * FROM cypher('ag_graph_2', $$ MATCH (a) RETURN
vertex_stats(a) $$) AS (r
{"id": 1125899906842625, "label": "Person", "in_degree": 0, "out_degree": 0,
"self_loops": 0}
(2 rows)
+--
+-- graph_stats command
+--
+-- what's in the current graphs?
+SELECT * FROM cypher('ag_graph_1', $$ RETURN graph_stats('ag_graph_1') $$) AS
(result agtype);
+ result
+--------------------------------------------------------------------------
+ {"graph": "ag_graph_1", "num_loaded_edges": 0, "num_loaded_vertices": 3}
+(1 row)
+
+SELECT * FROM cypher('ag_graph_1', $$ RETURN graph_stats('ag_graph_2') $$) AS
(result agtype);
+ result
+--------------------------------------------------------------------------
+ {"graph": "ag_graph_2", "num_loaded_edges": 0, "num_loaded_vertices": 2}
+(1 row)
+
+SELECT * FROM cypher('ag_graph_1', $$ RETURN graph_stats('ag_graph_3') $$) AS
(result agtype);
+ result
+--------------------------------------------------------------------------
+ {"graph": "ag_graph_3", "num_loaded_edges": 0, "num_loaded_vertices": 1}
+(1 row)
+
+-- add some edges
+SELECT * FROM cypher('ag_graph_1', $$ CREATE ()-[:knows]->() $$) AS (results
agtype);
+ results
+---------
+(0 rows)
+
+SELECT * FROM cypher('ag_graph_1', $$ CREATE ()-[:knows]->() $$) AS (results
agtype);
+ results
+---------
+(0 rows)
+
+SELECT * FROM cypher('ag_graph_1', $$ CREATE ()-[:knows]->() $$) AS (results
agtype);
+ results
+---------
+(0 rows)
+
+SELECT * FROM cypher('ag_graph_1', $$ CREATE ()-[:knows]->() $$) AS (results
agtype);
+ results
+---------
+(0 rows)
+
+-- what is there now?
+SELECT * FROM cypher('ag_graph_1', $$ RETURN graph_stats('ag_graph_1') $$) AS
(result agtype);
+ result
+---------------------------------------------------------------------------
+ {"graph": "ag_graph_1", "num_loaded_edges": 4, "num_loaded_vertices": 11}
+(1 row)
+
+-- add some more
+SELECT * FROM cypher('ag_graph_1', $$ MATCH (u)-[]->(v) SET u.id = id(u)
+ SET v.id = id(v)
+ SET u.name = 'u'
+ SET v.name = 'v'
+ RETURN u,v $$) AS (u agtype, v agtype);
+ u
| v
+--------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------
+ {"id": 281474976710659, "label": "", "properties": {"id": 281474976710659,
"name": "u"}}::vertex | {"id": 281474976710660, "label": "", "properties":
{"id": 281474976710660, "name": "v"}}::vertex
+ {"id": 281474976710661, "label": "", "properties": {"id": 281474976710661,
"name": "u"}}::vertex | {"id": 281474976710662, "label": "", "properties":
{"id": 281474976710662, "name": "v"}}::vertex
+ {"id": 281474976710663, "label": "", "properties": {"id": 281474976710663,
"name": "u"}}::vertex | {"id": 281474976710664, "label": "", "properties":
{"id": 281474976710664, "name": "v"}}::vertex
+ {"id": 281474976710665, "label": "", "properties": {"id": 281474976710665,
"name": "u"}}::vertex | {"id": 281474976710666, "label": "", "properties":
{"id": 281474976710666, "name": "v"}}::vertex
+(4 rows)
+
+SELECT * FROM cypher('ag_graph_1', $$ MATCH (u)-[]->(v) MERGE
(v)-[:stalks]->(u) $$) AS (result agtype);
+ result
+--------
+(0 rows)
+
+SELECT * FROM cypher('ag_graph_1', $$ MATCH (u)-[e]->(v) RETURN u, e, v $$) AS
(u agtype, e agtype, v agtype);
+ u
|
e |
v
+--------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------
+ {"id": 281474976710660, "label": "", "properties": {"id": 281474976710660,
"name": "v"}}::vertex | {"id": 1407374883553281, "label": "stalks", "end_id":
281474976710659, "start_id": 281474976710660, "properties": {}}::edge | {"id":
281474976710659, "label": "", "properties": {"id": 281474976710659, "name":
"u"}}::vertex
+ {"id": 281474976710659, "label": "", "properties": {"id": 281474976710659,
"name": "u"}}::vertex | {"id": 1125899906842625, "label": "knows", "end_id":
281474976710660, "start_id": 281474976710659, "properties": {}}::edge | {"id":
281474976710660, "label": "", "properties": {"id": 281474976710660, "name":
"v"}}::vertex
+ {"id": 281474976710662, "label": "", "properties": {"id": 281474976710662,
"name": "v"}}::vertex | {"id": 1407374883553282, "label": "stalks", "end_id":
281474976710661, "start_id": 281474976710662, "properties": {}}::edge | {"id":
281474976710661, "label": "", "properties": {"id": 281474976710661, "name":
"u"}}::vertex
+ {"id": 281474976710661, "label": "", "properties": {"id": 281474976710661,
"name": "u"}}::vertex | {"id": 1125899906842626, "label": "knows", "end_id":
281474976710662, "start_id": 281474976710661, "properties": {}}::edge | {"id":
281474976710662, "label": "", "properties": {"id": 281474976710662, "name":
"v"}}::vertex
+ {"id": 281474976710664, "label": "", "properties": {"id": 281474976710664,
"name": "v"}}::vertex | {"id": 1407374883553283, "label": "stalks", "end_id":
281474976710663, "start_id": 281474976710664, "properties": {}}::edge | {"id":
281474976710663, "label": "", "properties": {"id": 281474976710663, "name":
"u"}}::vertex
+ {"id": 281474976710663, "label": "", "properties": {"id": 281474976710663,
"name": "u"}}::vertex | {"id": 1125899906842627, "label": "knows", "end_id":
281474976710664, "start_id": 281474976710663, "properties": {}}::edge | {"id":
281474976710664, "label": "", "properties": {"id": 281474976710664, "name":
"v"}}::vertex
+ {"id": 281474976710666, "label": "", "properties": {"id": 281474976710666,
"name": "v"}}::vertex | {"id": 1407374883553284, "label": "stalks", "end_id":
281474976710665, "start_id": 281474976710666, "properties": {}}::edge | {"id":
281474976710665, "label": "", "properties": {"id": 281474976710665, "name":
"u"}}::vertex
+ {"id": 281474976710665, "label": "", "properties": {"id": 281474976710665,
"name": "u"}}::vertex | {"id": 1125899906842628, "label": "knows", "end_id":
281474976710666, "start_id": 281474976710665, "properties": {}}::edge | {"id":
281474976710666, "label": "", "properties": {"id": 281474976710666, "name":
"v"}}::vertex
+(8 rows)
+
+-- what is there now?
+SELECT * FROM cypher('ag_graph_1', $$ RETURN graph_stats('ag_graph_1') $$) AS
(result agtype);
+ result
+---------------------------------------------------------------------------
+ {"graph": "ag_graph_1", "num_loaded_edges": 8, "num_loaded_vertices": 11}
+(1 row)
+
+-- remove some vertices
+SELECT * FROM ag_graph_1._ag_label_vertex;
+ id | properties
+-----------------+--------------------------------------
+ 281474976710657 | {}
+ 281474976710658 | {}
+ 281474976710659 | {"id": 281474976710659, "name": "u"}
+ 281474976710660 | {"id": 281474976710660, "name": "v"}
+ 281474976710661 | {"id": 281474976710661, "name": "u"}
+ 281474976710662 | {"id": 281474976710662, "name": "v"}
+ 281474976710663 | {"id": 281474976710663, "name": "u"}
+ 281474976710664 | {"id": 281474976710664, "name": "v"}
+ 281474976710665 | {"id": 281474976710665, "name": "u"}
+ 281474976710666 | {"id": 281474976710666, "name": "v"}
+ 844424930131969 | {}
+(11 rows)
+
+DELETE FROM ag_graph_1._ag_label_vertex WHERE id::text = '281474976710661';
+DELETE FROM ag_graph_1._ag_label_vertex WHERE id::text = '281474976710662';
+DELETE FROM ag_graph_1._ag_label_vertex WHERE id::text = '281474976710664';
+SELECT * FROM ag_graph_1._ag_label_vertex;
+ id | properties
+-----------------+--------------------------------------
+ 281474976710657 | {}
+ 281474976710658 | {}
+ 281474976710659 | {"id": 281474976710659, "name": "u"}
+ 281474976710660 | {"id": 281474976710660, "name": "v"}
+ 281474976710663 | {"id": 281474976710663, "name": "u"}
+ 281474976710665 | {"id": 281474976710665, "name": "u"}
+ 281474976710666 | {"id": 281474976710666, "name": "v"}
+ 844424930131969 | {}
+(8 rows)
+
+SELECT * FROM ag_graph_1._ag_label_edge;
+ id | start_id | end_id | properties
+------------------+-----------------+-----------------+------------
+ 1125899906842625 | 281474976710659 | 281474976710660 | {}
+ 1125899906842626 | 281474976710661 | 281474976710662 | {}
+ 1125899906842627 | 281474976710663 | 281474976710664 | {}
+ 1125899906842628 | 281474976710665 | 281474976710666 | {}
+ 1407374883553281 | 281474976710660 | 281474976710659 | {}
+ 1407374883553282 | 281474976710662 | 281474976710661 | {}
+ 1407374883553283 | 281474976710664 | 281474976710663 | {}
+ 1407374883553284 | 281474976710666 | 281474976710665 | {}
+(8 rows)
+
+-- there should be warning messages
+SELECT * FROM cypher('ag_graph_1', $$ RETURN graph_stats('ag_graph_1') $$) AS
(result agtype);
+WARNING: edge: [id: 1125899906842626, start: 281474976710661, end:
281474976710662, label: knows] start and end vertices not found
+WARNING: ignored malformed or dangling edge
+WARNING: edge: [id: 1125899906842627, start: 281474976710663, end:
281474976710664, label: knows] end vertex not found
+WARNING: ignored malformed or dangling edge
+WARNING: edge: [id: 1407374883553282, start: 281474976710662, end:
281474976710661, label: stalks] start and end vertices not found
+WARNING: ignored malformed or dangling edge
+WARNING: edge: [id: 1407374883553283, start: 281474976710664, end:
281474976710663, label: stalks] start vertex not found
+WARNING: ignored malformed or dangling edge
+ result
+--------------------------------------------------------------------------
+ {"graph": "ag_graph_1", "num_loaded_edges": 8, "num_loaded_vertices": 8}
+(1 row)
+
--drop graphs
SELECT * FROM drop_graph('ag_graph_1', true);
-NOTICE: drop cascades to 3 other objects
+NOTICE: drop cascades to 5 other objects
DETAIL: drop cascades to table ag_graph_1._ag_label_vertex
drop cascades to table ag_graph_1._ag_label_edge
drop cascades to table ag_graph_1.vertex1
+drop cascades to table ag_graph_1.knows
+drop cascades to table ag_graph_1.stalks
NOTICE: graph "ag_graph_1" has been dropped
drop_graph
------------
diff --git a/regress/sql/age_global_graph.sql b/regress/sql/age_global_graph.sql
index badc0b5b..acd95fbf 100644
--- a/regress/sql/age_global_graph.sql
+++ b/regress/sql/age_global_graph.sql
@@ -90,6 +90,40 @@ SELECT * FROM cypher('ag_graph_1', $$ MATCH (n) RETURN
vertex_stats(n) $$) AS (r
--should return 1 vertice and 1 label
SELECT * FROM cypher('ag_graph_2', $$ MATCH (a) RETURN vertex_stats(a) $$) AS
(result agtype);
+--
+-- graph_stats command
+--
+-- what's in the current graphs?
+SELECT * FROM cypher('ag_graph_1', $$ RETURN graph_stats('ag_graph_1') $$) AS
(result agtype);
+SELECT * FROM cypher('ag_graph_1', $$ RETURN graph_stats('ag_graph_2') $$) AS
(result agtype);
+SELECT * FROM cypher('ag_graph_1', $$ RETURN graph_stats('ag_graph_3') $$) AS
(result agtype);
+-- add some edges
+SELECT * FROM cypher('ag_graph_1', $$ CREATE ()-[:knows]->() $$) AS (results
agtype);
+SELECT * FROM cypher('ag_graph_1', $$ CREATE ()-[:knows]->() $$) AS (results
agtype);
+SELECT * FROM cypher('ag_graph_1', $$ CREATE ()-[:knows]->() $$) AS (results
agtype);
+SELECT * FROM cypher('ag_graph_1', $$ CREATE ()-[:knows]->() $$) AS (results
agtype);
+-- what is there now?
+SELECT * FROM cypher('ag_graph_1', $$ RETURN graph_stats('ag_graph_1') $$) AS
(result agtype);
+-- add some more
+SELECT * FROM cypher('ag_graph_1', $$ MATCH (u)-[]->(v) SET u.id = id(u)
+ SET v.id = id(v)
+ SET u.name = 'u'
+ SET v.name = 'v'
+ RETURN u,v $$) AS (u agtype, v agtype);
+SELECT * FROM cypher('ag_graph_1', $$ MATCH (u)-[]->(v) MERGE
(v)-[:stalks]->(u) $$) AS (result agtype);
+SELECT * FROM cypher('ag_graph_1', $$ MATCH (u)-[e]->(v) RETURN u, e, v $$) AS
(u agtype, e agtype, v agtype);
+-- what is there now?
+SELECT * FROM cypher('ag_graph_1', $$ RETURN graph_stats('ag_graph_1') $$) AS
(result agtype);
+-- remove some vertices
+SELECT * FROM ag_graph_1._ag_label_vertex;
+DELETE FROM ag_graph_1._ag_label_vertex WHERE id::text = '281474976710661';
+DELETE FROM ag_graph_1._ag_label_vertex WHERE id::text = '281474976710662';
+DELETE FROM ag_graph_1._ag_label_vertex WHERE id::text = '281474976710664';
+SELECT * FROM ag_graph_1._ag_label_vertex;
+SELECT * FROM ag_graph_1._ag_label_edge;
+-- there should be warning messages
+SELECT * FROM cypher('ag_graph_1', $$ RETURN graph_stats('ag_graph_1') $$) AS
(result agtype);
+
--drop graphs
SELECT * FROM drop_graph('ag_graph_1', true);
diff --git a/sql/agtype_typecast.sql b/sql/agtype_typecast.sql
index 5326182f..aa551407 100644
--- a/sql/agtype_typecast.sql
+++ b/sql/agtype_typecast.sql
@@ -196,6 +196,13 @@ CREATE FUNCTION ag_catalog.age_vertex_stats(agtype, agtype)
PARALLEL SAFE
AS 'MODULE_PATHNAME';
+CREATE FUNCTION ag_catalog.age_graph_stats(agtype)
+ RETURNS agtype
+ LANGUAGE c
+ STABLE
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
CREATE FUNCTION ag_catalog.age_delete_global_graphs(agtype)
RETURNS boolean
LANGUAGE c
diff --git a/src/backend/utils/adt/age_global_graph.c
b/src/backend/utils/adt/age_global_graph.c
index 9967a78f..d4a02242 100644
--- a/src/backend/utils/adt/age_global_graph.c
+++ b/src/backend/utils/adt/age_global_graph.c
@@ -96,9 +96,9 @@ static void load_edge_hashtable(GRAPH_global_context *ggctx);
static void freeze_GRAPH_global_hashtables(GRAPH_global_context *ggctx);
static List *get_ag_labels_names(Snapshot snapshot, Oid graph_oid,
char label_type);
-static bool insert_edge(GRAPH_global_context *ggctx, graphid edge_id,
- Datum edge_properties, graphid start_vertex_id,
- graphid end_vertex_id, Oid edge_label_table_oid);
+static bool insert_edge_entry(GRAPH_global_context *ggctx, graphid edge_id,
+ Datum edge_properties, graphid start_vertex_id,
+ graphid end_vertex_id, Oid edge_label_table_oid);
static bool insert_vertex_edge(GRAPH_global_context *ggctx,
graphid start_vertex_id, graphid end_vertex_id,
graphid edge_id, char *edge_label_name);
@@ -237,39 +237,57 @@ static List *get_ag_labels_names(Snapshot snapshot, Oid
graph_oid,
* Helper function to insert one edge/edge->vertex, key/value pair, in the
* current GRAPH global edge hashtable.
*/
-static bool insert_edge(GRAPH_global_context *ggctx, graphid edge_id,
- Datum edge_properties, graphid start_vertex_id,
- graphid end_vertex_id, Oid edge_label_table_oid)
+static bool insert_edge_entry(GRAPH_global_context *ggctx, graphid edge_id,
+ Datum edge_properties, graphid start_vertex_id,
+ graphid end_vertex_id, Oid edge_label_table_oid)
{
- edge_entry *value = NULL;
+ edge_entry *ee = NULL;
bool found = false;
/* search for the edge */
- value = (edge_entry *)hash_search(ggctx->edge_hashtable, (void *)&edge_id,
+ ee = (edge_entry *)hash_search(ggctx->edge_hashtable, (void *)&edge_id,
HASH_ENTER, &found);
+
+ /* if the hash enter returned is NULL, error out */
+ if (ee == NULL)
+ {
+ elog(ERROR, "insert_edge_entry: hash table returned NULL for ee");
+ }
+
/*
* If we found the key, either we have a duplicate, or we made a mistake
and
* inserted it already. Either way, this isn't good so don't insert it and
- * return false. Likewise, if the value returned is NULL, don't do
anything,
- * just return false. This way the caller can decide what to do.
+ * return false.
*/
- if (found || value == NULL)
+ if (found)
{
+ ereport(WARNING,
+ (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("edge: [id: %ld, start: %ld, end: %ld, label oid: %d]
%s",
+ edge_id, start_vertex_id, end_vertex_id,
+ edge_label_table_oid, "duplicate edge found")));
+
+ ereport(WARNING,
+ (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("previous edge: [id: %ld, start: %ld, end: %ld, label
oid: %d]",
+ ee->edge_id, ee->start_vertex_id, ee->end_vertex_id,
+ ee->edge_label_table_oid)));
+
return false;
}
/* not sure if we really need to zero out the entry, as we set everything
*/
- MemSet(value, 0, sizeof(edge_entry));
+ MemSet(ee, 0, sizeof(edge_entry));
/*
* Set the edge id - this is important as this is the hash key value used
* for hash function collisions.
*/
- value->edge_id = edge_id;
- value->edge_properties = edge_properties;
- value->start_vertex_id = start_vertex_id;
- value->end_vertex_id = end_vertex_id;
- value->edge_label_table_oid = edge_label_table_oid;
+ ee->edge_id = edge_id;
+ ee->edge_properties = edge_properties;
+ ee->start_vertex_id = start_vertex_id;
+ ee->end_vertex_id = end_vertex_id;
+ ee->edge_label_table_oid = edge_label_table_oid;
/* increment the number of loaded edges */
ggctx->num_loaded_edges++;
@@ -292,9 +310,26 @@ static bool insert_vertex_entry(GRAPH_global_context
*ggctx, graphid vertex_id,
ve = (vertex_entry *)hash_search(ggctx->vertex_hashtable,
(void *)&vertex_id, HASH_ENTER, &found);
- /* we should never have duplicates, return false */
+ /* if the hash enter returned is NULL, error out */
+ if (ve == NULL)
+ {
+ elog(ERROR, "insert_vertex_entry: hash table returned NULL for ve");
+ }
+
+ /* we should never have duplicates, warn and return false */
if (found)
{
+ ereport(WARNING,
+ (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("vertex: [id: %ld, label oid: %d] %s",
+ vertex_id, vertex_label_table_oid,
+ "duplicate vertex found")));
+
+ ereport(WARNING,
+ (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("previous vertex: [id: %ld, label oid: %d]",
+ ve->vertex_id, ve->vertex_label_table_oid)));
+
return false;
}
@@ -482,10 +517,12 @@ static void load_vertex_hashtable(GRAPH_global_context
*ggctx)
vertex_label_table_oid,
vertex_properties);
- /* this insert must not fail, it means there is a duplicate */
+ /* warn if there is a duplicate */
if (!inserted)
{
- elog(ERROR, "insert_vertex_entry: failed due to duplicate");
+ ereport(WARNING,
+ (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("ignored duplicate vertex")));
}
}
@@ -598,14 +635,17 @@ static void load_edge_hashtable(GRAPH_global_context
*ggctx)
edge_properties = datumCopy(edge_properties, false, -1);
/* insert edge into edge hashtable */
- inserted = insert_edge(ggctx, edge_id, edge_properties,
- edge_vertex_start_id, edge_vertex_end_id,
- edge_label_table_oid);
+ inserted = insert_edge_entry(ggctx, edge_id, edge_properties,
+ edge_vertex_start_id,
+ edge_vertex_end_id,
+ edge_label_table_oid);
- /* this insert must not fail */
+ /* warn if there is a duplicate */
if (!inserted)
{
- elog(ERROR, "insert_edge: failed to insert");
+ ereport(WARNING,
+ (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("ignored duplicate edge")));
}
/* insert the edge into the start and end vertices edge lists */
@@ -1193,3 +1233,84 @@ Datum age_vertex_stats(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(agtype_value_to_agtype(result.res));
}
+
+/* PG wrapper function for age_graph_stats */
+PG_FUNCTION_INFO_V1(age_graph_stats);
+
+Datum age_graph_stats(PG_FUNCTION_ARGS)
+{
+ GRAPH_global_context *ggctx = NULL;
+ agtype_value *agtv_temp = NULL;
+ agtype_value agtv_integer;
+ agtype_in_state result;
+ char *graph_name = NULL;
+ Oid graph_oid = InvalidOid;
+
+ /* the graph name is required, but this generally isn't user supplied */
+ if (PG_ARGISNULL(0))
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("graph_stats: graph name cannot be NULL")));
+ }
+
+ /* get the graph name */
+ agtv_temp = get_agtype_value("graph_stats", AG_GET_ARG_AGTYPE_P(0),
+ AGTV_STRING, true);
+
+ graph_name = pnstrdup(agtv_temp->val.string.val,
+ agtv_temp->val.string.len);
+
+ /*
+ * Remove any context for this graph. This is done to allow graph_stats to
+ * show any load issues.
+ */
+ delete_specific_GRAPH_global_contexts(graph_name);
+
+ /* get the graph oid */
+ graph_oid = get_graph_oid(graph_name);
+
+ /*
+ * Create or retrieve the GRAPH global context for this graph. This
function
+ * will also purge off invalidated contexts.
+ */
+ ggctx = manage_GRAPH_global_contexts(graph_name, graph_oid);
+
+ /* free the graph name */
+ pfree(graph_name);
+
+ /* zero the state */
+ memset(&result, 0, sizeof(agtype_in_state));
+
+ /* start the object */
+ result.res = push_agtype_value(&result.parse_state, WAGT_BEGIN_OBJECT,
+ NULL);
+ /* store the graph name */
+ result.res = push_agtype_value(&result.parse_state, WAGT_KEY,
+ string_to_agtype_value("graph"));
+ result.res = push_agtype_value(&result.parse_state, WAGT_VALUE, agtv_temp);
+
+ /* set up an integer for returning values */
+ agtv_temp = &agtv_integer;
+ agtv_temp->type = AGTV_INTEGER;
+ agtv_temp->val.int_value = 0;
+
+ /* get and store num_loaded_vertices */
+ agtv_temp->val.int_value = ggctx->num_loaded_vertices;
+ result.res = push_agtype_value(&result.parse_state, WAGT_KEY,
+
string_to_agtype_value("num_loaded_vertices"));
+ result.res = push_agtype_value(&result.parse_state, WAGT_VALUE, agtv_temp);
+
+ /* get and store num_loaded_edges */
+ agtv_temp->val.int_value = ggctx->num_loaded_edges;
+ result.res = push_agtype_value(&result.parse_state, WAGT_KEY,
+ string_to_agtype_value("num_loaded_edges"));
+ result.res = push_agtype_value(&result.parse_state, WAGT_VALUE, agtv_temp);
+
+ /* close the object */
+ result.res = push_agtype_value(&result.parse_state, WAGT_END_OBJECT, NULL);
+
+ result.res->type = AGTV_OBJECT;
+
+ PG_RETURN_POINTER(agtype_value_to_agtype(result.res));
+}