1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-17 17:02:08 +03:00

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 work on the 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
This commit is contained in:
Michael Paquier
2018-12-27 10:16:19 +09:00
parent 8528e3d849
commit 1e504f01da
4 changed files with 316 additions and 3 deletions

View File

@ -1373,8 +1373,9 @@ ExecuteTruncate(TruncateStmt *stmt)
Relation rel;
bool recurse = rv->inh;
Oid myrelid;
LOCKMODE lockmode = AccessExclusiveLock;
myrelid = RangeVarGetRelidExtended(rv, AccessExclusiveLock,
myrelid = RangeVarGetRelidExtended(rv, lockmode,
0, RangeVarCallbackForTruncate,
NULL);
@ -1384,7 +1385,7 @@ ExecuteTruncate(TruncateStmt *stmt)
/* don't throw error for "TRUNCATE foo, foo" */
if (list_member_oid(relids, myrelid))
{
heap_close(rel, AccessExclusiveLock);
heap_close(rel, lockmode);
continue;
}
@ -1405,7 +1406,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)
{
@ -1416,6 +1417,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_activity() called below, still it is kept
* here for simplicity.
*/
if (RELATION_IS_OTHER_TEMP(rel))
{
heap_close(rel, lockmode);
continue;
}
truncate_check_rel(RelationGetRelid(rel), rel->rd_rel);
truncate_check_activity(rel);