Skip to content

Protect object creation from dropping referenced objects#1795

Merged
whitehawk merged 36 commits intoadb-6.x-devfrom
ADBDEV-7586
Jul 10, 2025
Merged

Protect object creation from dropping referenced objects#1795
whitehawk merged 36 commits intoadb-6.x-devfrom
ADBDEV-7586

Conversation

@whitehawk
Copy link
Copy Markdown

@whitehawk whitehawk commented Jun 24, 2025

Protect object creation from dropping referenced objects

Problem description:
If an object had been created inside a transaction and it had a dependency on
some other object (like schema, custom data type, etc), and that referenced
object had been dropped from another transaction before the first transaction
had been committed, the new object was broken.

Ex. steps:

Session 1: create type test_type as enum ('one', 'two');
Session 1: begin;
Session 1: create table test_table(a test_type);
Session 2: drop type test_type;
Session 1: commit;
Session 1: select * from test_table;

gave result:

ERROR:  cache lookup failed for type 16385 (lsyscache.c:2796)

The issue reproduced for all dependencies that are registered in 'pg_depend'.

Root cause:
No protection from stealing the objects that are marked as dependencies in
'pg_depend' before the transaction is committed.

Fix:
Lock the referenced object with AccessShareLock when the dependency is created.
Lock is done only for 'normal' dependencies (which means here 'normal
relationship between separately-created objects', when the dependent object may
be dropped without affecting the referenced object, while the referenced object
may only be dropped with CASCADE, in which case the dependent object is dropped
too) and 'auto' (meaning that the dependent object can be dropped separately
from the referenced object, and should be automatically dropped if the
referenced object is dropped).
After the lock is released, do a recheck of the object's presence and error out
if the object was dropped while we waited for the lock.

@whitehawk whitehawk changed the title ADBDEV-7586 - draft for CI Protect object creation from stealing referenced objects Jun 26, 2025
@whitehawk whitehawk changed the title Protect object creation from stealing referenced objects Protect object creation from dropping referenced objects Jun 27, 2025
@whitehawk whitehawk marked this pull request as ready for review June 27, 2025 03:37
@hilltracer hilltracer self-requested a review June 27, 2025 11:43
@RekGRpth
Copy link
Copy Markdown
Member

Deadlocks are possible. But it can be resolved by the deadlock detection algorithm. So, these 2 transactions trigger ERROR: deadlock detected with one of the transactions aborted.

Could you add a test for this?

Comment thread src/test/isolation2/expected/dependency.out Outdated
@RekGRpth
Copy link
Copy Markdown
Member

RekGRpth commented Jun 30, 2025

Is it expected that the patch does not cover the case where the object being deleted is used in the function body?

Type

diff --git a/src/test/isolation2/expected/dependency.out b/src/test/isolation2/expected/dependency.out
index f7a88622630..5d6df295a02 100644
--- a/src/test/isolation2/expected/dependency.out
+++ b/src/test/isolation2/expected/dependency.out
@@ -121,26 +121,28 @@ CREATE
 
 1: begin;
 BEGIN
-1: create function test_3_function(a test_3_type) returns text as $$ select 'Return ' || a; /**/ $$ language sql;
+1: create function test_3_function(a text) returns text as $$ select 'Return ' || a::test_3_type; /**/ $$ language sql;
 CREATE
 
 2&: drop type test_3_type;  <waiting ...>
+FAILED:  Forked command is not blocking; got output: DROP
 
 1: commit;
 COMMIT
 
 2<:  <... completed>
-ERROR:  cannot drop type test_3_type because other objects depend on it
-DETAIL:  function test_3_function(test_3_type) depends on type test_3_type
-HINT:  Use DROP ... CASCADE to drop the dependent objects too.
+FAILED:  Execution failed
 
 1: select test_3_function('one');
- test_3_function 
------------------
- Return one      
-(1 row)
+ERROR:  type "test_3_type" does not exist
+LINE 2:     select 'Return ' || a::test_3_type; /**/
+                                   ^
+QUERY:  
+    select 'Return ' || a::test_3_type; /**/
 
-drop type test_3_type cascade;
+CONTEXT:  SQL function "test_3_function" during inlining
+
+drop function test_3_function(a text) cascade;
 DROP
 
 -- Check if dependency is dropped before the creation of the dependent object.
@@ -152,13 +154,21 @@ BEGIN
 BEGIN
 2: drop type test_3_type;
 DROP
-1&: create function test_3_function(a test_3_type) returns text as $$ select 'Return ' || a; /**/ $$ language sql;  <waiting ...>
+1&: create function test_3_function(a text) returns text as $$ select 'Return ' || a::test_3_type; /**/ $$ language sql;  <waiting ...>
+FAILED:  Forked command is not blocking; got output: CREATE
 
 2: commit;
 COMMIT
 1<:  <... completed>
-ERROR:  cache lookup failed for type XXXXX (lsyscache.c:XXX)
-CONTEXT:  SQL function "test_3_function"
+FAILED:  Execution failed
+1: select test_3_function('one');
+ERROR:  type "test_3_type" does not exist
+LINE 2:     select 'Return ' || a::test_3_type; /**/
+                                   ^
+QUERY:  
+    select 'Return ' || a::test_3_type; /**/
+
+CONTEXT:  SQL function "test_3_function" during inlining
 1: end;
 END
 
diff --git a/src/test/isolation2/sql/dependency.sql b/src/test/isolation2/sql/dependency.sql
index b8bfe65a214..fe3afe39140 100644
--- a/src/test/isolation2/sql/dependency.sql
+++ b/src/test/isolation2/sql/dependency.sql
@@ -84,8 +84,8 @@ $$ language sql;
 create type test_3_type as enum ('one', 'two');
 
 1: begin;
-1: create function test_3_function(a test_3_type) returns text as $$
-    select 'Return ' || a; /**/
+1: create function test_3_function(a text) returns text as $$
+    select 'Return ' || a::test_3_type; /**/
 $$ language sql;
 
 2&: drop type test_3_type;
