This is an automated email from the ASF dual-hosted git repository.

jgemignani pushed a commit to branch PG12
in repository https://gitbox.apache.org/repos/asf/age.git

commit 87a7d1090fae7ea8cccf215c9fd5f87f51f2b1c8
Author: John Gemignani <[email protected]>
AuthorDate: Thu Mar 16 19:42:17 2023 -0700

    Fix property constraints against resolved variables in concurrent MATCH 
clauses(#701) (#747)
    
    Fixed an issue where an already resolved variable, when used for
    a property constraint in a second MATCH clause, errored out.
    See #701 and #724  for more details. This is part of a series of
    PRs done to refactor MATCH clause behavior.
    
    This also fixed a regression test that was erroring out, but was
    overlooked.
    
    Adjusted and added additional regression tests.
    
    Co-authored-by: Dehowe Feng <[email protected]>
---
 regress/expected/cypher_match.out  | 225 ++++++++++++++++++++++++++++++++++++-
 regress/expected/cypher_merge.out  |  40 +++----
 regress/sql/cypher_match.sql       |  73 ++++++++++++
 src/backend/parser/cypher_clause.c | 167 +++++++++++++++++++++++----
 4 files changed, 461 insertions(+), 44 deletions(-)

diff --git a/regress/expected/cypher_match.out 
b/regress/expected/cypher_match.out
index 4888556d..f3817a50 100644
--- a/regress/expected/cypher_match.out
+++ b/regress/expected/cypher_match.out
@@ -1450,11 +1450,233 @@ $$) as (n agtype);
  {"id": 281474976710662, "label": "", "properties": {"i": 1, "j": 2, "k": 
3}}::vertex
 (1 row)
 
+--
+-- Regression tests to check previous clause variable refs
+--
+-- set up initial state and show what we're working with
+SELECT * FROM cypher('cypher_match', $$
+    CREATE (a {age: 4}) RETURN a $$) as (a agtype);
+                                   a                                    
+------------------------------------------------------------------------
+ {"id": 281474976710665, "label": "", "properties": {"age": 4}}::vertex
+(1 row)
+
+SELECT * FROM cypher('cypher_match', $$
+       CREATE (b {age: 6}) RETURN b $$) as (b agtype);
+                                   b                                    
+------------------------------------------------------------------------
+ {"id": 281474976710666, "label": "", "properties": {"age": 6}}::vertex
+(1 row)
+
+SELECT * FROM cypher('cypher_match', $$
+    MATCH (a) RETURN a $$) as (a agtype);
+                                          a                                    
       
+--------------------------------------------------------------------------------------
+ {"id": 281474976710659, "label": "", "properties": {"name": "orphan"}}::vertex
+ {"id": 281474976710660, "label": "", "properties": {"name": "F"}}::vertex
+ {"id": 281474976710661, "label": "", "properties": {"name": "T"}}::vertex
+ {"id": 281474976710662, "label": "", "properties": {"i": 1, "j": 2, "k": 
3}}::vertex
+ {"id": 281474976710663, "label": "", "properties": {"i": 1, "j": 3}}::vertex
+ {"id": 281474976710664, "label": "", "properties": {"i": 2, "k": 3}}::vertex
+ {"id": 281474976710665, "label": "", "properties": {"age": 4}}::vertex
+ {"id": 281474976710666, "label": "", "properties": {"age": 6}}::vertex
+(8 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+    MATCH (a) WHERE exists(a.name) RETURN a $$) as (a agtype);
+                                       a                                       
 
