Set partitioned_rels appropriately when UNION ALL is used.
authorRobert Haas <rhaas@postgresql.org>
Thu, 14 Sep 2017 14:43:44 +0000 (10:43 -0400)
committerRobert Haas <rhaas@postgresql.org>
Thu, 14 Sep 2017 15:00:39 +0000 (11:00 -0400)
In most cases, this omission won't matter, because the appropriate
locks will have been acquired during parse/plan or by AcquireExecutorLocks.
But it's a bug all the same.

Report by Ashutosh Bapat.  Patch by me, reviewed by Amit Langote.

Discussion: http://postgr.es/m/CAFjFpRdHb_ZnoDTuBXqrudWXh3H1ibLkr6nHsCFT96fSK4DXtA@mail.gmail.com

src/backend/optimizer/path/allpaths.c
src/backend/optimizer/plan/planner.c

index 2d7e1d84d099818f6e5d622d5397b7261cce4d49..e8e7202e1153fd6d1370f0c10797f4af26d0ad71 100644 (file)
@@ -1287,13 +1287,34 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
    ListCell   *l;
    List       *partitioned_rels = NIL;
    RangeTblEntry *rte;
+   bool        build_partitioned_rels = false;
 
+   /*
+    * A plain relation will already have a PartitionedChildRelInfo if it is
+    * partitioned.  For a subquery RTE, no PartitionedChildRelInfo exists; we
+    * collect all partitioned_rels associated with any child.  (This assumes
+    * that we don't need to look through multiple levels of subquery RTEs; if
+    * we ever do, we could create a PartitionedChildRelInfo with the
+    * accumulated list of partitioned_rels which would then be found when
+    * populated our parent rel with paths.  For the present, that appears to
+    * be unnecessary.)
+    */
    rte = planner_rt_fetch(rel->relid, root);
-   if (rte->relkind == RELKIND_PARTITIONED_TABLE)
+   switch (rte->rtekind)
    {
-       partitioned_rels = get_partitioned_child_rels(root, rel->relid);
-       /* The root partitioned table is included as a child rel */
-       Assert(list_length(partitioned_rels) >= 1);
+       case RTE_RELATION:
+           if (rte->relkind == RELKIND_PARTITIONED_TABLE)
+           {
+               partitioned_rels =
+                   get_partitioned_child_rels(root, rel->relid);
+               Assert(list_length(partitioned_rels) >= 1);
+           }
+           break;
+       case RTE_SUBQUERY:
+           build_partitioned_rels = true;
+           break;
+       default:
+           elog(ERROR, "unexpcted rtekind: %d", (int) rte->rtekind);
    }
 
    /*
@@ -1306,6 +1327,19 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
        RelOptInfo *childrel = lfirst(l);
        ListCell   *lcp;
 
+       /*
+        * If we need to build partitioned_rels, accumulate the partitioned
+        * rels for this child.
+        */
+       if (build_partitioned_rels)
+       {
+           List       *cprels;
+
+           cprels = get_partitioned_child_rels(root, childrel->relid);
+           partitioned_rels = list_concat(partitioned_rels,
+                                          list_copy(cprels));
+       }
+
        /*
         * If child has an unparameterized cheapest-total path, add that to
         * the unparameterized Append path we are constructing for the parent.
index 6b79b3ad994b8c6f351e8aff8981dae2b3d33188..907622eadbb5d5f9c2938162be2fb73339ab976a 100644 (file)
@@ -6076,7 +6076,8 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid)
  *     Returns a list of the RT indexes of the partitioned child relations
  *     with rti as the root parent RT index.
  *
- * Note: Only call this function on RTEs known to be partitioned tables.
+ * Note: This function might get called even for range table entries that
+ * are not partitioned tables; in such a case, it will simply return NIL.
  */
 List *
 get_partitioned_child_rels(PlannerInfo *root, Index rti)
@@ -6095,8 +6096,5 @@ get_partitioned_child_rels(PlannerInfo *root, Index rti)
        }
    }
 
-   /* The root partitioned table is included as a child rel */
-   Assert(list_length(result) >= 1);
-
    return result;
 }