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

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

commit c2faa133308b79d579507003fc790c0f00045500
Author: Muhammad Taha Naveed <mt...@apache.org>
AuthorDate: Tue Jun 10 23:07:49 2025 +0500

    Reimplement list comprehension (#2169)
    
    * Revert "Fix issue 1955 - List comprehension in WHERE clause (#2094)"
    
    This reverts commit 0f0d9be9ba02fb90272d2053986f2b5aa4a0c25c.
    
    * Revert "Fix error using list comprehension with WITH * (#1838)"
    
    This reverts commit 5e08a2f58693adca55085da8d56eb1831d963d20.
    
    * Revert "Fix shift/reduce conflict in grammar (#1719)"
    
    This reverts commit fab3119a109280fd63237ce17c6d4dd60b7dfc03.
    
    * Revert "Implement list comprehension (#1610)"
    
    This reverts commit 3b2b394eb669c4f80fc893ad224cf5ea4e10c5a9.
    
    * Reimplement list comprehension
    
    - Reimplement list comprehension to use ARRAY sublinks.
    - Some test results were not correct. All the test results that are
      modified are correct and are verified with neo4j.
    - Also resolves the issue of using list comprehension in MERGE clause (1611)
      and issue 1850
    
    * Add expression tree walkers for cypher nodes
    
    - Added cypher_raw_expr_tree_walker and cypher_expr_tree_walker, based
      on Postgres's raw_expression_tree_walker and expression_tree_walker.
      These follow the same walker API as Postgres and add support for
      Cypher-specific nodes.
    - Also added the agtype[] to agtype func and typecast to 1.5.0-y.y.y.sql
    - Simplifies logic for cypher_subquery handling in where clause.
    - Fixes a crash when list comprehension in the WHERE clause references a
      variable from the preceding MATCH clause.
---
 age--1.5.0--y.y.y.sql                   |  13 +-
 regress/expected/list_comprehension.out | 102 ++++++--
 regress/sql/list_comprehension.sql      |  16 +-
 sql/agtype_coercions.sql                |  11 +
 sql/agtype_typecast.sql                 |   3 +-
 src/backend/nodes/ag_nodes.c            |   2 +
 src/backend/nodes/cypher_outfuncs.c     |  14 +-
 src/backend/optimizer/cypher_pathnode.c |  82 ++++++-
 src/backend/parser/cypher_analyze.c     | 416 +++++++++-----------------------
 src/backend/parser/cypher_clause.c      | 319 ++++++++++++------------
 src/backend/parser/cypher_expr.c        |  67 +----
 src/backend/parser/cypher_gram.y        | 148 ++++--------
 src/backend/parser/cypher_item.c        | 242 +------------------
 src/backend/utils/adt/agtype.c          |  55 +----
 src/include/nodes/ag_nodes.h            |   2 +-
 src/include/nodes/cypher_nodes.h        |  14 +-
 src/include/nodes/cypher_outfuncs.h     |   1 +
 src/include/parser/cypher_analyze.h     |  12 +-
 src/include/parser/cypher_clause.h      |   9 -
 src/include/parser/cypher_item.h        |   2 -
 src/include/parser/cypher_parse_node.h  |   1 -
 21 files changed, 570 insertions(+), 961 deletions(-)

diff --git a/age--1.5.0--y.y.y.sql b/age--1.5.0--y.y.y.sql
index 1d4aa602..5bf45a2a 100644
--- a/age--1.5.0--y.y.y.sql
+++ b/age--1.5.0--y.y.y.sql
@@ -156,4 +156,15 @@ PARALLEL SAFE
 AS 'MODULE_PATHNAME';
 
 CREATE CAST (agtype AS json)
-    WITH FUNCTION ag_catalog.agtype_to_json(agtype);
\ No newline at end of file
+    WITH FUNCTION ag_catalog.agtype_to_json(agtype);
+
+CREATE FUNCTION ag_catalog.agtype_array_to_agtype(agtype[])
+    RETURNS agtype
+    LANGUAGE c
+    IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE CAST (agtype[] AS agtype)
+    WITH FUNCTION ag_catalog.agtype_array_to_agtype(agtype[]);
\ No newline at end of file
diff --git a/regress/expected/list_comprehension.out 
b/regress/expected/list_comprehension.out
index bf5731d2..07f77770 100644
--- a/regress/expected/list_comprehension.out
+++ b/regress/expected/list_comprehension.out
@@ -166,9 +166,9 @@ SELECT * FROM cypher('list_comprehension', $$ MATCH p=(u) 
RETURN [i IN range(0,
 SELECT * FROM cypher('list_comprehension', $$ MATCH (u) RETURN [i IN u.list] 
$$) AS (result agtype);
          result          
 -------------------------
+ [0, 2, 4, 6, 8, 10, 12]
  [1, 3, 5, 7, 9, 11, 13]
  []
- [0, 2, 4, 6, 8, 10, 12]
 (3 rows)
 
 SELECT * FROM cypher('list_comprehension', $$ MATCH (u) RETURN [i IN u.list 
WHERE i % 3 = 0] $$) AS (result agtype);
@@ -176,35 +176,40 @@ SELECT * FROM cypher('list_comprehension', $$ MATCH (u) 
RETURN [i IN u.list WHER
 ------------
  [0, 6, 12]
  [3, 9]
-(2 rows)
+ []
+(3 rows)
 
 SELECT * FROM cypher('list_comprehension', $$ MATCH (u) RETURN [i IN u.list 
WHERE i % 3 = 0 | i/3] $$) AS (result agtype);
   result   
 -----------
  [0, 2, 4]
  [1, 3]
-(2 rows)
+ []
+(3 rows)
 
 SELECT * FROM cypher('list_comprehension', $$ MATCH (u) RETURN [i IN u.list 
WHERE i % 3 = 0 | i/3][1] $$) AS (result agtype);
  result 
 --------
  2
  3
-(2 rows)
+ 
+(3 rows)
 
 SELECT * FROM cypher('list_comprehension', $$ MATCH (u) RETURN [i IN u.list 
WHERE i % 3 = 0 | i/3][0..2] $$) AS (result agtype);
  result 
 --------
  [0, 2]
  [1, 3]
-(2 rows)
+ []
+(3 rows)
 
 SELECT * FROM cypher('list_comprehension', $$ MATCH (u) RETURN [i IN u.list 
WHERE i % 3 = 0 | i/3][0..2][1] $$) AS (result agtype);
  result 
 --------
  2
  3
-(2 rows)
+ 
+(3 rows)
 
 -- Nested cases
 SELECT * FROM cypher('list_comprehension', $$ RETURN [i IN [i IN [1,2,3]]] $$) 
AS (result agtype);
@@ -299,9 +304,9 @@ SELECT * FROM cypher('list_comprehension', $$ MATCH (u) 
WHERE u.list@>[i IN rang
 SELECT * FROM cypher('list_comprehension', $$ MATCH (u) MATCH (v) WHERE 
v.list=[i IN u.list] RETURN v $$) AS (result agtype);
                                             result                             
                
 
-----------------------------------------------------------------------------------------------
- {"id": 281474976710659, "label": "", "properties": {"list": []}}::vertex
  {"id": 281474976710657, "label": "", "properties": {"list": [0, 2, 4, 6, 8, 
10, 12]}}::vertex
  {"id": 281474976710658, "label": "", "properties": {"list": [1, 3, 5, 7, 9, 
11, 13]}}::vertex
+ {"id": 281474976710659, "label": "", "properties": {"list": []}}::vertex
 (3 rows)
 
 SELECT * FROM cypher('list_comprehension', $$ MATCH (u {list:[i IN 
range(0,12,2)]}) RETURN u $$) AS (result agtype);
@@ -330,11 +335,11 @@ SELECT * FROM cypher('list_comprehension', $$ MATCH (u 
{list:[i IN range(1,13,2)
 SELECT * FROM cypher('list_comprehension', $$ MATCH (u) MATCH (v {list:[i IN 
u.list]}) RETURN v $$) AS (result agtype);
                                             result                             
                
 
-----------------------------------------------------------------------------------------------
- {"id": 281474976710658, "label": "", "properties": {"list": [1, 3, 5, 7, 9, 
11, 13]}}::vertex
  {"id": 281474976710657, "label": "", "properties": {"list": [0, 2, 4, 6, 8, 
10, 12]}}::vertex
- {"id": 281474976710659, "label": "", "properties": {"list": []}}::vertex
+ {"id": 281474976710658, "label": "", "properties": {"list": [1, 3, 5, 7, 9, 
11, 13]}}::vertex
  {"id": 281474976710657, "label": "", "properties": {"list": [0, 2, 4, 6, 8, 
10, 12]}}::vertex
  {"id": 281474976710658, "label": "", "properties": {"list": [1, 3, 5, 7, 9, 
11, 13]}}::vertex
+ {"id": 281474976710659, "label": "", "properties": {"list": []}}::vertex
 (5 rows)
 
 SELECT * FROM cypher('list_comprehension', $$ CREATE (u {list:[i IN 
range(12,24,2)]}) RETURN u $$) AS (result agtype);
@@ -371,26 +376,26 @@ SELECT * FROM cypher('list_comprehension', $$ MATCH(u) 
WITH u WHERE u.list = [u
 SELECT * FROM cypher('list_comprehension', $$ MATCH(u) WITH u WHERE u.list = 
[u IN [0, 2, 4, 6, 8, 10, 12]] OR size(u.list) = 0 RETURN u $$) AS (u agtype);
                                                u                               
                
 
-----------------------------------------------------------------------------------------------
- {"id": 281474976710659, "label": "", "properties": {"list": []}}::vertex
  {"id": 281474976710657, "label": "", "properties": {"list": [0, 2, 4, 6, 8, 
10, 12]}}::vertex
+ {"id": 281474976710659, "label": "", "properties": {"list": []}}::vertex
 (2 rows)
 
 SELECT * FROM cypher('list_comprehension', $$ MATCH(u) WITH u WHERE u.list = 
[u IN [0, 2, 4, 6, 8, 10, 12]] OR size(u.list)::bool RETURN u $$) AS (u agtype);
                                                    u                           
                         
 
--------------------------------------------------------------------------------------------------------
+ {"id": 281474976710657, "label": "", "properties": {"list": [0, 2, 4, 6, 8, 
10, 12]}}::vertex
  {"id": 281474976710658, "label": "", "properties": {"list": [1, 3, 5, 7, 9, 
11, 13]}}::vertex
- {"id": 281474976710661, "label": "", "properties": {"list": [6, 8, 10, 
12]}}::vertex
  {"id": 281474976710660, "label": "", "properties": {"list": [12, 14, 16, 18, 
20, 22, 24]}}::vertex
+ {"id": 281474976710661, "label": "", "properties": {"list": [6, 8, 10, 
12]}}::vertex
  {"id": 281474976710662, "label": "", "properties": {"list": [25.0, 49.0, 
81.0, 121.0, 169.0]}}::vertex
- {"id": 281474976710657, "label": "", "properties": {"list": [0, 2, 4, 6, 8, 
10, 12]}}::vertex
  {"id": 281474976710663, "label": "", "properties": {"list": [1, 2, 
3]}}::vertex
 (6 rows)
 
 SELECT * FROM cypher('list_comprehension', $$ MATCH(u) WITH u WHERE u.list = 
[u IN [0, 2, 4, 6, 8, 10, 12]] OR NOT size(u.list)::bool RETURN u $$) AS (u 
agtype);
                                                u                               
                
 
-----------------------------------------------------------------------------------------------
- {"id": 281474976710659, "label": "", "properties": {"list": []}}::vertex
  {"id": 281474976710657, "label": "", "properties": {"list": [0, 2, 4, 6, 8, 
10, 12]}}::vertex
+ {"id": 281474976710659, "label": "", "properties": {"list": []}}::vertex
 (2 rows)
 
 SELECT * FROM cypher('list_comprehension', $$ CREATE(u:csm_match {list: 
['abc', 'def', 'ghi']}) $$) AS (u agtype);
@@ -473,9 +478,6 @@ SELECT * FROM cypher('list_comprehension', $$ MATCH(u 
{list: [0, 2, 4, 6, 8, 10,
 ERROR:  Invalid use of aggregation in this context
 LINE 1: ..., $$ MATCH(u {list: [0, 2, 4, 6, 8, 10, 12]}) SET u.c = coll...
                                                              ^
--- Known issue
-SELECT * FROM cypher('list_comprehension', $$ MERGE (u {list:[i IN [1,2,3]]}) 
RETURN u $$) AS (result agtype);
-ERROR:  Aggref found in non-Agg plan node
 -- List comprehension variable scoping
 SELECT * FROM cypher('list_comprehension', $$ WITH 1 AS m, [m IN [1, 2, 3]] AS 
n RETURN [m IN [1, 2, 3]] $$) AS (result agtype);
   result   
@@ -622,12 +624,12 @@ SELECT * FROM cypher('list_comprehension', $$ MATCH (u) 
WHERE u.list=[i IN u.lis
                                                                             
result                                                                          
   
 
---------------------------------------------------------------------------------------------------------------------------------------------------------------
  {"id": 281474976710658, "label": "", "properties": {"list": [1, 3, 5, 7, 9, 
11, 13]}}::vertex
+ {"id": 281474976710659, "label": "", "properties": {"list": []}}::vertex
  {"id": 281474976710660, "label": "", "properties": {"list": [12, 14, 16, 18, 
20, 22, 24]}}::vertex
+ {"id": 281474976710661, "label": "", "properties": {"list": [6, 8, 10, 
12]}}::vertex
  {"id": 281474976710662, "label": "", "properties": {"list": [25.0, 49.0, 
81.0, 121.0, 169.0]}}::vertex
- {"id": 281474976710657, "label": "", "properties": {"a": [], "b": [0, 1, 2, 
3, 4, 5], "c": [0, 2, 4, 6, 8, 10, 12], "list": [0, 2, 4, 6, 8, 10, 
12]}}::vertex
  {"id": 281474976710663, "label": "", "properties": {"list": [1, 2, 
3]}}::vertex
- {"id": 281474976710659, "label": "", "properties": {"list": []}}::vertex
- {"id": 281474976710661, "label": "", "properties": {"list": [6, 8, 10, 
12]}}::vertex
+ {"id": 281474976710657, "label": "", "properties": {"a": [], "b": [0, 1, 2, 
3, 4, 5], "c": [0, 2, 4, 6, 8, 10, 12], "list": [0, 2, 4, 6, 8, 10, 
12]}}::vertex
  {"id": 844424930131969, "label": "csm_match", "properties": {"list": ["abc", 
"def", "ghi"]}}::vertex
 (8 rows)
 
@@ -635,11 +637,12 @@ SELECT * FROM cypher('list_comprehension', $$ MATCH (u) 
WHERE u.list=[i IN u.lis
                                                  result                        
                         
 
--------------------------------------------------------------------------------------------------------
  {"id": 281474976710658, "label": "", "properties": {"list": [1, 3, 5, 7, 9, 
11, 13]}}::vertex
+ {"id": 281474976710659, "label": "", "properties": {"list": []}}::vertex
  {"id": 281474976710660, "label": "", "properties": {"list": [12, 14, 16, 18, 
20, 22, 24]}}::vertex
+ {"id": 281474976710661, "label": "", "properties": {"list": [6, 8, 10, 
12]}}::vertex
  {"id": 281474976710662, "label": "", "properties": {"list": [25.0, 49.0, 
81.0, 121.0, 169.0]}}::vertex
  {"id": 281474976710663, "label": "", "properties": {"list": [1, 2, 
3]}}::vertex
- {"id": 281474976710661, "label": "", "properties": {"list": [6, 8, 10, 
12]}}::vertex
-(5 rows)
+(6 rows)
 
 SELECT * FROM cypher('list_comprehension', $$ MATCH (u) WHERE size([e in 
u.list where e starts with "a"])>0 RETURN u $$) AS (result agtype);
                                                 result                         
                       
@@ -657,11 +660,64 @@ SELECT * FROM cypher('list_comprehension', $$ MATCH (u 
={list:[i IN u.list WHERE
                                                  result                        
                         
 
--------------------------------------------------------------------------------------------------------
  {"id": 281474976710658, "label": "", "properties": {"list": [1, 3, 5, 7, 9, 
11, 13]}}::vertex
+ {"id": 281474976710659, "label": "", "properties": {"list": []}}::vertex
  {"id": 281474976710660, "label": "", "properties": {"list": [12, 14, 16, 18, 
20, 22, 24]}}::vertex
+ {"id": 281474976710661, "label": "", "properties": {"list": [6, 8, 10, 
12]}}::vertex
  {"id": 281474976710662, "label": "", "properties": {"list": [25.0, 49.0, 
81.0, 121.0, 169.0]}}::vertex
  {"id": 281474976710663, "label": "", "properties": {"list": [1, 2, 
3]}}::vertex
- {"id": 281474976710661, "label": "", "properties": {"list": [6, 8, 10, 
12]}}::vertex
-(5 rows)
+(6 rows)
+
+-- List comprehension in MERGE
+SELECT * FROM cypher('list_comprehension', $$ MERGE (u {list:[i IN [1,2,3]]}) 
RETURN u $$) AS (result agtype);
+                                     result                                    
  
+---------------------------------------------------------------------------------
+ {"id": 281474976710663, "label": "", "properties": {"list": [1, 2, 
3]}}::vertex
+(1 row)
+
+SELECT * FROM cypher('list_comprehension', $$ MERGE (u ={list:[i IN [1,2,3] 
WHERE i>1]}) RETURN u $$) AS (result agtype);
+                                    result                                    
+------------------------------------------------------------------------------
+ {"id": 281474976710666, "label": "", "properties": {"list": [2, 3]}}::vertex
+(1 row)
+
+SELECT * FROM cypher('list_comprehension', $$ MERGE (u ={list:[i IN [1,2,3] 
WHERE i>1 | i^2]}) RETURN u $$) AS (result agtype);
+                                      result                                   
   
+----------------------------------------------------------------------------------
+ {"id": 281474976710667, "label": "", "properties": {"list": [4.0, 
9.0]}}::vertex
+(1 row)
+
+-- Issue 1850
+SELECT * FROM cypher('list_comprehension', $$ CREATE (u {list: [0, 2, 4, 6, 8, 
10, 12]}) $$) AS (result agtype);
+ result 
+--------
+(0 rows)
+
+SELECT * FROM cypher('list_comprehension', $$ WITH [1, 2, 3] AS u UNWIND 
collect(u) AS v RETURN v $$) AS (result agtype);
+ERROR:  Invalid use of aggregation in this context
+LINE 1: ...ist_comprehension', $$ WITH [1, 2, 3] AS u UNWIND collect(u)...
+                                                             ^
+SELECT * FROM cypher('list_comprehension', $$ MATCH (u {list: [0, 2, 4, 6, 8, 
10, 12]}) WITH u, collect(u.list) AS v SET u += {b: [u IN range(0, 5)]} SET u.c 
= [u IN v[0]] RETURN u $$) AS (result agtype);
+                                                                            
result                                                                          
   
+---------------------------------------------------------------------------------------------------------------------------------------------------------------
+ {"id": 281474976710657, "label": "", "properties": {"a": [], "b": [0, 1, 2, 
3, 4, 5], "c": [0, 2, 4, 6, 8, 10, 12], "list": [0, 2, 4, 6, 8, 10, 
12]}}::vertex
+ {"id": 281474976710668, "label": "", "properties": {"b": [0, 1, 2, 3, 4, 5], 
"c": [0, 2, 4, 6, 8, 10, 12], "list": [0, 2, 4, 6, 8, 10, 12]}}::vertex
+(2 rows)
+
+SELECT * FROM cypher('list_comprehension', $$ MATCH (u {list: [0, 2, 4, 6, 8, 
10, 12]}) SET u.c = collect(u.list) RETURN u $$) AS (u agtype);
+ERROR:  Invalid use of aggregation in this context
+LINE 1: ... $$ MATCH (u {list: [0, 2, 4, 6, 8, 10, 12]}) SET u.c = coll...
+                                                             ^
+SELECT * FROM cypher('list_comprehension', $$ MATCH (u {list: [0, 2, 4, 6, 8, 
10, 12]}) WHERE u.list = [u IN [1, u]] RETURN u $$) AS (u agtype);
+ u 
+---
+(0 rows)
+
+SELECT * FROM cypher('list_comprehension', $$ MATCH (u {list: [0, 2, 4, 6, 8, 
10, 12]}) WHERE u.list IN [u IN [1, u.list]] RETURN u $$) AS (u agtype);
+                                                                               
u                                                                               
+---------------------------------------------------------------------------------------------------------------------------------------------------------------
+ {"id": 281474976710657, "label": "", "properties": {"a": [], "b": [0, 1, 2, 
3, 4, 5], "c": [0, 2, 4, 6, 8, 10, 12], "list": [0, 2, 4, 6, 8, 10, 
12]}}::vertex
+ {"id": 281474976710668, "label": "", "properties": {"b": [0, 1, 2, 3, 4, 5], 
"c": [0, 2, 4, 6, 8, 10, 12], "list": [0, 2, 4, 6, 8, 10, 12]}}::vertex
+(2 rows)
 
 -- Clean up
 SELECT * FROM drop_graph('list_comprehension', true);
diff --git a/regress/sql/list_comprehension.sql 
b/regress/sql/list_comprehension.sql
index cb941a61..572b2e6b 100644
--- a/regress/sql/list_comprehension.sql
+++ b/regress/sql/list_comprehension.sql
@@ -117,9 +117,6 @@ SELECT * FROM cypher('list_comprehension', $$ MATCH(u 
{list: [0, 2, 4, 6, 8, 10,
 -- invalid use of aggregation in SET
 SELECT * FROM cypher('list_comprehension', $$ MATCH(u {list: [0, 2, 4, 6, 8, 
10, 12]}) SET u.c = collect(u.list) RETURN u $$) AS (u agtype);
 
--- Known issue
-SELECT * FROM cypher('list_comprehension', $$ MERGE (u {list:[i IN [1,2,3]]}) 
RETURN u $$) AS (result agtype);
-
 -- List comprehension variable scoping
 SELECT * FROM cypher('list_comprehension', $$ WITH 1 AS m, [m IN [1, 2, 3]] AS 
n RETURN [m IN [1, 2, 3]] $$) AS (result agtype);
 SELECT * FROM cypher('list_comprehension', $$ WITH 1 AS m RETURN [m IN [1, 2, 
3]], m $$) AS (result agtype, result2 agtype);
@@ -164,5 +161,18 @@ SELECT * FROM cypher('list_comprehension', $$ MATCH (u) 
WHERE size([e in u.list
 SELECT * FROM cypher('list_comprehension', $$ MATCH (u ={list:[i IN u.list | 
i+1]}) RETURN u $$) AS (result agtype);
 SELECT * FROM cypher('list_comprehension', $$ MATCH (u ={list:[i IN u.list 
WHERE i>0]}) RETURN u$$) AS (result agtype);
 
+-- List comprehension in MERGE
+SELECT * FROM cypher('list_comprehension', $$ MERGE (u {list:[i IN [1,2,3]]}) 
RETURN u $$) AS (result agtype);
+SELECT * FROM cypher('list_comprehension', $$ MERGE (u ={list:[i IN [1,2,3] 
WHERE i>1]}) RETURN u $$) AS (result agtype);
+SELECT * FROM cypher('list_comprehension', $$ MERGE (u ={list:[i IN [1,2,3] 
WHERE i>1 | i^2]}) RETURN u $$) AS (result agtype);
+
+-- Issue 1850
+SELECT * FROM cypher('list_comprehension', $$ CREATE (u {list: [0, 2, 4, 6, 8, 
10, 12]}) $$) AS (result agtype);
+SELECT * FROM cypher('list_comprehension', $$ WITH [1, 2, 3] AS u UNWIND 
collect(u) AS v RETURN v $$) AS (result agtype);
+SELECT * FROM cypher('list_comprehension', $$ MATCH (u {list: [0, 2, 4, 6, 8, 
10, 12]}) WITH u, collect(u.list) AS v SET u += {b: [u IN range(0, 5)]} SET u.c 
= [u IN v[0]] RETURN u $$) AS (result agtype);
+SELECT * FROM cypher('list_comprehension', $$ MATCH (u {list: [0, 2, 4, 6, 8, 
10, 12]}) SET u.c = collect(u.list) RETURN u $$) AS (u agtype);
+SELECT * FROM cypher('list_comprehension', $$ MATCH (u {list: [0, 2, 4, 6, 8, 
10, 12]}) WHERE u.list = [u IN [1, u]] RETURN u $$) AS (u agtype);
+SELECT * FROM cypher('list_comprehension', $$ MATCH (u {list: [0, 2, 4, 6, 8, 
10, 12]}) WHERE u.list IN [u IN [1, u.list]] RETURN u $$) AS (u agtype);
+
 -- Clean up
 SELECT * FROM drop_graph('list_comprehension', true);
\ No newline at end of file
diff --git a/sql/agtype_coercions.sql b/sql/agtype_coercions.sql
index bdc33af8..c7895fab 100644
--- a/sql/agtype_coercions.sql
+++ b/sql/agtype_coercions.sql
@@ -173,3 +173,14 @@ AS 'MODULE_PATHNAME';
 
 CREATE CAST (agtype AS json)
     WITH FUNCTION ag_catalog.agtype_to_json(agtype);
+
+CREATE FUNCTION ag_catalog.agtype_array_to_agtype(agtype[])
+    RETURNS agtype
+    LANGUAGE c
+    IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE CAST (agtype[] AS agtype)
+    WITH FUNCTION ag_catalog.agtype_array_to_agtype(agtype[]);
diff --git a/sql/agtype_typecast.sql b/sql/agtype_typecast.sql
index aa551407..c29c0a65 100644
--- a/sql/agtype_typecast.sql
+++ b/sql/agtype_typecast.sql
@@ -181,8 +181,7 @@ CREATE FUNCTION ag_catalog.age_range(variadic "any")
 PARALLEL SAFE
 AS 'MODULE_PATHNAME';
 
-CREATE FUNCTION ag_catalog.age_unnest(agtype,
-                                      list_comprehension boolean = false)
+CREATE FUNCTION ag_catalog.age_unnest(agtype)
     RETURNS SETOF agtype
 LANGUAGE c
 IMMUTABLE
diff --git a/src/backend/nodes/ag_nodes.c b/src/backend/nodes/ag_nodes.c
index e20670b2..9cab568d 100644
--- a/src/backend/nodes/ag_nodes.c
+++ b/src/backend/nodes/ag_nodes.c
@@ -48,6 +48,7 @@ const char *node_names[] = {
     "cypher_map_projection",
     "cypher_map_projection_element",
     "cypher_list",
+    "cypher_list_comprehension",
     "cypher_comparison_aexpr",
     "cypher_comparison_boolexpr",
     "cypher_string_match",
@@ -115,6 +116,7 @@ const ExtensibleNodeMethods node_methods[] = {
     DEFINE_NODE_METHODS(cypher_map),
     DEFINE_NODE_METHODS(cypher_map_projection),
     DEFINE_NODE_METHODS(cypher_list),
+    DEFINE_NODE_METHODS(cypher_list_comprehension),
     DEFINE_NODE_METHODS(cypher_comparison_aexpr),
     DEFINE_NODE_METHODS(cypher_comparison_boolexpr),
     DEFINE_NODE_METHODS(cypher_string_match),
diff --git a/src/backend/nodes/cypher_outfuncs.c 
b/src/backend/nodes/cypher_outfuncs.c
index ea3d3f98..7aebbc31 100644
--- a/src/backend/nodes/cypher_outfuncs.c
+++ b/src/backend/nodes/cypher_outfuncs.c
@@ -116,7 +116,6 @@ void out_cypher_with(StringInfo str, const ExtensibleNode 
*node)
     DEFINE_AG_NODE(cypher_with);
 
     WRITE_BOOL_FIELD(distinct);
-    WRITE_BOOL_FIELD(subquery_intermediate);
     WRITE_NODE_FIELD(items);
     WRITE_NODE_FIELD(order_by);
     WRITE_NODE_FIELD(skip);
@@ -175,9 +174,20 @@ void out_cypher_unwind(StringInfo str, const 
ExtensibleNode *node)
     DEFINE_AG_NODE(cypher_unwind);
 
     WRITE_NODE_FIELD(target);
-    WRITE_NODE_FIELD(collect);
 }
 
+/* serialization function for the cypher_list_comprehension ExtensibleNode. */
+void out_cypher_list_comprehension(StringInfo str, const ExtensibleNode *node)
+{
+    DEFINE_AG_NODE(cypher_list_comprehension);
+
+    WRITE_STRING_FIELD(varname);
+    WRITE_NODE_FIELD(expr);
+    WRITE_NODE_FIELD(where);
+    WRITE_NODE_FIELD(mapping_expr);
+}
+
+
 /* serialization function for the cypher_delete ExtensibleNode. */
 void out_cypher_merge(StringInfo str, const ExtensibleNode *node)
 {
diff --git a/src/backend/optimizer/cypher_pathnode.c 
b/src/backend/optimizer/cypher_pathnode.c
index a08cd30e..5e434425 100644
--- a/src/backend/optimizer/cypher_pathnode.c
+++ b/src/backend/optimizer/cypher_pathnode.c
@@ -23,6 +23,14 @@
 
 #include "optimizer/cypher_createplan.h"
 #include "optimizer/cypher_pathnode.h"
+#include "parser/cypher_analyze.h"
+#include "executor/cypher_utils.h"
+#include "optimizer/subselect.h"
+#include "nodes/makefuncs.h"
+
+static Const *convert_sublink_to_subplan(PlannerInfo *root,
+                                         List *custom_private);
+static bool expr_has_sublink(Node *node, void *context);
 
 const CustomPathMethods cypher_create_path_methods = {
     CREATE_PATH_NAME, plan_cypher_create_path, NULL};
@@ -183,10 +191,80 @@ CustomPath *create_cypher_merge_path(PlannerInfo *root, 
RelOptInfo *rel,
 
     /* Make the original paths the children of the new path */
     cp->custom_paths = rel->pathlist;
-    /* Store the metadata Delete will need in the execution phase. */
-    cp->custom_private = custom_private;
+
+    /*
+     * Store the metadata Merge will need in the execution phase.
+     * We may have a sublink here in case the user used a list
+     * comprehension in merge.
+     */
+    if (rel->subroot->parse->hasSubLinks)
+    {
+        cp->custom_private = list_make1(convert_sublink_to_subplan(root, 
custom_private));
+    }
+    else
+    {
+        cp->custom_private = custom_private;
+    }
+
     /* Tells Postgres how to turn this path to the correct CustomScan */
     cp->methods = &cypher_merge_path_methods;
 
     return cp;
 }
+
+/*
+ * Deserializes the merge information and checks if any property
+ * expression (prop_expr) contains a SubLink.
+ * If found, converts the SubLink to a SubPlan, updates the
+ * structure accordingly, and serializes it back.
+ */
+static Const *convert_sublink_to_subplan(PlannerInfo *root, List 
*custom_private)
+{
+    cypher_merge_information *merge_information;
+    char *serialized_data = NULL;
+    Const *c = NULL;
+    ListCell *lc = NULL;
+    StringInfo str = makeStringInfo();
+
+    c = linitial(custom_private);
+    serialized_data = (char *)c->constvalue;
+    merge_information = stringToNode(serialized_data);
+
+    Assert(is_ag_node(merge_information, cypher_merge_information));
+
+    /* Only part where we can expect a sublink is in prop_expr. */
+    foreach (lc, merge_information->path->target_nodes)
+    {
+        cypher_target_node *node = (cypher_target_node *)lfirst(lc);
+        Node *prop_expr = (Node *) node->prop_expr;
+
+        if (expr_has_sublink(prop_expr, NULL))
+        {
+            node->prop_expr = (Expr *) SS_process_sublinks(root, prop_expr, 
false);
+        }
+    }
+
+    /* Serialize the information again and return it. */
+    outNode(str, (Node *)merge_information);
+
+    return makeConst(INTERNALOID, -1, InvalidOid, str->len,
+                     PointerGetDatum(str->data), false, false);
+}
+
+/*
+ * Helper function to check if the node has a sublink.
+ */
+static bool expr_has_sublink(Node *node, void *context)
+{
+    if (node == NULL)
+    {
+        return false;
+    }
+
+    if (IsA(node, SubLink))
+    {
+        return true;
+    }
+
+    return cypher_expr_tree_walker(node, expr_has_sublink, context);
+}
diff --git a/src/backend/parser/cypher_analyze.c 
b/src/backend/parser/cypher_analyze.c
index 6390b342..14f8547f 100644
--- a/src/backend/parser/cypher_analyze.c
+++ b/src/backend/parser/cypher_analyze.c
@@ -67,12 +67,6 @@ static Query *analyze_cypher_and_coerce(List *stmt, 
RangeTblFunction *rtfunc,
                                         const char *query_str, int query_loc,
                                         char *graph_name, uint32 graph_oid,
                                         Param *params);
-cypher_clause *build_subquery_node(cypher_clause *next);
-
-/* expr tree walker */
-bool expr_contains_node(cypher_expression_condition is_expr, Node *expr);
-bool expr_has_subquery(Node * expr);
-
 
 void post_parse_analyze_init(void)
 {
@@ -681,148 +675,40 @@ static int get_query_location(const int location, const 
char *source_str)
     return strchr(p + 1, '$') - source_str + 1;
 }
 
+
 /*
- * This is a specialized expression tree walker for finding exprs of a 
specified
- * type. Create a function that checks for the type you want, and this function
- * will iterate through the tree.
+ * This is an extension of postgres's raw_expression_tree_walker() function.
+ * It can walk cypher-specific nodes found in the expression tree during
+ * parse analysis.
+ * 
+ * More nodes can be added to this function as needed.
  */
-
-bool expr_contains_node(cypher_expression_condition is_expr, Node *expr)
+bool cypher_raw_expr_tree_walker(Node *node,
+                                 bool (*walker)(),
+                                 void *context)
 {
-    if (!expr)
-    {
-        return false;
-    }
-
-    switch (nodeTag(expr))
-    {
-    case T_A_Const:
-    case T_ColumnRef:
-    case T_A_Indirection:
-        {
-            break;
-        }
-    case T_A_Expr:
-    {
-        A_Expr *a = (A_Expr *)expr;
-
-        switch (a->kind)
-        {
-        case AEXPR_OP:
-        case AEXPR_IN:
-            {
-                if (expr_contains_node(is_expr, a->lexpr) ||
-                    expr_contains_node(is_expr, a->rexpr))
-                {
-                    return true;
-                }
-                break;
-            }
-        default:
-            ereport(ERROR, (errmsg_internal("unrecognized A_Expr kind: %d",
-                                            a->kind)));
-        }
-        break;
-    }
-    case T_BoolExpr:
-    {
-        BoolExpr *b = (BoolExpr *)expr;
-        ListCell *la;
-
-        foreach(la, b->args)
-        {
-            Node *arg = lfirst(la);
-
-            if (expr_contains_node(is_expr, arg))
-            {
-                return true;
-            }
-        }
-        break;
-    }
-    case T_NullTest:
-    {
-        NullTest *n = (NullTest *)expr;
-
-        if (expr_contains_node(is_expr, (Node *)n->arg))
-        {
-            return true;
-        }
-        break;
-    }
-    case T_CaseExpr:
-    {
-        CaseExpr *cexpr = (CaseExpr *)expr;
-        ListCell   *l;
-
-        if (cexpr->arg && expr_contains_node(is_expr, (Node *) cexpr->arg))
-        {
-            return true;
-        }
-
-        foreach(l, cexpr->args)
-        {
-            CaseWhen *w = lfirst_node(CaseWhen, l);
-            Node *warg;
-
-            warg = (Node *) w->expr;
-
-            if (expr_contains_node(is_expr, warg))
-            {
-                return true;
-            }
-            warg = (Node *)w->result;
-
-            if (expr_contains_node(is_expr, warg))
-            {
-                return true;
-            }
-        }
-
-        if (expr_contains_node(is_expr , (Node *)cexpr->defresult))
-        {
-            return true;
-        }
+    ListCell *temp;
 
-        break;
-    }
-    case T_CaseTestExpr:
-    {
-        break;
-    }
-    case T_CoalesceExpr:
-    {
-        CoalesceExpr *cexpr = (CoalesceExpr *) expr;
-        ListCell *args;
+    if (node == NULL)
+        return false;
 
-        foreach(args, cexpr->args)
-        {
-            Node *e = (Node *)lfirst(args);
+#define WALK(n) walker((Node *) (n), context)
+#define LIST_WALK(l) cypher_raw_expr_tree_walker((Node *) (l), walker, context)
 
-            if (expr_contains_node(is_expr, e))
-            {
-                return true;
-            }
-        }
-        break;
-    }
-    case T_ExtensibleNode:
+    if (IsA(node, ExtensibleNode))
     {
-        if (is_ag_node(expr, cypher_bool_const))
+        if (is_ag_node(node, cypher_bool_const) ||
+            is_ag_node(node, cypher_integer_const) ||
+            is_ag_node(node, cypher_param) ||
+            is_ag_node(node, cypher_sub_pattern) ||
+            is_ag_node(node, cypher_sub_query))
+            /* Add more non-recursible node types here as needed */
         {
-            return is_expr(expr);
-        }
-        if (is_ag_node(expr, cypher_integer_const))
-        {
-            return is_expr(expr);
-        }
-        if (is_ag_node(expr, cypher_param))
-        {
-            return is_expr(expr);
+            return false;
         }
-        if (is_ag_node(expr, cypher_map))
+        else if (is_ag_node(node, cypher_map))
         {
-            cypher_map *cm = (cypher_map *)expr;
+            cypher_map *cm = (cypher_map *)node;
             ListCell *le;
 
             Assert(list_length(cm->keyvals) % 2 == 0);
@@ -837,7 +723,7 @@ bool expr_contains_node(cypher_expression_condition 
is_expr, Node *expr)
 
                 val = lfirst(le);
 
-                if (expr_contains_node(is_expr, val))
+                if (WALK(val))
                 {
                     return true;
                 }
@@ -845,216 +731,163 @@ bool expr_contains_node(cypher_expression_condition 
is_expr, Node *expr)
                 le = lnext(cm->keyvals, le);
 
             }
-            break;
         }
-        if (is_ag_node(expr, cypher_map_projection))
+        else if (is_ag_node(node, cypher_map_projection))
         {
-            cypher_map_projection *cmp = (cypher_map_projection *)expr;
-            ListCell *lc;
+            cypher_map_projection *cmp = (cypher_map_projection *)node;
 
-            foreach(lc, cmp->map_elements)
+            if (LIST_WALK(cmp->map_elements))
             {
-                cypher_map_projection_element *elem;
-
-                elem = lfirst(lc);
-
-                if (expr_contains_node(is_expr, elem->value))
-                {
-                    return true;
-                }
+                return true;
             }
-
-            break;
         }
-        if (is_ag_node(expr, cypher_list))
+        else if (is_ag_node(node, cypher_list))
         {
-            cypher_list *cl = (cypher_list *)expr;
-            ListCell *le = NULL;
-
-            foreach(le, cl->elems)
+            cypher_list *cl = (cypher_list *)node;
+            
+            if (LIST_WALK(cl->elems))
             {
-                Node *texpr = lfirst(le);
-
-                if (expr_contains_node(is_expr, texpr))
-                {
-                    return true;
-                }
+                return true;
             }
-            break;
         }
-        if (is_ag_node(expr, cypher_string_match))
+        else if (is_ag_node(node, cypher_string_match))
         {
-            cypher_string_match *csm = (cypher_string_match *)expr;
+            cypher_string_match *csm = (cypher_string_match *)node;
 
-            if (expr_contains_node(is_expr, csm->lhs) ||
-                expr_contains_node(is_expr, csm->rhs))
+            if (WALK(csm->lhs))
             {
                 return true;
             }
-            break;
-        }
-        if (is_ag_node(expr, cypher_typecast))
-        {
-            cypher_typecast *t = (cypher_typecast *) expr;
 
-            if (expr_contains_node(is_expr, t->expr))
+            if (WALK(csm->rhs))
             {
                 return true;
             }
-            break;
         }
-        if (is_ag_node(expr, cypher_comparison_aexpr))
+        else if (is_ag_node(node, cypher_typecast))
         {
-            cypher_comparison_aexpr *a = (cypher_comparison_aexpr *) expr;
+            cypher_typecast *t = (cypher_typecast *)node;
 
-            if (expr_contains_node(is_expr, a->lexpr) ||
-                expr_contains_node(is_expr, a->rexpr))
+            if (WALK(t->expr))
             {
                 return true;
             }
-            break;
         }
-        if (is_ag_node(expr, cypher_comparison_boolexpr))
+        else if (is_ag_node(node, cypher_comparison_aexpr))
         {
-            cypher_comparison_boolexpr *b = (cypher_comparison_boolexpr *) 
expr;
-            ListCell *la;
+            cypher_comparison_aexpr *a = (cypher_comparison_aexpr *)node;
 
-            foreach(la, b->args)
+            if (WALK(a->lexpr))
             {
-                Node *arg = lfirst(la);
+                return true;
+            }
 
-                if (expr_contains_node(is_expr, arg))
-                {
-                    return true;
-                }
+            if (WALK(a->rexpr))
+            {
+                return true;
             }
-            break;
         }
-        if (is_ag_node(expr, cypher_unwind))
+        else if (is_ag_node(node, cypher_comparison_boolexpr))
         {
-            cypher_unwind* lc = (cypher_unwind *)expr;
-
-            if (expr_contains_node(is_expr, lc->where) ||
-                expr_contains_node(is_expr, lc->collect))
+            cypher_comparison_boolexpr *b = (cypher_comparison_boolexpr *)node;
+            
+            if (LIST_WALK(b->args))
             {
                 return true;
             }
-            break;
         }
-
-        if (is_ag_node(expr, cypher_sub_pattern))
+        else if (is_ag_node(node, cypher_unwind))
         {
-            break;
-        }
+            cypher_unwind *unw = (cypher_unwind *)node;
 
-        if (is_ag_node(expr, cypher_sub_query))
-        {
-            break;
+            if (WALK(unw->target))
+            {
+                return true;
+            }
         }
 
-        ereport(ERROR,
-                (errmsg_internal("unrecognized ExtensibleNode: %s",
-                                 ((ExtensibleNode *)expr)->extnodename)));
-
-        break;
-    }
-    case T_FuncCall:
-    {
-        FuncCall *fn = (FuncCall *)expr;
-        ListCell *arg;
-
-        foreach(arg, fn->args)
+        else if (is_ag_node(node, cypher_list_comprehension))
         {
-            Node *farg = NULL;
+            cypher_list_comprehension *lc = (cypher_list_comprehension *)node;
 
-            farg = (Node *)lfirst(arg);
+            if (WALK(lc->expr))
+            {
+                return true;
+            }
+
+            if (WALK(lc->where))
+            {
+                return true;
+            }
 
-            if (expr_contains_node(is_expr, farg))
+            if (WALK(lc->mapping_expr))
             {
                 return true;
             }
         }
-        break;
+        /* Add more node types here as needed */
+        else
+        {
+            ereport(ERROR,
+                (errmsg_internal("unrecognized ExtensibleNode: %s",
+                                 ((ExtensibleNode *)node)->extnodename)));
+        }
     }
-    case T_SubLink:
+    /*
+     * postgres's raw expresssion tree walker does not handle List
+     */
+    else if (IsA(node, List))
     {
-       SubLink *s = (SubLink *)expr;
-
-        if (expr_contains_node(is_expr, s->subselect))
+        foreach(temp, (List *) node)
         {
-            return true;
+            if (WALK((Node *) lfirst(temp)))
+                return true;
         }
-      break;
-    }
-    default:
-        ereport(ERROR, (errmsg_internal("unrecognized node type: %d",
-                                        nodeTag(expr))));
     }
 
-    return (is_expr(expr));
+#undef LIST_WALK
+    else
+    {
+        return raw_expression_tree_walker(node, walker, context);
+    }
+    
+    return false;
 }
 
 /*
- * Function that checks if an expr is a cypher_sub_query. Used in tandem with
- * expr_contains_node. Can write more similar to this to find similar nodes.
+ * This is an extension of postgres's expression_tree_walker() function.
+ * It is meant to walk cypher-specific nodes found in the expression tree
+ * post parse analysis.
+ *
+ * More nodes can be added to this function as needed.
  */
-
-bool expr_has_subquery(Node * expr)
+bool cypher_expr_tree_walker(Node *node,
+                             bool (*walker)(),
+                             void *context)
 {
-    if (expr == NULL)
+    if (node == NULL)
     {
         return false;
     }
 
-    if (IsA(expr, ExtensibleNode))
-    {
-        if (is_ag_node(expr, cypher_sub_query))
-        {
-            return true;
-        }
-    }
-    return false;
-}
+#define LIST_WALK(l) cypher_expr_tree_walker((Node *) (l), walker, context)
 
-/*
- * This function constructs an intermediate WITH node for processing subqueries
- */
-cypher_clause *build_subquery_node(cypher_clause *next)
-{
-    cypher_match *match = (cypher_match *)next->self;
-    cypher_clause *where_container_clause;
-    cypher_with *with_clause = make_ag_node(cypher_with);
-    ColumnRef *cr;
-    ResTarget *rt;
-
-    /* construct the column ref star */
-    cr = makeNode(ColumnRef);
-    cr->fields = list_make1(makeNode(A_Star));
-    cr->location = exprLocation((Node *)next);
-
-    /*construct the restarget */
-    rt = makeNode(ResTarget);
-    rt->name = NULL;
-    rt->indirection = NIL;
-    rt->val = (Node *)cr;
-    rt->location = exprLocation((Node *)next);
-
-
-    /* construct the with_clause */
-    with_clause->items = list_make1(rt);
-    with_clause->where = match->where;
-    with_clause->subquery_intermediate = true;
+    if (IsA(node, ExtensibleNode))
+    {
+        /* Add our nodes that can appear post parsing stage */
 
-    /*
-     * create the where container, and set the match (next) as the
-     * prev of the where container
-     */
-    where_container_clause = palloc(sizeof(*where_container_clause));
-    where_container_clause->self = (Node *)with_clause;
-    where_container_clause->next = NULL;
-    where_container_clause->prev = next;
+        ereport(ERROR,
+                (errmsg_internal("unrecognized ExtensibleNode: %s",
+                                 ((ExtensibleNode *)node)->extnodename)));
+    }
+#undef WALK
+#undef LIST_WALK
+    else
+    {
+        return expression_tree_walker(node, walker, context);
+    }
 
-    return where_container_clause;
+    return false;
 }
 
 static Query *analyze_cypher(List *stmt, ParseState *parent_pstate,
@@ -1083,23 +916,6 @@ static Query *analyze_cypher(List *stmt, ParseState 
*parent_pstate,
         next->self = lfirst(lc);
         next->prev = clause;
 
-        /* check for subqueries in match */
-        if (is_ag_node(next->self, cypher_match))
-        {
-            cypher_match *match = (cypher_match *)next->self;
-
-            if (match->where != NULL && expr_contains_node(expr_has_subquery, 
match->where))
-            {
-               /* advance the clause iterator to the intermediate clause 
position */
-               clause = build_subquery_node(next);
-
-               /* set the next of the match to the where_container_clause */
-               match->where = NULL;
-               next->next = clause;
-               continue;
-            }
-        }
-
         if (clause != NULL)
         {
             clause->next = next;
diff --git a/src/backend/parser/cypher_clause.c 
b/src/backend/parser/cypher_clause.c
index 2495042a..22c5b823 100644
--- a/src/backend/parser/cypher_clause.c
+++ b/src/backend/parser/cypher_clause.c
@@ -248,6 +248,11 @@ static void get_res_cols(ParseState *pstate, 
ParseNamespaceItem *l_pnsi,
 /* unwind */
 static Query *transform_cypher_unwind(cypher_parsestate *cpstate,
                                       cypher_clause *clause);
+
+/* list comprehension */
+static Query *transform_cypher_list_comprehension(cypher_parsestate *cpstate,
+                                                  cypher_clause *clause);
+
 /* merge */
 static Query *transform_cypher_merge(cypher_parsestate *cpstate,
                                      cypher_clause *clause);
@@ -290,7 +295,7 @@ static Query 
*transform_cypher_call_subquery(cypher_parsestate *cpstate,
 #define transform_prev_cypher_clause(cpstate, prev_clause, add_rte_to_query) \
     transform_cypher_clause_as_subquery(cpstate, transform_cypher_clause, \
                                         prev_clause, NULL, add_rte_to_query)
-ParseNamespaceItem
+static ParseNamespaceItem
 *transform_cypher_clause_as_subquery(cypher_parsestate *cpstate,
                                      transform_method transform,
                                      cypher_clause *clause,
@@ -326,9 +331,9 @@ static FuncExpr *make_clause_func_expr(char *function_name,
 /* for VLE support */
 static ParseNamespaceItem *transform_RangeFunction(cypher_parsestate *cpstate,
                                                    RangeFunction *r);
-static Node *transform_VLE_Function(cypher_parsestate *cpstate, Node *n,
-                                    RangeTblEntry **top_rte, int *top_rti,
-                                    List **namespace);
+static Node *transform_from_clause_item(cypher_parsestate *cpstate, Node *n,
+                                        RangeTblEntry **top_rte, int *top_rti,
+                                        List **namespace);
 static ParseNamespaceItem *append_VLE_Func_to_FromClause(cypher_parsestate 
*cpstate,
                                                          Node *n);
 static void setNamespaceLateralState(List *namespace, bool lateral_only,
@@ -336,6 +341,7 @@ static void setNamespaceLateralState(List *namespace, bool 
lateral_only,
 static bool isa_special_VLE_case(cypher_path *path);
 
 static ParseNamespaceItem *find_pnsi(cypher_parsestate *cpstate, char 
*varname);
+static bool has_list_comp_or_subquery(Node *expr, void *context);
 
 /*
  * transform a cypher_clause
@@ -398,19 +404,16 @@ Query *transform_cypher_clause(cypher_parsestate *cpstate,
     }
     else if (is_ag_node(self, cypher_unwind))
     {
-        cypher_unwind *n = (cypher_unwind *) self;
-        if (n->collect != NULL)
-        {
-            cpstate->p_list_comp = true;
-        }
-        result = transform_cypher_clause_with_where(cpstate,
-                                                    transform_cypher_unwind,
-                                                    clause, n->where);
+        result = transform_cypher_unwind(cpstate, clause);
     }
     else if (is_ag_node(self, cypher_call))
     {
         result = transform_cypher_call_stmt(cpstate, clause);
     }
+    else if (is_ag_node(self, cypher_list_comprehension))
+    {
+        result = transform_cypher_list_comprehension(cpstate, clause);
+    }
     else
     {
         ereport(ERROR, (errmsg_internal("unexpected Node for cypher_clause")));
@@ -446,23 +449,6 @@ static cypher_clause *make_cypher_clause(List *stmt)
         next->self = lfirst(lc);
         next->prev = clause;
 
-        /* check for subqueries in match */
-        if (is_ag_node(next->self, cypher_match))
-        {
-            cypher_match *match = (cypher_match *)next->self;
-
-            if (match->where != NULL && expr_contains_node(expr_has_subquery, 
match->where))
-            {
-               /* advance the clause iterator to the intermediate clause 
position */
-               clause = build_subquery_node(next);
-
-               /* set the next of the match to the where_container_clause */
-               match->where = NULL;
-               next->next = clause;
-               continue;
-            }
-        }
-
         if (clause != NULL)
         {
             clause->next = next;
@@ -660,6 +646,7 @@ static Query *transform_cypher_union(cypher_parsestate 
*cpstate,
     qry->rtable = pstate->p_rtable;
     qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
     qry->hasAggs = pstate->p_hasAggs;
+    qry->hasSubLinks = pstate->p_hasSubLinks;
 
     assign_query_collations(pstate, qry);
 
@@ -1259,6 +1246,7 @@ static Query 
*transform_cypher_call_subquery(cypher_parsestate *cpstate,
     query->rtable = cpstate->pstate.p_rtable;
     query->jointree = makeFromExpr(cpstate->pstate.p_joinlist, (Node 
*)where_qual);
     query->hasAggs = pstate->p_hasAggs;
+    query->hasSubLinks = pstate->p_hasSubLinks;
 
     assign_query_collations(pstate, query);
 
@@ -1330,6 +1318,8 @@ static Query *transform_cypher_delete(cypher_parsestate 
*cpstate,
 
     query->rtable = pstate->p_rtable;
     query->jointree = makeFromExpr(pstate->p_joinlist, NULL);
+    query->hasAggs = pstate->p_hasAggs;
+    query->hasSubLinks = pstate->p_hasSubLinks;
 
     return query;
 }
@@ -1353,9 +1343,6 @@ static Query *transform_cypher_unwind(cypher_parsestate 
*cpstate,
     Node *funcexpr;
     TargetEntry *te;
     ParseNamespaceItem *pnsi;
-    bool is_list_comp = self->collect != NULL;
-    bool has_agg =
-        is_list_comp || 
has_a_cypher_list_comprehension_node(self->target->val);
 
     query = makeNode(Query);
     query->commandType = CMD_SELECT;
@@ -1384,13 +1371,14 @@ static Query *transform_cypher_unwind(cypher_parsestate 
*cpstate,
         ereport(ERROR,
                 (errcode(ERRCODE_DUPLICATE_ALIAS),
                         errmsg("duplicate variable \"%s\"", 
self->target->name),
-                        parser_errposition(pstate, target_syntax_loc)));
+                        parser_errposition((ParseState *) cpstate,
+                                           target_syntax_loc)));
     }
 
     expr = transform_cypher_expr(cpstate, self->target->val,
                                  EXPR_KIND_SELECT_TARGET);
 
-    if (!has_agg && nodeTag(expr) == T_Aggref)
+    if (nodeTag(expr) == T_Aggref)
     {
         ereport(ERROR, errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("Invalid use of aggregation in this context"),
@@ -1403,12 +1391,11 @@ static Query *transform_cypher_unwind(cypher_parsestate 
*cpstate,
     old_expr_kind = pstate->p_expr_kind;
     pstate->p_expr_kind = EXPR_KIND_SELECT_TARGET;
     funcexpr = ParseFuncOrColumn(pstate, unwind->funcname,
-                                 list_make2(expr, makeBoolConst(is_list_comp, 
false)),
+                                 list_make1(expr),
                                  pstate->p_last_srf, unwind, false,
                                  target_syntax_loc);
 
     pstate->p_expr_kind = old_expr_kind;
-    pstate->p_hasAggs = has_agg;
 
     te = makeTargetEntry((Expr *) funcexpr,
                          (AttrNumber) pstate->p_next_resno++,
@@ -1419,12 +1406,94 @@ static Query *transform_cypher_unwind(cypher_parsestate 
*cpstate,
     query->jointree = makeFromExpr(pstate->p_joinlist, NULL);
     query->hasTargetSRFs = pstate->p_hasTargetSRFs;
     query->hasAggs = pstate->p_hasAggs;
+    query->hasSubLinks = pstate->p_hasSubLinks;
 
     assign_query_collations(pstate, query);
 
     return query;
 }
 
+/*
+ * [i IN u WHERE i<2 | i^2]
+ *
+ *   |    |    |    |    |
+ *  \|/  \|/  \|/  \|/  \|/
+ *
+ * SELECT i^2 FROM age_unnest(u) AS i WHERE i>2;
+ */
+static Query *transform_cypher_list_comprehension(cypher_parsestate *cpstate,
+                                                  cypher_clause *clause)
+{
+    Query *query;
+    RangeFunction *rf;
+    cypher_list_comprehension *list_comp = (cypher_list_comprehension *) 
clause->self;
+    FuncCall *func_call;
+    Node *return_expr, *qual, *n;
+    RangeTblEntry *rte = NULL;
+    int rtindex;
+    List *namespace = NULL;
+    TargetEntry *te;
+    cypher_parsestate *child_cpstate = make_cypher_parsestate(cpstate);
+    ParseState *child_pstate = (ParseState *) child_cpstate;
+
+    query = makeNode(Query);
+    query->commandType = CMD_SELECT;
+
+    func_call = makeFuncCall(list_make1(makeString("unnest")),
+                             list_make1(list_comp->expr),
+                             COERCE_SQL_SYNTAX, -1);
+
+    rf = makeNode(RangeFunction);
+    rf->lateral = false;
+    rf->ordinality = false;
+    rf->is_rowsfrom = false;
+    rf->functions = list_make1(list_make2((Node *) func_call, NIL));
+    rf->alias = makeAlias(list_comp->varname, NIL);
+    rf->coldeflist = NIL;
+
+    n = transform_from_clause_item(child_cpstate, (Node *) rf,
+                                   &rte, &rtindex, &namespace);
+    checkNameSpaceConflicts(child_pstate, child_pstate->p_namespace, 
namespace);
+    child_pstate->p_joinlist = lappend(child_pstate->p_joinlist, n);
+    child_pstate->p_namespace = list_concat(child_pstate->p_namespace, 
namespace);
+
+    /* make all namespace items unconditionally visible */
+    setNamespaceLateralState(child_pstate->p_namespace, false, true);
+
+    return_expr = transform_cypher_expr(child_cpstate, list_comp->mapping_expr,
+                                        EXPR_KIND_SELECT_TARGET);
+    
+    te = makeTargetEntry((Expr *) return_expr,
+                         (AttrNumber) child_pstate->p_next_resno++,
+                         list_comp->varname, false);
+
+    qual = transform_cypher_expr(child_cpstate, list_comp->where,
+                                 EXPR_KIND_WHERE);
+    if (qual)
+    {
+        qual = coerce_to_boolean(child_pstate, qual, "WHERE");
+    }
+
+    query->targetList = lappend(query->targetList, te);
+    query->jointree = makeFromExpr(child_pstate->p_joinlist, (Node *) qual);
+    query->rtable = child_pstate->p_rtable;
+    query->hasAggs = child_pstate->p_hasAggs;
+    query->hasSubLinks = child_pstate->p_hasSubLinks;
+    query->hasTargetSRFs = child_pstate->p_hasTargetSRFs;
+
+    assign_query_collations(child_pstate, query);
+
+    if (child_pstate->p_hasAggs ||
+        query->groupClause || query->groupingSets || query->havingQual)
+    {
+        parse_check_aggregates(child_pstate, query);
+    }
+
+    free_cypher_parsestate(child_cpstate);
+
+    return query;
+}
+
 /*
  * Iterate through the list of items to delete and extract the variable name.
  * Then find the resno that the variable name belongs to.
@@ -1560,6 +1629,8 @@ static Query *transform_cypher_set(cypher_parsestate 
*cpstate,
 
     query->rtable = pstate->p_rtable;
     query->jointree = makeFromExpr(pstate->p_joinlist, NULL);
+    query->hasAggs = pstate->p_hasAggs;
+    query->hasSubLinks = pstate->p_hasSubLinks;
 
     return query;
 }
@@ -1833,12 +1904,7 @@ cypher_update_information 
*transform_cypher_set_item_list(
                                             EXPR_KIND_SELECT_TARGET, NULL,
                                             false);
 
-        if (has_a_cypher_list_comprehension_node(set_item->expr))
-        {
-            query->hasAggs = true;
-        }
-
-        if (!query->hasAggs && nodeTag(target_item->expr) == T_Aggref)
+        if (nodeTag(target_item->expr) == T_Aggref)
         {
             ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("Invalid use of aggregation in this context"),
@@ -2169,6 +2235,7 @@ static Query *transform_cypher_return(cypher_parsestate 
*cpstate,
     query->rtable = pstate->p_rtable;
     query->jointree = makeFromExpr(pstate->p_joinlist, NULL);
     query->hasAggs = pstate->p_hasAggs;
+    query->hasSubLinks = pstate->p_hasSubLinks;
 
     assign_query_collations(pstate, query);
 
@@ -2357,7 +2424,6 @@ static Query 
*transform_cypher_clause_with_where(cypher_parsestate *cpstate,
 {
     ParseState *pstate = (ParseState *)cpstate;
     Query *query;
-    Node *self = clause->self;
     Node *where_qual = NULL;
 
     if (where)
@@ -2370,10 +2436,8 @@ static Query 
*transform_cypher_clause_with_where(cypher_parsestate *cpstate,
 
         pnsi = transform_cypher_clause_as_subquery(cpstate, transform, clause,
                                                    NULL, true);
-        
         Assert(pnsi != NULL);
         rtindex = list_length(pstate->p_rtable);
-
         /* rte is the only RangeTblEntry in pstate */
         if (rtindex != 1)
         {
@@ -2388,78 +2452,14 @@ static Query 
*transform_cypher_clause_with_where(cypher_parsestate *cpstate,
          * next clause
          */
         query->targetList = expandNSItemAttrs(pstate, pnsi, 0, true, -1);
-
         markTargetListOrigins(pstate, query->targetList);
-
         query->rtable = pstate->p_rtable;
 
         where_qual = transform_cypher_expr(cpstate, where, EXPR_KIND_WHERE);
-
         where_qual = coerce_to_boolean(pstate, where_qual, "WHERE");
 
-        /* check if we have a list comprehension in the where clause */
-        if (cpstate->p_list_comp &&
-            has_a_cypher_list_comprehension_node(where))
-        {
-            List *groupClause = NIL;
-            ListCell *li;
-            bool has_a_star;
-
-            has_a_star = false;
-            query->jointree = makeFromExpr(pstate->p_joinlist, NULL);
-            query->havingQual = where_qual;
-
-            foreach (li, ((cypher_return *)self)->items)
-            {
-                ResTarget *item = lfirst(li);
-                ColumnRef *cref;
-                
-                /*
-                 * We need to handle the case where the item is a A_star. In 
this
-                 * case we will need to build group by using targetList.
-                 */
-                if (IsA(item->val, ColumnRef))
-                {
-                    cref = (ColumnRef *)item->val;
-                    if (IsA(linitial(cref->fields), A_Star))
-                    {
-                        has_a_star = true;
-                        continue;
-                    }
-                }
-
-                groupClause = lappend(groupClause, item->val);
-            }
-
-            /*
-             * If there is A_star flag, build the group by clause
-             * using the targetList.
-             */
-            if (has_a_star)
-            {
-                ListCell *lc;
-                foreach (lc, query->targetList)
-                {
-                    TargetEntry *te = lfirst(lc);
-                    ColumnRef *cref = makeNode(ColumnRef);
-
-                    cref->fields = list_make1(makeString(te->resname));
-                    cref->location = exprLocation((Node *)te->expr);
-
-                    groupClause = lappend(groupClause, cref);
-                }
-            }
-            query->groupClause = transform_group_clause(cpstate, groupClause,
-                                                        &query->groupingSets,
-                                                        &query->targetList,
-                                                        query->sortClause,
-                                                        EXPR_KIND_GROUP_BY);
-            
-        }
-        else
-        {
-            query->jointree = makeFromExpr(pstate->p_joinlist, where_qual);
-        }
+        query->jointree = makeFromExpr(pstate->p_joinlist, where_qual);
+        assign_query_collations(pstate, query);
     }
     else
     {
@@ -2470,8 +2470,6 @@ static Query 
*transform_cypher_clause_with_where(cypher_parsestate *cpstate,
     query->hasTargetSRFs = pstate->p_hasTargetSRFs;
     query->hasAggs = pstate->p_hasAggs;
 
-    assign_query_collations(pstate, query);
-
     return query;
 }
 
@@ -2479,6 +2477,7 @@ static Query *transform_cypher_match(cypher_parsestate 
*cpstate,
                                      cypher_clause *clause)
 {
     cypher_match *match_self = (cypher_match*) clause->self;
+    Node *where = match_self->where;
 
     if(!match_check_valid_label(match_self, cpstate))
     {
@@ -2496,9 +2495,39 @@ static Query *transform_cypher_match(cypher_parsestate 
*cpstate,
                                                      (Node *)r, -1);
     }
 
+    if (has_list_comp_or_subquery((Node *)match_self->where, NULL))
+    {
+        match_self->where = NULL;
+        return transform_cypher_clause_with_where(cpstate,
+                transform_cypher_match_pattern, clause, where);
+    }
+
     return transform_cypher_match_pattern(cpstate, clause);
 }
 
+/*
+ * Function that checks if an expr has a cypher_sub_query or
+ * cypher_list_comprehension.
+ */
+static bool has_list_comp_or_subquery(Node *expr, void *context)
+{
+    if (expr == NULL)
+    {
+        return false;
+    }
+
+    if (IsA(expr, ExtensibleNode))
+    {
+        if (is_ag_node(expr, cypher_sub_query) ||
+            is_ag_node(expr, cypher_list_comprehension))
+        {
+            return true;
+        }
+    }
+
+    return cypher_raw_expr_tree_walker(expr, has_list_comp_or_subquery, 
context);
+}
+
 /*
  * Transform the clause into a subquery. This subquery will be used
  * in a join so setup the namespace item and the created the rtr
@@ -2679,18 +2708,6 @@ static Query 
*transform_cypher_match_pattern(cypher_parsestate *cpstate,
     {
         cypher_clause *next = clause->next;
 
-        /*
-         * check if optional match has a subquery node-- it could still
-         * be following a match
-         */
-        if(is_ag_node(next->self, cypher_with))
-        {
-            cypher_with *next_with = (cypher_with *)next->self;
-            if (next_with->subquery_intermediate == true)
-            {
-                next = next->next;
-            }
-        }
         if (is_ag_node(next->self, cypher_match))
         {
             cypher_match *next_self = (cypher_match *)next->self;
@@ -2950,9 +2967,9 @@ static Query 
*transform_cypher_sub_query(cypher_parsestate *cpstate,
  * will transform the VLE function, depending on type. Currently, only
  * RangeFunctions are supported. But, others may be in the future.
  */
-static Node *transform_VLE_Function(cypher_parsestate *cpstate, Node *n,
-                                    RangeTblEntry **top_rte, int *top_rti,
-                                    List **namespace)
+static Node *transform_from_clause_item(cypher_parsestate *cpstate, Node *n,
+                                        RangeTblEntry **top_rte, int *top_rti,
+                                        List **namespace)
 {
     ParseState *pstate = &cpstate->pstate;
 
@@ -3020,7 +3037,7 @@ static ParseNamespaceItem 
*append_VLE_Func_to_FromClause(cypher_parsestate *cpst
      * Following PG's FROM clause logic, just in case we need to expand it in
      * the future, we process the items in another function.
      */
-    n = transform_VLE_Function(cpstate, n, &rte, &rtindex, &namespace);
+    n = transform_from_clause_item(cpstate, n, &rte, &rtindex, &namespace);
 
     /* this should not happen */
     Assert(n != NULL);
@@ -3212,36 +3229,7 @@ static void transform_match_pattern(cypher_parsestate 
*cpstate, Query *query,
     }
 
     query->rtable = cpstate->pstate.p_rtable;
-
-    if (cpstate->p_list_comp)
-    {
-        List *groupList = NIL;
-
-        query->jointree = makeFromExpr(cpstate->pstate.p_joinlist, NULL);
-        query->havingQual = (Node *)expr;
-
-        foreach (lc, query->targetList)
-        {
-            TargetEntry *te = lfirst(lc);
-            ColumnRef *cref = makeNode(ColumnRef);
-
-            cref->fields = list_make1(makeString(te->resname));
-            cref->location = exprLocation((Node *)te->expr);
-
-            groupList = lappend(groupList, cref);
-        }
-
-        query->groupClause = transform_group_clause(cpstate, groupList,
-                                                    &query->groupingSets,
-                                                    &query->targetList,
-                                                    query->sortClause,
-                                                    EXPR_KIND_GROUP_BY);
-    }
-    else
-    {
-        query->jointree = makeFromExpr(cpstate->pstate.p_joinlist,
-                                       (Node *)expr);
-    }
+    query->jointree = makeFromExpr(cpstate->pstate.p_joinlist, (Node *)expr);
 }
 
 /*
@@ -5610,6 +5598,7 @@ static Query *transform_cypher_create(cypher_parsestate 
*cpstate,
     query->rtable = pstate->p_rtable;
     query->jointree = makeFromExpr(pstate->p_joinlist, NULL);
     query->hasAggs = pstate->p_hasAggs;
+    query->hasSubLinks = pstate->p_hasSubLinks;
 
     return query;
 }
@@ -6245,7 +6234,7 @@ static Expr *cypher_create_properties(cypher_parsestate 
*cpstate,
  * This function is similar to transformFromClause() that is called with a
  * single RangeSubselect.
  */
-ParseNamespaceItem *
+static ParseNamespaceItem *
 transform_cypher_clause_as_subquery(cypher_parsestate *cpstate,
                                     transform_method transform,
                                     cypher_clause *clause,
@@ -6267,8 +6256,7 @@ transform_cypher_clause_as_subquery(cypher_parsestate 
*cpstate,
            pstate->p_expr_kind == EXPR_KIND_OTHER ||
            pstate->p_expr_kind == EXPR_KIND_WHERE ||
            pstate->p_expr_kind == EXPR_KIND_SELECT_TARGET ||
-           pstate->p_expr_kind == EXPR_KIND_FROM_SUBSELECT ||
-           pstate->p_expr_kind == EXPR_KIND_INSERT_TARGET);
+           pstate->p_expr_kind == EXPR_KIND_FROM_SUBSELECT);
 
     /*
      * As these are all sub queries, if this is just of type NONE, note it as a
@@ -6472,6 +6460,12 @@ Query *cypher_parse_sub_analyze(Node *parseTree,
     cypher_clause *clause;
     Query *query;
 
+    if (IsA(parseTree, Query))
+    {
+        /* Already transformed, just return it */
+        return (Query *)parseTree;
+    }
+
     pstate->p_parent_cte = parentCTE;
     pstate->p_locked_from_parent = locked_from_parent;
     pstate->p_resolve_unknowns = resolve_unknowns;
@@ -6621,7 +6615,6 @@ static Query *transform_cypher_merge(cypher_parsestate 
*cpstate,
     query->rtable = pstate->p_rtable;
     query->jointree = makeFromExpr(pstate->p_joinlist, NULL);
     query->hasAggs = pstate->p_hasAggs;
-
     query->hasSubLinks = pstate->p_hasSubLinks;
 
     assign_query_collations(pstate, query);
diff --git a/src/backend/parser/cypher_expr.c b/src/backend/parser/cypher_expr.c
index 8afc0c41..5b3ab319 100644
--- a/src/backend/parser/cypher_expr.c
+++ b/src/backend/parser/cypher_expr.c
@@ -98,8 +98,6 @@ static Node *transform_WholeRowRef(ParseState *pstate, 
ParseNamespaceItem *pnsi,
 static ArrayExpr *make_agtype_array_expr(List *args);
 static Node *transform_column_ref_for_indirection(cypher_parsestate *cpstate,
                                                   ColumnRef *cr);
-static Node *transform_cypher_list_comprehension(cypher_parsestate *cpstate,
-                                                 cypher_unwind *expr);
 static Node *transform_external_ext_FuncCall(cypher_parsestate *cpstate,
                                              FuncCall *fn, List *targs,
                                              Form_pg_proc procform,
@@ -242,12 +240,6 @@ static Node 
*transform_cypher_expr_recurse(cypher_parsestate *cpstate,
             return transform_cypher_comparison_boolexpr(cpstate,
                                              (cypher_comparison_boolexpr 
*)expr);
         }
-        if (is_ag_node(expr, cypher_unwind))
-        {
-            return transform_cypher_list_comprehension(cpstate,
-                                                       (cypher_unwind *) expr);
-        }
-
         ereport(ERROR,
                 (errmsg_internal("unrecognized ExtensibleNode: %s",
                                  ((ExtensibleNode *)expr)->extnodename)));
@@ -258,7 +250,9 @@ static Node 
*transform_cypher_expr_recurse(cypher_parsestate *cpstate,
         return transform_FuncCall(cpstate, (FuncCall *)expr);
     case T_SubLink:
         return transform_SubLink(cpstate, (SubLink *)expr);
-        break;
+    case T_Const:
+        /* Already transformed */
+        return expr;
     default:
         ereport(ERROR, (errmsg_internal("unrecognized node type: %d",
                                         nodeTag(expr))));
@@ -390,26 +384,8 @@ static Node *transform_ColumnRef(cypher_parsestate 
*cpstate, ColumnRef *cref)
                 Assert(IsA(field1, String));
                 colname = strVal(field1);
 
-                if (cpstate->p_list_comp &&
-                    (pstate->p_expr_kind == EXPR_KIND_WHERE ||
-                     pstate->p_expr_kind == EXPR_KIND_SELECT_TARGET) &&
-                     list_length(pstate->p_namespace) > 0)
-                {
-                    /*
-                     * Just scan through the last pnsi(that is for list comp)
-                     * to find the column.
-                     */
-                    node = scanNSItemForColumn(pstate,
-                                               llast(pstate->p_namespace),
-                                               0, colname, cref->location);
-                }
-                else
-                {
-                    /* Try to identify as an unqualified column */
-                    node = colNameToVar(pstate, colname, false,
-                                        cref->location);
-                }
-
+                /* Try to identify as an unqualified column */
+                node = colNameToVar(pstate, colname, false, cref->location);
                 if (node != NULL)
                 {
                         break;
@@ -1321,7 +1297,7 @@ static Node 
*transform_column_ref_for_indirection(cypher_parsestate *cpstate,
     }
 
     /* find the properties column of the NSI and return a var for it */
-    node = scanNSItemForColumn(pstate, pnsi, levels_up, "properties",
+    node = scanNSItemForColumn(pstate, pnsi, levels_up, "properties", 
                                cr->location);
 
     /*
@@ -2372,6 +2348,7 @@ static Node *transform_SubLink(cypher_parsestate 
*cpstate, SubLink *sublink)
         case EXPR_KIND_SELECT_TARGET:
         case EXPR_KIND_FROM_SUBSELECT:
         case EXPR_KIND_WHERE:
+        case EXPR_KIND_INSERT_TARGET:
             /* okay */
             break;
         default:
@@ -2411,7 +2388,7 @@ static Node *transform_SubLink(cypher_parsestate 
*cpstate, SubLink *sublink)
         sublink->operName = NIL;
     }
     else if (sublink->subLinkType == EXPR_SUBLINK ||
-            sublink->subLinkType == ARRAY_SUBLINK)
+             sublink->subLinkType == ARRAY_SUBLINK)
     {
         /*
          * Make sure the subselect delivers a single column (ignoring resjunk
@@ -2443,31 +2420,3 @@ static Node *transform_SubLink(cypher_parsestate 
*cpstate, SubLink *sublink)
 
     return result;
 }
-
-static Node *transform_cypher_list_comprehension(cypher_parsestate *cpstate,
-                                                 cypher_unwind *unwind)
-{
-    cypher_clause cc;
-    Node* expr;
-    ParseNamespaceItem *pnsi;
-    ParseState *pstate = (ParseState *)cpstate;
-
-    cpstate->p_list_comp = true;
-    pstate->p_lateral_active = true;
-
-    cc.prev = NULL;
-    cc.next = NULL;
-    cc.self = (Node *)unwind;
-
-    pnsi = transform_cypher_clause_as_subquery(cpstate,
-                                               transform_cypher_clause,
-                                               &cc, NULL, true);
-
-    expr = transform_cypher_expr(cpstate, unwind->collect,
-                                 EXPR_KIND_SELECT_TARGET);
-
-    pnsi->p_cols_visible = false;
-    pstate->p_lateral_active = false;
-
-    return expr;
-}
diff --git a/src/backend/parser/cypher_gram.y b/src/backend/parser/cypher_gram.y
index 31e062a5..31c07a5b 100644
--- a/src/backend/parser/cypher_gram.y
+++ b/src/backend/parser/cypher_gram.y
@@ -21,6 +21,7 @@
 #include "postgres.h"
 
 #include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
 #include "parser/parser.h"
 
 #include "parser/cypher_gram.h"
@@ -259,15 +260,9 @@ static Node *build_comparison_expression(Node 
*left_grammar_node,
                                          char *opr_name, int location);
 
 /* list_comprehension */
-static Node *verify_rule_as_list_comprehension(Node *expr, Node *expr2,
-                                               Node *where, Node *mapping_expr,
-                                               int var_loc, int expr_loc,
-                                               int where_loc, int mapping_loc);
-
-static Node *build_list_comprehension_node(ColumnRef *var_name, Node *expr,
+static Node *build_list_comprehension_node(Node *var, Node *expr,
                                            Node *where, Node *mapping_expr,
-                                           int var_loc, int expr_loc,
-                                           int where_loc,int mapping_loc);
+                                           int location);
 
 %}
 %%
@@ -1078,8 +1073,6 @@ unwind:
 
             n = make_ag_node(cypher_unwind);
             n->target = res;
-            n->where = NULL;
-            n->collect = NULL;
             $$ = (Node *) n;
         }
 
@@ -2083,6 +2076,7 @@ expr_literal:
     | map
     | map_projection
     | list
+    | list_comprehension
     ;
 
 map:
@@ -2202,7 +2196,6 @@ list:
 
             $$ = (Node *)n;
         }
-    | list_comprehension
     ;
 
 /*
@@ -2213,40 +2206,28 @@ list:
 list_comprehension:
     '[' expr IN expr ']'
         {
-            Node *n = $2;
-            Node *result = NULL;
-            
             /*
-             * If the first expr is a ColumnRef(variable), then the rule
-             * should evaluate as a list comprehension. Otherwise, it should
-             * evaluate as an IN operator.
+             * If the first expr is not a ColumnRef(variable), then the rule
+             * should evaluate as an IN operator.
              */
-            if (nodeTag(n) == T_ColumnRef)
+            if (!IsA($2, ColumnRef))
             {
-                ColumnRef *cref = (ColumnRef *)n;
-                result = build_list_comprehension_node(cref, $4, NULL, NULL,
-                                                       @2, @4, 0, 0);
+                $$ = (Node *)makeSimpleA_Expr(AEXPR_IN, "=", $2, $4, @3);
             }
-            else
-            {
-                result = (Node *)makeSimpleA_Expr(AEXPR_IN, "=", n, $4, @3);
-            }
-            $$ = result;
+
+            $$ = build_list_comprehension_node($2, $4, NULL, NULL, @1);
         }
     | '[' expr IN expr WHERE expr ']'
         {
-            $$ = verify_rule_as_list_comprehension($2, $4, $6, NULL,
-                                                   @2, @4, @6, 0);
+            $$ = build_list_comprehension_node($2, $4, $6, NULL, @1);
         }
     | '[' expr IN expr '|' expr ']'
         {
-            $$ = verify_rule_as_list_comprehension($2, $4, NULL, $6,
-                                                   @2, @4, 0, @6);
+            $$ = build_list_comprehension_node($2, $4, NULL, $6, @1);
         }
     | '[' expr IN expr WHERE expr '|' expr ']'
         {
-            $$ = verify_rule_as_list_comprehension($2, $4, $6, $8,
-                                                   @2, @4, @6, @8);
+            $$ = build_list_comprehension_node($2, $4, $6, $8, @1);
         }
     ;
 
@@ -2897,6 +2878,10 @@ static FuncCall *node_to_agtype(Node * fnode, char 
*type, int location)
     {
         funcname = lappend(funcname, makeString("bool_to_agtype"));
     }
+    else if (pg_strcasecmp(type, "agtype[]") == 0)
+    {
+        funcname = lappend(funcname, makeString("agtype_array_to_agtype"));
+    }
     else
     {
         ereport(ERROR,
@@ -3277,90 +3262,51 @@ static cypher_relationship *build_VLE_relation(List 
*left_arg,
     return cr;
 }
 
-/* Helper function to verify that the rule is a list comprehension */
-static Node *verify_rule_as_list_comprehension(Node *expr, Node *expr2,
-                                               Node *where, Node *mapping_expr,
-                                               int var_loc, int expr_loc,
-                                               int where_loc, int mapping_loc)
+/* helper function to build a list_comprehension grammar node */
+static Node *build_list_comprehension_node(Node *var, Node *expr,
+                                           Node *where, Node *mapping_expr,
+                                           int location)
 {
-    Node *result = NULL;
+    SubLink *sub;
+    String *val;
+    ColumnRef *cref = NULL;
+    cypher_list_comprehension *list_comp = NULL;
 
-    /*
-     * If the first expression is a ColumnRef, then we can build a
-     * list_comprehension node.
-     * Else its an invalid use of IN operator.
-     */
-    if (nodeTag(expr) == T_ColumnRef)
-    {
-        ColumnRef *cref = (ColumnRef *)expr;
-        result = build_list_comprehension_node(cref, expr2, where,
-                                               mapping_expr, var_loc,
-                                               expr_loc, where_loc,
-                                               mapping_loc);
-    }
-    else
+    if (!IsA(var, ColumnRef))
     {
         ereport(ERROR,
                 (errcode(ERRCODE_SYNTAX_ERROR),
                  errmsg("Syntax error at or near IN")));
     }
-    return result;
-}
 
-/* helper function to build a list_comprehension grammar node */
-static Node *build_list_comprehension_node(ColumnRef *cref, Node *expr,
-                                           Node *where, Node *mapping_expr,
-                                           int var_loc, int expr_loc,
-                                           int where_loc, int mapping_loc)
-{
-    ResTarget *res = NULL;
-    cypher_unwind *unwind = NULL;
-    char *var_name = NULL;
-    String *val;
-
-    /* Extract name from cref */
+    cref = (ColumnRef *)var;
     val = linitial(cref->fields);
-
     if (!IsA(val, String))
     {
         ereport(ERROR,
-                (errmsg_internal("unexpected Node for cypher_clause")));
+                (errcode(ERRCODE_SYNTAX_ERROR),
+                 errmsg("Invalid list comprehension variable name")));
     }
 
-    var_name = val->sval;
+    /* build the list comprehension node */
+    list_comp = make_ag_node(cypher_list_comprehension);
+    list_comp->varname = val->sval;
+    list_comp->expr = expr;
+    list_comp->where = where;
+    list_comp->mapping_expr = (mapping_expr != NULL) ? mapping_expr :
+                                                       (Node *) cref;
 
     /*
-     * Build the ResTarget node for the UNWIND variable var_name attached to
-     * expr.
+     * Build an ARRAY sublink and attach list_comp as sub-select,
+     * it will be transformed in to query tree by us and reattached for 
+     * pg to process.
      */
-    res = makeNode(ResTarget);
-    res->name = var_name;
-    res->val = (Node *)expr;
-    res->location = expr_loc;
-
-    /* build the UNWIND node */
-    unwind = make_ag_node(cypher_unwind);
-    unwind->target = res;
-    unwind->where = where;
-
-    /* if there is a mapping function, add its arg to collect */
-    if (mapping_expr != NULL)
-    {
-        unwind->collect = make_function_expr(list_make1(makeString("collect")),
-                                             list_make1(mapping_expr),
-                                             mapping_loc);
-    }
-    /*
-     * Otherwise, we need to add in the ColumnRef of the variable var_name as
-     * the arg to collect instead. This implies that the RETURN variable is
-     * var_name.
-     */
-    else
-    {
-        unwind->collect = make_function_expr(list_make1(makeString("collect")),
-                                             list_make1(cref), mapping_loc);
-    }
-
-    /* return the UNWIND node */
-    return (Node *)unwind;
+    sub = makeNode(SubLink);
+    sub->subLinkType = ARRAY_SUBLINK;
+    sub->subLinkId = 0;
+    sub->testexpr = NULL;
+    sub->subselect = (Node *)list_comp;
+    sub->location = location;
+
+    return (Node *) node_to_agtype((Node *)sub, "agtype[]", location);
 }
diff --git a/src/backend/parser/cypher_item.c b/src/backend/parser/cypher_item.c
index 81413fa3..e9fb046e 100644
--- a/src/backend/parser/cypher_item.c
+++ b/src/backend/parser/cypher_item.c
@@ -27,16 +27,13 @@
 #include "nodes/makefuncs.h"
 #include "parser/parse_relation.h"
 #include "parser/parse_target.h"
-#include "miscadmin.h"
 
 #include "parser/cypher_expr.h"
 #include "parser/cypher_item.h"
-#include "parser/cypher_clause.h"
 
 static List *ExpandAllTables(ParseState *pstate, int location);
 static List *expand_rel_attrs(ParseState *pstate, RangeTblEntry *rte,
                               int rtindex, int sublevels_up, int location);
-bool has_a_cypher_list_comprehension_node(Node *expr);
 
 /* see transformTargetEntry() */
 TargetEntry *transform_cypher_item(cypher_parsestate *cpstate, Node *node,
@@ -44,17 +41,10 @@ TargetEntry *transform_cypher_item(cypher_parsestate 
*cpstate, Node *node,
                                    char *colname, bool resjunk)
 {
     ParseState *pstate = (ParseState *)cpstate;
-    bool old_p_lateral_active = pstate->p_lateral_active;
-
-    /* we want to see lateral variables */
-    pstate->p_lateral_active = true;
 
     if (!expr)
         expr = transform_cypher_expr(cpstate, node, expr_kind);
 
-    /* set lateral back to what it was */
-    pstate->p_lateral_active = old_p_lateral_active;
-
     if (!colname && !resjunk)
         colname = FigureColname(node);
 
@@ -62,143 +52,6 @@ TargetEntry *transform_cypher_item(cypher_parsestate 
*cpstate, Node *node,
                            colname, resjunk);
 }
 
-/*
- * Helper function to determine if the passed node has a list_comprehension
- * node embedded in it.
- */
-bool has_a_cypher_list_comprehension_node(Node *expr)
-{
-    /* return false on NULL input */
-    if (expr == NULL)
-    {
-        return false;
-    }
-
-    /* since this function recurses, it could be driven to stack overflow */
-    check_stack_depth();
-
-    switch (nodeTag(expr))
-    {
-    case T_A_Expr:
-    {
-        /*
-         * We need to recurse into the left and right nodes
-         * to check if there is an unwind node in there
-         */
-        A_Expr *a_expr = (A_Expr *)expr;
-
-        return (has_a_cypher_list_comprehension_node(a_expr->lexpr) ||
-                has_a_cypher_list_comprehension_node(a_expr->rexpr));
-    }
-    case T_BoolExpr:
-    {
-        BoolExpr *bexpr = (BoolExpr *)expr;
-        ListCell *lc;
-
-        /* is any of the boolean expression argument a list comprehension? */
-        foreach(lc, bexpr->args)
-        {
-            Node *arg = lfirst(lc);
-
-            if (has_a_cypher_list_comprehension_node(arg))
-            {
-                return true;
-            }
-        }
-        break;
-    }
-    case T_A_Indirection:
-    {
-        /* set expr to the object of the indirection */
-        expr = ((A_Indirection *)expr)->arg;
-
-        /* check the object of the indirection */
-        return has_a_cypher_list_comprehension_node(expr);
-    }
-    case T_ExtensibleNode:
-    {
-        if (is_ag_node(expr, cypher_unwind))
-        {
-            cypher_unwind *cu = (cypher_unwind *)expr;
-
-            /* it is a list comprehension if it has a collect node */
-            return cu->collect != NULL;
-        }
-        else if (is_ag_node(expr, cypher_map))
-        {
-            cypher_map *map;
-            int i;
-
-            map = (cypher_map *)expr;
-
-            if (map->keyvals == NULL || map->keyvals->length == 0)
-            {
-                return false;
-            }
-
-            /* check each key and value for a list comprehension */
-            for (i = 0; i < map->keyvals->length; i += 2)
-            {
-                Node *val;
-
-                /* get the value */
-                val = (Node *)map->keyvals->elements[i + 1].ptr_value;
-
-                /* check the value */
-                if (has_a_cypher_list_comprehension_node(val))
-                {
-                    return true;
-                }
-            }
-        }
-        else if (is_ag_node(expr, cypher_string_match))
-        {
-            cypher_string_match *csm_match = (cypher_string_match *)expr;
-
-            /* is lhs or rhs of the string match a list comprehension? */
-            return (has_a_cypher_list_comprehension_node(csm_match->lhs) ||
-                    has_a_cypher_list_comprehension_node(csm_match->rhs));
-        }
-        else if (is_ag_node(expr, cypher_typecast))
-        {
-            cypher_typecast *ctypecast = (cypher_typecast *)expr;
-
-            /* is expr being typecasted a list comprehension? */
-            return has_a_cypher_list_comprehension_node(ctypecast->expr);
-        }
-        else if (is_ag_node(expr, cypher_comparison_aexpr))
-        {
-            cypher_comparison_aexpr *aexpr = (cypher_comparison_aexpr *)expr;
-
-            /* is left or right argument a list comprehension? */
-            return (has_a_cypher_list_comprehension_node(aexpr->lexpr) ||
-                    has_a_cypher_list_comprehension_node(aexpr->rexpr));
-        }
-        else if (is_ag_node(expr, cypher_comparison_boolexpr))
-        {
-            cypher_comparison_boolexpr *bexpr = (cypher_comparison_boolexpr 
*)expr;
-            ListCell *lc;
-
-            /* is any of the boolean expression argument a list comprehension? 
*/
-            foreach(lc, bexpr->args)
-            {
-                Node *arg = lfirst(lc);
-
-                if (has_a_cypher_list_comprehension_node(arg))
-                {
-                    return true;
-                }
-            }
-        }
-        break;
-    }
-    default:
-        break;
-    }
-    /* otherwise, return false */
-    return false;
-}
-
 /* see transformTargetList() */
 List *transform_cypher_item_list(cypher_parsestate *cpstate, List *item_list,
                                  List **groupClause, ParseExprKind expr_kind)
@@ -215,7 +68,6 @@ List *transform_cypher_item_list(cypher_parsestate *cpstate, 
List *item_list,
     {
         ResTarget *item = lfirst(li);
         TargetEntry *te;
-        bool has_list_comp = false;
 
         if (expand_star)
         {
@@ -243,48 +95,14 @@ List *transform_cypher_item_list(cypher_parsestate 
*cpstate, List *item_list,
                 }
             }
         }
-
-        /* Check if we have a list comprehension */
-        has_list_comp = has_a_cypher_list_comprehension_node(item->val);
-
         /* Clear the exprHasAgg flag to check transform for an aggregate */
         cpstate->exprHasAgg = false;
 
-        if (has_list_comp && item_list->length > 1)
-        {
-            /*
-             * Create a subquery for the list comprehension and transform it
-             * as a subquery. Then expand the target list of the subquery.
-             * This is to avoid multiple unnest functions in the same query
-             * level and collect not able to distinguish correctly.
-             */
-            ParseNamespaceItem *pnsi;
-            cypher_return *cr;
-            cypher_clause cc;
-
-            cr = make_ag_node(cypher_return);
-            cr->items = list_make1(item);
-
-            cc.prev = NULL;
-            cc.next = NULL;
-            cc.self = (Node *)cr;
-
-            pnsi = transform_cypher_clause_as_subquery(cpstate,
-                                                       transform_cypher_clause,
-                                                       &cc, NULL, true);
-
-            target_list = list_concat(target_list,
-                                      expandNSItemAttrs(&cpstate->pstate, pnsi,
-                                                        0, true, -1));
-        }
-        else
-        {
-            /* transform the item */
-            te = transform_cypher_item(cpstate, item->val, NULL, expr_kind,
-                                       item->name, false);
+        /* transform the item */
+        te = transform_cypher_item(cpstate, item->val, NULL, expr_kind,
+                                   item->name, false);
 
-            target_list = lappend(target_list, te);
-        }
+        target_list = lappend(target_list, te);
 
         /*
          * Did the transformed item contain an aggregate function? If it 
didn't,
@@ -299,58 +117,6 @@ List *transform_cypher_item_list(cypher_parsestate 
*cpstate, List *item_list,
         {
             hasAgg = true;
         }
-
-        /*
-         * This is for a special case with list comprehension, which is 
embedded
-         * in a cypher_unwind node. We need to group the results but not expose
-         * the grouping expression.
-         */
-        if (has_list_comp)
-        {
-            ParseState *pstate = &cpstate->pstate;
-            ParseNamespaceItem *nsitem = NULL;
-            RangeTblEntry *rte = NULL;
-
-            /*
-             * There should be at least 2 entries in p_namespace. One for the
-             * variable in the reading clause and one for the variable in the
-             * list_comprehension expression. Otherwise, there is nothing to
-             * group with.
-             */
-            if (list_length(pstate->p_namespace) > 1)
-            {
-                /*
-                 * Get the first namespace item which should be the first
-                 * variable from the reading clause.
-                 */
-                nsitem = lfirst(list_head(pstate->p_namespace));
-                /* extract the rte */
-                rte = nsitem->p_rte;
-
-                /*
-                 * If we have a non-null column name make a ColumnRef to it.
-                 * Otherwise, there wasn't a variable specified in the reading
-                 * clause. If that is the case don't. Because there isn't
-                 * anything to group with.
-                 */
-                if (rte->eref->colnames != NULL && nsitem->p_cols_visible)
-                {
-                    ColumnRef *cref = NULL;
-                    char *colname = NULL;
-
-                    /* get the name of the column (varname) */
-                    colname = strVal(lfirst(list_head(rte->eref->colnames)));
-
-                    /* create the ColumnRef */
-                    cref = makeNode(ColumnRef);
-                    cref->fields = list_make1(makeString(colname));
-                    cref->location = -1;
-
-                    /* add the expression for grouping */
-                    group_clause = lappend(group_clause, cref);
-                }
-            }
-        }
     }
 
     /*
diff --git a/src/backend/utils/adt/agtype.c b/src/backend/utils/adt/agtype.c
index c0e14110..78559a36 100644
--- a/src/backend/utils/adt/agtype.c
+++ b/src/backend/utils/adt/agtype.c
@@ -1836,6 +1836,19 @@ static void array_to_agtype_internal(Datum array, 
agtype_in_state *result)
     pfree_if_not_null(nulls);
 }
 
+PG_FUNCTION_INFO_V1(agtype_array_to_agtype);
+Datum agtype_array_to_agtype(PG_FUNCTION_ARGS)
+{
+    agtype_in_state result;
+
+    result.parse_state = NULL;
+    result.res = NULL;
+
+    array_to_agtype_internal(PG_GETARG_DATUM(0), &result);
+
+    PG_RETURN_POINTER(agtype_value_to_agtype(result.res));
+}
+
 /*
  * Turn a composite / record into agtype.
  */
@@ -11910,7 +11923,6 @@ PG_FUNCTION_INFO_V1(age_unnest);
 Datum age_unnest(PG_FUNCTION_ARGS)
 {
     agtype *agtype_arg = NULL;
-    bool list_comprehension = false;
     ReturnSetInfo *rsi;
     Tuplestorestate *tuple_store;
     TupleDesc tupdesc;
@@ -11921,35 +11933,13 @@ Datum age_unnest(PG_FUNCTION_ARGS)
     agtype_value v;
     agtype_iterator_token r;
 
-    /* verify that we have the correct number of args */
-    if (PG_NARGS() != 2)
-    {
-        ereport(ERROR,
-                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                        errmsg("invalid number of arguments to unnest")));
-    }
-
-    /* verify that our flags are not null */
-    if (PG_ARGISNULL(1))
-    {
-        ereport(ERROR,
-                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                        errmsg("invalid unnest boolean flags passed")));
-    }
-
     /* check for a NULL expr */
     if (PG_ARGISNULL(0))
     {
         PG_RETURN_NULL();
     }
 
-    /* get our flags */
-    list_comprehension = PG_GETARG_BOOL(1);
-
-    /* get the input expression */
     agtype_arg = AG_GET_ARG_AGTYPE_P(0);
-
-    /* verify that it resolves to an array */
     if (!AGT_ROOT_IS_ARRAY(agtype_arg))
     {
         ereport(ERROR,
@@ -12006,25 +11996,6 @@ Datum age_unnest(PG_FUNCTION_ARGS)
         }
     }
 
-    /*
-     * If this is for list_comprehension, we need to add a NULL as the last 
row.
-     * This NULL will allow empty lists (either filtered out by where, creating
-     * an empty list, or just a generic empty list) to be preserved.
-     */
-    if (list_comprehension)
-    {
-        Datum values[1] = {0};
-        bool nulls[1] = {true};
-
-        old_cxt = MemoryContextSwitchTo(tmp_cxt);
-
-        tuplestore_puttuple(tuple_store,
-                            heap_form_tuple(ret_tdesc, values, nulls));
-
-        MemoryContextSwitchTo(old_cxt);
-        MemoryContextReset(tmp_cxt);
-    }
-
     MemoryContextDelete(tmp_cxt);
 
     rsi->setResult = tuple_store;
diff --git a/src/include/nodes/ag_nodes.h b/src/include/nodes/ag_nodes.h
index fe9c9663..f0cc2204 100644
--- a/src/include/nodes/ag_nodes.h
+++ b/src/include/nodes/ag_nodes.h
@@ -50,6 +50,7 @@ typedef enum ag_node_tag
     cypher_map_projection_t,
     cypher_map_projection_element_t,
     cypher_list_t,
+    cypher_list_comprehension_t,
     /* comparison expression */
     cypher_comparison_aexpr_t,
     cypher_comparison_boolexpr_t,
@@ -106,6 +107,5 @@ static inline bool _is_ag_node(Node *node, const char 
*extnodename)
 }
 
 #define is_ag_node(node, type) _is_ag_node((Node *)(node), CppAsString(type))
-#define get_ag_node_tag(node) ((ag_node_tag)(((ExtensibleNode 
*)(node))->extnodename))
 
 #endif
diff --git a/src/include/nodes/cypher_nodes.h b/src/include/nodes/cypher_nodes.h
index e7e293f3..0b5fec1c 100644
--- a/src/include/nodes/cypher_nodes.h
+++ b/src/include/nodes/cypher_nodes.h
@@ -67,7 +67,6 @@ typedef struct cypher_with
 {
     ExtensibleNode extensible;
     bool distinct;
-    bool subquery_intermediate; /* flag that denotes a subquery node */
     List *items; /* a list of ResTarget's */
     List *order_by;
     Node *skip;
@@ -118,10 +117,6 @@ typedef struct cypher_unwind
 {
     ExtensibleNode extensible;
     ResTarget *target;
-
-    /* for list comprehension */
-    Node *where;
-    Node *collect;
 } cypher_unwind;
 
 typedef struct cypher_merge
@@ -219,6 +214,15 @@ typedef struct cypher_map_projection
     int location;
 } cypher_map_projection;
 
+ typedef struct cypher_list_comprehension
+ {
+    ExtensibleNode extensible;
+    char *varname;
+    Node *expr;
+    Node *where;
+    Node *mapping_expr;
+ } cypher_list_comprehension;
+
 typedef enum cypher_map_projection_element_type
 {
     PROPERTY_SELECTOR = 0,  /* map_var { .key } */
diff --git a/src/include/nodes/cypher_outfuncs.h 
b/src/include/nodes/cypher_outfuncs.h
index 4a04cf94..418d35f4 100644
--- a/src/include/nodes/cypher_outfuncs.h
+++ b/src/include/nodes/cypher_outfuncs.h
@@ -48,6 +48,7 @@ void out_cypher_param(StringInfo str, const ExtensibleNode 
*node);
 void out_cypher_map(StringInfo str, const ExtensibleNode *node);
 void out_cypher_map_projection(StringInfo str, const ExtensibleNode *node);
 void out_cypher_list(StringInfo str, const ExtensibleNode *node);
+void out_cypher_list_comprehension(StringInfo str, const ExtensibleNode *node);
 
 /* comparison expression */
 void out_cypher_comparison_aexpr(StringInfo str, const ExtensibleNode *node);
diff --git a/src/include/parser/cypher_analyze.h 
b/src/include/parser/cypher_analyze.h
index 97616e54..c74de0b0 100644
--- a/src/include/parser/cypher_analyze.h
+++ b/src/include/parser/cypher_analyze.h
@@ -21,16 +21,14 @@
 #define AG_CYPHER_ANALYZE_H
 
 #include "parser/cypher_clause.h"
-
-typedef bool (*cypher_expression_condition)( Node *expr);
+#include "nodes/nodeFuncs.h"
 
 void post_parse_analyze_init(void);
 void post_parse_analyze_fini(void);
 
-cypher_clause *build_subquery_node(cypher_clause *next);
-
-/*expr tree walker */
-bool expr_contains_node(cypher_expression_condition is_expr, Node *expr);
-bool expr_has_subquery(Node * expr);
+bool cypher_expr_tree_walker(Node *node, bool (*walker) (),
+                             void *context);
+bool cypher_raw_expr_tree_walker(Node *node, bool (*walker) (),
+                                 void *context);
 
 #endif
diff --git a/src/include/parser/cypher_clause.h 
b/src/include/parser/cypher_clause.h
index 51ba5cb4..461a664c 100644
--- a/src/include/parser/cypher_clause.h
+++ b/src/include/parser/cypher_clause.h
@@ -39,13 +39,4 @@ Query *cypher_parse_sub_analyze(Node *parseTree,
                                 CommonTableExpr *parentCTE,
                                 bool locked_from_parent,
                                 bool resolve_unknowns);
-
-typedef Query *(*transform_method)(cypher_parsestate *cpstate,
-                                   cypher_clause *clause);
-
-ParseNamespaceItem *transform_cypher_clause_as_subquery(cypher_parsestate 
*cpstate,
-                                                        transform_method 
transform,
-                                                        cypher_clause *clause,
-                                                        Alias *alias,
-                                                        bool add_rte_to_query);
 #endif
diff --git a/src/include/parser/cypher_item.h b/src/include/parser/cypher_item.h
index ba4e7e9a..92b6c95f 100644
--- a/src/include/parser/cypher_item.h
+++ b/src/include/parser/cypher_item.h
@@ -26,6 +26,4 @@ TargetEntry *transform_cypher_item(cypher_parsestate 
*cpstate, Node *node,
 List *transform_cypher_item_list(cypher_parsestate *cpstate, List *item_list,
                                  List **groupClause, ParseExprKind expr_kind);
 
-bool has_a_cypher_list_comprehension_node(Node *expr);
-
 #endif
diff --git a/src/include/parser/cypher_parse_node.h 
b/src/include/parser/cypher_parse_node.h
index f7169380..263ea197 100644
--- a/src/include/parser/cypher_parse_node.h
+++ b/src/include/parser/cypher_parse_node.h
@@ -50,7 +50,6 @@ typedef struct cypher_parsestate
      */
     bool exprHasAgg;
     bool p_opt_match;
-    bool p_list_comp;
 } cypher_parsestate;
 
 typedef struct errpos_ecb_state


Reply via email to