@@ -96,19 +96,20 @@ $$ language sql;
 
 1: select test_3_function('one');
 
-drop type test_3_type cascade;
+drop function test_3_function(a text) cascade;
 
 -- Check if dependency is dropped before the creation of the dependent object.
 create type test_3_type as enum ('one', 'two');
 1: begin;
 2: begin;
 2: drop type test_3_type;
-1&: create function test_3_function(a test_3_type) returns text as $$
-    select 'Return ' || a; /**/
+1&: create function test_3_function(a text) returns text as $$
+    select 'Return ' || a::test_3_type; /**/
 $$ language sql;
 
 2: commit;
 1<:
+1: select test_3_function('one');
 1: end;
 
 -- Case 4. Function dependency on the language.

Table

diff --git a/src/test/isolation2/expected/dependency.out b/src/test/isolation2/expected/dependency.out
index f7a88622630..ad632597a43 100644
--- a/src/test/isolation2/expected/dependency.out
+++ b/src/test/isolation2/expected/dependency.out
@@ -65,53 +65,53 @@ ERROR:  schema "test_1_schema" does not exist  (seg0 127.0.1.1:6002 pid=2715327)
 END
 
 -- Case 2. Function dependency on the return type.
-create type test_2_type as (a int);
+create table test_2_type (a int);
 CREATE
 
 1: begin;
 BEGIN
-1: create function test_2_function() returns setof test_2_type as $$ select i from generate_series(1,5)i; /**/ $$ language sql;
+1: create function test_2_function() returns setof int as $$ select * from test_2_type; /**/ $$ language sql;
 CREATE
 
-2&: drop type test_2_type;  <waiting ...>
+2&: drop table test_2_type;  <waiting ...>
 
 1: commit;
 COMMIT
 
 2<:  <... completed>
-ERROR:  cannot drop type test_2_type because other objects depend on it
-DETAIL:  function test_2_function() depends on type test_2_type
-HINT:  Use DROP ... CASCADE to drop the dependent objects too.
+DROP
 
 1: select test_2_function();
- test_2_function 
------------------
- (1)             
- (2)             
- (3)             
- (4)             
- (5)             
-(5 rows)
-
-drop type test_2_type cascade;
+ERROR:  relation "test_2_type" does not exist
+LINE 2:     select * from test_2_type; /**/
+                          ^
+QUERY:  
+    select * from test_2_type; /**/
+
+CONTEXT:  SQL function "test_2_function" during startup
+
+drop table test_2_type cascade;
+ERROR:  table "test_2_type" does not exist
+drop function test_2_function();
 DROP
 
 -- Check if dependency is dropped before the creation of the dependent object.
-create type test_2_type as (a int);
+create table test_2_type (a int);
 CREATE
 1: begin;
 BEGIN
 2: begin;
 BEGIN
-2: drop type test_2_type;
+2: drop table test_2_type;
 DROP
-1&: create function test_2_function() returns setof test_2_type as $$ select i from generate_series(1,5)i; /**/ $$ language sql;  <waiting ...>
+1&: create function test_2_function() returns setof int as $$ select * from test_2_type; /**/ $$ language sql;  <waiting ...>
 
 2: commit;
 COMMIT
 1<:  <... completed>
-ERROR:  cache lookup failed for type XXXXX (format_type.c:XXX)
-CONTEXT:  SQL function "test_2_function"
+ERROR:  relation "test_2_type" does not exist
+LINE 2:     select * from test_2_type; /**/
+                          ^
 1: end;
 END
 
diff --git a/src/test/isolation2/sql/dependency.sql b/src/test/isolation2/sql/dependency.sql
index b8bfe65a214..a1fdb32b9fb 100644
--- a/src/test/isolation2/sql/dependency.sql
+++ b/src/test/isolation2/sql/dependency.sql
@@ -50,14 +50,14 @@ $$ language sql;
 1: end;
 
 -- Case 2. Function dependency on the return type.
-create type test_2_type as (a int);
+create table test_2_type (a int);
 
 1: begin;
-1: create function test_2_function() returns setof test_2_type as $$
-    select i from generate_series(1,5)i; /**/
+1: create function test_2_function() returns setof int as $$
+    select * from test_2_type; /**/
 $$ language sql;
 
-2&: drop type test_2_type;
+2&: drop table test_2_type;
 
 1: commit;
 
@@ -65,15 +65,16 @@ $$ language sql;
 
 1: select test_2_function();
 
-drop type test_2_type cascade;
+drop table test_2_type cascade;
+drop function test_2_function();
 
 -- Check if dependency is dropped before the creation of the dependent object.
-create type test_2_type as (a int);
+create table test_2_type (a int);
 1: begin;
 2: begin;
-2: drop type test_2_type;
-1&: create function test_2_function() returns setof test_2_type as $$
-    select i from generate_series(1,5)i; /**/
+2: drop table test_2_type;
+1&: create function test_2_function() returns setof int as $$
+    select * from test_2_type; /**/
 $$ language sql;
 
 2: commit;

Default

diff --git a/src/test/isolation2/expected/dependency.out b/src/test/isolation2/expected/dependency.out
index f7a88622630..75024f2494e 100644
--- a/src/test/isolation2/expected/dependency.out
+++ b/src/test/isolation2/expected/dependency.out
@@ -215,26 +215,27 @@ CREATE
 
 1: begin;
 BEGIN
-1: create function test_5_function(a text default test5_default_value_function()) returns text as $$ begin return a; /**/ end $$ language plpgsql;
+1: create function test_5_function(a text default 'qwe') returns text as $$ declare b text default test5_default_value_function(); /**/ begin return a || b; /**/ end $$ language plpgsql;
 CREATE
 
 2&: drop function test5_default_value_function();  <waiting ...>
