You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@age.apache.org by jg...@apache.org on 2022/01/06 21:36:35 UTC
[incubator-age] branch master updated: Add zero boundary case [*0..x] to VLE
This is an automated email from the ASF dual-hosted git repository.
jgemignani pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-age.git
The following commit(s) were added to refs/heads/master by this push:
new e64df3b Add zero boundary case [*0..x] to VLE
e64df3b is described below
commit e64df3b96d7da57fbbb12e910dda141c36ca4db3
Author: John Gemignani <jr...@gmail.com>
AuthorDate: Tue Jan 4 15:22:10 2022 -0800
Add zero boundary case [*0..x] to VLE
Added the zero boundary case [*0..x] to the VLE.
Fixed some Travis CI warnings in the VLE code.
Added additional regression tests.
---
regress/expected/cypher_vle.out | 43 ++++++++++++++++++-
regress/sql/cypher_vle.sql | 25 ++++-------
src/backend/parser/cypher_clause.c | 23 ++++++++---
src/backend/utils/adt/agtype_vle.c | 85 ++++++++++++++++++++++++++++++++------
4 files changed, 140 insertions(+), 36 deletions(-)
diff --git a/regress/expected/cypher_vle.out b/regress/expected/cypher_vle.out
index 66acfc2..bfc7b0f 100644
--- a/regress/expected/cypher_vle.out
+++ b/regress/expected/cypher_vle.out
@@ -332,7 +332,7 @@ SELECT * FROM cypher('cypher_vle', $$MATCH p=(u:begin)-[*3..3]-(v:end) RETURN p
[{"id": 844424930131969, "label": "begin", "properties": {}}::vertex, {"id": 1125899906842628, "label": "edge", "end_id": 1407374883553281, "start_id": 844424930131969, "properties": {"name": "main edge", "number": 1, "dangerous": {"type": "all", "level": "all"}}}::edge, {"id": 1407374883553281, "label": "middle", "properties": {}}::vertex, {"id": 1125899906842627, "label": "edge", "end_id": 1407374883553282, "start_id": 1407374883553281, "properties": {"name": "main edge", "number": 2, [...]
(12 rows)
--- Should find 2
+-- Each should find 2
SELECT * FROM cypher('cypher_vle', $$MATCH p=(u:begin)<-[*]-(v:end) RETURN p $$) AS (e agtype);
[...]
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ [...]
@@ -449,13 +449,52 @@ $$) AS (e1 agtype);
13
(1 row)
--- should return 1 path
+-- Should return 1 path
SELECT * FROM cypher('cypher_vle', $$ MATCH p=()<-[e1*]-(:end)-[e2*]->(:begin) RETURN p $$) AS (result agtype);
[...]
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ [...]
[{"id": 1688849860263937, "label": "end", "properties": {}}::vertex, {"id": 1970324836974594, "label": "self_loop", "end_id": 1688849860263937, "start_id": 1688849860263937, "properties": {"name": "self loop", "number": 2, "dangerous": {"type": "all", "level": "all"}}}::edge, {"id": 1688849860263937, "label": "end", "properties": {}}::vertex, {"id": 2251799813685252, "label": "alternate_edge", "end_id": 1407374883553283, "start_id": 1688849860263937, "properties": {"name": "backup edge" [...]
(1 row)
+-- Each should return 3
+SELECT * FROM cypher('cypher_vle', $$MATCH (u:begin)-[e*0..1]->(v) RETURN id(u), e, id(v) $$) AS (u agtype, e agtype, v agtype);
+ u | e | v
+-----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------
+ 844424930131969 | [] | 844424930131969
+ 844424930131969 | [{"id": 2251799813685249, "label": "alternate_edge", "end_id": 1407374883553281, "start_id": 844424930131969, "properties": {"name": "alternate edge", "number": 1, "packages": [2, 4, 6], "dangerous": {"type": "poisons", "level": "all"}}}::edge] | 1407374883553281
+ 844424930131969 | [{"id": 1125899906842628, "label": "edge", "end_id": 1407374883553281, "start_id": 844424930131969, "properties": {"name": "main edge", "number": 1, "dangerous": {"type": "all", "level": "all"}}}::edge] | 1407374883553281
+(3 rows)
+
+SELECT * FROM cypher('cypher_vle', $$MATCH p=(u:begin)-[e*0..1]->(v) RETURN p $$) AS (p agtype);
+ p
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ [{"id": 844424930131969, "label": "begin", "properties": {}}::vertex]::path
+ [{"id": 844424930131969, "label": "begin", "properties": {}}::vertex, {"id": 2251799813685249, "label": "alternate_edge", "end_id": 1407374883553281, "start_id": 844424930131969, "properties": {"name": "alternate edge", "number": 1, "packages": [2, 4, 6], "dangerous": {"type": "poisons", "level": "all"}}}::edge, {"id": 1407374883553281, "label": "middle", "properties": {}}::vertex]::path
+ [{"id": 844424930131969, "label": "begin", "properties": {}}::vertex, {"id": 1125899906842628, "label": "edge", "end_id": 1407374883553281, "start_id": 844424930131969, "properties": {"name": "main edge", "number": 1, "dangerous": {"type": "all", "level": "all"}}}::edge, {"id": 1407374883553281, "label": "middle", "properties": {}}::vertex]::path
+(3 rows)
+
+-- Each should return 5
+SELECT * FROM cypher('cypher_vle', $$MATCH (u)-[e*0..0]->(v) RETURN id(u), e, id(v) $$) AS (u agtype, e agtype, v agtype);
+ u | e | v
+------------------+----+------------------
+ 844424930131969 | [] | 844424930131969
+ 1407374883553281 | [] | 1407374883553281
+ 1407374883553282 | [] | 1407374883553282
+ 1407374883553283 | [] | 1407374883553283
+ 1688849860263937 | [] | 1688849860263937
+(5 rows)
+
+SELECT * FROM cypher('cypher_vle', $$MATCH p=(u)-[e*0..0]->(v) RETURN id(u), p, id(v) $$) AS (u agtype, p agtype, v agtype);
+ u | p | v
+------------------+-------------------------------------------------------------------------------+------------------
+ 844424930131969 | [{"id": 844424930131969, "label": "begin", "properties": {}}::vertex]::path | 844424930131969
+ 1407374883553281 | [{"id": 1407374883553281, "label": "middle", "properties": {}}::vertex]::path | 1407374883553281
+ 1407374883553282 | [{"id": 1407374883553282, "label": "middle", "properties": {}}::vertex]::path | 1407374883553282
+ 1407374883553283 | [{"id": 1407374883553283, "label": "middle", "properties": {}}::vertex]::path | 1407374883553283
+ 1688849860263937 | [{"id": 1688849860263937, "label": "end", "properties": {}}::vertex]::path | 1688849860263937
+(5 rows)
+
+--
-- Clean up
--
DROP TABLE start_and_end_points;
diff --git a/regress/sql/cypher_vle.sql b/regress/sql/cypher_vle.sql
index dbf520f..7f3b8fb 100644
--- a/regress/sql/cypher_vle.sql
+++ b/regress/sql/cypher_vle.sql
@@ -114,66 +114,59 @@ SELECT * FROM cypher('cypher_vle', $$MATCH p=()-[*]->(v) RETURN count(*) $$) AS
SELECT * FROM cypher('cypher_vle', $$MATCH p=(u:begin)-[*3..3]->(v:end) RETURN p $$) AS (e agtype);
-- Should find 12
SELECT * FROM cypher('cypher_vle', $$MATCH p=(u:begin)-[*3..3]-(v:end) RETURN p $$) AS (e agtype);
--- Should find 2
+-- Each should find 2
SELECT * FROM cypher('cypher_vle', $$MATCH p=(u:begin)<-[*]-(v:end) RETURN p $$) AS (e agtype);
SELECT * FROM cypher('cypher_vle', $$MATCH p=(u:begin)<-[e*]-(v:end) RETURN p $$) AS (e agtype);
SELECT * FROM cypher('cypher_vle', $$MATCH p=(u:begin)<-[e*]-(v:end) RETURN e $$) AS (e agtype);
SELECT * FROM cypher('cypher_vle', $$MATCH p=(:begin)<-[*]-()<-[]-(:end) RETURN p $$) AS (e agtype);
-- Each should return 31
SELECT count(*) FROM cypher('cypher_vle', $$ MATCH ()-[e1]->(v)-[e2]->() RETURN e1,e2 $$) AS (e1 agtype, e2 agtype);
-
SELECT count(*) FROM cypher('cypher_vle', $$
MATCH ()-[e1*1..1]->(v)-[e2*1..1]->()
RETURN e1, e2
$$) AS (e1 agtype, e2 agtype);
-
SELECT count(*) FROM cypher('cypher_vle', $$
MATCH (v)-[e1*1..1]->()-[e2*1..1]->()
RETURN e1, e2
$$) AS (e1 agtype, e2 agtype);
-
-
SELECT count(*) FROM cypher('cypher_vle', $$
MATCH ()-[e1]->(v)-[e2*1..1]->()
RETURN e1, e2
$$) AS (e1 agtype, e2 agtype);
-
SELECT count(*) FROM cypher('cypher_vle', $$
MATCH ()-[e1]->()-[e2*1..1]->()
RETURN e1, e2
$$) AS (e1 agtype, e2 agtype);
-
SELECT count(*) FROM cypher('cypher_vle', $$
MATCH ()-[e1*1..1]->(v)-[e2]->()
RETURN e1, e2
$$) AS (e1 agtype, e2 agtype);
-
SELECT count(*) FROM cypher('cypher_vle', $$
MATCH ()-[e1*1..1]->()-[e2]->()
RETURN e1, e2
$$) AS (e1 agtype, e2 agtype);
-
SELECT count(*) FROM cypher('cypher_vle', $$
MATCH (a)-[e1]->(a)-[e2*1..1]->()
RETURN e1, e2
$$) AS (e1 agtype, e2 agtype);
-
SELECT count(*) FROM cypher('cypher_vle', $$
MATCH (a) MATCH (a)-[e1*1..1]->(v)
RETURN e1
$$) AS (e1 agtype);
-
-
SELECT count(*) FROM cypher('cypher_vle', $$
MATCH (a) MATCH ()-[e1*1..1]->(a)
RETURN e1
$$) AS (e1 agtype);
-
-
--- should return 1 path
+-- Should return 1 path
SELECT * FROM cypher('cypher_vle', $$ MATCH p=()<-[e1*]-(:end)-[e2*]->(:begin) RETURN p $$) AS (result agtype);
+-- Each should return 3
+SELECT * FROM cypher('cypher_vle', $$MATCH (u:begin)-[e*0..1]->(v) RETURN id(u), e, id(v) $$) AS (u agtype, e agtype, v agtype);
+SELECT * FROM cypher('cypher_vle', $$MATCH p=(u:begin)-[e*0..1]->(v) RETURN p $$) AS (p agtype);
+-- Each should return 5
+SELECT * FROM cypher('cypher_vle', $$MATCH (u)-[e*0..0]->(v) RETURN id(u), e, id(v) $$) AS (u agtype, e agtype, v agtype);
+SELECT * FROM cypher('cypher_vle', $$MATCH p=(u)-[e*0..0]->(v) RETURN id(u), p, id(v) $$) AS (u agtype, p agtype, v agtype);
-
+--
-- Clean up
--
diff --git a/src/backend/parser/cypher_clause.c b/src/backend/parser/cypher_clause.c
index b85f323..7644184 100644
--- a/src/backend/parser/cypher_clause.c
+++ b/src/backend/parser/cypher_clause.c
@@ -2469,8 +2469,13 @@ static transform_entity *transform_VLE_edge_entity(cypher_parsestate *cpstate,
/* get the function */
func = (FuncCall*)rel->varlen;
- /* it better be one of our functions */
- Assert(list_length(func->funcname) == 1);
+ /* only our functions are supported here */
+ if (list_length(func->funcname) != 1)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("only AGE functions are supported here")));
+ }
/* set the pstate */
pstate = &cpstate->pstate;
@@ -3936,11 +3941,19 @@ transform_cypher_clause_as_subquery(cypher_parsestate *cpstate,
*/
if (list_length(pstate->p_rtable) > 1)
{
- List *namespace;
- int rtindex;
+ List *namespace = NULL;
+ int rtindex = 0;
+ /* get the index of the last entry */
rtindex = list_length(pstate->p_rtable);
- Assert(rte == rt_fetch(rtindex, pstate->p_rtable));
+
+ /* the rte at the end should be the rte just added */
+ if (rte != rt_fetch(rtindex, pstate->p_rtable))
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("rte must be last entry in p_rtable")));
+ }
namespace = list_make1(makeNamespaceItem(rte, true, true, false, true));
diff --git a/src/backend/utils/adt/agtype_vle.c b/src/backend/utils/adt/agtype_vle.c
index 9c949cc..2da3bd1 100644
--- a/src/backend/utils/adt/agtype_vle.c
+++ b/src/backend/utils/adt/agtype_vle.c
@@ -228,6 +228,7 @@ static bool is_edge_in_path(VLE_local_context *vlelctx, graphid edge_id);
/* VLE path and edge building functions */
static VLE_path_container *create_VLE_path_container(int64 path_size);
static VLE_path_container *build_VLE_path_container(VLE_local_context *vlelctx);
+static VLE_path_container *build_VLE_zero_container(VLE_local_context *vlelctx);
static agtype_value *build_path(VLE_path_container *vpc);
static agtype_value *build_edge_list(VLE_path_container *vpc);
@@ -1390,7 +1391,7 @@ static VLE_local_context *build_local_vle_context(FunctionCallInfo fcinfo)
/* get the left range index */
if (PG_ARGISNULL(4) || is_agtype_null(AG_GET_ARG_AGTYPE_P(4)))
{
- vlelctx->lidx = 0;
+ vlelctx->lidx = 1;
}
else
{
@@ -2147,6 +2148,36 @@ static VLE_path_container *build_VLE_path_container(VLE_local_context *vlelctx)
return vpc;
}
+/* helper function to build a VPC for just the start vertex */
+static VLE_path_container *build_VLE_zero_container(VLE_local_context *vlelctx)
+{
+ ListGraphId *stack = vlelctx->dfs_path_stack;
+ VLE_path_container *vpc = NULL;
+ graphid *graphid_array = NULL;
+ graphid vid = 0;
+
+ /* we should have an empty stack */
+ Assert(stack->size == 0);
+
+ /*
+ * Create the container. Note that the path size will always be 1 as this is
+ * just the starting vertex.
+ */
+ vpc = create_VLE_path_container(1);
+
+ /* set the graph_oid */
+ vpc->graph_oid = vlelctx->graph_oid;
+
+ /* get the graphid_array from the container */
+ graphid_array = GET_GRAPHID_ARRAY_FROM_CONTAINER(vpc);
+
+ /* get and store the start vertex */
+ vid = vlelctx->vsid;
+ graphid_array[0] = vid;
+
+ return vpc;
+}
+
/*
* Helper function to find the VLE_global_context used by the specified
* graph_oid. If not found, it returns NULL.
@@ -2382,6 +2413,7 @@ Datum age_vle(PG_FUNCTION_ARGS)
VLE_local_context *vlelctx = NULL;
bool found_a_path = false;
bool done = false;
+ bool is_zero_bound = false;
MemoryContext oldctx;
/* Initialization for the first call to the SRF */
@@ -2413,6 +2445,13 @@ Datum age_vle(PG_FUNCTION_ARGS)
funcctx->user_fctx = vlelctx;
MemoryContextSwitchTo(oldctx);
+
+ /* if we are starting from zero [*0..x] flag it */
+ if (vlelctx->lidx == 0)
+ {
+ is_zero_bound = true;
+ done = true;
+ }
}
/* stuff done on every call of the function */
@@ -2469,7 +2508,17 @@ Datum age_vle(PG_FUNCTION_ARGS)
/* load in the starting edge(s) */
load_initial_dfs_stacks(vlelctx);
- done = false;
+ /* if we are starting from zero [*0..x] flag it */
+ if (vlelctx->lidx == 0)
+ {
+ is_zero_bound = true;
+ done = true;
+ }
+ /* otherwise we need to loop back around */
+ else
+ {
+ done = false;
+ }
}
/* we shouldn't get here */
else
@@ -2487,19 +2536,29 @@ Datum age_vle(PG_FUNCTION_ARGS)
* If we find a path, we need to convert the path_stack into a list that
* the outside world can use.
*/
- if (found_a_path)
+ if (found_a_path || is_zero_bound)
{
VLE_path_container *vpc = NULL;
- /* the path_stack should have something in it if we have a path */
- Assert(vlelctx->dfs_path_stack > 0);
+ /* if this isn't the zero boundary case generate a normal vpc */
+ if (!is_zero_bound)
+ {
+ /* the path_stack should have something in it if we have a path */
+ Assert(vlelctx->dfs_path_stack > 0);
+
+ /*
+ * Build the graphid array into a VLE_path_container from the
+ * path_stack. This will also correct for the path_stack being last
+ * in, first out.
+ */
+ vpc = build_VLE_path_container(vlelctx);
+ }
+ /* otherwise, this is the zero boundary case [*0..x] */
+ else
+ {
+ vpc = build_VLE_zero_container(vlelctx);
+ }
- /*
- * Build the graphid array into a VLE_path_container from the
- * path_stack. This will also correct for the path_stack being last in,
- * first out.
- */
- vpc = build_VLE_path_container(vlelctx);
/* return the result and signal that the function is not yet done */
SRF_RETURN_NEXT(funcctx, PointerGetDatum(vpc));
}
@@ -2858,8 +2917,8 @@ Datum age_match_vle_terminal_edge(PG_FUNCTION_ARGS)
/* get the gida array size */
gidasize = vpc->graphid_array_size;
- /* verify the minimum size is 3 */
- Assert(gidasize >= 3);
+ /* verify the minimum size is 3 or 1 */
+ Assert(gidasize >= 3 || gidasize == 1);
/* get the vsid */
if (!PG_ARGISNULL(0))