From a2f2bf2dadd670b3cdf452abced1cbbd4c99b373 Mon Sep 17 00:00:00 2001
From: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Date: Tue, 9 Jun 2026 20:14:13 +0530
Subject: [PATCH v20260610 9/9] Prohibit Locking Clauses on GRAPH_TABLE

Specifying a locking clause (FOR UPDATE/SHARE) that names a GRAPH_TABLE
alias currently results in an unhelpful "unrecognized RTE type: 8"
error. This commit explicitly prohibits specifying a locking clause on a
GRAPH_TABLE alias, raising a more user-friendly "FOR ... cannot be
applied to a GRAPH_TABLE" error instead.

Author: SATYANARAYANA NARLAPURAM <satyanarlapuram@gmail.com>
Author: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Reported-by: SATYANARAYANA NARLAPURAM <satyanarlapuram@gmail.com>
Reviewed-by: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Discussion: https://postgr.es/m/CAHg%2BQDcE9wp6nOEC3SCRQ90nrCO%3DQF%2BOZq1MG8Qc6hnusmogqw%40mail.gmail.com
---
 src/backend/parser/analyze.c              | 15 ++++++++++++++-
 src/test/regress/expected/graph_table.out | 13 +++++++++++++
 src/test/regress/sql/graph_table.sql      |  4 ++++
 3 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 93fa66ae57c..f762b653e77 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -3866,7 +3866,11 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
 										   allrels, true);
 					break;
 				default:
-					/* ignore JOIN, SPECIAL, FUNCTION, VALUES, CTE RTEs */
+
+					/*
+					 * ignore JOIN, SPECIAL, FUNCTION, VALUES, CTE,
+					 * GRAPH_TABLE
+					 */
 					break;
 			}
 		}
@@ -4001,6 +4005,15 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
 											LCS_asString(lc->strength)),
 									 parser_errposition(pstate, thisrel->location)));
 							break;
+						case RTE_GRAPH_TABLE:
+							ereport(ERROR,
+									(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							/*------
+							  translator: %s is a SQL row locking clause such as FOR UPDATE */
+									 errmsg("%s cannot be applied to a GRAPH_TABLE",
+											LCS_asString(lc->strength)),
+									 parser_errposition(pstate, thisrel->location)));
+							break;
 
 							/* Shouldn't be possible to see RTE_RESULT here */
 
diff --git a/src/test/regress/expected/graph_table.out b/src/test/regress/expected/graph_table.out
index c229212cb51..c0622ab7234 100644
--- a/src/test/regress/expected/graph_table.out
+++ b/src/test/regress/expected/graph_table.out
@@ -1129,4 +1129,17 @@ SELECT src.vname, count(*) FROM v1 AS src
  v13   |     1
 (3 rows)
 
+-- Locking clause on GRAPH_TABLE
+SELECT * FROM GRAPH_TABLE (g1 MATCH (src IS vl1) COLUMNS (src.vname)) gt FOR UPDATE OF gt;  -- not supported
+ERROR:  FOR UPDATE cannot be applied to a GRAPH_TABLE
+LINE 1: ...MATCH (src IS vl1) COLUMNS (src.vname)) gt FOR UPDATE OF gt;
+                                                                    ^
+SELECT * FROM GRAPH_TABLE (g1 MATCH (src IS vl1) COLUMNS (src.vname)) gt FOR UPDATE; -- ignored
+ vname 
+-------
+ v11
+ v12
+ v13
+(3 rows)
+
 -- leave the objects behind for pg_upgrade/pg_dump tests
diff --git a/src/test/regress/sql/graph_table.sql b/src/test/regress/sql/graph_table.sql
index e30c908dccc..437fb3b01f2 100644
--- a/src/test/regress/sql/graph_table.sql
+++ b/src/test/regress/sql/graph_table.sql
@@ -637,4 +637,8 @@ SELECT src.vname, count(*) FROM v1 AS src
   HAVING count(*) >= (SELECT count(*) FROM GRAPH_TABLE (g1 MATCH (a IS vl1 | vl2) COLUMNS (a.vname AS n)) WHERE n = src.vname)
   ORDER BY vname;
 
+-- Locking clause on GRAPH_TABLE
+SELECT * FROM GRAPH_TABLE (g1 MATCH (src IS vl1) COLUMNS (src.vname)) gt FOR UPDATE OF gt;  -- not supported
+SELECT * FROM GRAPH_TABLE (g1 MATCH (src IS vl1) COLUMNS (src.vname)) gt FOR UPDATE; -- ignored
+
 -- leave the objects behind for pg_upgrade/pg_dump tests
-- 
2.34.1