+FAILED:  Forked command is not blocking; got output: DROP
 
 1: commit;
 COMMIT
 
 2<:  <... completed>
-ERROR:  cannot drop function test5_default_value_function() because other objects depend on it
-DETAIL:  function test_5_function(text) depends on function test5_default_value_function()
-HINT:  Use DROP ... CASCADE to drop the dependent objects too.
+FAILED:  Execution failed
 
 1: select test_5_function();
- test_5_function 
------------------
- test            
-(1 row)
+ERROR:  function test5_default_value_function() does not exist
+LINE 1: SELECT test5_default_value_function()
+               ^
+HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
+QUERY:  SELECT test5_default_value_function()
+CONTEXT:  PL/pgSQL function test_5_function(text) line 4 during statement block local variable initialization
 
-drop function test5_default_value_function() cascade;
+drop function test_5_function(a text) cascade;
 DROP
 
 -- Check if dependency is dropped before the creation of the dependent object.
@@ -247,13 +248,13 @@ BEGIN
 BEGIN
 2: drop function test5_default_value_function();
 DROP
-1&: create function test_5_function(a text default test5_default_value_function()) returns text as $$ begin return a; /**/ end $$ language plpgsql;  <waiting ...>
+1&: create function test_5_function(a text default 'qwe') returns text as $$ declare b text default test5_default_value_function(); /**/ begin return a || b; /**/ end $$ language plpgsql;  <waiting ...>
+FAILED:  Forked command is not blocking; got output: CREATE
 
 2: commit;
 COMMIT
 1<:  <... completed>
-ERROR:  function test5_default_value_function() does not exist  (seg0 127.0.1.1:6002 pid=2718914)
-HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
+FAILED:  Execution failed
 1: end;
 END
 
diff --git a/src/test/isolation2/sql/dependency.sql b/src/test/isolation2/sql/dependency.sql
index b8bfe65a214..beee8115eff 100644
--- a/src/test/isolation2/sql/dependency.sql
+++ b/src/test/isolation2/sql/dependency.sql
@@ -152,10 +152,12 @@ create function test5_default_value_function() returns text as $$
 $$ language sql;
 
 1: begin;
-1: create function test_5_function(a text default test5_default_value_function()) returns text as
+1: create function test_5_function(a text default 'qwe') returns text as
 $$
+declare
+    b text default test5_default_value_function(); /**/
 begin
-	return a; /**/
+	return a || b; /**/
 end
 $$ language plpgsql;
 
@@ -167,7 +169,7 @@ $$ language plpgsql;
 
 1: select test_5_function();
 
-drop function test5_default_value_function() cascade;
+drop function test_5_function(a text) cascade;
 
 -- Check if dependency is dropped before the creation of the dependent object.
 create function test5_default_value_function() returns text as $$
@@ -177,10 +179,12 @@ $$ language sql;
 1: begin;
 2: begin;
 2: drop function test5_default_value_function();
-1&: create function test_5_function(a text default test5_default_value_function()) returns text as
+1&: create function test_5_function(a text default 'qwe') returns text as
 $$
+declare
+    b text default test5_default_value_function(); /**/
 begin
-	return a; /**/
+	return a || b; /**/
 end
 $$ language plpgsql;
 

@RekGRpth
Copy link
Copy Markdown
Member

RekGRpth commented Jun 30, 2025

Could you add tests for creating a view that depends on the function being removed, and for changing the column type of a table, and also for the rules that depend on the table being dropped?

@RekGRpth
Copy link
Copy Markdown
Member

Could you benchmark the performance degradation due to adding new extra locks?

hilltracer

This comment was marked as resolved.

@whitehawk
Copy link
Copy Markdown
Author

@hilltracer

Should we add the ticket number into the PR description?

I usually do not add it, as it can be obtained from the branch name. And it is not mandated by the review checklist.

Maybe add a regression test that checks pg_locks to ensure we don't add extra locks for pinned objects (e.g., int4, text, etc.).

Maybe also add a test that checks pg_locks to show how the added locks are distributed across our MPP between the coordinator and segments?

I've added check of pg_locks into the first couple of test cases.


@RekGRpth

Could you benchmark the performance degradation due to adding new extra locks?

I've done performance testing with the help of functions below:

CREATE OR REPLACE FUNCTION create_many_objects()
RETURNS VOID
AS $$
BEGIN
	for counter in 1..1000 loop
		EXECUTE FORMAT($fmt$CREATE TYPE new_type_%1$s as enum ('one', 'two');$fmt$,
			counter);
		EXECUTE FORMAT($fmt$CREATE TABLE new_table_%1$s (a new_type_%1$s, b new_type_%1$s, c new_type_%1$s) DISTRIBUTED BY (a);$fmt$,
			counter);
	end loop;
END$$
LANGUAGE plpgsql VOLATILE
EXECUTE ON MASTER;

CREATE OR REPLACE FUNCTION remove_many_objects()
RETURNS VOID
AS $$
BEGIN
	-- cleanup
	for counter in 1..1000 loop
		EXECUTE FORMAT($fmt$DROP table new_table_%1$s;$fmt$,
			counter);
		EXECUTE FORMAT($fmt$DROP TYPE new_type_%1$s;$fmt$,
			counter);
	end loop;
END$$
LANGUAGE plpgsql VOLATILE
EXECUTE ON MASTER;

commands used for perf measurement:

for i in {1..10};
do
	TIME="\t%E sec" time psql postgres -c "select create_many_objects();" > /dev/null
	psql postgres -c "select remove_many_objects();" > /dev/null
done

results without the patch:

        0:13.64 sec
        0:19.30 sec
        0:22.13 sec
        0:21.60 sec
        0:19.96 sec
        0:20.14 sec
        0:21.98 sec
        0:21.73 sec
        0:22.72 sec
        0:21.62 sec

total 204,82 sec.

