]> granicus.if.org Git - postgresql/commitdiff
Fix bugs in RelationGetPartitionDispatchInfo.
authorRobert Haas <rhaas@postgresql.org>
Tue, 13 Dec 2016 16:29:08 +0000 (11:29 -0500)
committerRobert Haas <rhaas@postgresql.org>
Tue, 13 Dec 2016 16:29:08 +0000 (11:29 -0500)
The previous coding was not quite right for cases involving multiple
levels of partitioning.

Amit Langote

src/backend/catalog/partition.c

index 63d9b13db44aad7e1aaa3ec4cd68f687be30ceac..9980582b777af65838dcca0a7675b9c4ae70be14 100644 (file)
@@ -950,7 +950,8 @@ RelationGetPartitionDispatchInfo(Relation rel, int lockmode,
                           *parted_rels;
        ListCell   *lc;
        int                     i,
-                               k;
+                               k,
+                               offset;
 
        /*
         * Lock partitions and make a list of the partitioned ones to prepare
@@ -990,11 +991,19 @@ RelationGetPartitionDispatchInfo(Relation rel, int lockmode,
                 */
        }
 
-       /* Generate PartitionDispatch objects for all partitioned tables */
+       /*
+        * We want to create two arrays - one for leaf partitions and another for
+        * partitioned tables (including the root table and internal partitions).
+        * While we only create the latter here, leaf partition array of suitable
+        * objects (such as, ResultRelInfo) is created by the caller using the
+        * list of OIDs we return.  Indexes into these arrays get assigned in a
+        * breadth-first manner, whereby partitions of any given level are placed
+        * consecutively in the respective arrays.
+        */
        pd = (PartitionDispatchData **) palloc(*num_parted *
                                                                                   sizeof(PartitionDispatchData *));
        *leaf_part_oids = NIL;
-       i = k = 0;
+       i = k = offset = 0;
        foreach(lc, parted_rels)
        {
                Relation        partrel = lfirst(lc);
@@ -1010,6 +1019,16 @@ RelationGetPartitionDispatchInfo(Relation rel, int lockmode,
                pd[i]->partdesc = partdesc;
                pd[i]->indexes = (int *) palloc(partdesc->nparts * sizeof(int));
 
+               /*
+                * Indexes corresponding to the internal partitions are multiplied by
+                * -1 to distinguish them from those of leaf partitions.  Encountering
+                * an index >= 0 means we found a leaf partition, which is immediately
+                * returned as the partition we are looking for.  A negative index
+                * means we found a partitioned table, whose PartitionDispatch object
+                * is located at the above index multiplied back by -1.  Using the
+                * PartitionDispatch object, search is continued further down the
+                * partition tree.
+                */
                m = 0;
                for (j = 0; j < partdesc->nparts; j++)
                {
@@ -1023,14 +1042,22 @@ RelationGetPartitionDispatchInfo(Relation rel, int lockmode,
                        else
                        {
                                /*
-                                * We can assign indexes this way because of the way
-                                * parted_rels has been generated.
+                                * offset denotes the number of partitioned tables of upper
+                                * levels including those of the current level.  Any partition
+                                * of this table must belong to the next level and hence will
+                                * be placed after the last partitioned table of this level.
                                 */
-                               pd[i]->indexes[j] = -(i + 1 + m);
+                               pd[i]->indexes[j] = -(1 + offset + m);
                                m++;
                        }
                }
                i++;
+
+               /*
+                * This counts the number of partitioned tables at upper levels
+                * including those of the current level.
+                */
+               offset += m;
        }
 
        return pd;