@@ -399,6 +399,7 @@ static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId,
399
399
static void validateForeignKeyConstraint(char *conname,
400
400
Relation rel, Relation pkrel,
401
401
Oid pkindOid, Oid constraintOid);
402
+ static void CheckAlterTableIsSafe(Relation rel);
402
403
static void ATController(AlterTableStmt *parsetree,
403
404
Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
404
405
AlterTableUtilityContext *context);
@@ -4269,6 +4270,37 @@ CheckTableNotInUse(Relation rel, const char *stmt)
4269
4270
stmt, RelationGetRelationName(rel))));
4270
4271
}
4271
4272
4273
+ /*
4274
+ * CheckAlterTableIsSafe
4275
+ * Verify that it's safe to allow ALTER TABLE on this relation.
4276
+ *
4277
+ * This consists of CheckTableNotInUse() plus a check that the relation
4278
+ * isn't another session's temp table. We must split out the temp-table
4279
+ * check because there are callers of CheckTableNotInUse() that don't want
4280
+ * that, notably DROP TABLE. (We must allow DROP or we couldn't clean out
4281
+ * an orphaned temp schema.) Compare truncate_check_activity().
4282
+ */
4283
+ static void
4284
+ CheckAlterTableIsSafe(Relation rel)
4285
+ {
4286
+ /*
4287
+ * Don't allow ALTER on temp tables of other backends. Their local buffer
4288
+ * manager is not going to cope if we need to change the table's contents.
4289
+ * Even if we don't, there may be optimizations that assume temp tables
4290
+ * aren't subject to such interference.
4291
+ */
4292
+ if (RELATION_IS_OTHER_TEMP(rel))
4293
+ ereport(ERROR,
4294
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4295
+ errmsg("cannot alter temporary tables of other sessions")));
4296
+
4297
+ /*
4298
+ * Also check for active uses of the relation in the current transaction,
4299
+ * including open scans and pending AFTER trigger events.
4300
+ */
4301
+ CheckTableNotInUse(rel, "ALTER TABLE");
4302
+ }
4303
+
4272
4304
/*
4273
4305
* AlterTableLookupRelation
4274
4306
* Look up, and lock, the OID for the relation named by an alter table
@@ -4342,7 +4374,7 @@ AlterTable(AlterTableStmt *stmt, LOCKMODE lockmode,
4342
4374
/* Caller is required to provide an adequate lock. */
4343
4375
rel = relation_open(context->relid, NoLock);
4344
4376
4345
- CheckTableNotInUse (rel, "ALTER TABLE" );
4377
+ CheckAlterTableIsSafe (rel);
4346
4378
4347
4379
ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4348
4380
}
@@ -5748,7 +5780,9 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode,
5748
5780
5749
5781
/*
5750
5782
* Don't allow rewrite on temp tables of other backends ... their
5751
- * local buffer manager is not going to cope.
5783
+ * local buffer manager is not going to cope. (This is redundant
5784
+ * with the check in CheckAlterTableIsSafe, but for safety we'll
5785
+ * check here too.)
5752
5786
*/
5753
5787
if (RELATION_IS_OTHER_TEMP(OldHeap))
5754
5788
ereport(ERROR,
@@ -6619,7 +6653,7 @@ ATSimpleRecursion(List **wqueue, Relation rel,
6619
6653
continue;
6620
6654
/* find_all_inheritors already got lock */
6621
6655
childrel = relation_open(childrelid, NoLock);
6622
- CheckTableNotInUse (childrel, "ALTER TABLE" );
6656
+ CheckAlterTableIsSafe (childrel);
6623
6657
ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
6624
6658
relation_close(childrel, NoLock);
6625
6659
}
@@ -6628,7 +6662,7 @@ ATSimpleRecursion(List **wqueue, Relation rel,
6628
6662
6629
6663
/*
6630
6664
* Obtain list of partitions of the given table, locking them all at the given
6631
- * lockmode and ensuring that they all pass CheckTableNotInUse .
6665
+ * lockmode and ensuring that they all pass CheckAlterTableIsSafe .
6632
6666
*
6633
6667
* This function is a no-op if the given relation is not a partitioned table;
6634
6668
* in particular, nothing is done if it's a legacy inheritance parent.
@@ -6649,7 +6683,7 @@ ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode)
6649
6683
6650
6684
/* find_all_inheritors already got lock */
6651
6685
childrel = table_open(lfirst_oid(cell), NoLock);
6652
- CheckTableNotInUse (childrel, "ALTER TABLE" );
6686
+ CheckAlterTableIsSafe (childrel);
6653
6687
table_close(childrel, NoLock);
6654
6688
}
6655
6689
list_free(inh);
@@ -6682,7 +6716,7 @@ ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
6682
6716
Relation childrel;
6683
6717
6684
6718
childrel = relation_open(childrelid, lockmode);
6685
- CheckTableNotInUse (childrel, "ALTER TABLE" );
6719
+ CheckAlterTableIsSafe (childrel);
6686
6720
ATPrepCmd(wqueue, childrel, cmd, true, true, lockmode, context);
6687
6721
relation_close(childrel, NoLock);
6688
6722
}
@@ -7354,7 +7388,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
7354
7388
7355
7389
/* find_inheritance_children already got lock */
7356
7390
childrel = table_open(childrelid, NoLock);
7357
- CheckTableNotInUse (childrel, "ALTER TABLE" );
7391
+ CheckAlterTableIsSafe (childrel);
7358
7392
7359
7393
/* Find or create work queue entry for this table */
7360
7394
childtab = ATGetQueueEntry(wqueue, childrel);
@@ -9031,7 +9065,7 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
9031
9065
9032
9066
/* find_inheritance_children already got lock */
9033
9067
childrel = table_open(childrelid, NoLock);
9034
- CheckTableNotInUse (childrel, "ALTER TABLE" );
9068
+ CheckAlterTableIsSafe (childrel);
9035
9069
9036
9070
tuple = SearchSysCacheCopyAttName(childrelid, colName);
9037
9071
if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
@@ -9514,7 +9548,7 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
9514
9548
9515
9549
/* find_inheritance_children already got lock */
9516
9550
childrel = table_open(childrelid, NoLock);
9517
- CheckTableNotInUse (childrel, "ALTER TABLE" );
9551
+ CheckAlterTableIsSafe (childrel);
9518
9552
9519
9553
/* Find or create work queue entry for this table */
9520
9554
childtab = ATGetQueueEntry(wqueue, childrel);
@@ -10343,7 +10377,7 @@ addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel,
10343
10377
referenced;
10344
10378
ListCell *cell;
10345
10379
10346
- CheckTableNotInUse (partition, "ALTER TABLE" );
10380
+ CheckAlterTableIsSafe (partition);
10347
10381
10348
10382
attmap = build_attrmap_by_name(RelationGetDescr(partition),
10349
10383
RelationGetDescr(rel),
@@ -12460,7 +12494,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
12460
12494
12461
12495
/* Must match lock taken by RemoveTriggerById: */
12462
12496
frel = table_open(con->confrelid, AccessExclusiveLock);
12463
- CheckTableNotInUse (frel, "ALTER TABLE" );
12497
+ CheckAlterTableIsSafe (frel);
12464
12498
table_close(frel, NoLock);
12465
12499
}
12466
12500
@@ -12537,7 +12571,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
12537
12571
12538
12572
/* find_inheritance_children already got lock */
12539
12573
childrel = table_open(childrelid, NoLock);
12540
- CheckTableNotInUse (childrel, "ALTER TABLE" );
12574
+ CheckAlterTableIsSafe (childrel);
12541
12575
12542
12576
ScanKeyInit(&skey[0],
12543
12577
Anum_pg_constraint_conrelid,
@@ -12840,7 +12874,7 @@ ATPrepAlterColumnType(List **wqueue,
12840
12874
12841
12875
/* find_all_inheritors already got lock */
12842
12876
childrel = relation_open(childrelid, NoLock);
12843
- CheckTableNotInUse (childrel, "ALTER TABLE" );
12877
+ CheckAlterTableIsSafe (childrel);
12844
12878
12845
12879
/*
12846
12880
* Verify that the child doesn't have any inherited definitions of
0 commit comments