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 2023/01/03 22:26:58 UTC
[age] branch master updated: Fix bug #339 - entities in WHERE clause have wrong Expr (#391)
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/age.git
The following commit(s) were added to refs/heads/master by this push:
new e396815 Fix bug #339 - entities in WHERE clause have wrong Expr (#391)
e396815 is described below
commit e39681551f403addbfb74c51596350521d5b780a
Author: Rafsun Masud <ra...@gmail.com>
AuthorDate: Tue Jan 3 17:26:52 2023 -0500
Fix bug #339 - entities in WHERE clause have wrong Expr (#391)
Whenever a node or an edge within a WHERE clause uses a Var type
expr retrieved from a different cypher parsestate, the Var->varlevelsup
is adjusted.
---
regress/expected/cypher_match.out | 80 ++++++++++++++++++++++++++++
regress/sql/cypher_match.sql | 44 +++++++++++++++
src/backend/parser/cypher_clause.c | 5 +-
src/backend/parser/cypher_transform_entity.c | 31 +++++++++++
src/include/parser/cypher_transform_entity.h | 2 +
5 files changed, 159 insertions(+), 3 deletions(-)
diff --git a/regress/expected/cypher_match.out b/regress/expected/cypher_match.out
index 4757392..6ff9a3c 100644
--- a/regress/expected/cypher_match.out
+++ b/regress/expected/cypher_match.out
@@ -1000,6 +1000,73 @@ SELECT * FROM cypher('cypher_match', $$
"nobody" | | | "anybody" | |
(12 rows)
+--
+-- Tests retrieving Var from some parent's cpstate during transformation
+--
+SELECT create_graph('test_retrieve_var');
+NOTICE: graph "test_retrieve_var" has been created
+ create_graph
+--------------
+
+(1 row)
+
+SELECT * FROM cypher('test_retrieve_var', $$ CREATE (:A)-[:incs]->(:C) $$) as (a agtype);
+ a
+---
+(0 rows)
+
+-- Tests with node Var
+-- both queries should return the same result
+-- first query does not retrieve any variable from any parent's cpstate
+-- second query retrieves variable 'a', inside WHERE, from parent's parent's cpstate
+SELECT * FROM cypher('test_retrieve_var', $$
+ MATCH (a:A) WITH a
+ OPTIONAL MATCH (a)-[:incs]->(c)
+ WHERE EXISTS((c)<-[:incs]-())
+ RETURN a, c
+$$) AS (a agtype, c agtype);
+ a | c
+-----------------------------------------------------------------+------------------------------------------------------------------
+ {"id": 844424930131969, "label": "A", "properties": {}}::vertex | {"id": 1407374883553281, "label": "C", "properties": {}}::vertex
+(1 row)
+
+SELECT * FROM cypher('test_retrieve_var', $$
+ MATCH (a:A) WITH a
+ OPTIONAL MATCH (a)-[:incs]->(c)
+ WHERE EXISTS((c)<-[:incs]-(a))
+ RETURN a, c
+$$) AS (a agtype, c agtype);
+ a | c
+-----------------------------------------------------------------+------------------------------------------------------------------
+ {"id": 844424930131969, "label": "A", "properties": {}}::vertex | {"id": 1407374883553281, "label": "C", "properties": {}}::vertex
+(1 row)
+
+-- Tests with edge Var
+-- both queries should return the same result
+-- first query does not retrieve any variable from any parent's cpstate
+-- second query retrieves variable 'r', inside WHERE, from parent's parent's cpstate
+SELECT * FROM cypher('test_retrieve_var', $$
+ MATCH (a:A)-[r:incs]->() WITH a, r
+ OPTIONAL MATCH (a)-[r]->(c)
+ WHERE EXISTS(()<-[]-(c))
+ RETURN a, r
+$$) AS (a agtype, r agtype);
+ a | r
+-----------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------
+ {"id": 844424930131969, "label": "A", "properties": {}}::vertex | {"id": 1125899906842625, "label": "incs", "end_id": 1407374883553281, "start_id": 844424930131969, "properties": {}}::edge
+(1 row)
+
+SELECT * FROM cypher('test_retrieve_var', $$
+ MATCH (a:A)-[r:incs]->() WITH a, r
+ OPTIONAL MATCH (a)-[r]->(c)
+ WHERE EXISTS(()<-[r]-(c))
+ RETURN a, r
+$$) AS (a agtype, r agtype);
+ a | r
+-----------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------
+ {"id": 844424930131969, "label": "A", "properties": {}}::vertex | {"id": 1125899906842625, "label": "incs", "end_id": 1407374883553281, "start_id": 844424930131969, "properties": {}}::edge
+(1 row)
+
--
-- JIRA: AGE2-544
--
@@ -1135,6 +1202,19 @@ NOTICE: graph "cypher_match" has been dropped
(1 row)
+SELECT drop_graph('test_retrieve_var', true);
+NOTICE: drop cascades to 5 other objects
+DETAIL: drop cascades to table test_retrieve_var._ag_label_vertex
+drop cascades to table test_retrieve_var._ag_label_edge
+drop cascades to table test_retrieve_var."A"
+drop cascades to table test_retrieve_var.incs
+drop cascades to table test_retrieve_var."C"
+NOTICE: graph "test_retrieve_var" has been dropped
+ drop_graph
+------------
+
+(1 row)
+
--
-- End
--
diff --git a/regress/sql/cypher_match.sql b/regress/sql/cypher_match.sql
index 1128296..c4c48bf 100644
--- a/regress/sql/cypher_match.sql
+++ b/regress/sql/cypher_match.sql
@@ -501,6 +501,49 @@ SELECT * FROM cypher('cypher_match', $$
ORDER BY n, p, m, q
$$) AS (n agtype, r agtype, p agtype, m agtype, s agtype, q agtype);
+
+--
+-- Tests retrieving Var from some parent's cpstate during transformation
+--
+SELECT create_graph('test_retrieve_var');
+SELECT * FROM cypher('test_retrieve_var', $$ CREATE (:A)-[:incs]->(:C) $$) as (a agtype);
+
+-- Tests with node Var
+-- both queries should return the same result
+-- first query does not retrieve any variable from any parent's cpstate
+-- second query retrieves variable 'a', inside WHERE, from parent's parent's cpstate
+SELECT * FROM cypher('test_retrieve_var', $$
+ MATCH (a:A) WITH a
+ OPTIONAL MATCH (a)-[:incs]->(c)
+ WHERE EXISTS((c)<-[:incs]-())
+ RETURN a, c
+$$) AS (a agtype, c agtype);
+
+SELECT * FROM cypher('test_retrieve_var', $$
+ MATCH (a:A) WITH a
+ OPTIONAL MATCH (a)-[:incs]->(c)
+ WHERE EXISTS((c)<-[:incs]-(a))
+ RETURN a, c
+$$) AS (a agtype, c agtype);
+
+-- Tests with edge Var
+-- both queries should return the same result
+-- first query does not retrieve any variable from any parent's cpstate
+-- second query retrieves variable 'r', inside WHERE, from parent's parent's cpstate
+SELECT * FROM cypher('test_retrieve_var', $$
+ MATCH (a:A)-[r:incs]->() WITH a, r
+ OPTIONAL MATCH (a)-[r]->(c)
+ WHERE EXISTS(()<-[]-(c))
+ RETURN a, r
+$$) AS (a agtype, r agtype);
+
+SELECT * FROM cypher('test_retrieve_var', $$
+ MATCH (a:A)-[r:incs]->() WITH a, r
+ OPTIONAL MATCH (a)-[r]->(c)
+ WHERE EXISTS(()<-[r]-(c))
+ RETURN a, r
+$$) AS (a agtype, r agtype);
+
--
-- JIRA: AGE2-544
--
@@ -561,6 +604,7 @@ $$) as (n agtype);
-- Clean up
--
SELECT drop_graph('cypher_match', true);
+SELECT drop_graph('test_retrieve_var', true);
--
-- End
diff --git a/src/backend/parser/cypher_clause.c b/src/backend/parser/cypher_clause.c
index 9b0c76e..a541fb4 100644
--- a/src/backend/parser/cypher_clause.c
+++ b/src/backend/parser/cypher_clause.c
@@ -4146,7 +4146,7 @@ static Expr *transform_cypher_edge(cypher_parsestate *cpstate,
if (entity != NULL)
{
- return entity->expr;
+ return get_relative_expr(entity, 2);
}
else
{
@@ -4294,10 +4294,9 @@ static Expr *transform_cypher_node(cypher_parsestate *cpstate,
*/
transform_entity *entity = find_variable(parent_cpstate, node->name);
-
if (entity != NULL)
{
- return entity->expr;
+ return get_relative_expr(entity, 2);
}
else
{
diff --git a/src/backend/parser/cypher_transform_entity.c b/src/backend/parser/cypher_transform_entity.c
index 6d4b2c7..b80c228 100644
--- a/src/backend/parser/cypher_transform_entity.c
+++ b/src/backend/parser/cypher_transform_entity.c
@@ -152,3 +152,34 @@ char *get_entity_name(transform_entity *entity)
return NULL;
}
+
+/*
+ * Returns entity->expr relative to the current cpstate.
+ *
+ * For example,
+ * If entity is from current cpstate, its levelsup = 0.
+ * If entity is from immediate parent cpstate, its levelsup = 1.
+ * If entity is from parent's parent's cpstate, its levelsup = 2.
+ *
+ * Relative Expr is necessary when entity->expr is a Var and the entity
+ * is not from the current cpstate. In this case, Var->varlevelsup must
+ * reflect the distance between source cpstate of the entity and the
+ * cpstate where the Var is being used.
+ */
+Expr *get_relative_expr(transform_entity *entity, Index levelsup)
+{
+ Var *var;
+ Var *updated_var;
+
+ if (!IsA(entity->expr, Var))
+ {
+ return entity->expr;
+ }
+
+ var = (Var *)entity->expr;
+ updated_var = makeVar(var->varno, var->varattno, var->vartype,
+ var->vartypmod, var->varcollid,
+ var->varlevelsup + levelsup);
+
+ return (Expr *)updated_var;
+}
diff --git a/src/include/parser/cypher_transform_entity.h b/src/include/parser/cypher_transform_entity.h
index 5732c83..79a8a33 100644
--- a/src/include/parser/cypher_transform_entity.h
+++ b/src/include/parser/cypher_transform_entity.h
@@ -24,6 +24,7 @@
#include "parser/parse_node.h"
#include "nodes/cypher_nodes.h"
+#include "nodes/makefuncs.h"
#include "parser/cypher_parse_node.h"
enum transform_entity_type
@@ -93,5 +94,6 @@ transform_entity *make_transform_entity(cypher_parsestate *cpstate,
enum transform_entity_type type,
Node *node, Expr *expr);
char *get_entity_name(transform_entity *entity);
+Expr *get_relative_expr(transform_entity *entity, Index levelsup);
#endif