aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/tablecmds.c
diff options
context:
space:
mode:
authorAlvaro Herrera <alvherre@alvh.no-ip.org>2019-01-24 14:09:56 -0300
committerAlvaro Herrera <alvherre@alvh.no-ip.org>2019-01-24 14:09:56 -0300
commitefd9366dcedec8db9fc85e77d071b0c5a6badea2 (patch)
treebba4b7e271cc847cb1045a5c250c2e672423052e /src/backend/commands/tablecmds.c
parente6c3ba7fbfd59ceabcf9bdaf52d71b44831b09d2 (diff)
downloadpostgresql-efd9366dcedec8db9fc85e77d071b0c5a6badea2.tar.gz
postgresql-efd9366dcedec8db9fc85e77d071b0c5a6badea2.zip
Fix droppability of constraints upon partition detach
We were failing to set conislocal correctly for constraints in partitions after partition detach, leading to those constraints becoming undroppable. Fix by setting the flag correctly. Existing databases might contain constraints with the conislocal wrongly set to false, for partitions that were detached; this situation should be fixable by applying an UPDATE on pg_constraint to set conislocal true. This problem should otherwise be innocuous and should disappear across a dump/restore or pg_upgrade. Secondarily, when constraint drop was attempted in a partitioned table, ATExecDropConstraint would try to recurse to partitions after doing performDeletion() of the constraint in the partitioned table itself; but since the constraint in the partitions are dropped by the initial call of performDeletion() (because of following dependencies), the recursion step would fail since it would not find the constraint, causing the whole operation to fail. Fix by preventing recursion. Reported-by: Amit Langote Diagnosed-by: Amit Langote Author: Amit Langote, Álvaro Herrera Discussion: https://postgr.es/m/f2b8ead5-4131-d5a8-8016-2ea0a31250af@lab.ntt.co.jp
Diffstat (limited to 'src/backend/commands/tablecmds.c')
-rw-r--r--src/backend/commands/tablecmds.c26
1 files changed, 23 insertions, 3 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 887c19c3eff..e010586dd67 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -7243,6 +7243,7 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
Oid pfeqoperators[INDEX_MAX_KEYS];
Oid ppeqoperators[INDEX_MAX_KEYS];
Oid ffeqoperators[INDEX_MAX_KEYS];
+ bool connoinherit;
int i;
int numfks,
numpks;
@@ -7587,6 +7588,12 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
}
/*
+ * FKs always inherit for partitioned tables, and never for legacy
+ * inheritance.
+ */
+ connoinherit = rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE;
+
+ /*
* Record the FK constraint in pg_constraint.
*/
constrOid = CreateConstraintEntry(fkconstraint->conname,
@@ -7616,7 +7623,7 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
NULL,
true, /* islocal */
0, /* inhcount */
- true, /* isnoinherit */
+ connoinherit, /* conNoInherit */
false); /* is_internal */
ObjectAddressSet(address, ConstraintRelationId, constrOid);
@@ -7937,7 +7944,7 @@ CloneFkReferencing(Relation pg_constraint, Relation parentRel,
}
systable_endscan(scan);
- heap_close(trigrel, RowExclusiveLock);
+ table_close(trigrel, RowExclusiveLock);
ConstraintSetParentConstraint(fk->conoid, parentConstrOid);
CommandCounterIncrement();
@@ -9131,6 +9138,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
HeapTuple tuple;
bool found = false;
bool is_no_inherit_constraint = false;
+ char contype;
/* At top level, permission check was done in ATPrepCmd, else do it */
if (recursing)
@@ -9171,6 +9179,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
constrName, RelationGetRelationName(rel))));
is_no_inherit_constraint = con->connoinherit;
+ contype = con->contype;
/*
* If it's a foreign-key constraint, we'd better lock the referenced
@@ -9179,7 +9188,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
* that has unfired events). But we can/must skip that in the
* self-referential case.
*/
- if (con->contype == CONSTRAINT_FOREIGN &&
+ if (contype == CONSTRAINT_FOREIGN &&
con->confrelid != RelationGetRelid(rel))
{
Relation frel;
@@ -9224,6 +9233,17 @@ ATExecDropConstraint(Relation rel, const char *constrName,
}
/*
+ * For partitioned tables, non-CHECK inherited constraints are dropped via
+ * the dependency mechanism, so we're done here.
+ */
+ if (contype != CONSTRAINT_CHECK &&
+ rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ table_close(conrel, RowExclusiveLock);
+ return;
+ }
+
+ /*
* Propagate to children as appropriate. Unlike most other ALTER
* routines, we have to do this one level of recursion at a time; we can't
* use find_all_inheritors to do it in one pass.