Skip to content
Permalink
Browse files
Add openCypher relationships() function AGE2-423
Added the openCypher relationships() function. This is Jira ticket
AGE2-423.

Added regression tests.
  • Loading branch information
jrgemignani committed Oct 5, 2021
1 parent cb5b4dd commit c1d84ddafd38981bec642a47b83c7592b64cb7a3
Showing 5 changed files with 162 additions and 11 deletions.
@@ -3727,15 +3727,23 @@ STABLE
PARALLEL SAFE
AS 'MODULE_PATHNAME';

CREATE OR REPLACE FUNCTION ag_catalog.age_vle(
IN agtype, IN agtype, IN agtype, IN agtype,
IN agtype, IN agtype, IN agtype,
OUT edges agtype)
CREATE FUNCTION ag_catalog.age_vle(IN agtype, IN agtype, IN agtype, IN agtype,
IN agtype, IN agtype, IN agtype,
OUT edges agtype)
RETURNS SETOF agtype
LANGUAGE C
IMMUTABLE
STRICT
AS 'MODULE_PATHNAME';

-- list functions
CREATE FUNCTION ag_catalog.age_relationships(agtype)
RETURNS agtype
LANGUAGE c
STABLE
PARALLEL SAFE
AS 'MODULE_PATHNAME';

--
-- End
--
@@ -337,10 +337,10 @@ NOTICE: ELabel "r" has been created
SELECT * FROM ag_label;
name | graph | id | kind | relation
------------------+-------+----+------+--------------------
_ag_label_vertex | 17623 | 1 | v | g._ag_label_vertex
_ag_label_edge | 17623 | 2 | e | g._ag_label_edge
n | 17623 | 3 | v | g.n
r | 17623 | 4 | e | g.r
_ag_label_vertex | 17625 | 1 | v | g._ag_label_vertex
_ag_label_edge | 17625 | 2 | e | g._ag_label_edge
n | 17625 | 3 | v | g.n
r | 17625 | 4 | e | g.r
(4 rows)

-- try to create duplicate labels
@@ -367,8 +367,8 @@ NOTICE: label "g"."r" has been dropped
SELECT * FROM ag_label;
name | graph | id | kind | relation
------------------+-------+----+------+--------------------
_ag_label_vertex | 17623 | 1 | v | g._ag_label_vertex
_ag_label_edge | 17623 | 2 | e | g._ag_label_edge
_ag_label_vertex | 17625 | 1 | v | g._ag_label_vertex
_ag_label_edge | 17625 | 2 | e | g._ag_label_edge
(2 rows)

