@@ -355,6 +355,7 @@ static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId,
355
355
static void validateForeignKeyConstraint(char *conname,
356
356
Relation rel, Relation pkrel,
357
357
Oid pkindOid, Oid constraintOid);
358
+ static void CheckAlterTableIsSafe(Relation rel);
358
359
static void ATController(AlterTableStmt *parsetree,
359
360
Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
360
361
AlterTableUtilityContext *context);
@@ -3697,6 +3698,37 @@ CheckTableNotInUse(Relation rel, const char *stmt)
3697
3698
stmt, RelationGetRelationName(rel))));
3698
3699
}
3699
3700
3701
+ /*
3702
+ * CheckAlterTableIsSafe
3703
+ *Verify that it's safe to allow ALTER TABLE on this relation.
3704
+ *
3705
+ * This consists of CheckTableNotInUse() plus a check that the relation
3706
+ * isn't another session's temp table. We must split out the temp-table
3707
+ * check because there are callers of CheckTableNotInUse() that don't want
3708
+ * that, notably DROP TABLE. (We must allow DROP or we couldn't clean out
3709
+ * an orphaned temp schema.) Compare truncate_check_activity().
3710
+ */
3711
+ static void
3712
+ CheckAlterTableIsSafe(Relation rel)
3713
+ {
3714
+ /*
3715
+ * Don't allow ALTER on temp tables of other backends. Their local buffer
3716
+ * manager is not going to cope if we need to change the table's contents.
3717
+ * Even if we don't, there may be optimizations that assume temp tables
3718
+ * aren't subject to such interference.
3719
+ */
3720
+ if (RELATION_IS_OTHER_TEMP(rel))
3721
+ ereport(ERROR,
3722
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3723
+ errmsg("cannot alter temporary tables of other sessions")));
3724
+
3725
+ /*
3726
+ * Also check for active uses of the relation in the current transaction,
3727
+ * including open scans and pending AFTER trigger events.
3728
+ */
3729
+ CheckTableNotInUse(rel, "ALTER TABLE");
3730
+ }
3731
+
3700
3732
/*
3701
3733
* AlterTableLookupRelation
3702
3734
*Look up, and lock, the OID for the relation named by an alter table
@@ -3771,7 +3803,7 @@ AlterTable(AlterTableStmt *stmt, LOCKMODE lockmode,
3771
3803
/* Caller is required to provide an adequate lock. */
3772
3804
rel = relation_open(context->relid, NoLock);
3773
3805
3774
- CheckTableNotInUse (rel, "ALTER TABLE" );
3806
+ CheckAlterTableIsSafe (rel);
3775
3807
3776
3808
ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
3777
3809
}
@@ -5092,7 +5124,9 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode,
5092
5124
5093
5125
/*
5094
5126
* Don't allow rewrite on temp tables of other backends ... their
5095
- * local buffer manager is not going to cope.
5127
+ * local buffer manager is not going to cope. (This is redundant
5128
+ * with the check in CheckAlterTableIsSafe, but for safety we'll
5129
+ * check here too.)
5096
5130
*/
5097
5131
if (RELATION_IS_OTHER_TEMP(OldHeap))
5098
5132
ereport(ERROR,
@@ -5835,7 +5869,7 @@ ATSimpleRecursion(List **wqueue, Relation rel,
5835
5869
continue;
5836
5870
/* find_all_inheritors already got lock */
5837
5871
childrel = relation_open(childrelid, NoLock);
5838
- CheckTableNotInUse (childrel, "ALTER TABLE" );
5872
+ CheckAlterTableIsSafe (childrel);
5839
5873
ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
5840
5874
relation_close(childrel, NoLock);
5841
5875
}
@@ -5844,7 +5878,7 @@ ATSimpleRecursion(List **wqueue, Relation rel,
5844
5878
5845
5879
/*
5846
5880
* Obtain list of partitions of the given table, locking them all at the given
5847
- * lockmode and ensuring that they all passCheckTableNotInUse .
5881
+ * lockmode and ensuring that they all passCheckAlterTableIsSafe .
5848
5882
*
5849
5883
* This function is a no-op if the given relation is not a partitioned table;
5850
5884
* in particular, nothing is done if it's a legacy inheritance parent.
@@ -5865,7 +5899,7 @@ ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode)
5865
5899
5866
5900
/* find_all_inheritors already got lock */
5867
5901
childrel = table_open(lfirst_oid(cell), NoLock);
5868
- CheckTableNotInUse (childrel, "ALTER TABLE" );
5902
+ CheckAlterTableIsSafe (childrel);
5869
5903
table_close(childrel, NoLock);
5870
5904
}
5871
5905
list_free(inh);
@@ -5898,7 +5932,7 @@ ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
5898
5932
Relationchildrel;
5899
5933
5900
5934
childrel = relation_open(childrelid, lockmode);
5901
- CheckTableNotInUse (childrel, "ALTER TABLE" );
5935
+ CheckAlterTableIsSafe (childrel);
5902
5936
ATPrepCmd(wqueue, childrel, cmd, true, true, lockmode, context);
5903
5937
relation_close(childrel, NoLock);
5904
5938
}
@@ -6591,7 +6625,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
6591
6625
6592
6626
/* find_inheritance_children already got lock */
6593
6627
childrel = table_open(childrelid, NoLock);
6594
- CheckTableNotInUse (childrel, "ALTER TABLE" );
6628
+ CheckAlterTableIsSafe (childrel);
6595
6629
6596
6630
/* Find or create work queue entry for this table */
6597
6631
childtab = ATGetQueueEntry(wqueue, childrel);
@@ -8050,7 +8084,7 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
8050
8084
8051
8085
/* find_inheritance_children already got lock */
8052
8086
childrel = table_open(childrelid, NoLock);
8053
- CheckTableNotInUse (childrel, "ALTER TABLE" );
8087
+ CheckAlterTableIsSafe (childrel);
8054
8088
8055
8089
tuple = SearchSysCacheCopyAttName(childrelid, colName);
8056
8090
if (!HeapTupleIsValid(tuple))/* shouldn't happen */
@@ -8508,7 +8542,7 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
8508
8542
8509
8543
/* find_inheritance_children already got lock */
8510
8544
childrel = table_open(childrelid, NoLock);
8511
- CheckTableNotInUse (childrel, "ALTER TABLE" );
8545
+ CheckAlterTableIsSafe (childrel);
8512
8546
8513
8547
/* Find or create work queue entry for this table */
8514
8548
childtab = ATGetQueueEntry(wqueue, childrel);
@@ -9258,7 +9292,7 @@ addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel,
9258
9292
referenced;
9259
9293
ListCell *cell;
9260
9294
9261
- CheckTableNotInUse (partition, "ALTER TABLE" );
9295
+ CheckAlterTableIsSafe (partition);
9262
9296
9263
9297
attmap = build_attrmap_by_name(RelationGetDescr(partition),
9264
9298
RelationGetDescr(rel));
@@ -11131,7 +11165,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
11131
11165
11132
11166
/* Must match lock taken by RemoveTriggerById: */
11133
11167
frel = table_open(con->confrelid, AccessExclusiveLock);
11134
- CheckTableNotInUse (frel, "ALTER TABLE" );
11168
+ CheckAlterTableIsSafe (frel);
11135
11169
table_close(frel, NoLock);
11136
11170
}
11137
11171
@@ -11209,7 +11243,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
11209
11243
11210
11244
/* find_inheritance_children already got lock */
11211
11245
childrel = table_open(childrelid, NoLock);
11212
- CheckTableNotInUse (childrel, "ALTER TABLE" );
11246
+ CheckAlterTableIsSafe (childrel);
11213
11247
11214
11248
ScanKeyInit(&skey[0],
11215
11249
Anum_pg_constraint_conrelid,
@@ -11512,7 +11546,7 @@ ATPrepAlterColumnType(List **wqueue,
11512
11546
11513
11547
/* find_all_inheritors already got lock */
11514
11548
childrel = relation_open(childrelid, NoLock);
11515
- CheckTableNotInUse (childrel, "ALTER TABLE" );
11549
+ CheckAlterTableIsSafe (childrel);
11516
11550
11517
11551
/*
11518
11552
* Verify that the child doesn't have any inherited definitions of