aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/tablecmds.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/tablecmds.c')
-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 c209061a63a..7642334b376 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -352,6 +352,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);
static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
@@ -3656,6 +3657,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.
@@ -3723,7 +3755,7 @@ AlterTable(Oid relid, LOCKMODE lockmode, AlterTableStmt *stmt)
/* Caller is required to provide an adequate lock. */
rel = relation_open(relid, NoLock);
- CheckTableNotInUse(rel, "ALTER TABLE");
+ CheckAlterTableIsSafe(rel);
ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode);
}
@@ -4830,7 +4862,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,
@@ -5553,7 +5587,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);
relation_close(childrel, NoLock);
}
@@ -5562,7 +5596,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.
@@ -5583,7 +5617,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);
@@ -5616,7 +5650,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);
relation_close(childrel, NoLock);
}
@@ -6277,7 +6311,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);
@@ -7599,7 +7633,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 */
@@ -8052,7 +8086,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);
@@ -8802,7 +8836,7 @@ addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel,
referenced;
ListCell *cell;
- CheckTableNotInUse(partition, "ALTER TABLE");
+ CheckAlterTableIsSafe(partition);
attmap = convert_tuples_by_name_map(RelationGetDescr(partition),
RelationGetDescr(rel),
@@ -10680,7 +10714,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);
}
@@ -10758,7 +10792,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,
@@ -11046,7 +11080,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