results with the patch:

        0:14.24 sec
        0:21.03 sec
        0:22.06 sec
        0:22.06 sec
        0:20.36 sec
        0:20.16 sec
        0:21.23 sec
        0:21.71 sec
        0:21.60 sec
        0:20.81 sec

total 205,26 sec.

So the difference between total numbers looks neglectable.

Could you add tests for creating a view that depends on the function being removed,
and for changing the column type of a table, and also for the rules that depend on the table being dropped?

Added

Is it expected that the patch does not cover the case where the object being deleted is used in the function body?

Yes, according to postgres documentation:
For a user-defined function or procedure whose body is defined as a string literal, PostgreSQL tracks dependencies associated with the function's externally-visible properties, such as its argument and result types, but not dependencies that could only be known by examining the function body.

Deadlocks are possible. But it can be resolved by the deadlock detection algorithm. So, these 2 transactions trigger ERROR: deadlock detected with one of the transactions aborted.

Could you add a test for this?

Added.

@whitehawk whitehawk marked this pull request as ready for review July 3, 2025 11:34
hilltracer

This comment was marked as resolved.

@whitehawk
Copy link
Copy Markdown
Author

@hilltracer

Good result, but it only shows performance in a single-session scenario. What happens if multiple sessions create objects in parallel and all access the same referenced objects, putting more pressure on the lock manager?
Maybe run another experiment where many clients each execute create_many_objects() in their own transaction?

Ok,

test code in sql
CREATE OR REPLACE FUNCTION create_many_types()
RETURNS VOID
AS $$
BEGIN
	for counter in 1..1000 loop
		EXECUTE FORMAT($fmt$CREATE TYPE new_type_%1$s as enum ('one', 'two');$fmt$,
			counter);
	end loop;
END$$
LANGUAGE plpgsql VOLATILE
EXECUTE ON MASTER;

CREATE OR REPLACE FUNCTION create_many_tables()
RETURNS VOID
AS $$
DECLARE
    backend_pid INTEGER;
BEGIN
	select pg_backend_pid() into backend_pid;
	for counter in 1..1000 loop
		EXECUTE FORMAT($fmt$CREATE TABLE new_table_%2$s_%1$s (a new_type_%1$s, b new_type_%1$s, c new_type_%1$s) DISTRIBUTED BY (a);$fmt$,
			counter, backend_pid);
	end loop;
END$$
LANGUAGE plpgsql VOLATILE
EXECUTE ON MASTER;

select create_many_types();
test command
for i in {1..10};
do
	seq 10 | parallel --bar -j 10 --gnu "DUMMY={}; TIME=\"\t%E sec\" time psql postgres -c \"begin; select create_many_tables(); rollback;\" > /dev/null"
done
Test results without the patch
for i in {1..10};
do
        seq 10 | parallel --bar -j 10 --gnu "DUMMY={}; TIME=\"\t%E sec\" time psql postgres -c \"begin; select create_many_tables(); rollback;\" > /dev/null"
