diff options
author | Alvaro Herrera <alvherre@alvh.no-ip.org> | 2019-01-24 14:09:56 -0300 |
---|---|---|
committer | Alvaro Herrera <alvherre@alvh.no-ip.org> | 2019-01-24 14:09:56 -0300 |
commit | efd9366dcedec8db9fc85e77d071b0c5a6badea2 (patch) | |
tree | bba4b7e271cc847cb1045a5c250c2e672423052e /src/backend/commands/tablecmds.c | |
parent | e6c3ba7fbfd59ceabcf9bdaf52d71b44831b09d2 (diff) | |
download | postgresql-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.c | 26 |
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. |