v2-0001-Fix-assertion-failure-in-LATERAL-GRAPH_TABLE-with-multi-label-pattern.patch

application/octet-stream

Filename: v2-0001-Fix-assertion-failure-in-LATERAL-GRAPH_TABLE-with-multi-label-pattern.patch
Type: application/octet-stream
Part: 0
Message: Re: [Bug]Assertion failure in LATERAL GRAPH_TABLE with multi-label pattern
From ad6c9007ba5d092ee530b3a6e964b05c7ff2c7e7 Mon Sep 17 00:00:00 2001
From: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Date: Tue, 19 May 2026 00:00:00 +0000
Subject: [PATCH v2] Fix assertion failure in LATERAL GRAPH_TABLE with
 multi-label pattern

rewriteGraphTable() rewrites GRAPH_TABLE into a subquery RTE.  During
that rewrite, replace_property_refs_mutator() bumps Vars that already
refer outside the GRAPH_TABLE expression by one query level, which is
sufficient for patterns that produce a single path query.

For patterns that produce multiple path queries, however,
generate_setop_from_pathqueries() additionally inserts each path query as
a subquery RTE of the UNION ALL query.  Lateral Vars inside those path
queries were not adjusted for that extra query level.  As a result, such
Vars could be interpreted as references to the rewritten GRAPH_TABLE RTE
itself, causing create_lateral_join_info() to see a lateral self-reference
and trip its assertion.

Increment only Vars that already refer outside each path query before
adding it to the setop range table.  Local Vars belonging to the path
query remain unchanged.

Add regression coverage for a multi-label GRAPH_TABLE pattern with
lateral references in both WHERE and COLUMNS.

Author: Satya Narlapuram <satyanarlapuram@gmail.com>
Reviewed-by: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Discussion: https://www.postgresql.org/message-id/CAHg+QDfnLzsgjaQ_CiKSpP4JH3MKOiwoawEcCzXa9uYr45yiWw@mail.gmail.com
---
 src/backend/rewrite/rewriteGraphTable.c   |  7 +++++++
 src/test/regress/expected/graph_table.out | 13 +++++++++++++
 src/test/regress/sql/graph_table.sql      |  5 +++++
 3 files changed, 25 insertions(+)

diff --git a/src/backend/rewrite/rewriteGraphTable.c b/src/backend/rewrite/rewriteGraphTable.c
index 33d4e866d74..a62ef926a5c 100644
--- a/src/backend/rewrite/rewriteGraphTable.c
+++ b/src/backend/rewrite/rewriteGraphTable.c
@@ -714,6 +714,13 @@ generate_setop_from_pathqueries(List *pathqueries, List **rtable, List **targetl
 
 	lquery = linitial_node(Query, pathqueries);
 
+	/*
+	 * Each path query is being inserted as a subquery RTE of the setop
+	 * query, so any Vars that already refer outside the path query must be
+	 * adjusted for the additional query level.
+	 */
+	IncrementVarSublevelsUp((Node *) lquery, 1, 1);
+
 	pni = addRangeTableEntryForSubquery(make_parsestate(NULL), lquery, NULL,
 										false, false);
 	*rtable = lappend(*rtable, pni->p_rte);
diff --git a/src/test/regress/expected/graph_table.out b/src/test/regress/expected/graph_table.out
index cc6d80afd82..d783cb94dff 100644
--- a/src/test/regress/expected/graph_table.out
+++ b/src/test/regress/expected/graph_table.out
@@ -254,6 +254,19 @@ SELECT x1.a, g.* FROM x1, GRAPH_TABLE (myshop MATCH (x1 IS customers WHERE x1.ad
  2 | customer1     |   1 |        1
 (2 rows)
 
+-- lateral reference with multi-label pattern (UNION ALL rewrite)
+SELECT x1.a, g.* FROM x1,
+    GRAPH_TABLE (myshop MATCH (c IS customers WHERE c.customer_id = x1.a)-[IS customer_orders | customer_wishlists]->(l IS lists)-[IS list_items]->(p IS products)
+        COLUMNS (x1.a AS outer_id, c.name AS customer_name, p.name AS product_name, l.list_type)) g
+    ORDER BY 1, 3, 4, 5;
+ a | outer_id | customer_name | product_name | list_type 
+---+----------+---------------+--------------+-----------
+ 1 |        1 | customer1     | product1     | order
+ 1 |        1 | customer1     | product2     | order
+ 2 |        2 | customer2     | product1     | order
+ 2 |        2 | customer2     | product1     | wishlist
+(4 rows)
+
 -- non-local property references are not allowed, even if a lateral column
 -- reference is available
 SELECT x1.a, g.* FROM x1, GRAPH_TABLE (myshop MATCH (x1 IS customers)-[IS customer_orders]->(o IS orders WHERE o.order_id = x1.a) COLUMNS (x1.name AS customer_name, x1.customer_id AS cid, o.order_id)) g; -- error
diff --git a/src/test/regress/sql/graph_table.sql b/src/test/regress/sql/graph_table.sql
index 0e381ec72bc..f7e403f03f0 100644
--- a/src/test/regress/sql/graph_table.sql
+++ b/src/test/regress/sql/graph_table.sql
@@ -158,6 +158,11 @@ CREATE TABLE x1 (a int, address text);
 INSERT INTO x1 VALUES (1, 'one'), (2, 'two');
 SELECT * FROM x1, GRAPH_TABLE (myshop MATCH (c IS customers WHERE c.address = 'US' AND c.customer_id = x1.a)-[IS customer_orders]->(o IS orders) COLUMNS (c.name AS customer_name, c.customer_id AS cid));
 SELECT x1.a, g.* FROM x1, GRAPH_TABLE (myshop MATCH (x1 IS customers WHERE x1.address = 'US')-[IS customer_orders]->(o IS orders) COLUMNS (x1.name AS customer_name, x1.customer_id AS cid, o.order_id)) g;
+-- lateral reference with multi-label pattern (UNION ALL rewrite)
+SELECT x1.a, g.* FROM x1,
+    GRAPH_TABLE (myshop MATCH (c IS customers WHERE c.customer_id = x1.a)-[IS customer_orders | customer_wishlists]->(l IS lists)-[IS list_items]->(p IS products)
+        COLUMNS (x1.a AS outer_id, c.name AS customer_name, p.name AS product_name, l.list_type)) g
+    ORDER BY 1, 3, 4, 5;
 -- non-local property references are not allowed, even if a lateral column
 -- reference is available
 SELECT x1.a, g.* FROM x1, GRAPH_TABLE (myshop MATCH (x1 IS customers)-[IS customer_orders]->(o IS orders WHERE o.order_id = x1.a) COLUMNS (x1.name AS customer_name, x1.customer_id AS cid, o.order_id)) g; -- error