done
0% 0:10=0s 10                                                                                                                                                                    1:55.87 sec
10% 1:9=9s 10                                                                                                                                                                    1:56.64 sec
20% 2:8=6s 10                                                                                                                                                                    1:57.55 sec
30% 3:7=5s 10                                                                                                                                                                    1:57.55 sec
40% 4:6=3s 10                                                                                                                                                                    1:57.52 sec
50% 5:5=2s 10                                                                                                                                                                    1:57.77 sec
60% 6:4=1s 10                                                                                                                                                                    1:58.00 sec
70% 7:3=0s 10                                                                                                                                                                    1:58.02 sec
80% 8:2=0s 10                                                                                                                                                                    1:58.07 sec
90% 9:1=0s 10                                                                                                                                                                    1:58.39 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:24.24 sec
10% 1:9=0s 10                                                                                                                                                                    2:24.51 sec
20% 2:8=4s 10                                                                                                                                                                    2:25.35 sec
30% 3:7=2s 10                                                                                                                                                                    2:25.48 sec
40% 4:6=1s 10                                                                                                                                                                    2:25.65 sec
50% 5:5=1s 10                                                                                                                                                                    2:26.07 sec
60% 6:4=1s 10                                                                                                                                                                    2:26.55 sec
70% 7:3=0s 10                                                                                                                                                                    2:26.63 sec
80% 8:2=0s 10                                                                                                                                                                    2:26.85 sec
90% 9:1=0s 10                                                                                                                                                                    2:26.86 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:26.07 sec
10% 1:9=0s 10                                                                                                                                                                    2:26.39 sec
20% 2:8=0s 10                                                                                                                                                                    2:26.42 sec
30% 3:7=2s 10                                                                                                                                                                    2:27.60 sec
40% 4:6=2s 10                                                                                                                                                                    2:27.91 sec
50% 5:5=2s 10                                                                                                                                                                    2:27.96 sec
60% 6:4=1s 10                                                                                                                                                                    2:27.99 sec
70% 7:3=0s 10                                                                                                                                                                    2:28.00 sec
80% 8:2=0s 10                                                                                                                                                                    2:28.19 sec
90% 9:1=0s 10                                                                                                                                                                    2:28.72 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:27.51 sec
10% 1:9=9s 10                                                                                                                                                                    2:27.86 sec
20% 2:8=6s 10                                                                                                                                                                    2:28.80 sec
30% 3:7=5s 10                                                                                                                                                                    2:29.75 sec
40% 4:6=4s 10                                                                                                                                                                    2:30.20 sec
50% 5:5=3s 10                                                                                                                                                                    2:30.26 sec
60% 6:4=2s 10                                                                                                                                                                    2:30.82 sec
70% 7:3=1s 10                                                                                                                                                                    2:30.82 sec
80% 8:2=1s 10                                                                                                                                                                    2:31.53 sec
90% 9:1=0s 10                                                                                                                                                                    2:31.55 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:27.72 sec
10% 1:9=9s 10                                                                                                                                                                    2:27.96 sec
20% 2:8=6s 10                                                                                                                                                                    2:29.30 sec
30% 3:7=5s 10                                                                                                                                                                    2:29.31 sec
40% 4:6=3s 10                                                                                                                                                                    2:29.61 sec
50% 5:5=2s 10                                                                                                                                                                    2:29.89 sec
60% 6:4=1s 10                                                                                                                                                                    2:30.34 sec
70% 7:3=1s 10                                                                                                                                                                    2:30.68 sec
80% 8:2=0s 10                                                                                                                                                                    2:30.73 sec
90% 9:1=0s 10                                                                                                                                                                    2:30.82 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:26.57 sec
10% 1:9=9s 10                                                                                                                                                                    2:27.59 sec
20% 2:8=7s 10                                                                                                                                                                    2:27.99 sec
30% 3:7=5s 10                                                                                                                                                                    2:28.91 sec
40% 4:6=4s 10                                                                                                                                                                    2:28.96 sec
50% 5:5=3s 10                                                                                                                                                                    2:28.94 sec
60% 6:4=2s 10                                                                                                                                                                    2:29.04 sec
70% 7:3=1s 10                                                                                                                                                                    2:29.18 sec
80% 8:2=0s 10                                                                                                                                                                    2:29.57 sec
90% 9:1=0s 10                                                                                                                                                                    2:29.70 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:26.86 sec
10% 1:9=9s 10                                                                                                                                                                    2:27.42 sec
20% 2:8=7s 10                                                                                                                                                                    2:28.56 sec
30% 3:7=6s 10                                                                                                                                                                    2:29.46 sec
40% 4:6=4s 10                                                                                                                                                                    2:29.84 sec
50% 5:5=3s 10                                                                                                                                                                    2:30.12 sec
60% 6:4=2s 10                                                                                                                                                                    2:30.61 sec
70% 7:3=1s 10                                                                                                                                                                    2:30.72 sec
80% 8:2=1s 10                                                                                                                                                                    2:30.72 sec
90% 9:1=0s 10                                                                                                                                                                    2:30.81 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:25.62 sec
10% 1:9=12s 10                                                                                                                                                                   2:28.45 sec
20% 2:8=12s 10                                                                                                                                                                   2:28.56 sec
30% 3:7=9s 10                                                                                                                                                                    2:29.46 sec
40% 4:6=7s 10                                                                                                                                                                    2:29.53 sec
50% 5:5=4s 10                                                                                                                                                                    2:29.52 sec
60% 6:4=2s 10                                                                                                                                                                    2:29.65 sec
70% 7:3=2s 10                                                                                                                                                                    2:29.94 sec
80% 8:2=1s 10                                                                                                                                                                    2:30.11 sec
90% 9:1=0s 10                                                                                                                                                                    2:30.49 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:29.41 sec
10% 1:9=0s 10                                                                                                                                                                    2:29.45 sec
20% 2:8=4s 10                                                                                                                                                                    2:30.29 sec
30% 3:7=2s 10                                                                                                                                                                    2:30.63 sec
40% 4:6=2s 10                                                                                                                                                                    2:31.20 sec
50% 5:5=1s 10                                                                                                                                                                    2:31.26 sec
60% 6:4=1s 10                                                                                                                                                                    2:31.54 sec
70% 7:3=0s 10                                                                                                                                                                    2:31.68 sec
80% 8:2=0s 10                                                                                                                                                                    2:31.79 sec
90% 9:1=0s 10                                                                                                                                                                    2:32.01 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:28.13 sec
10% 1:9=9s 10                                                                                                                                                                    2:28.81 sec
20% 2:8=6s 10                                                                                                                                                                    2:29.14 sec
30% 3:7=3s 10                                                                                                                                                                    2:29.27 sec
40% 4:6=1s 10                                                                                                                                                                    2:29.47 sec
50% 5:5=1s 10                                                                                                                                                                    2:29.95 sec
60% 6:4=1s 10                                                                                                                                                                    2:30.52 sec
70% 7:3=0s 10                                                                                                                                                                    2:30.56 sec
80% 8:2=0s 10                                                                                                                                                                    2:30.86 sec
90% 9:1=0s 10                                                                                                                                                                    2:31.22 sec
100% 10:0=0s 10

In summ - 04h:03m:04s,37 (14584,37 sec)

Test results with the patch
for i in {1..10};
do
        seq 10 | parallel --bar -j 10 --gnu "DUMMY={}; TIME=\"\t%E sec\" time psql postgres -c \"begin; select create_many_tables(); rollback;\" > /dev/null"
