Fix partitioned index attachment
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Thu, 25 Apr 2019 15:37:08 +0000 (11:37 -0400)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Thu, 25 Apr 2019 15:37:08 +0000 (11:37 -0400)
When an existing index in a partition is attached to a new index on
its parent, we forgot to set the "relispartition" flag correctly, which
meant that it was not possible to find the index in various operations,
such as adding a foreign key constraint that references that partitioned
table.  One of four places that was assigning the parent index was
forgetting to do that, so fix by shifting responsibility of updating the
flag to the routine that changes the parent.

Author: Amit Langote, Álvaro Herrera
Reported-by: Hubert "depesz" Lubaczewski
Discussion: https://postgr.es/m/CA+HiwqHMsRtRYRWYTWavKJ8x14AFsv7bmAV46mYwnfD3vy8goQ@mail.gmail.com

src/backend/commands/indexcmds.c
src/backend/commands/tablecmds.c

index f8ee4b0a84b9c70216ef226c24d44c88308b25ca..63cc3e3f401bb4ffe7768bf578bd72edbf4d213c 100644 (file)
@@ -85,6 +85,7 @@ static List *ChooseIndexColumnNames(List *indexElems);
 static void RangeVarCallbackForReindexIndex(const RangeVar *relation,
                                                                Oid relId, Oid oldRelId, void *arg);
 static void ReindexPartitionedIndex(Relation parentIdx);
+static void update_relispartition(Oid relationId, bool newval);
 
 /*
  * CheckIndexCompatible
@@ -2617,6 +2618,9 @@ IndexSetParentIndex(Relation partitionIdx, Oid parentOid)
        systable_endscan(scan);
        relation_close(pg_inherits, RowExclusiveLock);
 
+       /* set relispartition correctly on the partition */
+       update_relispartition(partRelid, OidIsValid(parentOid));
+
        if (fix_dependencies)
        {
                ObjectAddress partIdx;
@@ -2654,3 +2658,23 @@ IndexSetParentIndex(Relation partitionIdx, Oid parentOid)
                CommandCounterIncrement();
        }
 }
+
+/*
+ * Subroutine of IndexSetParentIndex to update the relispartition flag of the
+ * given index to the given value.
+ */
+static void
+update_relispartition(Oid relationId, bool newval)
+{
+       HeapTuple       tup;
+       Relation        classRel;
+
+       classRel = heap_open(RelationRelationId, RowExclusiveLock);
+       tup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
+       Assert(((Form_pg_class) GETSTRUCT(tup))->relispartition != newval);
+       ((Form_pg_class) GETSTRUCT(tup))->relispartition = newval;
+       CatalogTupleUpdate(classRel, &tup->t_self, tup);
+       heap_freetuple(tup);
+
+       heap_close(classRel, RowExclusiveLock);
+}
index 65ede339f2c50d6d1bd8cd864245c46c0a311ad0..cf61cc1ac47ae1df65be0e34a4605d6b81cf1f95 100644 (file)
@@ -495,8 +495,6 @@ static ObjectAddress ATExecAttachPartitionIdx(List **wqueue, Relation rel,
 static void validatePartitionedIndex(Relation partedIdx, Relation partedTbl);
 static void refuseDupeIndexAttach(Relation parentIdx, Relation partIdx,
                                          Relation partitionTbl);
-static void update_relispartition(Relation classRel, Oid relationId,
-                                         bool newval);
 
 
 /* ----------------------------------------------------------------
@@ -15036,7 +15034,6 @@ AttachPartitionEnsureIndexes(Relation rel, Relation attachrel)
                                IndexSetParentIndex(attachrelIdxRels[i], idx);
                                if (OidIsValid(constraintOid))
                                        ConstraintSetParentConstraint(cldConstrOid, constraintOid);
-                               update_relispartition(NULL, cldIdxId, true);
                                found = true;
                                break;
                        }
@@ -15287,7 +15284,6 @@ ATExecDetachPartition(Relation rel, RangeVar *name)
 
                idx = index_open(idxid, AccessExclusiveLock);
                IndexSetParentIndex(idx, InvalidOid);
-               update_relispartition(classRel, idxid, false);
 
                /* If there's a constraint associated with the index, detach it too */
                constrOid = get_relation_idx_constraint_oid(RelationGetRelid(partRel),
@@ -15562,7 +15558,6 @@ ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx, RangeVar *name)
                IndexSetParentIndex(partIdx, RelationGetRelid(parentIdx));
                if (OidIsValid(constraintOid))
                        ConstraintSetParentConstraint(cldConstrId, constraintOid);
-               update_relispartition(NULL, partIdxId, true);
 
                pfree(attmap);
 
@@ -15712,35 +15707,3 @@ validatePartitionedIndex(Relation partedIdx, Relation partedTbl)
                relation_close(parentTbl, AccessExclusiveLock);
        }
 }
-
-/*
- * Update the relispartition flag of the given relation to the given value.
- *
- * classRel is the pg_class relation, already open and suitably locked.
- * It can be passed as NULL, in which case it's opened and closed locally.
- */
-static void
-update_relispartition(Relation classRel, Oid relationId, bool newval)
-{
-       HeapTuple       tup;
-       HeapTuple       newtup;
-       Form_pg_class classForm;
-       bool            opened = false;
-
-       if (classRel == NULL)
-       {
-               classRel = heap_open(RelationRelationId, RowExclusiveLock);
-               opened = true;
-       }
-
-       tup = SearchSysCache1(RELOID, ObjectIdGetDatum(relationId));
-       newtup = heap_copytuple(tup);
-       classForm = (Form_pg_class) GETSTRUCT(newtup);
-       classForm->relispartition = newval;
-       CatalogTupleUpdate(classRel, &tup->t_self, newtup);
-       heap_freetuple(newtup);
-       ReleaseSysCache(tup);
-
-       if (opened)
-               heap_close(classRel, RowExclusiveLock);
-}