@@ -387,6 +387,7 @@ static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId,
387
387
static void validateForeignKeyConstraint(char *conname,
388
388
Relation rel, Relation pkrel,
389
389
Oid pkindOid, Oid constraintOid);
390
+ static void CheckAlterTableIsSafe(Relation rel);
390
391
static void ATController(AlterTableStmt *parsetree,
391
392
Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
392
393
AlterTableUtilityContext *context);
@@ -4014,6 +4015,37 @@ CheckTableNotInUse(Relation rel, const char *stmt)
4014
4015
stmt, RelationGetRelationName(rel))));
4015
4016
}
4016
4017
4018
+ /*
4019
+ * CheckAlterTableIsSafe
4020
+ * Verify that it's safe to allow ALTER TABLE on this relation.
4021
+ *
4022
+ * This consists of CheckTableNotInUse() plus a check that the relation
4023
+ * isn't another session's temp table. We must split out the temp-table
4024
+ * check because there are callers of CheckTableNotInUse() that don't want
4025
+ * that, notably DROP TABLE. (We must allow DROP or we couldn't clean out
4026
+ * an orphaned temp schema.) Compare truncate_check_activity().
4027
+ */
4028
+ static void
4029
+ CheckAlterTableIsSafe(Relation rel)
4030
+ {
4031
+ /*
4032
+ * Don't allow ALTER on temp tables of other backends. Their local buffer
4033
+ * manager is not going to cope if we need to change the table's contents.
4034
+ * Even if we don't, there may be optimizations that assume temp tables
4035
+ * aren't subject to such interference.
4036
+ */
4037
+ if (RELATION_IS_OTHER_TEMP(rel))
4038
+ ereport(ERROR,
4039
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4040
+ errmsg("cannot alter temporary tables of other sessions")));
4041
+
4042
+ /*
4043
+ * Also check for active uses of the relation in the current transaction,
4044
+ * including open scans and pending AFTER trigger events.
4045
+ */
4046
+ CheckTableNotInUse(rel, "ALTER TABLE");
4047
+ }
4048
+
4017
4049
/*
4018
4050
* AlterTableLookupRelation
4019
4051
* Look up, and lock, the OID for the relation named by an alter table
@@ -4088,7 +4120,7 @@ AlterTable(AlterTableStmt *stmt, LOCKMODE lockmode,
4088
4120
/* Caller is required to provide an adequate lock. */
4089
4121
rel = relation_open(context->relid, NoLock);
4090
4122
4091
- CheckTableNotInUse (rel, "ALTER TABLE" );
4123
+ CheckAlterTableIsSafe (rel);
4092
4124
4093
4125
ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4094
4126
}
@@ -5480,7 +5512,9 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode,
5480
5512
5481
5513
/*
5482
5514
* Don't allow rewrite on temp tables of other backends ... their
5483
- * local buffer manager is not going to cope.
5515
+ * local buffer manager is not going to cope. (This is redundant
5516
+ * with the check in CheckAlterTableIsSafe, but for safety we'll
5517
+ * check here too.)
5484
5518
*/
5485
5519
if (RELATION_IS_OTHER_TEMP(OldHeap))
5486
5520
ereport(ERROR,
@@ -6348,7 +6382,7 @@ ATSimpleRecursion(List **wqueue, Relation rel,
6348
6382
continue;
6349
6383
/* find_all_inheritors already got lock */
6350
6384
childrel = relation_open(childrelid, NoLock);
6351
- CheckTableNotInUse (childrel, "ALTER TABLE" );
6385
+ CheckAlterTableIsSafe (childrel);
6352
6386
ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
6353
6387
relation_close(childrel, NoLock);
6354
6388
}
@@ -6357,7 +6391,7 @@ ATSimpleRecursion(List **wqueue, Relation rel,
6357
6391
6358
6392
/*
6359
6393
* Obtain list of partitions of the given table, locking them all at the given
6360
- * lockmode and ensuring that they all pass CheckTableNotInUse .
6394
+ * lockmode and ensuring that they all pass CheckAlterTableIsSafe .
6361
6395
*
6362
6396
* This function is a no-op if the given relation is not a partitioned table;
6363
6397
* in particular, nothing is done if it's a legacy inheritance parent.
@@ -6378,7 +6412,7 @@ ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode)
6378
6412
6379
6413
/* find_all_inheritors already got lock */
6380
6414
childrel = table_open(lfirst_oid(cell), NoLock);
6381
- CheckTableNotInUse (childrel, "ALTER TABLE" );
6415
+ CheckAlterTableIsSafe (childrel);
6382
6416
table_close(childrel, NoLock);
6383
6417
}
6384
6418
list_free(inh);
@@ -6411,7 +6445,7 @@ ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
6411
6445
Relation childrel;
6412
6446
6413
6447
childrel = relation_open(childrelid, lockmode);
6414
- CheckTableNotInUse (childrel, "ALTER TABLE" );
6448
+ CheckAlterTableIsSafe (childrel);
6415
6449
ATPrepCmd(wqueue, childrel, cmd, true, true, lockmode, context);
6416
6450
relation_close(childrel, NoLock);
6417
6451
}
@@ -7112,7 +7146,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
7112
7146
7113
7147
/* find_inheritance_children already got lock */
7114
7148
childrel = table_open(childrelid, NoLock);
7115
- CheckTableNotInUse (childrel, "ALTER TABLE" );
7149
+ CheckAlterTableIsSafe (childrel);
7116
7150
7117
7151
/* Find or create work queue entry for this table */
7118
7152
childtab = ATGetQueueEntry(wqueue, childrel);
@@ -8572,7 +8606,7 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
8572
8606
8573
8607
/* find_inheritance_children already got lock */
8574
8608
childrel = table_open(childrelid, NoLock);
8575
- CheckTableNotInUse (childrel, "ALTER TABLE" );
8609
+ CheckAlterTableIsSafe (childrel);
8576
8610
8577
8611
tuple = SearchSysCacheCopyAttName(childrelid, colName);
8578
8612
if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
@@ -9054,7 +9088,7 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
9054
9088
9055
9089
/* find_inheritance_children already got lock */
9056
9090
childrel = table_open(childrelid, NoLock);
9057
- CheckTableNotInUse (childrel, "ALTER TABLE" );
9091
+ CheckAlterTableIsSafe (childrel);
9058
9092
9059
9093
/* Find or create work queue entry for this table */
9060
9094
childtab = ATGetQueueEntry(wqueue, childrel);
@@ -9892,7 +9926,7 @@ addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel,
9892
9926
referenced;
9893
9927
ListCell *cell;
9894
9928
9895
- CheckTableNotInUse (partition, "ALTER TABLE" );
9929
+ CheckAlterTableIsSafe (partition);
9896
9930
9897
9931
attmap = build_attrmap_by_name(RelationGetDescr(partition),
9898
9932
RelationGetDescr(rel));
@@ -12019,7 +12053,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
12019
12053
12020
12054
/* Must match lock taken by RemoveTriggerById: */
12021
12055
frel = table_open(con->confrelid, AccessExclusiveLock);
12022
- CheckTableNotInUse (frel, "ALTER TABLE" );
12056
+ CheckAlterTableIsSafe (frel);
12023
12057
table_close(frel, NoLock);
12024
12058
}
12025
12059
@@ -12097,7 +12131,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
12097
12131
12098
12132
/* find_inheritance_children already got lock */
12099
12133
childrel = table_open(childrelid, NoLock);
12100
- CheckTableNotInUse (childrel, "ALTER TABLE" );
12134
+ CheckAlterTableIsSafe (childrel);
12101
12135
12102
12136
ScanKeyInit(&skey[0],
12103
12137
Anum_pg_constraint_conrelid,
@@ -12400,7 +12434,7 @@ ATPrepAlterColumnType(List **wqueue,
12400
12434
12401
12435
/* find_all_inheritors already got lock */
12402
12436
childrel = relation_open(childrelid, NoLock);
12403
- CheckTableNotInUse (childrel, "ALTER TABLE" );
12437
+ CheckAlterTableIsSafe (childrel);
12404
12438
12405
12439
/*
12406
12440
* Verify that the child doesn't have any inherited definitions of
0 commit comments