From b8839a128dc1074d973c2b217da25c437ea7f3bf Mon Sep 17 00:00:00 2001
From: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Date: Fri, 19 Jun 2026 17:08:06 +0530
Subject: [PATCH v20260619 02/11] Test concurrent modifications to a property
 graph

We hold an exclusive lock when modifying a property graph. Hence
modifications to a property graph will be serialized and there is no way
that conflicting modifications may render the property graph
inconsistent. However there is not testcase to verify this behaviour.
Add an isolation test for the same.

Author: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Discussion: https://www.postgresql.org/message-id/CAExHW5tMT71BwGzA7VCi3_6ZVYh-P2JCVrUW84DD-jw%2B7%2B3KuA%40mail.gmail.com
---
 .../expected/alter-propgraph-concurrently.out | 127 ++++++++++++++++++
 src/test/isolation/isolation_schedule         |   1 +
 .../specs/alter-propgraph-concurrently.spec   |  58 ++++++++
 3 files changed, 186 insertions(+)
 create mode 100644 src/test/isolation/expected/alter-propgraph-concurrently.out
 create mode 100644 src/test/isolation/specs/alter-propgraph-concurrently.spec

diff --git a/src/test/isolation/expected/alter-propgraph-concurrently.out b/src/test/isolation/expected/alter-propgraph-concurrently.out
new file mode 100644
index 00000000000..a75e75b3ca3
--- /dev/null
+++ b/src/test/isolation/expected/alter-propgraph-concurrently.out
@@ -0,0 +1,127 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1b s1dlabel s2dlabel s1c s2pgdef
+step s1b: BEGIN;
+step s1dlabel: ALTER PROPERTY GRAPH pgg1 ALTER VERTEX TABLE pgt1 DROP LABEL pgl1;
+step s2dlabel: ALTER PROPERTY GRAPH pgg1 ALTER VERTEX TABLE pgt1 DROP LABEL pgl2; <waiting ...>
+step s1c: COMMIT;
+step s2dlabel: <... completed>
+ERROR:  cannot drop the last label from element "pgt1"
+step s2pgdef: SELECT pg_get_propgraphdef('pgg1'::regclass);
+pg_get_propgraphdef                                                                                          
+-------------------------------------------------------------------------------------------------------------
+CREATE PROPERTY GRAPH public.pgg1
+    VERTEX TABLES (
+        pgt1 KEY (a) LABEL pgl2 PROPERTIES (a, b)
+    )
+(1 row)
+
+
+starting permutation: s1b s1dlabel s2dlabel s1r s2pgdef
+step s1b: BEGIN;
+step s1dlabel: ALTER PROPERTY GRAPH pgg1 ALTER VERTEX TABLE pgt1 DROP LABEL pgl1;
+step s2dlabel: ALTER PROPERTY GRAPH pgg1 ALTER VERTEX TABLE pgt1 DROP LABEL pgl2; <waiting ...>
+step s1r: ROLLBACK;
+step s2dlabel: <... completed>
+step s2pgdef: SELECT pg_get_propgraphdef('pgg1'::regclass);
+pg_get_propgraphdef                                                                                       
+----------------------------------------------------------------------------------------------------------
+CREATE PROPERTY GRAPH public.pgg1
+    VERTEX TABLES (
+        pgt1 KEY (a) LABEL pgl1 PROPERTIES (b)
+    )
+(1 row)
+
+
+starting permutation: s1b s1dlabel s2addp s1c s2pgdef
+step s1b: BEGIN;
+step s1dlabel: ALTER PROPERTY GRAPH pgg1 ALTER VERTEX TABLE pgt1 DROP LABEL pgl1;
+step s2addp: ALTER PROPERTY GRAPH pgg1 ALTER VERTEX TABLE pgt1 ALTER LABEL pgl1 ADD PROPERTIES (a + b AS c); <waiting ...>
+step s1c: COMMIT;
+step s2addp: <... completed>
+ERROR:  property graph "pgg1" element "pgt1" has no label "pgl1"
+step s2pgdef: SELECT pg_get_propgraphdef('pgg1'::regclass);
+pg_get_propgraphdef                                                                                          
+-------------------------------------------------------------------------------------------------------------
+CREATE PROPERTY GRAPH public.pgg1
+    VERTEX TABLES (
+        pgt1 KEY (a) LABEL pgl2 PROPERTIES (a, b)
+    )
+(1 row)
+
+
+starting permutation: s1b s1dlabel s2addp s1r s2pgdef
+step s1b: BEGIN;
+step s1dlabel: ALTER PROPERTY GRAPH pgg1 ALTER VERTEX TABLE pgt1 DROP LABEL pgl1;
+step s2addp: ALTER PROPERTY GRAPH pgg1 ALTER VERTEX TABLE pgt1 ALTER LABEL pgl1 ADD PROPERTIES (a + b AS c); <waiting ...>
+step s1r: ROLLBACK;
+step s2addp: <... completed>
+step s2pgdef: SELECT pg_get_propgraphdef('pgg1'::regclass);
+pg_get_propgraphdef                                                                                                                                  
+-----------------------------------------------------------------------------------------------------------------------------------------------------
+CREATE PROPERTY GRAPH public.pgg1
+    VERTEX TABLES (
+        pgt1 KEY (a) LABEL pgl1 PROPERTIES (b, (a + b) AS c) LABEL pgl2 PROPERTIES (a, b)
+    )
+(1 row)
+
+
+starting permutation: s1b s1delem s2alabel s1c s2pgdef
+step s1b: BEGIN;
+step s1delem: ALTER PROPERTY GRAPH pgg1 DROP VERTEX TABLES (pgt1);
+step s2alabel: ALTER PROPERTY GRAPH pgg1 ALTER VERTEX TABLE pgt1 ADD LABEL pgl3 PROPERTIES ALL COLUMNS; <waiting ...>
+step s1c: COMMIT;
+step s2alabel: <... completed>
+ERROR:  property graph "pgg1" has no element with alias "pgt1"
+step s2pgdef: SELECT pg_get_propgraphdef('pgg1'::regclass);
+pg_get_propgraphdef              
+---------------------------------
+CREATE PROPERTY GRAPH public.pgg1
+(1 row)
+
+
+starting permutation: s1b s1delem s2alabel s1r s2pgdef
+step s1b: BEGIN;
+step s1delem: ALTER PROPERTY GRAPH pgg1 DROP VERTEX TABLES (pgt1);
+step s2alabel: ALTER PROPERTY GRAPH pgg1 ALTER VERTEX TABLE pgt1 ADD LABEL pgl3 PROPERTIES ALL COLUMNS; <waiting ...>
+step s1r: ROLLBACK;
+step s2alabel: <... completed>
+step s2pgdef: SELECT pg_get_propgraphdef('pgg1'::regclass);
+pg_get_propgraphdef                                                                                                                                                 
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------
+CREATE PROPERTY GRAPH public.pgg1
+    VERTEX TABLES (
+        pgt1 KEY (a) LABEL pgl1 PROPERTIES (b) LABEL pgl2 PROPERTIES (a, b) LABEL pgl3 PROPERTIES (a, b)
+    )
+(1 row)
+
+
+starting permutation: s1b s1delem s2addp s1c s2pgdef
+step s1b: BEGIN;
+step s1delem: ALTER PROPERTY GRAPH pgg1 DROP VERTEX TABLES (pgt1);
+step s2addp: ALTER PROPERTY GRAPH pgg1 ALTER VERTEX TABLE pgt1 ALTER LABEL pgl1 ADD PROPERTIES (a + b AS c); <waiting ...>
+step s1c: COMMIT;
+step s2addp: <... completed>
+ERROR:  property graph "pgg1" has no element with alias "pgt1"
+step s2pgdef: SELECT pg_get_propgraphdef('pgg1'::regclass);
+pg_get_propgraphdef              
+---------------------------------
+CREATE PROPERTY GRAPH public.pgg1
+(1 row)
+
+
+starting permutation: s1b s1delem s2addp s1r s2pgdef
+step s1b: BEGIN;
+step s1delem: ALTER PROPERTY GRAPH pgg1 DROP VERTEX TABLES (pgt1);
+step s2addp: ALTER PROPERTY GRAPH pgg1 ALTER VERTEX TABLE pgt1 ALTER LABEL pgl1 ADD PROPERTIES (a + b AS c); <waiting ...>
+step s1r: ROLLBACK;
+step s2addp: <... completed>
+step s2pgdef: SELECT pg_get_propgraphdef('pgg1'::regclass);
+pg_get_propgraphdef                                                                                                                                  
+-----------------------------------------------------------------------------------------------------------------------------------------------------
+CREATE PROPERTY GRAPH public.pgg1
+    VERTEX TABLES (
+        pgt1 KEY (a) LABEL pgl1 PROPERTIES (b, (a + b) AS c) LABEL pgl2 PROPERTIES (a, b)
+    )
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..13829724a11 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,4 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: alter-propgraph-concurrently
diff --git a/src/test/isolation/specs/alter-propgraph-concurrently.spec b/src/test/isolation/specs/alter-propgraph-concurrently.spec
new file mode 100644
index 00000000000..50b7e0efe05
--- /dev/null
+++ b/src/test/isolation/specs/alter-propgraph-concurrently.spec
@@ -0,0 +1,58 @@
+# ALTER PROPERTY GRAPH - concurrent
+#
+# Verify that concurrent modifications to the property graph don't end up in an
+# inconsistent state. For example, adding properties to a label being dropped
+# should not be allowed because otherwise we will end up with an orphaned
+# property in the property graph.
+
+setup
+{
+ CREATE TABLE pgt1 (a int, b int);
+ CREATE PROPERTY GRAPH pgg1
+   VERTEX TABLES (pgt1 KEY (a)
+                  LABEL pgl1 PROPERTIES (b)
+                  LABEL pgl2 PROPERTIES (a, b));
+}
+
+teardown
+{
+ DROP PROPERTY GRAPH pgg1;
+ DROP TABLE pgt1;
+}
+
+session s1
+step s1b	{ BEGIN; }
+step s1dlabel	{ ALTER PROPERTY GRAPH pgg1 ALTER VERTEX TABLE pgt1 DROP LABEL pgl1; }
+step s1delem { ALTER PROPERTY GRAPH pgg1 DROP VERTEX TABLES (pgt1); }
+step s1c	{ COMMIT; }
+step s1r	{ ROLLBACK; }
+
+session s2
+step s2pgdef { SELECT pg_get_propgraphdef('pgg1'::regclass); }
+step s2dlabel	{ ALTER PROPERTY GRAPH pgg1 ALTER VERTEX TABLE pgt1 DROP LABEL pgl2; }
+step s2addp { ALTER PROPERTY GRAPH pgg1 ALTER VERTEX TABLE pgt1 ALTER LABEL pgl1 ADD PROPERTIES (a + b AS c); }
+step s2alabel { ALTER PROPERTY GRAPH pgg1 ALTER VERTEX TABLE pgt1 ADD LABEL pgl3 PROPERTIES ALL COLUMNS; }
+
+# s2dlabel fails since by then pgl2 is the only remaining label on pgt1
+permutation s1b s1dlabel s2dlabel s1c s2pgdef
+
+# s2dlabel succeeds since rollback leaves pgl1 behind
+permutation s1b s1dlabel s2dlabel s1r s2pgdef
+
+# s2addp fails since by then pgl1 is gone
+permutation s1b s1dlabel s2addp s1c s2pgdef
+
+# s2addp succeeds since the rollback leaves pgl1 behind
+permutation s1b s1dlabel s2addp s1r s2pgdef
+
+# s2alabel fails since by then pgt1 is gone from the graph
+permutation s1b s1delem s2alabel s1c s2pgdef
+
+# s2alabel succeeds since rollback leaves pgt1 in the graph
+permutation s1b s1delem s2alabel s1r s2pgdef
+
+# s2addp fails since by then pgt1 is gone from the graph
+permutation s1b s1delem s2addp s1c s2pgdef
+
+# s2addp succeeds since rollback leaves pgt1 in the graph
+permutation s1b s1delem s2addp s1r s2pgdef
-- 
2.34.1