-- try to remove labels that is not there
@@ -5378,6 +5378,62 @@ SELECT * FROM cypher('VLE', $$MATCH (u)-[*..5]-(v) RETURN u, v$$) AS (u agtype,
ERROR: variable length relationships are not supported
LINE 1: SELECT * FROM cypher('VLE', $$MATCH (u)-[*..5]-(v) RETURN u,...
^
-- list functions
SELECT create_graph('list');
NOTICE: graph "list" has been created
create_graph
--------------

(1 row)

SELECT * from cypher('list', $$CREATE p=()-[:knows]->() RETURN p$$) as (path agtype);
path
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
[{"id": 281474976710657, "label": "", "properties": {}}::vertex, {"id": 844424930131969, "label": "knows", "end_id": 281474976710658, "start_id": 281474976710657, "properties": {}}::edge, {"id": 281474976710658, "label": "", "properties": {}}::vertex]::path
(1 row)

SELECT * from cypher('list', $$CREATE p=()-[:knows]->()-[:knows]->() RETURN p$$) as (path agtype);
path
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
[{"id": 281474976710659, "label": "", "properties": {}}::vertex, {"id": 844424930131971, "label": "knows", "end_id": 281474976710660, "start_id": 281474976710659, "properties": {}}::edge, {"id": 281474976710660, "label": "", "properties": {}}::vertex, {"id": 844424930131970, "label": "knows", "end_id": 281474976710661, "start_id": 281474976710660, "properties": {}}::edge, {"id": 281474976710661, "label": "", "properties": {}}::vertex]::path
(1 row)

SELECT * from cypher('list', $$MATCH p=()-[]->() RETURN relationships(p)$$) as (relationships agtype);
relationships
-----------------------------------------------------------------------------------------------------------------------------
[{"id": 844424930131969, "label": "knows", "end_id": 281474976710658, "start_id": 281474976710657, "properties": {}}::edge]
[{"id": 844424930131971, "label": "knows", "end_id": 281474976710660, "start_id": 281474976710659, "properties": {}}::edge]
[{"id": 844424930131970, "label": "knows", "end_id": 281474976710661, "start_id": 281474976710660, "properties": {}}::edge]
(3 rows)

SELECT * from cypher('list', $$MATCH p=()-[]->()-[]->() RETURN relationships(p)$$) as (relationships agtype);
relationships
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
[{"id": 844424930131971, "label": "knows", "end_id": 281474976710660, "start_id": 281474976710659, "properties": {}}::edge, {"id": 844424930131970, "label": "knows", "end_id": 281474976710661, "start_id": 281474976710660, "properties": {}}::edge]
(1 row)

-- should return nothing
SELECT * from cypher('list', $$MATCH p=()-[]->()-[]->()-[]->() RETURN relationships(p)$$) as (relationships agtype);
relationships
---------------
(0 rows)

-- should return SQL NULL
SELECT * from cypher('list', $$RETURN relationships(NULL)$$) as (relationships agtype);
relationships
---------------

(1 row)

-- should return an error
SELECT * from cypher('list', $$MATCH (u) RETURN relationships([1,2,3])$$) as (relationships agtype);
ERROR: relationships() argument must resolve to a scalar value
SELECT * from cypher('list', $$MATCH (u) RETURN relationships("string")$$) as (relationships agtype);
ERROR: relationships() argument must be a path
SELECT * from cypher('list', $$MATCH (u) RETURN relationships(u)$$) as (relationships agtype);
ERROR: relationships() argument must be a path
SELECT * from cypher('list', $$MATCH ()-[e]->() RETURN relationships(e)$$) as (relationships agtype);
ERROR: relationships() argument must be a path
--
-- Cleanup
--
@@ -5481,6 +5537,17 @@ NOTICE: graph "regex" has been dropped

(1 row)

SELECT * FROM drop_graph('list', true);
NOTICE: drop cascades to 3 other objects
DETAIL: drop cascades to table list._ag_label_vertex
drop cascades to table list._ag_label_edge
drop cascades to table list.knows
NOTICE: graph "list" has been dropped
drop_graph
------------

(1 row)

--
-- End of tests
--
@@ -434,7 +434,6 @@ SELECT * FROM cypher('type_coercion', $$
RETURN 10000000000000000000
$$) AS (i smallint);


SELECT * FROM cypher('type_coercion', $$
RETURN 10000000000000000000
$$) AS (i int);
@@ -2214,6 +2213,22 @@ SELECT * FROM cypher('VLE', $$MATCH (u)-[*0..1]-(v) RETURN u, v$$) AS (u agtype,
SELECT * FROM cypher('VLE', $$MATCH (u)-[*..1]-(v) RETURN u, v$$) AS (u agtype, v agtype);
SELECT * FROM cypher('VLE', $$MATCH (u)-[*..5]-(v) RETURN u, v$$) AS (u agtype, v agtype);

-- list functions
SELECT create_graph('list');
SELECT * from cypher('list', $$CREATE p=()-[:knows]->() RETURN p$$) as (path agtype);
SELECT * from cypher('list', $$CREATE p=()-[:knows]->()-[:knows]->() RETURN p$$) as (path agtype);
SELECT * from cypher('list', $$MATCH p=()-[]->() RETURN relationships(p)$$) as (relationships agtype);
SELECT * from cypher('list', $$MATCH p=()-[]->()-[]->() RETURN relationships(p)$$) as (relationships agtype);
-- should return nothing
SELECT * from cypher('list', $$MATCH p=()-[]->()-[]->()-[]->() RETURN relationships(p)$$) as (relationships agtype);
-- should return SQL NULL
SELECT * from cypher('list', $$RETURN relationships(NULL)$$) as (relationships agtype);
-- should return an error
SELECT * from cypher('list', $$MATCH (u) RETURN relationships([1,2,3])$$) as (relationships agtype);
SELECT * from cypher('list', $$MATCH (u) RETURN relationships("string")$$) as (relationships agtype);
SELECT * from cypher('list', $$MATCH (u) RETURN relationships(u)$$) as (relationships agtype);
SELECT * from cypher('list', $$MATCH ()-[e]->() RETURN relationships(e)$$) as (relationships agtype);

--
-- Cleanup
--
@@ -2226,6 +2241,7 @@ SELECT * FROM drop_graph('group_by', true);
SELECT * FROM drop_graph('UCSC', true);
SELECT * FROM drop_graph('expr', true);
SELECT * FROM drop_graph('regex', true);
SELECT * FROM drop_graph('list', true);

--
-- End of tests
@@ -8281,3 +8281,63 @@ Datum age_eq_tilde(PG_FUNCTION_ARGS)
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("agtype string values expected")));
}

PG_FUNCTION_INFO_V1(age_relationships);
/*
* Execution function to implement openCypher relationships() function
*/
Datum age_relationships(PG_FUNCTION_ARGS)
{
agtype *agt_arg = NULL;
agtype_value *agtv_path = NULL;
agtype_in_state agis_result;
int i = 0;

/* check for null */
if (PG_ARGISNULL(0))
{
PG_RETURN_NULL();
}

agt_arg = AG_GET_ARG_AGTYPE_P(0);
/* check for a scalar object */
if (!AGT_ROOT_IS_SCALAR(agt_arg))
{
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("relationships() argument must resolve to a scalar value")));
}

/* get the potential path out of the array */
agtv_path = get_ith_agtype_value_from_container(&agt_arg->root, 0);

/* is it an agtype null? */
if (agtv_path->type == AGTV_NULL)
{
PG_RETURN_NULL();
}

/* verify that it is an agtype path */
if (agtv_path->type != AGTV_PATH)
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("relationships() argument must be a path")));

/* clear the result structure */
MemSet(&agis_result, 0, sizeof(agtype_in_state));

/* push the beginning of the array */
agis_result.res = push_agtype_value(&agis_result.parse_state,
WAGT_BEGIN_ARRAY, NULL);
/* push in each edge (every other entry) from the path */
for (i = 1; i < agtv_path->val.array.num_elems; i += 2)
{
agis_result.res = push_agtype_value(&agis_result.parse_state, WAGT_ELEM,
&agtv_path->val.array.elems[i]);
}

/* push the end of the array */
agis_result.res = push_agtype_value(&agis_result.parse_state,
WAGT_END_ARRAY, NULL);

/* convert the agtype_value to a datum to return to the caller */
PG_RETURN_POINTER(agtype_value_to_agtype(agis_result.res));
}

0 comments on commit c1d84dd

Please sign in to comment.