@@ -382,6 +382,7 @@ static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId,
382
382
static void validateForeignKeyConstraint(char *conname,
383
383
Relation rel, Relation pkrel,
384
384
Oid pkindOid, Oid constraintOid);
385
+ static void CheckAlterTableIsSafe(Relation rel);
385
386
static void ATController(AlterTableStmt *parsetree,
386
387
Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
387
388
AlterTableUtilityContext *context);
@@ -3982,6 +3983,37 @@ CheckTableNotInUse(Relation rel, const char *stmt)
3982
3983
stmt, RelationGetRelationName(rel))));
3983
3984
}
3984
3985
3986
+ /*
3987
+ * CheckAlterTableIsSafe
3988
+ * Verify that it's safe to allow ALTER TABLE on this relation.
3989
+ *
3990
+ * This consists of CheckTableNotInUse() plus a check that the relation
3991
+ * isn't another session's temp table. We must split out the temp-table
3992
+ * check because there are callers of CheckTableNotInUse() that don't want
3993
+ * that, notably DROP TABLE. (We must allow DROP or we couldn't clean out
3994
+ * an orphaned temp schema.) Compare truncate_check_activity().
3995
+ */
3996
+ static void
3997
+ CheckAlterTableIsSafe(Relation rel)
3998
+ {
3999
+ /*
4000
+ * Don't allow ALTER on temp tables of other backends. Their local buffer
4001
+ * manager is not going to cope if we need to change the table's contents.
4002
+ * Even if we don't, there may be optimizations that assume temp tables
4003
+ * aren't subject to such interference.
4004
+ */
4005
+ if (RELATION_IS_OTHER_TEMP(rel))
4006
+ ereport(ERROR,
4007
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4008
+ errmsg("cannot alter temporary tables of other sessions")));
4009
+
4010
+ /*
4011
+ * Also check for active uses of the relation in the current transaction,
4012
+ * including open scans and pending AFTER trigger events.
4013
+ */
4014
+ CheckTableNotInUse(rel, "ALTER TABLE");
4015
+ }
4016
+
3985
4017
/*
3986
4018
* AlterTableLookupRelation
3987
4019
* Look up, and lock, the OID for the relation named by an alter table
@@ -4056,7 +4088,7 @@ AlterTable(AlterTableStmt *stmt, LOCKMODE lockmode,
4056
4088
/* Caller is required to provide an adequate lock. */
4057
4089
rel = relation_open(context->relid, NoLock);
4058
4090
4059
- CheckTableNotInUse (rel, "ALTER TABLE" );
4091
+ CheckAlterTableIsSafe (rel);
4060
4092
4061
4093
ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4062
4094
}
@@ -5425,7 +5457,9 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode,
5425
5457
5426
5458
/*
5427
5459
* Don't allow rewrite on temp tables of other backends ... their
5428
- * local buffer manager is not going to cope.
5460
+ * local buffer manager is not going to cope. (This is redundant
5461
+ * with the check in CheckAlterTableIsSafe, but for safety we'll
5462
+ * check here too.)
5429
5463
*/
5430
5464
if (RELATION_IS_OTHER_TEMP(OldHeap))
5431
5465
ereport(ERROR,
@@ -6169,7 +6203,7 @@ ATSimpleRecursion(List **wqueue, Relation rel,
6169
6203
continue;
6170
6204
/* find_all_inheritors already got lock */
6171
6205
childrel = relation_open(childrelid, NoLock);
6172
- CheckTableNotInUse (childrel, "ALTER TABLE" );
6206
+ CheckAlterTableIsSafe (childrel);
6173
6207
ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
6174
6208
relation_close(childrel, NoLock);
6175
6209
}
@@ -6178,7 +6212,7 @@ ATSimpleRecursion(List **wqueue, Relation rel,
6178
6212
6179
6213
/*
6180
6214
* Obtain list of partitions of the given table, locking them all at the given
6181
- * lockmode and ensuring that they all pass CheckTableNotInUse .
6215
+ * lockmode and ensuring that they all pass CheckAlterTableIsSafe .
6182
6216
*
6183
6217
* This function is a no-op if the given relation is not a partitioned table;
6184
6218
* in particular, nothing is done if it's a legacy inheritance parent.
@@ -6199,7 +6233,7 @@ ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode)
6199
6233
6200
6234
/* find_all_inheritors already got lock */
6201
6235
childrel = table_open(lfirst_oid(cell), NoLock);
6202
- CheckTableNotInUse (childrel, "ALTER TABLE" );
6236
+ CheckAlterTableIsSafe (childrel);
6203
6237
table_close(childrel, NoLock);
6204
6238
}
6205
6239
list_free(inh);
@@ -6232,7 +6266,7 @@ ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
6232
6266
Relation childrel;
6233
6267
6234
6268
childrel = relation_open(childrelid, lockmode);
6235
- CheckTableNotInUse (childrel, "ALTER TABLE" );
6269
+ CheckAlterTableIsSafe (childrel);
6236
6270
ATPrepCmd(wqueue, childrel, cmd, true, true, lockmode, context);
6237
6271
relation_close(childrel, NoLock);
6238
6272
}
@@ -6933,7 +6967,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
6933
6967
6934
6968
/* find_inheritance_children already got lock */
6935
6969
childrel = table_open(childrelid, NoLock);
6936
- CheckTableNotInUse (childrel, "ALTER TABLE" );
6970
+ CheckAlterTableIsSafe (childrel);
6937
6971
6938
6972
/* Find or create work queue entry for this table */
6939
6973
childtab = ATGetQueueEntry(wqueue, childrel);
@@ -8419,7 +8453,7 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
8419
8453
8420
8454
/* find_inheritance_children already got lock */
8421
8455
childrel = table_open(childrelid, NoLock);
8422
- CheckTableNotInUse (childrel, "ALTER TABLE" );
8456
+ CheckAlterTableIsSafe (childrel);
8423
8457
8424
8458
tuple = SearchSysCacheCopyAttName(childrelid, colName);
8425
8459
if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
@@ -8901,7 +8935,7 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
8901
8935
8902
8936
/* find_inheritance_children already got lock */
8903
8937
childrel = table_open(childrelid, NoLock);
8904
- CheckTableNotInUse (childrel, "ALTER TABLE" );
8938
+ CheckAlterTableIsSafe (childrel);
8905
8939
8906
8940
/* Find or create work queue entry for this table */
8907
8941
childtab = ATGetQueueEntry(wqueue, childrel);
@@ -9651,7 +9685,7 @@ addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel,
9651
9685
referenced;
9652
9686
ListCell *cell;
9653
9687
9654
- CheckTableNotInUse (partition, "ALTER TABLE" );
9688
+ CheckAlterTableIsSafe (partition);
9655
9689
9656
9690
attmap = build_attrmap_by_name(RelationGetDescr(partition),
9657
9691
RelationGetDescr(rel));
@@ -11527,7 +11561,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
11527
11561
11528
11562
/* Must match lock taken by RemoveTriggerById: */
11529
11563
frel = table_open(con->confrelid, AccessExclusiveLock);
11530
- CheckTableNotInUse (frel, "ALTER TABLE" );
11564
+ CheckAlterTableIsSafe (frel);
11531
11565
table_close(frel, NoLock);
11532
11566
}
11533
11567
@@ -11605,7 +11639,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
11605
11639
11606
11640
/* find_inheritance_children already got lock */
11607
11641
childrel = table_open(childrelid, NoLock);
11608
- CheckTableNotInUse (childrel, "ALTER TABLE" );
11642
+ CheckAlterTableIsSafe (childrel);
11609
11643
11610
11644
ScanKeyInit(&skey[0],
11611
11645
Anum_pg_constraint_conrelid,
@@ -11908,7 +11942,7 @@ ATPrepAlterColumnType(List **wqueue,
11908
11942
11909
11943
/* find_all_inheritors already got lock */
11910
11944
childrel = relation_open(childrelid, NoLock);
11911
- CheckTableNotInUse (childrel, "ALTER TABLE" );
11945
+ CheckAlterTableIsSafe (childrel);
11912
11946
11913
11947
/*
11914
11948
* Verify that the child doesn't have any inherited definitions of
0 commit comments