From d4486700b58387e6b4d0304a61d0d89f1031595c Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Thu, 27 Dec 2018 10:17:13 +0900 Subject: Ignore inherited temp relations from other sessions when truncating Inheritance trees can include temporary tables if the parent is permanent, which makes possible the presence of multiple temporary children from different sessions. Trying to issue a TRUNCATE on the parent in this scenario causes a failure, so similarly to any other queries just ignore such cases, which makes TRUNCATE work transparently. This makes truncation behave similarly to any other DML query working on the parent table with queries which need to be issues on children. A set of isolation tests is added to cover basic cases. Reported-by: Zhou Digoal Author: Amit Langote, Michael Paquier Discussion: https://postgr.es/m/15565-ce67a48d0244436a@postgresql.org Backpatch-through: 9.4 --- src/backend/commands/tablecmds.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'src/backend/commands/tablecmds.c') diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index ec974d11833..016717d6287 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -1213,13 +1213,14 @@ ExecuteTruncate(TruncateStmt *stmt) Relation rel; bool recurse = rv->inh; Oid myrelid; + LOCKMODE lockmode = AccessExclusiveLock; - rel = heap_openrv(rv, AccessExclusiveLock); + rel = heap_openrv(rv, lockmode); myrelid = RelationGetRelid(rel); /* don't throw error for "TRUNCATE foo, foo" */ if (list_member_oid(relids, myrelid)) { - heap_close(rel, AccessExclusiveLock); + heap_close(rel, lockmode); continue; } truncate_check_rel(rel); @@ -1231,7 +1232,7 @@ ExecuteTruncate(TruncateStmt *stmt) ListCell *child; List *children; - children = find_all_inheritors(myrelid, AccessExclusiveLock, NULL); + children = find_all_inheritors(myrelid, lockmode, NULL); foreach(child, children) { @@ -1242,6 +1243,22 @@ ExecuteTruncate(TruncateStmt *stmt) /* find_all_inheritors already got lock */ rel = heap_open(childrelid, NoLock); + + /* + * It is possible that the parent table has children that are + * temp tables of other backends. We cannot safely access + * such tables (because of buffering issues), and the best + * thing to do is to silently ignore them. Note that this + * check is the same as one of the checks done in + * truncate_check_rel() called below, still it is kept + * here for simplicity. + */ + if (RELATION_IS_OTHER_TEMP(rel)) + { + heap_close(rel, lockmode); + continue; + } + truncate_check_rel(rel); rels = lappend(rels, rel); relids = lappend_oid(relids, childrelid); -- cgit v1.2.3