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))