in src/backend/utils/adt/age_global_graph.c [1260:1373]
Datum age_vertex_stats(PG_FUNCTION_ARGS)
{
GRAPH_global_context *ggctx = NULL;
vertex_entry *ve = NULL;
ListGraphId *edges = NULL;
agtype_value *agtv_vertex = NULL;
agtype_value *agtv_temp = NULL;
agtype_value agtv_integer;
agtype_in_state result;
char *graph_name = NULL;
Oid graph_oid = InvalidOid;
graphid vid = 0;
int64 self_loops = 0;
int64 degree = 0;
/* the graph name is required, but this generally isn't user supplied */
if (PG_ARGISNULL(0))
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("vertex_stats: graph name cannot be NULL")));
}
/* get the graph name */
agtv_temp = get_agtype_value("vertex_stats", AG_GET_ARG_AGTYPE_P(0),
AGTV_STRING, true);
/* we need the vertex */
if (PG_ARGISNULL(1))
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("vertex_stats: vertex cannot be NULL")));
}
/* get the vertex */
agtv_vertex = get_agtype_value("vertex_stats", AG_GET_ARG_AGTYPE_P(1),
AGTV_VERTEX, true);
graph_name = pnstrdup(agtv_temp->val.string.val,
agtv_temp->val.string.len);
/* 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_if_not_null(graph_name);
/* get the id */
agtv_temp = GET_AGTYPE_VALUE_OBJECT_VALUE(agtv_vertex, "id");
vid = agtv_temp->val.int_value;
/* get the vertex entry */
ve = get_vertex_entry(ggctx, vid);
/* 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 id */
result.res = push_agtype_value(&result.parse_state, WAGT_KEY,
string_to_agtype_value("id"));
result.res = push_agtype_value(&result.parse_state, WAGT_VALUE, agtv_temp);
/* store the label */
agtv_temp = GET_AGTYPE_VALUE_OBJECT_VALUE(agtv_vertex, "label");
result.res = push_agtype_value(&result.parse_state, WAGT_KEY,
string_to_agtype_value("label"));
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 the self_loops */
edges = get_vertex_entry_edges_self(ve);
self_loops = (edges != NULL) ? get_list_size(edges) : 0;
agtv_temp->val.int_value = self_loops;
result.res = push_agtype_value(&result.parse_state, WAGT_KEY,
string_to_agtype_value("self_loops"));
result.res = push_agtype_value(&result.parse_state, WAGT_VALUE, agtv_temp);
/* get and store the in_degree */
edges = get_vertex_entry_edges_in(ve);
degree = (edges != NULL) ? get_list_size(edges) : 0;
agtv_temp->val.int_value = degree + self_loops;
result.res = push_agtype_value(&result.parse_state, WAGT_KEY,
string_to_agtype_value("in_degree"));
result.res = push_agtype_value(&result.parse_state, WAGT_VALUE, agtv_temp);
/* get and store the out_degree */
edges = get_vertex_entry_edges_out(ve);
degree = (edges != NULL) ? get_list_size(edges) : 0;
agtv_temp->val.int_value = degree + self_loops;
result.res = push_agtype_value(&result.parse_state, WAGT_KEY,
string_to_agtype_value("out_degree"));
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));
}