+--------------------------------------------------------------------------------
+ {"id": 281474976710659, "label": "", "properties": {"name": "orphan"}}::vertex
+ {"id": 281474976710660, "label": "", "properties": {"name": "F"}}::vertex
+ {"id": 281474976710661, "label": "", "properties": {"name": "T"}}::vertex
+(3 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+    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
+ {"id": 281474976710660, "label": "", "properties": {"age": 4, "name": 
"F"}}::vertex
+ {"id": 281474976710661, "label": "", "properties": {"age": 4, "name": 
"T"}}::vertex
+(3 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+       MATCH (a),(b) WHERE a.age = 4 AND a.name = "T" AND b.age = 6
+       RETURN a,b $$) as (a agtype, b agtype);
+                                          a                                    
      |                                   b                                    
+-------------------------------------------------------------------------------------+------------------------------------------------------------------------
+ {"id": 281474976710661, "label": "", "properties": {"age": 4, "name": 
"T"}}::vertex | {"id": 281474976710666, "label": "", "properties": {"age": 
6}}::vertex
+(1 row)
+
+SELECT * FROM cypher('cypher_match', $$
+       MATCH (a),(b) WHERE a.age = 4 AND a.name = "T" AND b.age = 6 CREATE 
+       (a)-[:knows {relationship: "friends", years: 3}]->(b) $$) as (r agtype);
+ r 
+---
+(0 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+       MATCH (a),(b) WHERE a.age = 4 AND a.name = "orphan" AND b.age = 6 
CREATE 
+       (a)-[:knows {relationship: "enemies", years: 4}]->(b) $$) as (r agtype);
+ r 
+---
+(0 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+       MATCH (a)-[r]-(b) RETURN r $$) as (r agtype);
+                                                                               
 r                                                                              
  
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------
+ {"id": 4785074604081153, "label": "knows", "end_id": 281474976710666, 
"start_id": 281474976710661, "properties": {"years": 3, "relationship": 
"friends"}}::edge
+ {"id": 4785074604081153, "label": "knows", "end_id": 281474976710666, 
"start_id": 281474976710661, "properties": {"years": 3, "relationship": 
"friends"}}::edge
+ {"id": 4785074604081154, "label": "knows", "end_id": 281474976710666, 
"start_id": 281474976710659, "properties": {"years": 4, "relationship": 
"enemies"}}::edge
+ {"id": 4785074604081154, "label": "knows", "end_id": 281474976710666, 
"start_id": 281474976710659, "properties": {"years": 4, "relationship": 
"enemies"}}::edge
+ {"id": 1407374883553283, "label": "e1", "end_id": 281474976710661, 
"start_id": 281474976710660, "properties": {}}::edge
+ {"id": 1407374883553283, "label": "e1", "end_id": 281474976710661, 
"start_id": 281474976710660, "properties": {}}::edge
+(6 rows)
+
+-- check reuse of 'a'
+SELECT * FROM cypher('cypher_match', $$
+    MATCH (a {age:4}) RETURN a $$) as (a agtype);
+                                            a                                  
           
+------------------------------------------------------------------------------------------
+ {"id": 281474976710665, "label": "", "properties": {"age": 4}}::vertex
+ {"id": 281474976710659, "label": "", "properties": {"age": 4, "name": 
"orphan"}}::vertex
+ {"id": 281474976710660, "label": "", "properties": {"age": 4, "name": 
"F"}}::vertex
+ {"id": 281474976710661, "label": "", "properties": {"age": 4, "name": 
"T"}}::vertex
+(4 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+    MATCH (a) MATCH (a {age:4}) RETURN a $$) as (a agtype);
+                                            a                                  
           
+------------------------------------------------------------------------------------------
+ {"id": 281474976710665, "label": "", "properties": {"age": 4}}::vertex
+ {"id": 281474976710659, "label": "", "properties": {"age": 4, "name": 
"orphan"}}::vertex
+ {"id": 281474976710660, "label": "", "properties": {"age": 4, "name": 
"F"}}::vertex
+ {"id": 281474976710661, "label": "", "properties": {"age": 4, "name": 
"T"}}::vertex
+(4 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+    MATCH (a {age:4, name: "orphan"}) RETURN a $$) as (a agtype);
+                                            a                                  
           
+------------------------------------------------------------------------------------------
+ {"id": 281474976710659, "label": "", "properties": {"age": 4, "name": 
"orphan"}}::vertex
+(1 row)
+
+SELECT * FROM cypher('cypher_match', $$
+    MATCH (a) MATCH (a {age:4}) MATCH (a {name: "orphan"}) RETURN a $$) as (a 
agtype);
+                                            a                                  
           
+------------------------------------------------------------------------------------------
+ {"id": 281474976710659, "label": "", "properties": {"age": 4, "name": 
"orphan"}}::vertex
+(1 row)
+
+SELECT * FROM cypher('cypher_match', $$
+    MATCH (a {age:4}) MATCH (a {name: "orphan"}) RETURN a $$) as (a agtype);
+                                            a                                  
           
+------------------------------------------------------------------------------------------
+ {"id": 281474976710659, "label": "", "properties": {"age": 4, "name": 
"orphan"}}::vertex
+(1 row)
+
+SELECT * FROM cypher('cypher_match', $$
+    MATCH (a) MATCH (a {age:4}) MATCH (a {name: "orphan"}) SET a.age = 3 
RETURN a $$) as (a agtype);
+                                            a                                  
           
+------------------------------------------------------------------------------------------
+ {"id": 281474976710659, "label": "", "properties": {"age": 3, "name": 
"orphan"}}::vertex
+(1 row)
+
+SELECT * FROM cypher('cypher_match', $$
+    MATCH (a) MATCH (a {age:3}) MATCH (a {name: "orphan"}) RETURN a $$) as (a 
agtype);
+                                            a                                  
           
+------------------------------------------------------------------------------------------
+ {"id": 281474976710659, "label": "", "properties": {"age": 3, "name": 
"orphan"}}::vertex
+(1 row)
+
+SELECT * FROM cypher('cypher_match', $$
+    MATCH (a {name: "orphan"}) MATCH (a {age:3}) RETURN a $$) as (a agtype);
+                                            a                                  
           
+------------------------------------------------------------------------------------------
+ {"id": 281474976710659, "label": "", "properties": {"age": 3, "name": 
"orphan"}}::vertex
+(1 row)
+
+SELECT * FROM cypher('cypher_match', $$
+    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
+ {"id": 281474976710661, "label": "", "properties": {"age": 4, "name": 
"T"}}::vertex
+ {"id": 281474976710659, "label": "", "properties": {"age": 3, "name": 
"orphan"}}::vertex
+(3 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+    MATCH (a) WHERE exists(a.age) AND NOT exists(a.name) RETURN a $$) as (a 
agtype);
+                                   a                                    
+------------------------------------------------------------------------
+ {"id": 281474976710665, "label": "", "properties": {"age": 4}}::vertex
+ {"id": 281474976710666, "label": "", "properties": {"age": 6}}::vertex
+(2 rows)
+
+-- check reuse of 'r'
+SELECT * FROM cypher('cypher_match', $$
+       MATCH ()-[r]-() RETURN r $$) as (r agtype);
+                                                                               
 r                                                                              
  
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------
+ {"id": 4785074604081153, "label": "knows", "end_id": 281474976710666, 
"start_id": 281474976710661, "properties": {"years": 3, "relationship": 
"friends"}}::edge
+ {"id": 4785074604081153, "label": "knows", "end_id": 281474976710666, 
"start_id": 281474976710661, "properties": {"years": 3, "relationship": 
"friends"}}::edge
+ {"id": 4785074604081154, "label": "knows", "end_id": 281474976710666, 
"start_id": 281474976710659, "properties": {"years": 4, "relationship": 
"enemies"}}::edge
+ {"id": 4785074604081154, "label": "knows", "end_id": 281474976710666, 
"start_id": 281474976710659, "properties": {"years": 4, "relationship": 
"enemies"}}::edge
+ {"id": 1407374883553283, "label": "e1", "end_id": 281474976710661, 
"start_id": 281474976710660, "properties": {}}::edge
+ {"id": 1407374883553283, "label": "e1", "end_id": 281474976710661, 
"start_id": 281474976710660, "properties": {}}::edge
+(6 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+       MATCH ()-[r]-() MATCH ()-[r {relationship: "friends"}]-() RETURN r $$) 
as (r agtype);
+                                                                               
 r                                                                              
  
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------
+ {"id": 4785074604081153, "label": "knows", "end_id": 281474976710666, 
"start_id": 281474976710661, "properties": {"years": 3, "relationship": 
"friends"}}::edge
+ {"id": 4785074604081153, "label": "knows", "end_id": 281474976710666, 
"start_id": 281474976710661, "properties": {"years": 3, "relationship": 
"friends"}}::edge
+(2 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+       MATCH ()-[r {years:3, relationship: "friends"}]-() RETURN r $$) as (r 
agtype);
+                                                                               
 r                                                                              
  
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------
+ {"id": 4785074604081153, "label": "knows", "end_id": 281474976710666, 
"start_id": 281474976710661, "properties": {"years": 3, "relationship": 
"friends"}}::edge
+ {"id": 4785074604081153, "label": "knows", "end_id": 281474976710666, 
"start_id": 281474976710661, "properties": {"years": 3, "relationship": 
"friends"}}::edge
+(2 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+       MATCH ()-[r {years:3}]-() MATCH ()-[r {relationship: "friends"}]-() 
RETURN r $$) as (r agtype);
+                                                                               
 r                                                                              
  
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------
+ {"id": 4785074604081153, "label": "knows", "end_id": 281474976710666, 
"start_id": 281474976710661, "properties": {"years": 3, "relationship": 
"friends"}}::edge
+ {"id": 4785074604081153, "label": "knows", "end_id": 281474976710666, 
"start_id": 281474976710661, "properties": {"years": 3, "relationship": 
"friends"}}::edge
+(2 rows)
+
+--mismatch year #, should return nothing
+SELECT * FROM cypher('cypher_match', $$
+       MATCH ()-[r {years:2}]-() MATCH ()-[r {relationship: "friends"}]-() 
RETURN r $$) as (r agtype);
+ r 
+---
+(0 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+       MATCH ()-[r {relationship:"enemies"}]-() MATCH ()-[r {years:4}]-() 
RETURN r $$) as (r agtype);
+                                                                               
 r                                                                              
  
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------
+ {"id": 4785074604081154, "label": "knows", "end_id": 281474976710666, 
"start_id": 281474976710659, "properties": {"years": 4, "relationship": 
"enemies"}}::edge
+ {"id": 4785074604081154, "label": "knows", "end_id": 281474976710666, 
"start_id": 281474976710659, "properties": {"years": 4, "relationship": 
"enemies"}}::edge
+(2 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+       MATCH ()-[r {relationship:"enemies"}]-() MATCH ()-[r 
{relationship:"friends"}]-() RETURN r $$) as (r agtype);
+ r 
+---
+(0 rows)
+
 --
 -- Clean up
 --
 SELECT drop_graph('cypher_match', true);
-NOTICE:  drop cascades to 16 other objects
+NOTICE:  drop cascades to 17 other objects
 DETAIL:  drop cascades to table cypher_match._ag_label_vertex
 drop cascades to table cypher_match._ag_label_edge
 drop cascades to table cypher_match.v
@@ -1471,6 +1693,7 @@ drop cascades to table cypher_match.dup_edge
 drop cascades to table cypher_match.other_v
 drop cascades to table cypher_match.opt_match_v
 drop cascades to table cypher_match.opt_match_e
+drop cascades to table cypher_match.knows
 NOTICE:  graph "cypher_match" has been dropped
  drop_graph 
 ------------
diff --git a/regress/expected/cypher_merge.out 
b/regress/expected/cypher_merge.out
index 389c34d1..988dff3c 100644
--- a/regress/expected/cypher_merge.out
+++ b/regress/expected/cypher_merge.out
@@ -513,15 +513,17 @@ SELECT * FROM cypher('cypher_merge', $$MATCH (n) DETACH 
DELETE n $$) AS (a agtyp
  */
 --test query
 SELECT * FROM cypher('cypher_merge', $$CREATE (n {i : 1}) SET n.i = 2 MERGE 
({i: 2}) $$) AS (a agtype);
-ERROR:  missing FROM-clause entry for table "_age_default_alias_0"
-LINE 5: SELECT * FROM cypher('cypher_merge', $$CREATE (n {i : 1}) SE...
-                                               ^
---validate created correctly
-SELECT * FROM cypher('cypher_merge', $$MATCH (a) RETURN a$$) AS (a agtype);
  a 
 ---
 (0 rows)
 
+--validate created correctly
+SELECT * FROM cypher('cypher_merge', $$MATCH (a) RETURN a$$) AS (a agtype);
+                                  a                                   
+----------------------------------------------------------------------
+ {"id": 281474976710690, "label": "", "properties": {"i": 2}}::vertex
+(1 row)
+
 --clean up
 SELECT * FROM cypher('cypher_merge', $$MATCH (n) DETACH DELETE n $$) AS (a 
agtype);
  a 
@@ -541,7 +543,7 @@ SELECT * FROM cypher('cypher_merge', $$CREATE (n {i : 1}) 
SET n.i = 2 WITH n as
 SELECT * FROM cypher('cypher_merge', $$MATCH (a) RETURN a$$) AS (a agtype);
                                   a                                   
 ----------------------------------------------------------------------
- {"id": 281474976710690, "label": "", "properties": {"i": 2}}::vertex
+ {"id": 281474976710691, "label": "", "properties": {"i": 2}}::vertex
 (1 row)
 
 --clean up
@@ -569,7 +571,7 @@ SELECT * FROM cypher('cypher_merge', $$MATCH (n {i : 1}) 
SET n.i = 2 WITH n as a
 SELECT * FROM cypher('cypher_merge', $$MATCH (a) RETURN a$$) AS (a agtype);
                                   a                                   
 ----------------------------------------------------------------------
- {"id": 281474976710691, "label": "", "properties": {"i": 2}}::vertex
+ {"id": 281474976710692, "label": "", "properties": {"i": 2}}::vertex
 (1 row)
 
 --clean up
@@ -594,7 +596,7 @@ ERROR:  vertex assigned to variable n was deleted
 SELECT * FROM cypher('cypher_merge', $$MATCH (a) RETURN a$$) AS (a agtype);
                                   a                                   
 ----------------------------------------------------------------------
- {"id": 281474976710692, "label": "", "properties": {"i": 1}}::vertex
+ {"id": 281474976710693, "label": "", "properties": {"i": 1}}::vertex
 (1 row)
 
 --clean up
@@ -672,7 +674,7 @@ SELECT * FROM cypher('cypher_merge', $$MERGE ()-[:e]-()$$) 
AS (a agtype);
 SELECT * FROM cypher('cypher_merge', $$MATCH p=()-[]->() RETURN p$$) AS (a 
agtype);
                                                                                
                                                a                               
                                                                                
                
 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- [{"id": 281474976710693, "label": "", "properties": {}}::vertex, {"id": 
844424930131982, "label": "e", "end_id": 281474976710694, "start_id": 
281474976710693, "properties": {}}::edge, {"id": 281474976710694, "label": "", 
"properties": {}}::vertex]::path
+ [{"id": 281474976710694, "label": "", "properties": {}}::vertex, {"id": 
844424930131982, "label": "e", "end_id": 281474976710695, "start_id": 
281474976710694, "properties": {}}::edge, {"id": 281474976710695, "label": "", 
"properties": {}}::vertex]::path
 (1 row)
 
 --clean up
@@ -687,14 +689,14 @@ SELECT * FROM cypher('cypher_merge', $$MATCH (n) DETACH 
DELETE n $$) AS (a agtyp
 SELECT * FROM cypher('cypher_merge', $$MERGE (a) RETURN a$$) AS (a agtype);
                                a                                
 ----------------------------------------------------------------
- {"id": 281474976710695, "label": "", "properties": {}}::vertex
+ {"id": 281474976710696, "label": "", "properties": {}}::vertex
 (1 row)
 
 --validate
 SELECT * FROM cypher('cypher_merge', $$MATCH (a) RETURN a$$) AS (a agtype);
                                a                                
 ----------------------------------------------------------------
- {"id": 281474976710695, "label": "", "properties": {}}::vertex
+ {"id": 281474976710696, "label": "", "properties": {}}::vertex
 (1 row)
 
 --clean up
@@ -709,14 +711,14 @@ SELECT * FROM cypher('cypher_merge', $$MATCH (n) DETACH 
DELETE n $$) AS (a agtyp
 SELECT * FROM cypher('cypher_merge', $$MERGE p=()-[:e]-() RETURN p$$) AS (a 
agtype);
                                                                                
                                                a                               
                                                                                
                
 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- [{"id": 281474976710696, "label": "", "properties": {}}::vertex, {"id": 
844424930131983, "label": "e", "end_id": 281474976710697, "start_id": 
281474976710696, "properties": {}}::edge, {"id": 281474976710697, "label": "", 
"properties": {}}::vertex]::path
+ [{"id": 281474976710697, "label": "", "properties": {}}::vertex, {"id": 
844424930131983, "label": "e", "end_id": 281474976710698, "start_id": 
281474976710697, "properties": {}}::edge, {"id": 281474976710698, "label": "", 
"properties": {}}::vertex]::path
 (1 row)
 
 --validate
 SELECT * FROM cypher('cypher_merge', $$MATCH p=()-[]->() RETURN p$$) AS (a 
agtype);
                                                                                
                                                a                               
                                                                                
                
 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- [{"id": 281474976710696, "label": "", "properties": {}}::vertex, {"id": 
844424930131983, "label": "e", "end_id": 281474976710697, "start_id": 
281474976710696, "properties": {}}::edge, {"id": 281474976710697, "label": "", 
"properties": {}}::vertex]::path
+ [{"id": 281474976710697, "label": "", "properties": {}}::vertex, {"id": 
844424930131983, "label": "e", "end_id": 281474976710698, "start_id": 
281474976710697, "properties": {}}::edge, {"id": 281474976710698, "label": "", 
"properties": {}}::vertex]::path
 (1 row)
 
 --clean up
@@ -731,14 +733,14 @@ SELECT * FROM cypher('cypher_merge', $$MATCH (n) DETACH 
DELETE n $$) AS (a agtyp
 SELECT * FROM cypher('cypher_merge', $$MERGE (a)-[:e]-(b) RETURN a$$) AS (a 
agtype);
                                a                                
 ----------------------------------------------------------------
- {"id": 281474976710698, "label": "", "properties": {}}::vertex
+ {"id": 281474976710699, "label": "", "properties": {}}::vertex
 (1 row)
 
 --validate
 SELECT * FROM cypher('cypher_merge', $$MATCH p=()-[]->() RETURN p$$) AS (a 
agtype);
                                                                                
                                                a                               
                                                                                
                
 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- [{"id": 281474976710698, "label": "", "properties": {}}::vertex, {"id": 
844424930131984, "label": "e", "end_id": 281474976710699, "start_id": 
281474976710698, "properties": {}}::edge, {"id": 281474976710699, "label": "", 
"properties": {}}::vertex]::path
+ [{"id": 281474976710699, "label": "", "properties": {}}::vertex, {"id": 
844424930131984, "label": "e", "end_id": 281474976710700, "start_id": 
281474976710699, "properties": {}}::edge, {"id": 281474976710700, "label": "", 
"properties": {}}::vertex]::path
 (1 row)
 
 --clean up
@@ -753,14 +755,14 @@ SELECT * FROM cypher('cypher_merge', $$MATCH (n) DETACH 
DELETE n $$) AS (a agtyp
 SELECT  * FROM cypher('cypher_merge', $$CREATE p=()-[:e]->() RETURN p$$) AS (a 
agtype);
                                                                                
                                                a                               
                                                                                
                
 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- [{"id": 281474976710700, "label": "", "properties": {}}::vertex, {"id": 
844424930131985, "label": "e", "end_id": 281474976710701, "start_id": 
281474976710700, "properties": {}}::edge, {"id": 281474976710701, "label": "", 
"properties": {}}::vertex]::path
+ [{"id": 281474976710701, "label": "", "properties": {}}::vertex, {"id": 
844424930131985, "label": "e", "end_id": 281474976710702, "start_id": 
281474976710701, "properties": {}}::edge, {"id": 281474976710702, "label": "", 
"properties": {}}::vertex]::path
 (1 row)
 
 SELECT * FROM cypher('cypher_merge', $$MERGE p=()-[:e]-() RETURN p$$) AS (a 
agtype);
                                                                                
                                                a                               
                                                                                
                
 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- [{"id": 281474976710700, "label": "", "properties": {}}::vertex, {"id": 
844424930131985, "label": "e", "end_id": 281474976710701, "start_id": 
281474976710700, "properties": {}}::edge, {"id": 281474976710701, "label": "", 
"properties": {}}::vertex]::path
- [{"id": 281474976710701, "label": "", "properties": {}}::vertex, {"id": 
844424930131985, "label": "e", "end_id": 281474976710701, "start_id": 
281474976710700, "properties": {}}::edge, {"id": 281474976710700, "label": "", 
"properties": {}}::vertex]::path
+ [{"id": 281474976710701, "label": "", "properties": {}}::vertex, {"id": 
844424930131985, "label": "e", "end_id": 281474976710702, "start_id": 
281474976710701, "properties": {}}::edge, {"id": 281474976710702, "label": "", 
"properties": {}}::vertex]::path
+ [{"id": 281474976710702, "label": "", "properties": {}}::vertex, {"id": 
844424930131985, "label": "e", "end_id": 281474976710702, "start_id": 
281474976710701, "properties": {}}::edge, {"id": 281474976710701, "label": "", 
"properties": {}}::vertex]::path
 (2 rows)
 
 --clean up
@@ -805,7 +807,7 @@ ERROR:  Existing variable m cannot be NULL in MERGE clause
 SELECT * FROM cypher('cypher_merge', $$MATCH (n) RETURN n$$) AS (a agtype);
                                a                                
 ----------------------------------------------------------------
- {"id": 281474976710702, "label": "", "properties": {}}::vertex
+ {"id": 281474976710703, "label": "", "properties": {}}::vertex
 (1 row)
 
 --
diff --git a/regress/sql/cypher_match.sql b/regress/sql/cypher_match.sql
index 344453e0..f08f8dfb 100644
--- a/regress/sql/cypher_match.sql
+++ b/regress/sql/cypher_match.sql
@@ -734,6 +734,79 @@ SELECT * FROM cypher('cypher_match', $$
     RETURN n
 $$) as (n agtype);
 
+--
+-- Regression tests to check previous clause variable refs
+--
+-- set up initial state and show what we're working with
+SELECT * FROM cypher('cypher_match', $$
+    CREATE (a {age: 4}) RETURN a $$) as (a agtype);
+SELECT * FROM cypher('cypher_match', $$
+       CREATE (b {age: 6}) RETURN b $$) as (b agtype);
+
+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);
+SELECT * FROM cypher('cypher_match', $$
+    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
+       RETURN a,b $$) as (a agtype, b agtype);
+SELECT * FROM cypher('cypher_match', $$
+       MATCH (a),(b) WHERE a.age = 4 AND a.name = "T" AND b.age = 6 CREATE 
+       (a)-[:knows {relationship: "friends", years: 3}]->(b) $$) as (r agtype);
+SELECT * FROM cypher('cypher_match', $$
+       MATCH (a),(b) WHERE a.age = 4 AND a.name = "orphan" AND b.age = 6 
CREATE 
+       (a)-[:knows {relationship: "enemies", years: 4}]->(b) $$) as (r agtype);
+SELECT * FROM cypher('cypher_match', $$
+       MATCH (a)-[r]-(b) RETURN r $$) as (r agtype);
+
+-- check reuse of 'a'
+SELECT * FROM cypher('cypher_match', $$
+    MATCH (a {age:4}) RETURN a $$) as (a agtype);
+SELECT * FROM cypher('cypher_match', $$
+    MATCH (a) MATCH (a {age:4}) RETURN a $$) as (a agtype);
+
+SELECT * FROM cypher('cypher_match', $$
+    MATCH (a {age:4, name: "orphan"}) RETURN a $$) as (a agtype);
+SELECT * FROM cypher('cypher_match', $$
+    MATCH (a) MATCH (a {age:4}) MATCH (a {name: "orphan"}) RETURN a $$) as (a 
agtype);
+SELECT * FROM cypher('cypher_match', $$
+    MATCH (a {age:4}) MATCH (a {name: "orphan"}) RETURN a $$) as (a agtype);
+
+SELECT * FROM cypher('cypher_match', $$
+    MATCH (a) MATCH (a {age:4}) MATCH (a {name: "orphan"}) SET a.age = 3 
RETURN a $$) as (a agtype);
+
+SELECT * FROM cypher('cypher_match', $$
+    MATCH (a) MATCH (a {age:3}) MATCH (a {name: "orphan"}) RETURN a $$) as (a 
agtype);
+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);
+
+SELECT * FROM cypher('cypher_match', $$
+    MATCH (a) WHERE exists(a.age) AND NOT exists(a.name) RETURN a $$) as (a 
agtype);
+
+-- check reuse of 'r'
+SELECT * FROM cypher('cypher_match', $$
+       MATCH ()-[r]-() RETURN r $$) as (r agtype);
+SELECT * FROM cypher('cypher_match', $$
+       MATCH ()-[r]-() MATCH ()-[r {relationship: "friends"}]-() RETURN r $$) 
as (r agtype);
+SELECT * FROM cypher('cypher_match', $$
+       MATCH ()-[r {years:3, relationship: "friends"}]-() RETURN r $$) as (r 
agtype);
+SELECT * FROM cypher('cypher_match', $$
+       MATCH ()-[r {years:3}]-() MATCH ()-[r {relationship: "friends"}]-() 
RETURN r $$) as (r agtype);
+--mismatch year #, should return nothing
+SELECT * FROM cypher('cypher_match', $$
+       MATCH ()-[r {years:2}]-() MATCH ()-[r {relationship: "friends"}]-() 
RETURN r $$) as (r agtype);
+SELECT * FROM cypher('cypher_match', $$
+       MATCH ()-[r {relationship:"enemies"}]-() MATCH ()-[r {years:4}]-() 
RETURN r $$) as (r agtype);
+SELECT * FROM cypher('cypher_match', $$
+       MATCH ()-[r {relationship:"enemies"}]-() MATCH ()-[r 
{relationship:"friends"}]-() RETURN r $$) as (r agtype);
+
 --
 -- Clean up
 --
diff --git a/src/backend/parser/cypher_clause.c 
b/src/backend/parser/cypher_clause.c
index 8b6a4e3b..234e3aad 100644
--- a/src/backend/parser/cypher_clause.c
+++ b/src/backend/parser/cypher_clause.c
@@ -172,7 +172,8 @@ static A_Expr 
*filter_vertices_on_label_id(cypher_parsestate *cpstate,
                                            Node *id_field, char *label);
 static Node *create_property_constraints(cypher_parsestate *cpstate,
                                          transform_entity *entity,
-                                         Node *property_constraints);
+                                         Node *property_constraints,
+                                         Node *prop_expr);
 static TargetEntry *findTarget(List *targetList, char *resname);
 static transform_entity *transform_VLE_edge_entity(cypher_parsestate *cpstate,
                                                    cypher_relationship *rel,
@@ -3506,33 +3507,43 @@ static A_Expr 
*filter_vertices_on_label_id(cypher_parsestate *cpstate,
  */
 static Node *create_property_constraints(cypher_parsestate *cpstate,
                                          transform_entity *entity,
-                                         Node *property_constraints)
+                                         Node *property_constraints,
+                                         Node *prop_expr)
 {
     ParseState *pstate = (ParseState *)cpstate;
     char *entity_name;
-    ColumnRef *cr;
-    Node *prop_expr, *const_expr;
+    Node *const_expr;
     RangeTblEntry *rte;
     Node *last_srf = pstate->p_last_srf;
 
-    cr = makeNode(ColumnRef);
-
-    entity_name = get_entity_name(entity);
+    /*
+     * If the prop_expr node wasn't passed in, create it. Otherwise, skip
+     * the creation step.
+     */
+    if (prop_expr == NULL)
+    {
+        ColumnRef *cr = NULL;
 
-    cr->fields = list_make2(makeString(entity_name), makeString("properties"));
+        cr = makeNode(ColumnRef);
+        entity_name = get_entity_name(entity);
+        cr->fields = list_make2(makeString(entity_name),
+                                makeString("properties"));
 
-    // use Postgres to get the properties' transform node
-    if ((rte = find_rte(cpstate, entity_name)))
-    {
-        prop_expr = scanRTEForColumn(pstate, rte, AG_VERTEX_COLNAME_PROPERTIES,
-                                     -1, 0, NULL);
-    }
-    else
-    {
-        prop_expr = transformExpr(pstate, (Node *)cr, EXPR_KIND_WHERE);
+        /* use Postgres to get the properties' transform node */
+        rte = find_rte(cpstate, entity_name);
+        if (rte != NULL)
+        {
+            prop_expr = scanRTEForColumn(pstate, rte,
+                                         AG_VERTEX_COLNAME_PROPERTIES, -1, 0,
+                                         NULL);
+        }
+        else
+        {
+            prop_expr = transformExpr(pstate, (Node *)cr, EXPR_KIND_WHERE);
+        }
     }
 
-    // use cypher to get the constraints' transform node
+    /* use cypher to get the constraints' transform node */
     const_expr = transform_cypher_expr(cpstate, property_constraints,
                                        EXPR_KIND_WHERE);
 
@@ -3817,13 +3828,68 @@ static List *transform_match_entities(cypher_parsestate 
*cpstate, Query *query,
             entity = make_transform_entity(cpstate, ENT_VERTEX, (Node *)node,
                                            expr);
 
-            /* transform properties if they exist */
+            /* transform the properties if they exist */
             if (node->props)
             {
                 Node *n = NULL;
+                Node *prop_var = NULL;
+                Node *prop_expr = NULL;
+
+                /*
+                 * We need to build a transformed properties(prop_var)
+                 * expression IF the properties variable already exists from a
+                 * previous clause. Please note that the "found" prop_var was
+                 * previously transformed.
+                 */
+
+                /* get the prop_var if it was previously resolved */
+                if (node->name != NULL)
+                {
+                    prop_var = colNameToVar(pstate, node->name, false,
+                                            node->location);
+                }
+
+                /*
+                 * If prop_var exists and is an alias, just pass it through by
+                 * assigning the prop_expr the prop_var.
+                 */
+                if (prop_var != NULL &&
+                    pg_strncasecmp(node->name, AGE_DEFAULT_ALIAS_PREFIX,
+                                   strlen(AGE_DEFAULT_ALIAS_PREFIX)) == 0)
+                {
+                    prop_expr = prop_var;
+                }
+                /*
+                 * Else, if it exists and is not an alias, create the prop_expr
+                 * as a transformed properties(prop_var) function node.
+                 */
+                else if (prop_var != NULL)
+                {
+                    /*
+                     * Remember that prop_var is already transformed. We need
+                     * to built the transform manually.
+                     */
+                    FuncCall *fc = NULL;
+                    List *targs = NIL;
+                    List *fname = NIL;
+
+                    targs = lappend(targs, prop_var);
+                    fname = list_make2(makeString("ag_catalog"),
+                                       makeString("age_properties"));
+                    fc = makeFuncCall(fname, targs, -1);
+
+                    /*
+                     * Hand off to ParseFuncOrColumn to create the function
+                     * expression for properties(prop_var)
+                     */
+                    prop_expr = ParseFuncOrColumn(pstate, fname, targs,
+                                                  pstate->p_last_srf, fc, 
false,
+                                                  -1);
+                }
 
                 ((cypher_map*)node->props)->keep_null = true;
-                n = create_property_constraints(cpstate, entity, node->props);
+                n = create_property_constraints(cpstate, entity, node->props,
+                                                prop_expr);
 
                 cpstate->property_constraint_quals =
                     lappend(cpstate->property_constraint_quals, n);
@@ -3882,13 +3948,66 @@ static List *transform_match_entities(cypher_parsestate 
*cpstate, Query *query,
 
                 if (rel->props)
                 {
-                    Node *n;
+                    Node *r = NULL;
+                    Node *prop_var = NULL;
+                    Node *prop_expr = NULL;
+
+                    /*
+                     * We need to build a transformed properties(prop_var)
+                     * expression IF the properties variable already exists 
from
+                     * a previous clause. Please note that the "found" prop_var
+                     * was previously transformed.
+                     */
+
+                    /* get the prop_var if it was previously resolved */
+                    if (rel->name != NULL)
+                    {
+                        prop_var = colNameToVar(pstate, rel->name, false,
+                                                rel->location);
+                    }
+
+                    /*
+                     * If prop_var exists and is an alias, just pass it 
through by
+                     * assigning the prop_expr the prop_var.
+                     */
+                    if (prop_var != NULL &&
+                        pg_strncasecmp(rel->name, AGE_DEFAULT_ALIAS_PREFIX,
+                                       strlen(AGE_DEFAULT_ALIAS_PREFIX)) == 0)
+                    {
+                        prop_expr = prop_var;
+                    }
+                    /*
+                     * Else, if it exists and is not an alias, create the 
prop_expr
+                     * as a transformed properties(prop_var) function node.
+                     */
+                    else if (prop_var != NULL)
+                    {
+                        /*
+                         * Remember that prop_var is already transformed. We 
need
+                         * to built the transform manually.
+                         */
+                        FuncCall *fc = NULL;
+                        List *targs = NIL;
+                        List *fname = NIL;
+
+                        targs = lappend(targs, prop_var);
+                        fname = list_make2(makeString("ag_catalog"),
+                                           makeString("age_properties"));
+                        fc = makeFuncCall(fname, targs, -1);
+
+                        /*
+                         * Hand off to ParseFuncOrColumn to create the function
+                         * expression for properties(prop_var)
+                         */
+                        prop_expr = ParseFuncOrColumn(pstate, fname, targs,
+                                                      pstate->p_last_srf, fc,
+                                                      false, -1);
+                    }
 
                     ((cypher_map*)rel->props)->keep_null = true;
-                    n = create_property_constraints(cpstate, entity,
-                                                          rel->props);
+                    r = create_property_constraints(cpstate, entity, 
rel->props, prop_expr);
                     cpstate->property_constraint_quals =
-                        lappend(cpstate->property_constraint_quals, n);
+                        lappend(cpstate->property_constraint_quals, r);
                 }
 
                 entities = lappend(entities, entity);


Reply via email to