done
0% 0:10=0s 10                                                                                                                                                                    2:02.79 sec
10% 1:9=0s 10                                                                                                                                                                    2:02.86 sec
20% 2:8=4s 10                                                                                                                                                                    2:04.28 sec
30% 3:7=2s 10                                                                                                                                                                    2:04.43 sec
40% 4:6=2s 10                                                                                                                                                                    2:04.46 sec
50% 5:5=1s 10                                                                                                                                                                    2:05.27 sec
60% 6:4=1s 10                                                                                                                                                                    2:05.51 sec
70% 7:3=1s 10                                                                                                                                                                    2:05.76 sec
80% 8:2=0s 10                                                                                                                                                                    2:05.95 sec
90% 9:1=0s 10                                                                                                                                                                    2:05.96 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:29.97 sec
10% 1:9=9s 10                                                                                                                                                                    2:31.61 sec
20% 2:8=8s 10                                                                                                                                                                    2:31.77 sec
30% 3:7=6s 10                                                                                                                                                                    2:32.77 sec
40% 4:6=5s 10                                                                                                                                                                    2:33.24 sec
50% 5:5=4s 10                                                                                                                                                                    2:33.47 sec
60% 6:4=2s 10                                                                                                                                                                    2:33.47 sec
70% 7:3=1s 10                                                                                                                                                                    2:33.59 sec
80% 8:2=1s 10                                                                                                                                                                    2:33.64 sec
90% 9:1=0s 10                                                                                                                                                                    2:33.94 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:35.46 sec
10% 1:9=0s 10                                                                                                                                                                    2:35.85 sec
20% 2:8=4s 10                                                                                                                                                                    2:36.66 sec
30% 3:7=4s 10                                                                                                                                                                    2:37.42 sec
40% 4:6=3s 10                                                                                                                                                                    2:37.88 sec
50% 5:5=2s 10                                                                                                                                                                    2:38.19 sec
60% 6:4=2s 10                                                                                                                                                                    2:38.24 sec
70% 7:3=1s 10                                                                                                                                                                    2:38.30 sec
80% 8:2=0s 10                                                                                                                                                                    2:38.38 sec
90% 9:1=0s 10                                                                                                                                                                    2:38.61 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:37.60 sec
10% 1:9=0s 10                                                                                                                                                                    2:37.76 sec
20% 2:8=0s 10                                                                                                                                                                    2:38.02 sec
30% 3:7=3s 10                                                                                                                                                                    2:39.73 sec
40% 4:6=3s 10                                                                                                                                                                    2:39.81 sec
50% 5:5=2s 10                                                                                                                                                                    2:40.04 sec
60% 6:4=1s 10                                                                                                                                                                    2:40.11 sec
70% 7:3=0s 10                                                                                                                                                                    2:40.15 sec
80% 8:2=0s 10                                                                                                                                                                    2:40.18 sec
90% 9:1=0s 10                                                                                                                                                                    2:40.46 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:36.77 sec
10% 1:9=9s 10                                                                                                                                                                    2:38.60 sec
20% 2:8=8s 10                                                                                                                                                                    2:38.82 sec
30% 3:7=5s 10                                                                                                                                                                    2:39.25 sec
40% 4:6=4s 10                                                                                                                                                                    2:39.86 sec
50% 5:5=3s 10                                                                                                                                                                    2:39.93 sec
60% 6:4=2s 10                                                                                                                                                                    2:40.15 sec
70% 7:3=1s 10                                                                                                                                                                    2:40.16 sec
80% 8:2=0s 10                                                                                                                                                                    2:40.21 sec
90% 9:1=0s 10                                                                                                                                                                    2:40.50 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:37.85 sec
10% 1:9=0s 10                                                                                                                                                                    2:37.88 sec
20% 2:8=4s 10                                                                                                                                                                    2:38.92 sec
30% 3:7=3s 10                                                                                                                                                                    2:39.65 sec
40% 4:6=2s 10                                                                                                                                                                    2:39.73 sec
50% 5:5=2s 10                                                                                                                                                                    2:39.96 sec
60% 6:4=1s 10                                                                                                                                                                    2:40.00 sec
70% 7:3=0s 10                                                                                                                                                                    2:40.09 sec
80% 8:2=0s 10                                                                                                                                                                    2:40.48 sec
90% 9:1=0s 10                                                                                                                                                                    2:40.71 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:36.91 sec
10% 1:9=0s 10                                                                                                                                                                    2:37.32 sec
20% 2:8=0s 10                                                                                                                                                                    2:37.35 sec
30% 3:7=0s 10                                                                                                                                                                    2:37.41 sec
40% 4:6=1s 10                                                                                                                                                                    2:38.60 sec
50% 5:5=1s 10                                                                                                                                                                    2:38.89 sec
60% 6:4=1s 10                                                                                                                                                                    2:39.55 sec
70% 7:3=0s 10                                                                                                                                                                    2:39.58 sec
80% 8:2=0s 10                                                                                                                                                                    2:39.57 sec
90% 9:1=0s 10                                                                                                                                                                    2:40.04 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:34.69 sec
10% 1:9=0s 10                                                                                                                                                                    2:35.04 sec
20% 2:8=4s 10                                                                                                                                                                    2:35.89 sec
30% 3:7=3s 10                                                                                                                                                                    2:36.41 sec
40% 4:6=3s 10                                                                                                                                                                    2:37.00 sec
50% 5:5=2s 10                                                                                                                                                                    2:37.06 sec
60% 6:4=1s 10                                                                                                                                                                    2:37.07 sec
70% 7:3=0s 10                                                                                                                                                                    2:37.21 sec
80% 8:2=0s 10                                                                                                                                                                    2:37.19 sec
90% 9:1=0s 10                                                                                                                                                                    2:37.21 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:36.41 sec
10% 1:9=9s 10                                                                                                                                                                    2:36.71 sec
20% 2:8=5s 10                                                                                                                                                                    2:37.29 sec
30% 3:7=3s 10                                                                                                                                                                    2:37.80 sec
40% 4:6=3s 10                                                                                                                                                                    2:38.08 sec
50% 5:5=2s 10                                                                                                                                                                    2:38.29 sec
60% 6:4=1s 10                                                                                                                                                                    2:38.33 sec
70% 7:3=0s 10                                                                                                                                                                    2:38.54 sec
80% 8:2=0s 10                                                                                                                                                                    2:38.68 sec
90% 9:1=0s 10                                                                                                                                                                    2:38.94 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:39.42 sec
10% 1:9=9s 10                                                                                                                                                                    2:39.68 sec
20% 2:8=5s 10                                                                                                                                                                    2:40.39 sec
30% 3:7=3s 10                                                                                                                                                                    2:40.41 sec
40% 4:6=3s 10                                                                                                                                                                    2:40.99 sec
50% 5:5=2s 10                                                                                                                                                                    2:41.08 sec
60% 6:4=1s 10                                                                                                                                                                    2:41.25 sec
70% 7:3=1s 10                                                                                                                                                                    2:41.71 sec
80% 8:2=0s 10                                                                                                                                                                    2:41.77 sec
90% 9:1=0s 10                                                                                                                                                                    2:42.09 sec
100% 10:0=0s 10

In summ - 04h:17m:50s,96 (15470,96 sec), the delta is ~6% slower.

