aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/commands/tablecmds.c60
1 files changed, 47 insertions, 13 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index b9d24b49db3..9ec5d692d9b 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -382,6 +382,7 @@ static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId,
static void validateForeignKeyConstraint(char *conname,
Relation rel, Relation pkrel,
Oid pkindOid, Oid constraintOid);
+static void CheckAlterTableIsSafe(Relation rel);
static void ATController(AlterTableStmt *parsetree,
Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
AlterTableUtilityContext *context);
@@ -3983,6 +3984,37 @@ CheckTableNotInUse(Relation rel, const char *stmt)
}
/*
+ * CheckAlterTableIsSafe
+ * Verify that it's safe to allow ALTER TABLE on this relation.
+ *
+ * This consists of CheckTableNotInUse() plus a check that the relation
+ * isn't another session's temp table. We must split out the temp-table
+ * check because there are callers of CheckTableNotInUse() that don't want
+ * that, notably DROP TABLE. (We must allow DROP or we couldn't clean out
+ * an orphaned temp schema.) Compare truncate_check_activity().
+ */
+static void
+CheckAlterTableIsSafe(Relation rel)
+{
+ /*
+ * Don't allow ALTER on temp tables of other backends. Their local buffer
+ * manager is not going to cope if we need to change the table's contents.
+ * Even if we don't, there may be optimizations that assume temp tables
+ * aren't subject to such interference.
+ */
+ if (RELATION_IS_OTHER_TEMP(rel))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot alter temporary tables of other sessions")));
+
+ /*
+ * Also check for active uses of the relation in the current transaction,
+ * including open scans and pending AFTER trigger events.
+ */
+ CheckTableNotInUse(rel, "ALTER TABLE");
+}
+
+/*
* AlterTableLookupRelation
* Look up, and lock, the OID for the relation named by an alter table
* statement.
@@ -4056,7 +4088,7 @@ AlterTable(AlterTableStmt *stmt, LOCKMODE lockmode,
/* Caller is required to provide an adequate lock. */
rel = relation_open(context->relid, NoLock);
- CheckTableNotInUse(rel, "ALTER TABLE");
+ CheckAlterTableIsSafe(rel);
ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
}
@@ -5425,7 +5457,9 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode,
/*
* Don't allow rewrite on temp tables of other backends ... their
- * local buffer manager is not going to cope.
+ * local buffer manager is not going to cope. (This is redundant
+ * with the check in CheckAlterTableIsSafe, but for safety we'll
+ * check here too.)
*/
if (RELATION_IS_OTHER_TEMP(OldHeap))
ereport(ERROR,
@@ -6169,7 +6203,7 @@ ATSimpleRecursion(List **wqueue, Relation rel,
continue;
/* find_all_inheritors already got lock */
childrel = relation_open(childrelid, NoLock);
- CheckTableNotInUse(childrel, "ALTER TABLE");
+ CheckAlterTableIsSafe(childrel);
ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
relation_close(childrel, NoLock);
}
@@ -6178,7 +6212,7 @@ ATSimpleRecursion(List **wqueue, Relation rel,
/*
* Obtain list of partitions of the given table, locking them all at the given
- * lockmode and ensuring that they all pass CheckTableNotInUse.
+ * lockmode and ensuring that they all pass CheckAlterTableIsSafe.
*
* This function is a no-op if the given relation is not a partitioned table;
* in particular, nothing is done if it's a legacy inheritance parent.
@@ -6199,7 +6233,7 @@ ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode)
/* find_all_inheritors already got lock */
childrel = table_open(lfirst_oid(cell), NoLock);
- CheckTableNotInUse(childrel, "ALTER TABLE");
+ CheckAlterTableIsSafe(childrel);
table_close(childrel, NoLock);
}
list_free(inh);
@@ -6232,7 +6266,7 @@ ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
Relation childrel;
childrel = relation_open(childrelid, lockmode);
- CheckTableNotInUse(childrel, "ALTER TABLE");
+ CheckAlterTableIsSafe(childrel);
ATPrepCmd(wqueue, childrel, cmd, true, true, lockmode, context);
relation_close(childrel, NoLock);
}
@@ -6933,7 +6967,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
/* find_inheritance_children already got lock */
childrel = table_open(childrelid, NoLock);
- CheckTableNotInUse(childrel, "ALTER TABLE");
+ CheckAlterTableIsSafe(childrel);
/* Find or create work queue entry for this table */
childtab = ATGetQueueEntry(wqueue, childrel);
@@ -8419,7 +8453,7 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
/* find_inheritance_children already got lock */
childrel = table_open(childrelid, NoLock);
- CheckTableNotInUse(childrel, "ALTER TABLE");
+ CheckAlterTableIsSafe(childrel);
tuple = SearchSysCacheCopyAttName(childrelid, colName);
if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
@@ -8901,7 +8935,7 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
/* find_inheritance_children already got lock */
childrel = table_open(childrelid, NoLock);
- CheckTableNotInUse(childrel, "ALTER TABLE");
+ CheckAlterTableIsSafe(childrel);
/* Find or create work queue entry for this table */
childtab = ATGetQueueEntry(wqueue, childrel);
@@ -9651,7 +9685,7 @@ addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel,
referenced;
ListCell *cell;
- CheckTableNotInUse(partition, "ALTER TABLE");
+ CheckAlterTableIsSafe(partition);
attmap = build_attrmap_by_name(RelationGetDescr(partition),
RelationGetDescr(rel));
@@ -11527,7 +11561,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
/* Must match lock taken by RemoveTriggerById: */
frel = table_open(con->confrelid, AccessExclusiveLock);
- CheckTableNotInUse(frel, "ALTER TABLE");
+ CheckAlterTableIsSafe(frel);
table_close(frel, NoLock);
}
@@ -11605,7 +11639,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
/* find_inheritance_children already got lock */
childrel = table_open(childrelid, NoLock);
- CheckTableNotInUse(childrel, "ALTER TABLE");
+ CheckAlterTableIsSafe(childrel);
ScanKeyInit(&skey[0],
Anum_pg_constraint_conrelid,
@@ -11908,7 +11942,7 @@ ATPrepAlterColumnType(List **wqueue,
/* find_all_inheritors already got lock */
childrel = relation_open(childrelid, NoLock);
- CheckTableNotInUse(childrel, "ALTER TABLE");
+ CheckAlterTableIsSafe(childrel);
/*
* Verify that the child doesn't have any inherited definitions of