From 00ca796fb8aab72aab316b116ab615da29b879cf Mon Sep 17 00:00:00 2001 From: John Gemignani Date: Tue, 28 Nov 2023 17:08:14 -0800 Subject: [PATCH] Fix issue 1393 - previous clause variables not seen with EXISTS (#1426) (#1429) Fixed issue 1393 - Unexpected error when matching nodes that are connected to nodes resulted from a previous MATCH clause. Basically, variables from the previous clauses where not seen when using the EXISTS clause for path pattern matches. This only affected EXISTS and only for the EXISTS (anonymous_path) grammar component. The original issue was only with vertices, but this also affected edges. Both cases are now fixed. Fixed 1 regression test that was incorrect. Added regression tests. Resolved - Conflicts: src/backend/parser/cypher_clause.c --- regress/expected/cypher_match.out | 379 ++++++++++++++++++++++++++--- regress/sql/cypher_match.sql | 164 +++++++++++-- src/backend/parser/cypher_clause.c | 67 +++-- 3 files changed, 536 insertions(+), 74 deletions(-) diff --git a/regress/expected/cypher_match.out b/regress/expected/cypher_match.out index a42ccf5cf..d989141de 100644 --- a/regress/expected/cypher_match.out +++ b/regress/expected/cypher_match.out @@ -1192,20 +1192,6 @@ AS (exists agtype); true (15 rows) -SELECT * FROM cypher('cypher_match', - $$MATCH p=(u)-[e]->(v) RETURN EXISTS((p)) $$) -AS (exists agtype); - exists --------- - true - true - true - true - true - true - true -(7 rows) - SELECT * FROM cypher('cypher_match', $$MATCH (u)-[e]->(v) RETURN EXISTS((u)-[e]->(v)-[e]->(u))$$) AS (exists agtype); @@ -1235,6 +1221,13 @@ AS (u agtype, e agtype, v agtype); ERROR: variable `x` does not exist LINE 2: $$MATCH (u)-[e]->(v) WHERE EXISTS((u)-[e]->(x)) RETURN u, e... ^ +-- path variable not allowed in EXISTS +SELECT * FROM cypher('cypher_match', + $$MATCH p=(u)-[e]->(v) RETURN EXISTS((p)) $$) +AS (exists agtype); +ERROR: a path variable 'p' is not allowed here +LINE 2: $$MATCH p=(u)-[e]->(v) RETURN EXISTS((p)) $$) + ^ -- -- Tests for EXISTS(property) -- @@ -1965,7 +1958,7 @@ SELECT * FROM cypher('cypher_match', $$ (8 rows) SELECT * FROM cypher('cypher_match', $$ - MATCH (a) WHERE exists(a.name) RETURN a $$) as (a agtype); + MATCH (a) WHERE EXISTS(a.name) RETURN a $$) as (a agtype); a -------------------------------------------------------------------------------- {"id": 281474976710659, "label": "", "properties": {"name": "orphan"}}::vertex @@ -1974,7 +1967,7 @@ SELECT * FROM cypher('cypher_match', $$ (3 rows) SELECT * FROM cypher('cypher_match', $$ - MATCH (a) WHERE exists(a.name) SET a.age = 4 RETURN a $$) as (a agtype); + MATCH (a) WHERE EXISTS(a.name) SET a.age = 4 RETURN a $$) as (a agtype); a ------------------------------------------------------------------------------------------ {"id": 281474976710659, "label": "", "properties": {"age": 4, "name": "orphan"}}::vertex @@ -2080,7 +2073,7 @@ SELECT * FROM cypher('cypher_match', $$ (1 row) SELECT * FROM cypher('cypher_match', $$ - MATCH (a) WHERE exists(a.age) AND exists(a.name) RETURN a $$) as (a agtype); + MATCH (a) WHERE EXISTS(a.age) AND EXISTS(a.name) RETURN a $$) as (a agtype); a ------------------------------------------------------------------------------------------ {"id": 281474976710660, "label": "", "properties": {"age": 4, "name": "F"}}::vertex @@ -2089,7 +2082,7 @@ SELECT * FROM cypher('cypher_match', $$ (3 rows) SELECT * FROM cypher('cypher_match', $$ - MATCH (a) WHERE exists(a.age) AND NOT exists(a.name) RETURN a $$) as (a agtype); + MATCH (a) WHERE EXISTS(a.age) AND NOT EXISTS(a.name) RETURN a $$) as (a agtype); a ------------------------------------------------------------------------ {"id": 281474976710665, "label": "", "properties": {"age": 4}}::vertex @@ -2839,7 +2832,7 @@ NOTICE: graph "issue_1399" has been created -- this is an empty graph so these should return 0 SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE exists((foo)-[]->()) + WHERE EXISTS((foo)-[]->()) RETURN foo $$) as (c agtype); c @@ -2848,7 +2841,7 @@ $$) as (c agtype); SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE NOT exists((foo)-[]->()) + WHERE NOT EXISTS((foo)-[]->()) RETURN foo $$) as (c agtype); c @@ -2857,7 +2850,7 @@ $$) as (c agtype); SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE exists((foo)-[:BAR]->()) + WHERE EXISTS((foo)-[:BAR]->()) RETURN foo $$) as (c agtype); c @@ -2866,7 +2859,7 @@ $$) as (c agtype); SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE NOT exists((foo)-[:BAR]->()) + WHERE NOT EXISTS((foo)-[:BAR]->()) RETURN foo $$) as (c agtype); c @@ -2876,7 +2869,7 @@ $$) as (c agtype); -- this is an empty graph so these should return false SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE exists((foo)-[]->()) + WHERE EXISTS((foo)-[]->()) RETURN count(foo) > 0 $$) as (c agtype); c @@ -2886,7 +2879,7 @@ $$) as (c agtype); SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE NOT exists((foo)-[]->()) + WHERE NOT EXISTS((foo)-[]->()) RETURN count(foo) > 0 $$) as (c agtype); c @@ -2896,7 +2889,7 @@ $$) as (c agtype); SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE exists((foo)-[:BAR]->()) + WHERE EXISTS((foo)-[:BAR]->()) RETURN count(foo) > 0 $$) as (c agtype); c @@ -2906,7 +2899,7 @@ $$) as (c agtype); SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE NOT exists((foo)-[:BAR]->()) + WHERE NOT EXISTS((foo)-[:BAR]->()) RETURN count(foo) > 0 $$) as (c agtype); c @@ -2927,7 +2920,7 @@ $$) as (c agtype); -- only one vertex can match. SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE exists((foo)-[]->()) + WHERE EXISTS((foo)-[]->()) RETURN foo $$) as (c agtype); c @@ -2937,7 +2930,7 @@ $$) as (c agtype); SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE NOT exists((foo)-[]->()) + WHERE NOT EXISTS((foo)-[]->()) RETURN foo $$) as (c agtype); c @@ -2947,7 +2940,7 @@ $$) as (c agtype); SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE exists((foo)-[:BAR]->()) + WHERE EXISTS((foo)-[:BAR]->()) RETURN foo $$) as (c agtype); c @@ -2957,7 +2950,7 @@ $$) as (c agtype); SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE NOT exists((foo)-[:BAR]->()) + WHERE NOT EXISTS((foo)-[:BAR]->()) RETURN foo $$) as (c agtype); c @@ -2968,7 +2961,7 @@ $$) as (c agtype); -- this should return 0 rows as it can't exist - that path isn't in BAR2 SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE exists((foo)-[:BAR2]->()) + WHERE EXISTS((foo)-[:BAR2]->()) RETURN foo $$) as (c agtype); c @@ -2978,7 +2971,7 @@ $$) as (c agtype); -- this should return 2 rows as they all exist SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE NOT exists((foo)-[:BAR2]->()) + WHERE NOT EXISTS((foo)-[:BAR2]->()) RETURN foo $$) as (c agtype); c @@ -2987,6 +2980,316 @@ $$) as (c agtype); {"id": 281474976710658, "label": "", "properties": {}}::vertex (2 rows) +-- Issue 1393 EXISTS doesn't see previous clauses' variables +SELECT FROM create_graph('issue_1393'); +NOTICE: graph "issue_1393" has been created +-- +(1 row) + +SELECT * FROM cypher('issue_1393', $$ + CREATE (n1:Object) RETURN n1 +$$) AS (n1 agtype); + n1 +---------------------------------------------------------------------- + {"id": 844424930131969, "label": "Object", "properties": {}}::vertex +(1 row) + +-- vertex cases +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE EXISTS((n1)-[]->(n2)) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); + n1 | n2 +----+---- +(0 rows) + +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE EXISTS((n1:Object)-[]->(n2:Object)) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); + n1 | n2 +----+---- +(0 rows) + +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE NOT EXISTS((n1)-[]->(n2)) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); + n1 | n2 +----------------------------------------------------------------------+---------------------------------------------------------------------- + {"id": 844424930131969, "label": "Object", "properties": {}}::vertex | {"id": 844424930131969, "label": "Object", "properties": {}}::vertex +(1 row) + +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE NOT EXISTS((n1:Object)-[]->(n2:Object)) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); + n1 | n2 +----------------------------------------------------------------------+---------------------------------------------------------------------- + {"id": 844424930131969, "label": "Object", "properties": {}}::vertex | {"id": 844424930131969, "label": "Object", "properties": {}}::vertex +(1 row) + +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE EXISTS((n1)-[]->()) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); + n1 | n2 +----+---- +(0 rows) + +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE NOT EXISTS((n1)-[]->()) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); + n1 | n2 +----------------------------------------------------------------------+---------------------------------------------------------------------- + {"id": 844424930131969, "label": "Object", "properties": {}}::vertex | {"id": 844424930131969, "label": "Object", "properties": {}}::vertex +(1 row) + +SELECT * FROM cypher('issue_1393', $$ + CREATE (n1:Object)-[e:knows]->(n2:Object) RETURN n1, e, n2 +$$) AS (n1 agtype, e agtype, n2 agtype); + n1 | e | n2 +----------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------- + {"id": 844424930131970, "label": "Object", "properties": {}}::vertex | {"id": 1125899906842625, "label": "knows", "end_id": 844424930131971, "start_id": 844424930131970, "properties": {}}::edge | {"id": 844424930131971, "label": "Object", "properties": {}}::vertex +(1 row) + +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE EXISTS((n1)-[]->(n2)) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); + n1 | n2 +----------------------------------------------------------------------+---------------------------------------------------------------------- + {"id": 844424930131970, "label": "Object", "properties": {}}::vertex | {"id": 844424930131971, "label": "Object", "properties": {}}::vertex +(1 row) + +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE EXISTS((n1:Object)-[]->(n2:Object)) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); + n1 | n2 +----------------------------------------------------------------------+---------------------------------------------------------------------- + {"id": 844424930131970, "label": "Object", "properties": {}}::vertex | {"id": 844424930131971, "label": "Object", "properties": {}}::vertex +(1 row) + +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE NOT EXISTS((n1)-[]->(n2)) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); + n1 | n2 +----------------------------------------------------------------------+---------------------------------------------------------------------- + {"id": 844424930131969, "label": "Object", "properties": {}}::vertex | {"id": 844424930131969, "label": "Object", "properties": {}}::vertex + {"id": 844424930131969, "label": "Object", "properties": {}}::vertex | {"id": 844424930131970, "label": "Object", "properties": {}}::vertex + {"id": 844424930131969, "label": "Object", "properties": {}}::vertex | {"id": 844424930131971, "label": "Object", "properties": {}}::vertex + {"id": 844424930131970, "label": "Object", "properties": {}}::vertex | {"id": 844424930131969, "label": "Object", "properties": {}}::vertex + {"id": 844424930131970, "label": "Object", "properties": {}}::vertex | {"id": 844424930131970, "label": "Object", "properties": {}}::vertex + {"id": 844424930131971, "label": "Object", "properties": {}}::vertex | {"id": 844424930131969, "label": "Object", "properties": {}}::vertex + {"id": 844424930131971, "label": "Object", "properties": {}}::vertex | {"id": 844424930131970, "label": "Object", "properties": {}}::vertex + {"id": 844424930131971, "label": "Object", "properties": {}}::vertex | {"id": 844424930131971, "label": "Object", "properties": {}}::vertex +(8 rows) + +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE NOT EXISTS((n1:Object)-[]->(n2:Object)) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); + n1 | n2 +----------------------------------------------------------------------+---------------------------------------------------------------------- + {"id": 844424930131969, "label": "Object", "properties": {}}::vertex | {"id": 844424930131969, "label": "Object", "properties": {}}::vertex + {"id": 844424930131969, "label": "Object", "properties": {}}::vertex | {"id": 844424930131970, "label": "Object", "properties": {}}::vertex + {"id": 844424930131969, "label": "Object", "properties": {}}::vertex | {"id": 844424930131971, "label": "Object", "properties": {}}::vertex + {"id": 844424930131970, "label": "Object", "properties": {}}::vertex | {"id": 844424930131969, "label": "Object", "properties": {}}::vertex + {"id": 844424930131970, "label": "Object", "properties": {}}::vertex | {"id": 844424930131970, "label": "Object", "properties": {}}::vertex + {"id": 844424930131971, "label": "Object", "properties": {}}::vertex | {"id": 844424930131969, "label": "Object", "properties": {}}::vertex + {"id": 844424930131971, "label": "Object", "properties": {}}::vertex | {"id": 844424930131970, "label": "Object", "properties": {}}::vertex + {"id": 844424930131971, "label": "Object", "properties": {}}::vertex | {"id": 844424930131971, "label": "Object", "properties": {}}::vertex +(8 rows) + +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE EXISTS((n1)-[]->()) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); + n1 | n2 +----------------------------------------------------------------------+---------------------------------------------------------------------- + {"id": 844424930131970, "label": "Object", "properties": {}}::vertex | {"id": 844424930131969, "label": "Object", "properties": {}}::vertex + {"id": 844424930131970, "label": "Object", "properties": {}}::vertex | {"id": 844424930131970, "label": "Object", "properties": {}}::vertex + {"id": 844424930131970, "label": "Object", "properties": {}}::vertex | {"id": 844424930131971, "label": "Object", "properties": {}}::vertex +(3 rows) + +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE NOT EXISTS((n1)-[]->()) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); + n1 | n2 +----------------------------------------------------------------------+---------------------------------------------------------------------- + {"id": 844424930131969, "label": "Object", "properties": {}}::vertex | {"id": 844424930131969, "label": "Object", "properties": {}}::vertex + {"id": 844424930131971, "label": "Object", "properties": {}}::vertex | {"id": 844424930131969, "label": "Object", "properties": {}}::vertex + {"id": 844424930131969, "label": "Object", "properties": {}}::vertex | {"id": 844424930131970, "label": "Object", "properties": {}}::vertex + {"id": 844424930131971, "label": "Object", "properties": {}}::vertex | {"id": 844424930131970, "label": "Object", "properties": {}}::vertex + {"id": 844424930131969, "label": "Object", "properties": {}}::vertex | {"id": 844424930131971, "label": "Object", "properties": {}}::vertex + {"id": 844424930131971, "label": "Object", "properties": {}}::vertex | {"id": 844424930131971, "label": "Object", "properties": {}}::vertex +(6 rows) + +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE EXISTS((n1:Object)-[]->()) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); + n1 | n2 +----------------------------------------------------------------------+---------------------------------------------------------------------- + {"id": 844424930131970, "label": "Object", "properties": {}}::vertex | {"id": 844424930131969, "label": "Object", "properties": {}}::vertex + {"id": 844424930131970, "label": "Object", "properties": {}}::vertex | {"id": 844424930131970, "label": "Object", "properties": {}}::vertex + {"id": 844424930131970, "label": "Object", "properties": {}}::vertex | {"id": 844424930131971, "label": "Object", "properties": {}}::vertex +(3 rows) + +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE NOT EXISTS((n1:Object)-[]->()) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); + n1 | n2 +----------------------------------------------------------------------+---------------------------------------------------------------------- + {"id": 844424930131969, "label": "Object", "properties": {}}::vertex | {"id": 844424930131969, "label": "Object", "properties": {}}::vertex + {"id": 844424930131971, "label": "Object", "properties": {}}::vertex | {"id": 844424930131969, "label": "Object", "properties": {}}::vertex + {"id": 844424930131969, "label": "Object", "properties": {}}::vertex | {"id": 844424930131970, "label": "Object", "properties": {}}::vertex + {"id": 844424930131971, "label": "Object", "properties": {}}::vertex | {"id": 844424930131970, "label": "Object", "properties": {}}::vertex + {"id": 844424930131969, "label": "Object", "properties": {}}::vertex | {"id": 844424930131971, "label": "Object", "properties": {}}::vertex + {"id": 844424930131971, "label": "Object", "properties": {}}::vertex | {"id": 844424930131971, "label": "Object", "properties": {}}::vertex +(6 rows) + +-- should error +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE EXISTS((n1:object)-[]->()) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); +ERROR: multiple labels for variable 'n1' are not supported +LINE 2: ...MATCH (n1:Object) MATCH (n2:Object) WHERE EXISTS((n1:object)... + ^ +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE NOT EXISTS((n1:object)-[]->()) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); +ERROR: multiple labels for variable 'n1' are not supported +LINE 2: ...H (n1:Object) MATCH (n2:Object) WHERE NOT EXISTS((n1:object)... + ^ +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE NOT EXISTS((n1)-[e]->()) RETURN n1,n2,e +$$) AS (n1 agtype, n2 agtype, e agtype); +ERROR: variable `e` does not exist +LINE 2: ...1:Object) MATCH (n2:Object) WHERE NOT EXISTS((n1)-[e]->()) R... + ^ +-- edge cases +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE EXISTS((n1)-[e1]->(n2)) RETURN e1 +$$) AS (e1 agtype); + e1 +---------------------------------------------------------------------------------------------------------------------------- + {"id": 1125899906842625, "label": "knows", "end_id": 844424930131971, "start_id": 844424930131970, "properties": {}}::edge +(1 row) + +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE EXISTS((n1:Object)-[e1:knows]->(n2:Object)) RETURN e1 +$$) AS (e1 agtype); + e1 +---------------------------------------------------------------------------------------------------------------------------- + {"id": 1125899906842625, "label": "knows", "end_id": 844424930131971, "start_id": 844424930131970, "properties": {}}::edge +(1 row) + +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE NOT EXISTS((n1)-[e1]->(n2)) RETURN e1 +$$) AS (e1 agtype); + e1 +---------------------------------------------------------------------------------------------------------------------------- + {"id": 1125899906842625, "label": "knows", "end_id": 844424930131971, "start_id": 844424930131970, "properties": {}}::edge + {"id": 1125899906842625, "label": "knows", "end_id": 844424930131971, "start_id": 844424930131970, "properties": {}}::edge +(2 rows) + +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE NOT EXISTS((n1:Object)-[e1:knows]->(n2:Object)) RETURN e1 +$$) AS (e1 agtype); + e1 +---------------------------------------------------------------------------------------------------------------------------- + {"id": 1125899906842625, "label": "knows", "end_id": 844424930131971, "start_id": 844424930131970, "properties": {}}::edge + {"id": 1125899906842625, "label": "knows", "end_id": 844424930131971, "start_id": 844424930131970, "properties": {}}::edge +(2 rows) + +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE EXISTS((n1)-[e1]->()) RETURN e1 +$$) AS (e1 agtype); + e1 +---------------------------------------------------------------------------------------------------------------------------- + {"id": 1125899906842625, "label": "knows", "end_id": 844424930131971, "start_id": 844424930131970, "properties": {}}::edge + {"id": 1125899906842625, "label": "knows", "end_id": 844424930131971, "start_id": 844424930131970, "properties": {}}::edge + {"id": 1125899906842625, "label": "knows", "end_id": 844424930131971, "start_id": 844424930131970, "properties": {}}::edge +(3 rows) + +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE EXISTS((n1:Object)-[e1:knows]->(n2:Object)) RETURN e1 +$$) AS (e1 agtype); + e1 +---------------------------------------------------------------------------------------------------------------------------- + {"id": 1125899906842625, "label": "knows", "end_id": 844424930131971, "start_id": 844424930131970, "properties": {}}::edge +(1 row) + +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE NOT EXISTS((n1)-[e1]->()) RETURN e1 +$$) AS (e1 agtype); + e1 +---- +(0 rows) + +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE NOT EXISTS((n1:Object)-[e1:knows]->(n2:Object)) RETURN e1 +$$) AS (e1 agtype); + e1 +---------------------------------------------------------------------------------------------------------------------------- + {"id": 1125899906842625, "label": "knows", "end_id": 844424930131971, "start_id": 844424930131970, "properties": {}}::edge + {"id": 1125899906842625, "label": "knows", "end_id": 844424930131971, "start_id": 844424930131970, "properties": {}}::edge +(2 rows) + +-- should error +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE EXISTS((n1:Object)-[e1:Knows]->(n2:Object)) RETURN e1 +$$) AS (e1 agtype); +ERROR: multiple labels for variable 'e1' are not supported +LINE 2: ...s]->() MATCH (n2:Object) WHERE EXISTS((n1:Object)-[e1:Knows]... + ^ +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE NOT EXISTS((n1:Object)-[e1:Knows]->(n2:Object)) RETURN e1 +$$) AS (e1 agtype); +ERROR: multiple labels for variable 'e1' are not supported +LINE 2: ...() MATCH (n2:Object) WHERE NOT EXISTS((n1:Object)-[e1:Knows]... + ^ +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE EXISTS((e1:Object)-[e1:Knows]->(n2:Object)) RETURN e1 +$$) AS (e1 agtype); +ERROR: variable 'e1' is for an edge +LINE 2: ...t)-[e1:knows]->() MATCH (n2:Object) WHERE EXISTS((e1:Object)... + ^ +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE NOT EXISTS((n1:Object)-[e1:knows]->(e1)) RETURN e1 +$$) AS (e1 agtype); +ERROR: variable 'e1' is for an edge +LINE 2: ...Object) WHERE NOT EXISTS((n1:Object)-[e1:knows]->(e1)) RETUR... + ^ +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE NOT EXISTS((n1:Object)-[e1:knows]->(e2)) RETURN e1 +$$) AS (e1 agtype); +ERROR: variable `e2` does not exist +LINE 2: ...Object) WHERE NOT EXISTS((n1:Object)-[e1:knows]->(e2)) RETUR... + ^ +SELECT * FROM cypher('issue_1393', $$ + MATCH p=(n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE EXISTS((n1:Object)-[p]->(e2)) RETURN e1 +$$) AS (e1 agtype); +ERROR: variable 'p' is for a path +LINE 2: ...s]->() MATCH (n2:Object) WHERE EXISTS((n1:Object)-[p]->(e2))... + ^ +SELECT * FROM cypher('issue_1393', $$ + MATCH p=(n1)-[e1]->() MATCH (n2) WHERE EXISTS((n1)-[p]->(e2)) RETURN p +$$) AS (e1 agtype); +ERROR: variable 'p' is for a path +LINE 2: ...ATCH p=(n1)-[e1]->() MATCH (n2) WHERE EXISTS((n1)-[p]->(e2))... + ^ +-- long cases +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1) MATCH (n2) MATCH (n1)-[e1]->() MATCH (n2)<-[e2]-(n1) MATCH (n3) + WHERE EXISTS((n3)-[e1]->(n2)) RETURN n1,n2,n3,e1 +$$) AS (n1 agtype, n2 agtype, n3 agtype, e1 agtype); + n1 | n2 | n3 | e1 +----------------------------------------------------------------------+----------------------------------------------------------------------+----------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------- + {"id": 844424930131970, "label": "Object", "properties": {}}::vertex | {"id": 844424930131971, "label": "Object", "properties": {}}::vertex | {"id": 844424930131970, "label": "Object", "properties": {}}::vertex | {"id": 1125899906842625, "label": "knows", "end_id": 844424930131971, "start_id": 844424930131970, "properties": {}}::edge +(1 row) + +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) MATCH (n1)-[e1:knows]->() MATCH (n2)<-[e2:knows]-(n1) MATCH (n3:Object) + WHERE EXISTS((n3:Object)-[e1:knows]->(n2:Object)) RETURN n1,n2,n3,e1 +$$) AS (n1 agtype, n2 agtype, n3 agtype, e1 agtype); + n1 | n2 | n3 | e1 +----------------------------------------------------------------------+----------------------------------------------------------------------+----------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------- + {"id": 844424930131970, "label": "Object", "properties": {}}::vertex | {"id": 844424930131971, "label": "Object", "properties": {}}::vertex | {"id": 844424930131970, "label": "Object", "properties": {}}::vertex | {"id": 1125899906842625, "label": "knows", "end_id": 844424930131971, "start_id": 844424930131970, "properties": {}}::edge +(1 row) + -- -- Clean up -- @@ -3061,6 +3364,18 @@ NOTICE: graph "issue_1399" has been dropped (1 row) +SELECT drop_graph('issue_1393', true); +NOTICE: drop cascades to 4 other objects +DETAIL: drop cascades to table issue_1393._ag_label_vertex +drop cascades to table issue_1393._ag_label_edge +drop cascades to table issue_1393."Object" +drop cascades to table issue_1393.knows +NOTICE: graph "issue_1393" has been dropped + drop_graph +------------ + +(1 row) + -- -- End -- diff --git a/regress/sql/cypher_match.sql b/regress/sql/cypher_match.sql index 72748cf78..af1b150f9 100644 --- a/regress/sql/cypher_match.sql +++ b/regress/sql/cypher_match.sql @@ -561,10 +561,6 @@ SELECT * FROM cypher('cypher_match', $$MATCH (u) RETURN EXISTS((u)-[]->()) $$) AS (exists agtype); -SELECT * FROM cypher('cypher_match', - $$MATCH p=(u)-[e]->(v) RETURN EXISTS((p)) $$) -AS (exists agtype); - SELECT * FROM cypher('cypher_match', $$MATCH (u)-[e]->(v) RETURN EXISTS((u)-[e]->(v)-[e]->(u))$$) AS (exists agtype); @@ -580,6 +576,11 @@ SELECT * FROM cypher('cypher_match', $$MATCH (u)-[e]->(v) WHERE EXISTS((u)-[e]->(x)) RETURN u, e, v $$) AS (u agtype, e agtype, v agtype); +-- path variable not allowed in EXISTS +SELECT * FROM cypher('cypher_match', + $$MATCH p=(u)-[e]->(v) RETURN EXISTS((p)) $$) +AS (exists agtype); + -- -- Tests for EXISTS(property) -- @@ -950,9 +951,9 @@ SELECT * FROM cypher('cypher_match', $$ SELECT * FROM cypher('cypher_match', $$ MATCH (a) RETURN a $$) as (a agtype); SELECT * FROM cypher('cypher_match', $$ - MATCH (a) WHERE exists(a.name) RETURN a $$) as (a agtype); + MATCH (a) WHERE EXISTS(a.name) RETURN a $$) as (a agtype); SELECT * FROM cypher('cypher_match', $$ - MATCH (a) WHERE exists(a.name) SET a.age = 4 RETURN a $$) as (a agtype); + MATCH (a) WHERE EXISTS(a.name) SET a.age = 4 RETURN a $$) as (a agtype); SELECT * FROM cypher('cypher_match', $$ MATCH (a),(b) WHERE a.age = 4 AND a.name = "T" AND b.age = 6 @@ -988,10 +989,10 @@ SELECT * FROM cypher('cypher_match', $$ MATCH (a {name: "orphan"}) MATCH (a {age:3}) RETURN a $$) as (a agtype); SELECT * FROM cypher('cypher_match', $$ - MATCH (a) WHERE exists(a.age) AND exists(a.name) RETURN a $$) as (a agtype); + MATCH (a) WHERE EXISTS(a.age) AND EXISTS(a.name) RETURN a $$) as (a agtype); SELECT * FROM cypher('cypher_match', $$ - MATCH (a) WHERE exists(a.age) AND NOT exists(a.name) RETURN a $$) as (a agtype); + MATCH (a) WHERE EXISTS(a.age) AND NOT EXISTS(a.name) RETURN a $$) as (a agtype); -- check reuse of 'r' clause-to-clause - edges SELECT * FROM cypher('cypher_match', $$ @@ -1189,43 +1190,43 @@ SELECT create_graph('issue_1399'); -- this is an empty graph so these should return 0 SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE exists((foo)-[]->()) + WHERE EXISTS((foo)-[]->()) RETURN foo $$) as (c agtype); SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE NOT exists((foo)-[]->()) + WHERE NOT EXISTS((foo)-[]->()) RETURN foo $$) as (c agtype); SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE exists((foo)-[:BAR]->()) + WHERE EXISTS((foo)-[:BAR]->()) RETURN foo $$) as (c agtype); SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE NOT exists((foo)-[:BAR]->()) + WHERE NOT EXISTS((foo)-[:BAR]->()) RETURN foo $$) as (c agtype); -- this is an empty graph so these should return false SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE exists((foo)-[]->()) + WHERE EXISTS((foo)-[]->()) RETURN count(foo) > 0 $$) as (c agtype); SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE NOT exists((foo)-[]->()) + WHERE NOT EXISTS((foo)-[]->()) RETURN count(foo) > 0 $$) as (c agtype); SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE exists((foo)-[:BAR]->()) + WHERE EXISTS((foo)-[:BAR]->()) RETURN count(foo) > 0 $$) as (c agtype); SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE NOT exists((foo)-[:BAR]->()) + WHERE NOT EXISTS((foo)-[:BAR]->()) RETURN count(foo) > 0 $$) as (c agtype); -- create 1 path @@ -1236,37 +1237,155 @@ $$) as (c agtype); -- only one vertex can match. SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE exists((foo)-[]->()) + WHERE EXISTS((foo)-[]->()) RETURN foo $$) as (c agtype); SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE NOT exists((foo)-[]->()) + WHERE NOT EXISTS((foo)-[]->()) RETURN foo $$) as (c agtype); SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE exists((foo)-[:BAR]->()) + WHERE EXISTS((foo)-[:BAR]->()) RETURN foo $$) as (c agtype); SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE NOT exists((foo)-[:BAR]->()) + WHERE NOT EXISTS((foo)-[:BAR]->()) RETURN foo $$) as (c agtype); -- this should return 0 rows as it can't exist - that path isn't in BAR2 SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE exists((foo)-[:BAR2]->()) + WHERE EXISTS((foo)-[:BAR2]->()) RETURN foo $$) as (c agtype); -- this should return 2 rows as they all exist SELECT * FROM cypher('issue_1399', $$ MATCH (foo) - WHERE NOT exists((foo)-[:BAR2]->()) + WHERE NOT EXISTS((foo)-[:BAR2]->()) RETURN foo $$) as (c agtype); +-- Issue 1393 EXISTS doesn't see previous clauses' variables +SELECT FROM create_graph('issue_1393'); +SELECT * FROM cypher('issue_1393', $$ + CREATE (n1:Object) RETURN n1 +$$) AS (n1 agtype); +-- vertex cases +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE EXISTS((n1)-[]->(n2)) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE EXISTS((n1:Object)-[]->(n2:Object)) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE NOT EXISTS((n1)-[]->(n2)) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE NOT EXISTS((n1:Object)-[]->(n2:Object)) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE EXISTS((n1)-[]->()) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE NOT EXISTS((n1)-[]->()) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); +SELECT * FROM cypher('issue_1393', $$ + CREATE (n1:Object)-[e:knows]->(n2:Object) RETURN n1, e, n2 +$$) AS (n1 agtype, e agtype, n2 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE EXISTS((n1)-[]->(n2)) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE EXISTS((n1:Object)-[]->(n2:Object)) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE NOT EXISTS((n1)-[]->(n2)) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE NOT EXISTS((n1:Object)-[]->(n2:Object)) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE EXISTS((n1)-[]->()) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE NOT EXISTS((n1)-[]->()) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE EXISTS((n1:Object)-[]->()) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE NOT EXISTS((n1:Object)-[]->()) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); +-- should error +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE EXISTS((n1:object)-[]->()) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE NOT EXISTS((n1:object)-[]->()) RETURN n1,n2 +$$) AS (n1 agtype, n2 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) WHERE NOT EXISTS((n1)-[e]->()) RETURN n1,n2,e +$$) AS (n1 agtype, n2 agtype, e agtype); +-- edge cases +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE EXISTS((n1)-[e1]->(n2)) RETURN e1 +$$) AS (e1 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE EXISTS((n1:Object)-[e1:knows]->(n2:Object)) RETURN e1 +$$) AS (e1 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE NOT EXISTS((n1)-[e1]->(n2)) RETURN e1 +$$) AS (e1 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE NOT EXISTS((n1:Object)-[e1:knows]->(n2:Object)) RETURN e1 +$$) AS (e1 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE EXISTS((n1)-[e1]->()) RETURN e1 +$$) AS (e1 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE EXISTS((n1:Object)-[e1:knows]->(n2:Object)) RETURN e1 +$$) AS (e1 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE NOT EXISTS((n1)-[e1]->()) RETURN e1 +$$) AS (e1 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE NOT EXISTS((n1:Object)-[e1:knows]->(n2:Object)) RETURN e1 +$$) AS (e1 agtype); +-- should error +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE EXISTS((n1:Object)-[e1:Knows]->(n2:Object)) RETURN e1 +$$) AS (e1 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE NOT EXISTS((n1:Object)-[e1:Knows]->(n2:Object)) RETURN e1 +$$) AS (e1 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE EXISTS((e1:Object)-[e1:Knows]->(n2:Object)) RETURN e1 +$$) AS (e1 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE NOT EXISTS((n1:Object)-[e1:knows]->(e1)) RETURN e1 +$$) AS (e1 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE NOT EXISTS((n1:Object)-[e1:knows]->(e2)) RETURN e1 +$$) AS (e1 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH p=(n1:Object)-[e1:knows]->() MATCH (n2:Object) WHERE EXISTS((n1:Object)-[p]->(e2)) RETURN e1 +$$) AS (e1 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH p=(n1)-[e1]->() MATCH (n2) WHERE EXISTS((n1)-[p]->(e2)) RETURN p +$$) AS (e1 agtype); +-- long cases +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1) MATCH (n2) MATCH (n1)-[e1]->() MATCH (n2)<-[e2]-(n1) MATCH (n3) + WHERE EXISTS((n3)-[e1]->(n2)) RETURN n1,n2,n3,e1 +$$) AS (n1 agtype, n2 agtype, n3 agtype, e1 agtype); +SELECT * FROM cypher('issue_1393', $$ + MATCH (n1:Object) MATCH (n2:Object) MATCH (n1)-[e1:knows]->() MATCH (n2)<-[e2:knows]-(n1) MATCH (n3:Object) + WHERE EXISTS((n3:Object)-[e1:knows]->(n2:Object)) RETURN n1,n2,n3,e1 +$$) AS (n1 agtype, n2 agtype, n3 agtype, e1 agtype); + -- -- Clean up -- @@ -1275,6 +1394,7 @@ SELECT drop_graph('test_retrieve_var', true); SELECT drop_graph('test_enable_containment', true); SELECT drop_graph('issue_945', true); SELECT drop_graph('issue_1399', true); +SELECT drop_graph('issue_1393', true); -- -- End diff --git a/src/backend/parser/cypher_clause.c b/src/backend/parser/cypher_clause.c index b4c4a54bc..86b6d3cfa 100644 --- a/src/backend/parser/cypher_clause.c +++ b/src/backend/parser/cypher_clause.c @@ -4593,6 +4593,7 @@ static Expr *transform_cypher_edge(cypher_parsestate *cpstate, transform_entity *entity = NULL; cypher_relationship *cr = NULL; Node *expr = NULL; + Var *previous_clause_var = NULL; bool refs_var = false; /* @@ -4603,14 +4604,16 @@ static Expr *transform_cypher_edge(cypher_parsestate *cpstate, { te = findTarget(*target_list, rel->name); entity = find_variable(cpstate, rel->name); - expr = colNameToVar(pstate, rel->name, false, rel->location); + previous_clause_var = (Var *)colNameToVar(pstate, rel->name, false, + rel->location); /* * If we have a valid entity and te for this rel name, go ahead and get * the cypher relationship as we will need this for later and flag that * we have a variable reference. */ - if (te != NULL && entity != NULL) + if ((te != NULL && entity != NULL) || + (entity != NULL && previous_clause_var != NULL)) { cr = (cypher_relationship *)entity->entity.rel; refs_var = true; @@ -4633,7 +4636,8 @@ static Expr *transform_cypher_edge(cypher_parsestate *cpstate, errmsg("variable '%s' is for a VLE edge", rel->name), parser_errposition(pstate, rel->location))); } - else if (entity->type == ENT_PATH) + else if (entity->type == ENT_PATH && + pstate->p_expr_kind != EXPR_KIND_SELECT_TARGET) { ereport(ERROR, (errcode(ERRCODE_DUPLICATE_ALIAS), @@ -4706,7 +4710,7 @@ static Expr *transform_cypher_edge(cypher_parsestate *cpstate, * Variables for edges are not allowed to be used multiple times within the * same clause. */ - if (expr == NULL && refs_var) + if (previous_clause_var == NULL && refs_var) { ereport(ERROR, (errcode(ERRCODE_DUPLICATE_ALIAS), @@ -4749,9 +4753,15 @@ static Expr *transform_cypher_edge(cypher_parsestate *cpstate, * If expr_kind is WHERE, the expressions are in the parent's * parent's parsestate, due to the way we transform sublinks. */ - transform_entity *tentity = find_variable(parent_cpstate, - rel->name); + transform_entity *tentity = NULL; + + /* if we have the referenced var, just return it */ + if (previous_clause_var != NULL) + { + return (Expr *)previous_clause_var; + } + tentity = find_variable(parent_cpstate, rel->name); if (tentity != NULL) { return get_relative_expr(tentity, 2); @@ -4768,13 +4778,7 @@ static Expr *transform_cypher_edge(cypher_parsestate *cpstate, /* if this vertex is referencing an existing te var, return its expr */ if (refs_var) { - return te->expr; - } - - /* if this vertex is referencing an existing col var, return its expr */ - if (expr != NULL) - { - return (Expr *)expr; + return (te != NULL) ? te->expr : (Expr *)previous_clause_var; } } @@ -4842,19 +4846,24 @@ static Expr *transform_cypher_node(cypher_parsestate *cpstate, transform_entity *entity = NULL; cypher_node *cn = NULL; bool refs_var = false; + Var *previous_clause_var = NULL; /* if we have a node name, get any potential variable references */ if (node->name != NULL) { te = findTarget(*target_list, node->name); entity = find_variable(cpstate, node->name); + previous_clause_var = (Var *)colNameToVar(pstate, node->name, false, + node->location); /* - * If we have a valid entity and te for this rel name, go ahead and get - * the cypher relationship as we will need this for later and flag that - * we have a variable reference. + * If we have a valid entity and te or a valid entity and a previous var + * ref for this rel name, go ahead and get the cypher relationship. We + * will need this information for later. Additionally, flag that we have + * a variable reference. */ - if (te != NULL && entity != NULL) + if ((te != NULL && entity != NULL) || + (entity != NULL && previous_clause_var != NULL)) { cn = (cypher_node *)entity->entity.node; refs_var = true; @@ -4877,13 +4886,25 @@ static Expr *transform_cypher_node(cypher_parsestate *cpstate, errmsg("variable '%s' is for a VLE edge", node->name), parser_errposition(pstate, node->location))); } - else if (entity->type == ENT_PATH) + /* gets non EXISTS cases */ + else if (entity->type == ENT_PATH && + pstate->p_expr_kind != EXPR_KIND_SELECT_TARGET) { ereport(ERROR, (errcode(ERRCODE_DUPLICATE_ALIAS), errmsg("variable '%s' is for a path", node->name), parser_errposition(pstate, node->location))); } + /* gets EXISTS cases */ + else if (entity->type == ENT_PATH && + pstate->p_expr_kind == EXPR_KIND_SELECT_TARGET) + { + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_ALIAS), + errmsg("a path variable '%s' is not allowed here", + node->name), + parser_errposition(pstate, node->location))); + } } /* If their is a te but no entity, it implies that their is @@ -4992,6 +5013,12 @@ static Expr *transform_cypher_node(cypher_parsestate *cpstate, */ transform_entity *tentity = NULL; + /* if we have the referenced var, just return it */ + if (previous_clause_var != NULL) + { + return (Expr *)previous_clause_var; + } + tentity = find_variable(parent_cpstate, node->name); if (tentity != NULL) { @@ -5006,10 +5033,10 @@ static Expr *transform_cypher_node(cypher_parsestate *cpstate, } } - /* if this vertex is referencing an existing te var, return its expr */ + /* if this vertex is referencing an existing var, return its expr */ if (refs_var) { - return te->expr; + return (te != NULL) ? te->expr : (Expr *)previous_clause_var; } /* if this vertex is referencing an existing col var, return its expr */