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:
@ -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);
|
||||
|
||||
|
Reference in New Issue
Block a user