And one more round with the patch
for i in {1..10};
do
        seq 10 | parallel --bar -j 10 --gnu "DUMMY={}; TIME=\"\t%E sec\" time psql postgres -c \"begin; select create_many_tables(); rollback;\" > /dev/null"
done
0% 0:10=0s 10                                                                                                                                                                    2:19.11 sec
10% 1:9=9s 10                                                                                                                                                                    2:20.41 sec
20% 2:8=6s 10                                                                                                                                                                    2:20.56 sec
30% 3:7=4s 10                                                                                                                                                                    2:20.86 sec
40% 4:6=3s 10                                                                                                                                                                    2:21.69 sec
50% 5:5=3s 10                                                                                                                                                                    2:22.47 sec
60% 6:4=2s 10                                                                                                                                                                    2:22.52 sec
70% 7:3=1s 10                                                                                                                                                                    2:22.60 sec
80% 8:2=0s 10                                                                                                                                                                    2:22.63 sec
90% 9:1=0s 10                                                                                                                                                                    2:23.13 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:13.72 sec
10% 1:9=9s 10                                                                                                                                                                    2:14.32 sec
20% 2:8=6s 10                                                                                                                                                                    2:14.33 sec
30% 3:7=3s 10                                                                                                                                                                    2:14.75 sec
40% 4:6=2s 10                                                                                                                                                                    2:15.39 sec
50% 5:5=2s 10                                                                                                                                                                    2:15.52 sec
60% 6:4=1s 10                                                                                                                                                                    2:15.81 sec
70% 7:3=0s 10                                                                                                                                                                    2:15.82 sec
80% 8:2=0s 10                                                                                                                                                                    2:15.89 sec
90% 9:1=0s 10                                                                                                                                                                    2:16.33 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:08.80 sec
10% 1:9=9s 10                                                                                                                                                                    2:09.69 sec
20% 2:8=5s 10                                                                                                                                                                    2:10.11 sec
30% 3:7=2s 10                                                                                                                                                                    2:10.38 sec
40% 4:6=1s 10                                                                                                                                                                    2:10.53 sec
50% 5:5=1s 10                                                                                                                                                                    2:10.64 sec
60% 6:4=1s 10                                                                                                                                                                    2:10.62 sec
70% 7:3=0s 10                                                                                                                                                                    2:10.71 sec
80% 8:2=0s 10                                                                                                                                                                    2:11.00 sec
90% 9:1=0s 10                                                                                                                                                                    2:11.30 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:13.37 sec
10% 1:9=0s 10                                                                                                                                                                    2:13.59 sec
20% 2:8=0s 10                                                                                                                                                                    2:13.88 sec
30% 3:7=2s 10                                                                                                                                                                    2:14.33 sec
40% 4:6=1s 10                                                                                                                                                                    2:14.77 sec
50% 5:5=1s 10                                                                                                                                                                    2:15.00 sec
60% 6:4=1s 10                                                                                                                                                                    2:15.22 sec
70% 7:3=0s 10                                                                                                                                                                    2:15.49 sec
80% 8:2=0s 10                                                                                                                                                                    2:15.54 sec
90% 9:1=0s 10                                                                                                                                                                    2:15.66 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:12.75 sec
10% 1:9=9s 10                                                                                                                                                                    2:13.50 sec
20% 2:8=6s 10                                                                                                                                                                    2:13.73 sec
30% 3:7=3s 10                                                                                                                                                                    2:14.07 sec
40% 4:6=2s 10                                                                                                                                                                    2:14.23 sec
50% 5:5=2s 10                                                                                                                                                                    2:14.30 sec
60% 6:4=1s 10                                                                                                                                                                    2:14.38 sec
70% 7:3=0s 10                                                                                                                                                                    2:14.39 sec
80% 8:2=0s 10                                                                                                                                                                    2:14.90 sec
90% 9:1=0s 10                                                                                                                                                                    2:15.10 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:10.41 sec
10% 1:9=9s 10                                                                                                                                                                    2:11.46 sec
20% 2:8=6s 10                                                                                                                                                                    2:11.68 sec
30% 3:7=4s 10                                                                                                                                                                    2:12.05 sec
40% 4:6=3s 10                                                                                                                                                                    2:12.38 sec
50% 5:5=2s 10                                                                                                                                                                    2:12.75 sec
60% 6:4=2s 10                                                                                                                                                                    2:13.00 sec
70% 7:3=1s 10                                                                                                                                                                    2:13.26 sec
80% 8:2=0s 10                                                                                                                                                                    2:13.50 sec
90% 9:1=0s 10                                                                                                                                                                    2:13.59 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:14.03 sec
10% 1:9=0s 10                                                                                                                                                                    2:13.98 sec
20% 2:8=4s 10                                                                                                                                                                    2:15.17 sec
30% 3:7=2s 10                                                                                                                                                                    2:15.41 sec
40% 4:6=2s 10                                                                                                                                                                    2:15.38 sec
50% 5:5=1s 10                                                                                                                                                                    2:16.04 sec
60% 6:4=1s 10                                                                                                                                                                    2:16.06 sec
70% 7:3=0s 10                                                                                                                                                                    2:16.12 sec
80% 8:2=0s 10                                                                                                                                                                    2:16.12 sec
90% 9:1=0s 10                                                                                                                                                                    2:16.41 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:15.40 sec
10% 1:9=0s 10                                                                                                                                                                    2:15.51 sec
20% 2:8=4s 10                                                                                                                                                                    2:16.33 sec
30% 3:7=2s 10                                                                                                                                                                    2:16.64 sec
40% 4:6=1s 10                                                                                                                                                                    2:16.68 sec
50% 5:5=1s 10                                                                                                                                                                    2:16.77 sec
60% 6:4=0s 10                                                                                                                                                                    2:17.00 sec
70% 7:3=0s 10                                                                                                                                                                    2:17.07 sec
80% 8:2=0s 10                                                                                                                                                                    2:17.36 sec
90% 9:1=0s 10                                                                                                                                                                    2:17.95 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:12.87 sec
10% 1:9=0s 10                                                                                                                                                                    2:13.85 sec
20% 2:8=4s 10                                                                                                                                                                    2:14.01 sec
30% 3:7=2s 10                                                                                                                                                                    2:14.44 sec
40% 4:6=1s 10                                                                                                                                                                    2:14.89 sec
50% 5:5=1s 10                                                                                                                                                                    2:14.95 sec
60% 6:4=1s 10                                                                                                                                                                    2:15.20 sec
70% 7:3=0s 10                                                                                                                                                                    2:15.73 sec
80% 8:2=0s 10                                                                                                                                                                    2:15.90 sec
90% 9:1=0s 10                                                                                                                                                                    2:15.88 sec
100% 10:0=0s 10
0% 0:10=0s 10                                                                                                                                                                    2:19.08 sec
10% 1:9=0s 10                                                                                                                                                                    2:19.04 sec
20% 2:8=0s 10                                                                                                                                                                    2:19.36 sec
30% 3:7=2s 10                                                                                                                                                                    2:19.80 sec
40% 4:6=1s 10                                                                                                                                                                    2:20.57 sec
50% 5:5=1s 10                                                                                                                                                                    2:20.78 sec
60% 6:4=1s 10                                                                                                                                                                    2:20.87 sec
70% 7:3=0s 10                                                                                                                                                                    2:20.90 sec
80% 8:2=0s 10                                                                                                                                                                    2:21.13 sec
90% 9:1=0s 10                                                                                                                                                                    2:21.20 sec
100% 10:0=0s 10

