@@ -388,6 +388,7 @@ static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId,
388
388
static void validateForeignKeyConstraint(char *conname,
389
389
Relation rel, Relation pkrel,
390
390
Oid pkindOid, Oid constraintOid);
391
+ static void CheckAlterTableIsSafe(Relation rel);
391
392
static void ATController(AlterTableStmt *parsetree,
392
393
Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
393
394
AlterTableUtilityContext *context);
@@ -4111,6 +4112,37 @@ CheckTableNotInUse(Relation rel, const char *stmt)
4111
4112
stmt, RelationGetRelationName(rel))));
4112
4113
}
4113
4114
4115
+ /*
4116
+ * CheckAlterTableIsSafe
4117
+ *Verify that it's safe to allow ALTER TABLE on this relation.
4118
+ *
4119
+ * This consists of CheckTableNotInUse() plus a check that the relation
4120
+ * isn't another session's temp table. We must split out the temp-table
4121
+ * check because there are callers of CheckTableNotInUse() that don't want
4122
+ * that, notably DROP TABLE. (We must allow DROP or we couldn't clean out
4123
+ * an orphaned temp schema.) Compare truncate_check_activity().
4124
+ */
4125
+ static void
4126
+ CheckAlterTableIsSafe(Relation rel)
4127
+ {
4128
+ /*
4129
+ * Don't allow ALTER on temp tables of other backends. Their local buffer
4130
+ * manager is not going to cope if we need to change the table's contents.
4131
+ * Even if we don't, there may be optimizations that assume temp tables
4132
+ * aren't subject to such interference.
4133
+ */
4134
+ if (RELATION_IS_OTHER_TEMP(rel))
4135
+ ereport(ERROR,
4136
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4137
+ errmsg("cannot alter temporary tables of other sessions")));
4138
+
4139
+ /*
4140
+ * Also check for active uses of the relation in the current transaction,
4141
+ * including open scans and pending AFTER trigger events.
4142
+ */
4143
+ CheckTableNotInUse(rel, "ALTER TABLE");
4144
+ }
4145
+
4114
4146
/*
4115
4147
* AlterTableLookupRelation
4116
4148
*Look up, and lock, the OID for the relation named by an alter table
@@ -4184,7 +4216,7 @@ AlterTable(AlterTableStmt *stmt, LOCKMODE lockmode,
4184
4216
/* Caller is required to provide an adequate lock. */
4185
4217
rel = relation_open(context->relid, NoLock);
4186
4218
4187
- CheckTableNotInUse (rel, "ALTER TABLE" );
4219
+ CheckAlterTableIsSafe (rel);
4188
4220
4189
4221
ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4190
4222
}
@@ -5541,7 +5573,9 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode,
5541
5573
5542
5574
/*
5543
5575
* Don't allow rewrite on temp tables of other backends ... their
5544
- * local buffer manager is not going to cope.
5576
+ * local buffer manager is not going to cope. (This is redundant
5577
+ * with the check in CheckAlterTableIsSafe, but for safety we'll
5578
+ * check here too.)
5545
5579
*/
5546
5580
if (RELATION_IS_OTHER_TEMP(OldHeap))
5547
5581
ereport(ERROR,
@@ -6405,7 +6439,7 @@ ATSimpleRecursion(List **wqueue, Relation rel,
6405
6439
continue;
6406
6440
/* find_all_inheritors already got lock */
6407
6441
childrel = relation_open(childrelid, NoLock);
6408
- CheckTableNotInUse (childrel, "ALTER TABLE" );
6442
+ CheckAlterTableIsSafe (childrel);
6409
6443
ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
6410
6444
relation_close(childrel, NoLock);
6411
6445
}
@@ -6414,7 +6448,7 @@ ATSimpleRecursion(List **wqueue, Relation rel,
6414
6448
6415
6449
/*
6416
6450
* Obtain list of partitions of the given table, locking them all at the given
6417
- * lockmode and ensuring that they all passCheckTableNotInUse .
6451
+ * lockmode and ensuring that they all passCheckAlterTableIsSafe .
6418
6452
*
6419
6453
* This function is a no-op if the given relation is not a partitioned table;
6420
6454
* in particular, nothing is done if it's a legacy inheritance parent.
@@ -6435,7 +6469,7 @@ ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode)
6435
6469
6436
6470
/* find_all_inheritors already got lock */
6437
6471
childrel = table_open(lfirst_oid(cell), NoLock);
6438
- CheckTableNotInUse (childrel, "ALTER TABLE" );
6472
+ CheckAlterTableIsSafe (childrel);
6439
6473
table_close(childrel, NoLock);
6440
6474
}
6441
6475
list_free(inh);
@@ -6468,7 +6502,7 @@ ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
6468
6502
Relationchildrel;
6469
6503
6470
6504
childrel = relation_open(childrelid, lockmode);
6471
- CheckTableNotInUse (childrel, "ALTER TABLE" );
6505
+ CheckAlterTableIsSafe (childrel);
6472
6506
ATPrepCmd(wqueue, childrel, cmd, true, true, lockmode, context);
6473
6507
relation_close(childrel, NoLock);
6474
6508
}
@@ -7180,7 +7214,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
7180
7214
7181
7215
/* find_inheritance_children already got lock */
7182
7216
childrel = table_open(childrelid, NoLock);
7183
- CheckTableNotInUse (childrel, "ALTER TABLE" );
7217
+ CheckAlterTableIsSafe (childrel);
7184
7218
7185
7219
/* Find or create work queue entry for this table */
7186
7220
childtab = ATGetQueueEntry(wqueue, childrel);
@@ -8612,7 +8646,7 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
8612
8646
8613
8647
/* find_inheritance_children already got lock */
8614
8648
childrel = table_open(childrelid, NoLock);
8615
- CheckTableNotInUse (childrel, "ALTER TABLE" );
8649
+ CheckAlterTableIsSafe (childrel);
8616
8650
8617
8651
tuple = SearchSysCacheCopyAttName(childrelid, colName);
8618
8652
if (!HeapTupleIsValid(tuple))/* shouldn't happen */
@@ -9095,7 +9129,7 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
9095
9129
9096
9130
/* find_inheritance_children already got lock */
9097
9131
childrel = table_open(childrelid, NoLock);
9098
- CheckTableNotInUse (childrel, "ALTER TABLE" );
9132
+ CheckAlterTableIsSafe (childrel);
9099
9133
9100
9134
/* Find or create work queue entry for this table */
9101
9135
childtab = ATGetQueueEntry(wqueue, childrel);
@@ -9924,7 +9958,7 @@ addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel,
9924
9958
referenced;
9925
9959
ListCell *cell;
9926
9960
9927
- CheckTableNotInUse (partition, "ALTER TABLE" );
9961
+ CheckAlterTableIsSafe (partition);
9928
9962
9929
9963
attmap = build_attrmap_by_name(RelationGetDescr(partition),
9930
9964
RelationGetDescr(rel),
@@ -12045,7 +12079,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
12045
12079
12046
12080
/* Must match lock taken by RemoveTriggerById: */
12047
12081
frel = table_open(con->confrelid, AccessExclusiveLock);
12048
- CheckTableNotInUse (frel, "ALTER TABLE" );
12082
+ CheckAlterTableIsSafe (frel);
12049
12083
table_close(frel, NoLock);
12050
12084
}
12051
12085
@@ -12123,7 +12157,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
12123
12157
12124
12158
/* find_inheritance_children already got lock */
12125
12159
childrel = table_open(childrelid, NoLock);
12126
- CheckTableNotInUse (childrel, "ALTER TABLE" );
12160
+ CheckAlterTableIsSafe (childrel);
12127
12161
12128
12162
ScanKeyInit(&skey[0],
12129
12163
Anum_pg_constraint_conrelid,
@@ -12426,7 +12460,7 @@ ATPrepAlterColumnType(List **wqueue,
12426
12460
12427
12461
/* find_all_inheritors already got lock */
12428
12462
childrel = relation_open(childrelid, NoLock);
12429
- CheckTableNotInUse (childrel, "ALTER TABLE" );
12463
+ CheckAlterTableIsSafe (childrel);
12430
12464
12431
12465
/*
12432
12466
* Verify that the child doesn't have any inherited definitions of