Hi,

Michael pointed out a problem with specifying different ON COMMIT actions
on a temporary inheritance parent and its children:

https://www.postgresql.org/message-id/20181102051804.GV1727%40paquier.xyz

The problem is that when PreCommit_on_commit_actions() executes an ON
COMMIT DROP action on the parent, it will drop its children as well.  It
doesn't however remove the children's own actions, especially ON COMMIT
DELETE ROWS, from the list and when it gets around to executing them, the
children are already gone.  That causes the heap_open in heap_truncate to
fail with an error like this:

ERROR:  XX000: could not open relation with OID 16420
LOCATION:  relation_open, heapam.c:1138

One way to fix that is to remove the tables that no longer exist from the
list that's passed to heap_truncate(), which the attached patch implements.

Thanks,
Amit
From 37c97e6b9879b130a80305fd794a9e721332cb98 Mon Sep 17 00:00:00 2001
From: amit <amitlangot...@gmail.com>
Date: Fri, 2 Nov 2018 15:26:37 +0900
Subject: [PATCH] Check relation still exists before applying ON COMMIT action

---
 src/backend/commands/tablecmds.c   | 17 +++++++++++++++++
 src/test/regress/expected/temp.out | 23 +++++++++++++++++++++++
 src/test/regress/sql/temp.sql      | 15 +++++++++++++++
 3 files changed, 55 insertions(+)

diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 6048334c75..5b17a8679d 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -13353,6 +13353,23 @@ PreCommit_on_commit_actions(void)
        }
        if (oids_to_truncate != NIL)
        {
+               List   *tmp = oids_to_truncate;
+
+               /*
+                * Check that relations we're about to truncate still exist.  
Some of
+                * them might be inheritance children, which would be gone as a 
result
+                * of their parent being dropped due to ONCOMMIT_DROP action of 
its
+                * own.
+                */
+               oids_to_truncate = NIL;
+               foreach(l, tmp)
+               {
+                       Oid             relid = lfirst_oid(l);
+
+                       if (SearchSysCacheExists1(RELOID, 
ObjectIdGetDatum(relid)))
+                               oids_to_truncate = 
lappend_oid(oids_to_truncate, relid);
+               }
+
                heap_truncate(oids_to_truncate);
                CommandCounterIncrement();      /* XXX needed? */
        }
diff --git a/src/test/regress/expected/temp.out 
b/src/test/regress/expected/temp.out
index a769abe9bb..70be46ca1d 100644
--- a/src/test/regress/expected/temp.out
+++ b/src/test/regress/expected/temp.out
@@ -216,3 +216,26 @@ select * from temp_parted_oncommit;
 (0 rows)
 
 drop table temp_parted_oncommit;
+-- Another case where a child table is gone by the time it's ON COMMIT
+-- action is executed due to the ON COMMIT DROP action on its parent
+-- There are tests for both a partitioned table and regular inheritance.
+begin;
+create temp table temp_parted_oncommit_test (a int) partition by list (a) on 
commit drop;
+create temp table temp_parted_oncommit_test1 partition of 
temp_parted_oncommit_test for values in (1) on commit delete rows;
+insert into temp_parted_oncommit_test values (1);
+create temp table temp_inh_oncommit_test (a int) on commit drop;
+create temp table temp_inh_oncommit_test1 () inherits(temp_inh_oncommit_test) 
on commit delete rows;
+insert into temp_inh_oncommit_test1 values (1);
+commit;
+NOTICE:  drop cascades to table temp_inh_oncommit_test1
+-- zero rows in both cases
+select relname from pg_class where relname like 'temp_parted_oncommit_test%';
+ relname 
+---------
+(0 rows)
+
+select relname from pg_class where relname like 'temp_inh_oncommit_test%';
+ relname 
+---------
+(0 rows)
+
diff --git a/src/test/regress/sql/temp.sql b/src/test/regress/sql/temp.sql
index 1074c7cfac..ad8c5cb85a 100644
--- a/src/test/regress/sql/temp.sql
+++ b/src/test/regress/sql/temp.sql
@@ -165,3 +165,18 @@ commit;
 -- partitions are emptied by the previous commit
 select * from temp_parted_oncommit;
 drop table temp_parted_oncommit;
+
+-- Another case where a child table is gone by the time it's ON COMMIT
+-- action is executed due to the ON COMMIT DROP action on its parent
+-- There are tests for both a partitioned table and regular inheritance.
+begin;
+create temp table temp_parted_oncommit_test (a int) partition by list (a) on 
commit drop;
+create temp table temp_parted_oncommit_test1 partition of 
temp_parted_oncommit_test for values in (1) on commit delete rows;
+insert into temp_parted_oncommit_test values (1);
+create temp table temp_inh_oncommit_test (a int) on commit drop;
+create temp table temp_inh_oncommit_test1 () inherits(temp_inh_oncommit_test) 
on commit delete rows;
+insert into temp_inh_oncommit_test1 values (1);
+commit;
+-- zero rows in both cases
+select relname from pg_class where relname like 'temp_parted_oncommit_test%';
+select relname from pg_class where relname like 'temp_inh_oncommit_test%';
-- 
2.11.0

Reply via email to