In summ - 03h:45m:55s,80 (13555.8 sec) which is ~7% faster than without the patch.

So, in general looks ok from my point of view.

Also maybe discover Tom Lane’s concern about blowing past max_locks_per_transaction during a big pg_restore --single-transaction. So we can do something like SELECT count(*) FROM pg_locks WHERE pid = pg_backend_pid(); after create_many_objects() but before commit, query. And compare counts pre/post patch.

Without the patch:

postgres=# begin;
SELECT count(*) FROM pg_locks WHERE pid = pg_backend_pid();
select create_many_tables();
SELECT count(*) FROM pg_locks WHERE pid = pg_backend_pid();
rollback;
BEGIN
 count
-------
     3
(1 row)

 create_many_tables
--------------------

(1 row)

 count
-------
  1007
(1 row)

ROLLBACK

With the patch:

postgres=# begin;
SELECT count(*) FROM pg_locks WHERE pid = pg_backend_pid();
select create_many_tables();
SELECT count(*) FROM pg_locks WHERE pid = pg_backend_pid();
rollback;
BEGIN
 count
-------
     3
(1 row)

 create_many_tables
--------------------

(1 row)

 count
-------
  2007
(1 row)

ROLLBACK

The locks delta here (1000 locks) is expected, as we are creating 1000 tables, and each one depends on its own type.
Each table has 3 references for 1 type, and we do not duplicate these locks.
That's the price we need to pay - 1 lock per 1 unique dependency.

And, as you can see, even without the patch, we can easily hit the value of thousands of locks, if we need to create thousands of tables. Therefore, restore of a large database with many objects in a single transaction anyway can hit the limit.

Should we also check behavior with REPEATABLE READ and SERIALIZABLE in tests? Maybe add one case to show behavior with other isolation level, I hope it's should be identical.

Added test for REPEATABLE READ. SERIALIZABLE is not supported in GPDB - "If you specify SERIALIZABLE, Greenplum Database falls back to REPEATABLE READ.".

hilltracer
hilltracer previously approved these changes Jul 9, 2025
Copy link
Copy Markdown

@hilltracer hilltracer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the detailed experiments. I think we're now ready to present our results for Tom Lane and co.

Comment thread src/backend/catalog/pg_depend.c Outdated
Comment thread src/backend/catalog/pg_depend.c Outdated
Comment thread src/test/isolation2/sql/dependency.sql Outdated
Comment thread src/backend/catalog/pg_depend.c
Comment thread src/test/isolation2/sql/dependency.sql Outdated
Comment thread src/test/isolation2/sql/dependency.sql Outdated
Comment thread src/test/isolation2/sql/dependency.sql
Comment thread src/test/isolation2/expected/dependency.out
@whitehawk whitehawk merged commit 769ddb3 into adb-6.x-dev Jul 10, 2025
5 checks passed
@whitehawk whitehawk deleted the ADBDEV-7586 branch July 10, 2025 10:52
whitehawk added a commit that referenced this pull request Jul 11, 2025
Problem description:
If an object had been created inside a transaction and it had a dependency on
some other object (like schema, custom data type, etc), and that referenced
object had been dropped from another transaction before the first transaction
had been committed, the new object was broken.

Ex. steps:
```
Session 1: create type test_type as enum ('one', 'two');
Session 1: begin;
Session 1: create table test_table(a test_type);
Session 2: drop type test_type;
Session 1: commit;
Session 1: select * from test_table;
```
gave result:
```
ERROR:  cache lookup failed for type 16385 (lsyscache.c:2796)
```

The issue reproduced for all dependencies that are registered in 'pg_depend'.

Root cause:
No protection from stealing the objects that are marked as dependencies in
'pg_depend' before the transaction is committed.

Fix:
Lock the referenced object with AccessShareLock when the dependency is created.
Lock is done only for 'normal' dependencies (which means here 'normal
relationship between separately-created objects', when the dependent object may
be dropped without affecting the referenced object, while the referenced object
may only be dropped with CASCADE, in which case the dependent object is dropped
too) and 'auto' (meaning that the dependent object can be dropped separately
from the referenced object, and should be automatically dropped if the
referenced object is dropped).
After the lock is released, do a recheck of the object's presence and error out
if the object was dropped while we waited for the lock.

(cherry picked from commit 769ddb3)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants