From 724af0ee039df4e9d058f758bec3a2800b5e8127 Mon Sep 17 00:00:00 2001 From: Marco A S Date: Fri, 3 Feb 2023 10:58:26 -0300 Subject: [PATCH 1/4] Added function to create a Barbell Graph * Created auxiliary function to get_next_val_internal; * Currently creates a bridge of no vertexes between graphs, will be implemented next. --- src/backend/utils/graph_generation.c | 147 ++++++++++++++++++++++++++- 1 file changed, 144 insertions(+), 3 deletions(-) diff --git a/src/backend/utils/graph_generation.c b/src/backend/utils/graph_generation.c index 49da5f829..c28a47ca2 100644 --- a/src/backend/utils/graph_generation.c +++ b/src/backend/utils/graph_generation.c @@ -41,15 +41,20 @@ #include "catalog/ag_graph.h" #include "catalog/ag_label.h" +#include "commands/graph_commands.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); +PG_FUNCTION_INFO_V1(age_create_barbell_graph); + +int64 get_nextval_internal(graph_cache_data* graph_cache, + label_cache_data* label_cache); + /* * SELECT * FROM ag_catalog.create_complete_graph('graph_name',no_of_nodes, 'edge_label', 'node_label'=NULL); @@ -125,7 +130,6 @@ Datum create_complete_graph(PG_FUNCTION_ARGS) if (!graph_exists(graph_name_str)) { DirectFunctionCall1(create_graph, CStringGetDatum(graph_name)); - } graph_id = get_graph_oid(graph_name_str); @@ -194,10 +198,147 @@ Datum create_complete_graph(PG_FUNCTION_ARGS) insert_edge_simple(graph_id, edge_name_str, object_graph_id, start_vertex_graph_id, end_vertex_graph_id, props); - } } + PG_RETURN_VOID(); +} + +/* + * The barbell graph is two complete graphs connected by a bridge path + * Syntax: + * ag_catalog.age_create_barbell_graph(graph_name Name, + * m int, + * n int, + * vertex_label_name Name DEFAULT = NULL, + * vertex_properties agtype DEFAULT = NULL, + * edge_label_name Name DEAULT = NULL, + * edge_properties agtype DEFAULT = NULL) + * Input: + * + * graph_name - Name of the graph to be created. + * m - number of vertices in one complete graph. + * n - number of vertices in the bridge path. + * vertex_label_name - Name of the label to assign each vertex to. + * vertex_properties - Property values to assign each vertex. Default is NULL + * edge_label_name - Name of the label to assign each edge to. + * edge_properties - Property values to assign each edge. Default is NULL + * + * https://en.wikipedia.org/wiki/Barbell_graph + */ +Datum age_create_barbell_graph(PG_FUNCTION_ARGS) { + + FunctionCallInfo arguments; + Oid graph_oid; + Name graph_name; + char* graph_name_str; + + int64 start_node_index, end_node_index, nextval; + + Name node_label_name = NULL; + int32 node_label_id; + char* node_label_str; + + Name edge_label_name; + int32 edge_label_id; + char* edge_label_str; + + graphid object_graph_id; + graphid start_node_graph_id; + graphid end_node_graph_id; + + graph_cache_data* graph_cache; + label_cache_data* edge_cache; + + agtype* properties = NULL; + + arguments = fcinfo; + + // create two separate complete graphs + DirectFunctionCall4(create_complete_graph, arguments->arg[0], + arguments->arg[1], + arguments->arg[5], + arguments->arg[3]); + DirectFunctionCall4(create_complete_graph, arguments->arg[0], + arguments->arg[1], + arguments->arg[5], + arguments->arg[3]); + + // Handling remaining arguments + /* + * graph_name: doesn't need to validate, since the create_complete_graph + * function already does that. + */ + graph_name = PG_GETARG_NAME(0); + graph_name_str = NameStr(*graph_name); + graph_oid = get_graph_oid(graph_name_str); + + /* + * int64 bridge_size: currently only stays at zero. + * to do: implement bridge with variable number of nodes. + */ + if (PG_ARGISNULL(2) || PG_GETARG_INT32(2) < 0 ) + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Bridge size must not be NULL or lower than 0"))); + + // node label: if null, gets default label, which is "_ag_label_vertex" + if (PG_ARGISNULL(3)) + namestrcpy(node_label_name, AG_DEFAULT_LABEL_VERTEX); + else + node_label_name = PG_GETARG_NAME(3); + node_label_str = NameStr(*node_label_name); + node_label_id = get_label_id(node_label_str, graph_oid); + + /* + * edge_label: doesn't need to validate, since the create_complete_graph + * function already does that. + */ + edge_label_name = PG_GETARG_NAME(5); + edge_label_str = NameStr(*edge_label_name); + edge_label_id = get_label_id(edge_label_str, graph_oid); + + /* + * Fetching caches to get next values for graph id's, and access nodes + * to be connected with edges. + */ + graph_cache = search_graph_name_cache(graph_name_str); + edge_cache = search_label_name_graph_cache(edge_label_str,graph_oid); + + // connect a node from each graph + start_node_index = 1; // first created node, from the first complete graph + end_node_index = arguments->arg[1]*2; // last created node, second graph + + // next index to be assigned to a node or edge + nextval = get_nextval_internal(graph_cache, edge_cache); + + // build the graph id's of the edge to be created + object_graph_id = make_graphid(edge_label_id, nextval); + start_node_graph_id = make_graphid(node_label_id, start_node_index); + end_node_graph_id = make_graphid(node_label_id, end_node_index); + properties = create_empty_agtype(); + + // connect two nodes + insert_edge_simple(graph_oid, edge_label_str, + object_graph_id, start_node_graph_id, + end_node_graph_id, properties); + PG_RETURN_VOID(); } + +/* + * Auxiliary function to get the next internal value in the graph, + * so a new object (node or edge) graph id can be composed. + */ +int64 get_nextval_internal(graph_cache_data* graph_cache, + label_cache_data* label_cache) +{ + Oid obj_seq_id; + char* label_seq_name_str; + + label_seq_name_str = NameStr(label_cache->seq_name); + obj_seq_id = get_relname_relid(label_seq_name_str, + graph_cache->namespace); + + return nextval_internal(obj_seq_id, true); +} \ No newline at end of file From 654dadfd70b5fb2b5983a211d98079ac932c393b Mon Sep 17 00:00:00 2001 From: Marco A S Date: Fri, 3 Feb 2023 10:58:38 -0300 Subject: [PATCH 2/4] Added signature to age_create_barbell_graph --- age--1.2.0.sql | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/age--1.2.0.sql b/age--1.2.0.sql index 3075824c9..e34b3c97c 100644 --- a/age--1.2.0.sql +++ b/age--1.2.0.sql @@ -4182,6 +4182,19 @@ CALLED ON NULL INPUT PARALLEL SAFE AS 'MODULE_PATHNAME'; +CREATE FUNCTION ag_catalog.age_create_barbell_graph(graph_name name, + graph_size int, + bridge_size int, + node_label name = NULL, + node_properties agtype = NULL, + edge_label name = NULL, + edge_properties agtype = 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 From a37e5f308edaca7e5bdc7069e68f920b82ab5a86 Mon Sep 17 00:00:00 2001 From: Marco A S Date: Fri, 3 Feb 2023 12:20:18 -0300 Subject: [PATCH 3/4] Moved bracket to next line to macth code standards --- src/backend/utils/graph_generation.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/utils/graph_generation.c b/src/backend/utils/graph_generation.c index c28a47ca2..12ae523ae 100644 --- a/src/backend/utils/graph_generation.c +++ b/src/backend/utils/graph_generation.c @@ -226,8 +226,8 @@ Datum create_complete_graph(PG_FUNCTION_ARGS) * * https://en.wikipedia.org/wiki/Barbell_graph */ -Datum age_create_barbell_graph(PG_FUNCTION_ARGS) { - +Datum age_create_barbell_graph(PG_FUNCTION_ARGS) +{ FunctionCallInfo arguments; Oid graph_oid; Name graph_name; From 4a55ddaf3999ffe13962ab763a0cff83f012bbdd Mon Sep 17 00:00:00 2001 From: Marco A S Date: Fri, 17 Feb 2023 11:23:34 -0300 Subject: [PATCH 4/4] Fixed patterns to match code standards * moved PG_FUNCTION_INFO_V1(age_create_barbell_graph) next to age_create_barbell_graph function; * added brackets to if/else conditions if just one line; * moved get_nextval_internal auxiliary function to the beggining of the file. --- src/backend/utils/graph_generation.c | 53 ++++++++++++++++------------ 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/src/backend/utils/graph_generation.c b/src/backend/utils/graph_generation.c index 12ae523ae..80ef85f29 100644 --- a/src/backend/utils/graph_generation.c +++ b/src/backend/utils/graph_generation.c @@ -49,12 +49,28 @@ #include "utils/load/ag_load_labels.h" -PG_FUNCTION_INFO_V1(create_complete_graph); -PG_FUNCTION_INFO_V1(age_create_barbell_graph); - int64 get_nextval_internal(graph_cache_data* graph_cache, label_cache_data* label_cache); +/* + * Auxiliary function to get the next internal value in the graph, + * so a new object (node or edge) graph id can be composed. + */ + +int64 get_nextval_internal(graph_cache_data* graph_cache, + label_cache_data* label_cache) +{ + Oid obj_seq_id; + char* label_seq_name_str; + + label_seq_name_str = NameStr(label_cache->seq_name); + obj_seq_id = get_relname_relid(label_seq_name_str, + graph_cache->namespace); + + return nextval_internal(obj_seq_id, true); +} + +PG_FUNCTION_INFO_V1(create_complete_graph); /* * SELECT * FROM ag_catalog.create_complete_graph('graph_name',no_of_nodes, 'edge_label', 'node_label'=NULL); @@ -204,6 +220,8 @@ Datum create_complete_graph(PG_FUNCTION_ARGS) } +PG_FUNCTION_INFO_V1(age_create_barbell_graph); + /* * The barbell graph is two complete graphs connected by a bridge path * Syntax: @@ -226,6 +244,7 @@ Datum create_complete_graph(PG_FUNCTION_ARGS) * * https://en.wikipedia.org/wiki/Barbell_graph */ + Datum age_create_barbell_graph(PG_FUNCTION_ARGS) { FunctionCallInfo arguments; @@ -278,14 +297,20 @@ Datum age_create_barbell_graph(PG_FUNCTION_ARGS) * to do: implement bridge with variable number of nodes. */ if (PG_ARGISNULL(2) || PG_GETARG_INT32(2) < 0 ) + { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Bridge size must not be NULL or lower than 0"))); + } // node label: if null, gets default label, which is "_ag_label_vertex" if (PG_ARGISNULL(3)) + { namestrcpy(node_label_name, AG_DEFAULT_LABEL_VERTEX); + } else + { node_label_name = PG_GETARG_NAME(3); + } node_label_str = NameStr(*node_label_name); node_label_id = get_label_id(node_label_str, graph_oid); @@ -319,26 +344,8 @@ Datum age_create_barbell_graph(PG_FUNCTION_ARGS) // connect two nodes insert_edge_simple(graph_oid, edge_label_str, - object_graph_id, start_node_graph_id, - end_node_graph_id, properties); + object_graph_id, start_node_graph_id, + end_node_graph_id, properties); PG_RETURN_VOID(); } - - -/* - * Auxiliary function to get the next internal value in the graph, - * so a new object (node or edge) graph id can be composed. - */ -int64 get_nextval_internal(graph_cache_data* graph_cache, - label_cache_data* label_cache) -{ - Oid obj_seq_id; - char* label_seq_name_str; - - label_seq_name_str = NameStr(label_cache->seq_name); - obj_seq_id = get_relname_relid(label_seq_name_str, - graph_cache->namespace); - - return nextval_internal(obj_seq_id, true); -} \ No newline at end of file