diff --git a/regress/expected/graph_generation.out b/regress/expected/graph_generation.out index ca511eafa..c038f9d9e 100644 --- a/regress/expected/graph_generation.out +++ b/regress/expected/graph_generation.out @@ -203,6 +203,60 @@ ERROR: edge label can not be NULL -- Should error out because same labels are used for both vertices and edges SELECT * FROM age_create_barbell_graph('gp6',5,10,'label',NULL,'label',NULL); ERROR: vertex and edge label can not be same +/* + * node_label is declared with a NULL default, so passing NULL for it - either + * explicitly or by leaving the trailing arguments out - has to fall back to + * the default vertex label rather than crash the backend. + */ +SELECT * FROM age_create_barbell_graph('gp7',5,0,NULL,NULL,'edges',NULL); +NOTICE: graph "gp7" has been created +NOTICE: ELabel "edges" has been created + age_create_barbell_graph +-------------------------- + +(1 row) + +SELECT COUNT(*) FROM gp7."_ag_label_vertex"; + count +------- + 10 +(1 row) + +SELECT COUNT(*) FROM gp7."edges"; + count +------- + 21 +(1 row) + +SELECT * FROM cypher('gp7', $$MATCH (a)-[e]->(b) RETURN e$$) as (n agtype); + n +--------------------------------------------------------------------------------------------------------------------------- + {"id": 844424930131969, "label": "edges", "end_id": 281474976710658, "start_id": 281474976710657, "properties": {}}::edge + {"id": 844424930131970, "label": "edges", "end_id": 281474976710659, "start_id": 281474976710657, "properties": {}}::edge + {"id": 844424930131971, "label": "edges", "end_id": 281474976710660, "start_id": 281474976710657, "properties": {}}::edge + {"id": 844424930131972, "label": "edges", "end_id": 281474976710661, "start_id": 281474976710657, "properties": {}}::edge + {"id": 844424930131973, "label": "edges", "end_id": 281474976710659, "start_id": 281474976710658, "properties": {}}::edge + {"id": 844424930131974, "label": "edges", "end_id": 281474976710660, "start_id": 281474976710658, "properties": {}}::edge + {"id": 844424930131975, "label": "edges", "end_id": 281474976710661, "start_id": 281474976710658, "properties": {}}::edge + {"id": 844424930131976, "label": "edges", "end_id": 281474976710660, "start_id": 281474976710659, "properties": {}}::edge + {"id": 844424930131977, "label": "edges", "end_id": 281474976710661, "start_id": 281474976710659, "properties": {}}::edge + {"id": 844424930131978, "label": "edges", "end_id": 281474976710661, "start_id": 281474976710660, "properties": {}}::edge + {"id": 844424930131979, "label": "edges", "end_id": 281474976710663, "start_id": 281474976710662, "properties": {}}::edge + {"id": 844424930131980, "label": "edges", "end_id": 281474976710664, "start_id": 281474976710662, "properties": {}}::edge + {"id": 844424930131981, "label": "edges", "end_id": 281474976710665, "start_id": 281474976710662, "properties": {}}::edge + {"id": 844424930131982, "label": "edges", "end_id": 281474976710666, "start_id": 281474976710662, "properties": {}}::edge + {"id": 844424930131983, "label": "edges", "end_id": 281474976710664, "start_id": 281474976710663, "properties": {}}::edge + {"id": 844424930131984, "label": "edges", "end_id": 281474976710665, "start_id": 281474976710663, "properties": {}}::edge + {"id": 844424930131985, "label": "edges", "end_id": 281474976710666, "start_id": 281474976710663, "properties": {}}::edge + {"id": 844424930131986, "label": "edges", "end_id": 281474976710665, "start_id": 281474976710664, "properties": {}}::edge + {"id": 844424930131987, "label": "edges", "end_id": 281474976710666, "start_id": 281474976710664, "properties": {}}::edge + {"id": 844424930131988, "label": "edges", "end_id": 281474976710666, "start_id": 281474976710665, "properties": {}}::edge + {"id": 844424930131989, "label": "edges", "end_id": 281474976710666, "start_id": 281474976710657, "properties": {}}::edge +(21 rows) + +-- SHOULD FAIL, but with an error rather than a crash +SELECT * FROM age_create_barbell_graph('gp8',5,0); +ERROR: edge label can not be NULL -- DROPPING GRAPHS SELECT drop_graph('gp1', true); NOTICE: drop cascades to 4 other objects @@ -228,3 +282,14 @@ NOTICE: graph "gp2" has been dropped (1 row) +SELECT drop_graph('gp7', true); +NOTICE: drop cascades to 3 other objects +DETAIL: drop cascades to table gp7._ag_label_vertex +drop cascades to table gp7._ag_label_edge +drop cascades to table gp7.edges +NOTICE: graph "gp7" has been dropped + drop_graph +------------ + +(1 row) + diff --git a/regress/sql/graph_generation.sql b/regress/sql/graph_generation.sql index e9ee8ea81..ee359ce9b 100644 --- a/regress/sql/graph_generation.sql +++ b/regress/sql/graph_generation.sql @@ -76,7 +76,22 @@ SELECT * FROM age_create_barbell_graph('gp5',5,0,'vertices',NULL,NULL,NULL); -- Should error out because same labels are used for both vertices and edges SELECT * FROM age_create_barbell_graph('gp6',5,10,'label',NULL,'label',NULL); +/* + * node_label is declared with a NULL default, so passing NULL for it - either + * explicitly or by leaving the trailing arguments out - has to fall back to + * the default vertex label rather than crash the backend. + */ +SELECT * FROM age_create_barbell_graph('gp7',5,0,NULL,NULL,'edges',NULL); + +SELECT COUNT(*) FROM gp7."_ag_label_vertex"; +SELECT COUNT(*) FROM gp7."edges"; +SELECT * FROM cypher('gp7', $$MATCH (a)-[e]->(b) RETURN e$$) as (n agtype); + +-- SHOULD FAIL, but with an error rather than a crash +SELECT * FROM age_create_barbell_graph('gp8',5,0); + -- DROPPING GRAPHS SELECT drop_graph('gp1', true); SELECT drop_graph('gp2', true); +SELECT drop_graph('gp7', true); diff --git a/src/backend/utils/graph_generation.c b/src/backend/utils/graph_generation.c index ea8e1bd5b..4dea04260 100644 --- a/src/backend/utils/graph_generation.c +++ b/src/backend/utils/graph_generation.c @@ -238,6 +238,8 @@ Datum age_create_barbell_graph(PG_FUNCTION_ARGS) int64 start_node_index, end_node_index, nextval; Name node_label_name = NULL; + NameData default_node_label; + Datum node_label_datum; int32 node_label_id; char* node_label_str; @@ -284,16 +286,22 @@ Datum age_create_barbell_graph(PG_FUNCTION_ARGS) errmsg("Bridge size cannot be NULL or lower than 0"))); } - /* node label: if null, gets default label, which is "_ag_label_vertex" */ + /* + * node label: if null, gets default label, which is "_ag_label_vertex". + * The default needs storage of its own - namestrcpy() writes through the + * pointer it is given and does not allocate. + */ if (PG_ARGISNULL(3)) { - namestrcpy(node_label_name, AG_DEFAULT_LABEL_VERTEX); + namestrcpy(&default_node_label, AG_DEFAULT_LABEL_VERTEX); + node_label_name = &default_node_label; } else { node_label_name = PG_GETARG_NAME(3); } node_label_str = NameStr(*node_label_name); + node_label_datum = NameGetDatum(node_label_name); /* Name edge_label */ if (PG_ARGISNULL(5)) @@ -306,15 +314,20 @@ Datum age_create_barbell_graph(PG_FUNCTION_ARGS) edge_label_str = NameStr(*edge_label_name); - /* create two separate complete graphs */ + /* + * Create two separate complete graphs. node_label_datum is used rather + * than args[3].value because DirectFunctionCall4() marks every argument + * as not null, so a null node label would reach create_complete_graph() + * as a non-null NULL pointer. + */ DirectFunctionCall4(create_complete_graph, arguments->args[0].value, arguments->args[1].value, arguments->args[5].value, - arguments->args[3].value); + node_label_datum); DirectFunctionCall4(create_complete_graph, arguments->args[0].value, arguments->args[1].value, arguments->args[5].value, - arguments->args[3].value); + node_label_datum); graph_oid = get_graph_oid(graph_name_str); node_label_id = get_label_id(node_label_str, graph_oid);