aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2019-03-26 12:03:27 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2019-03-26 12:03:27 -0400
commite8d5dd6be79ed532710922105c31a2d25b14430f (patch)
tree32e30b46dfdf7300f68053952e299fb6df7e2232
parent1af25ca0c2d9d110bd7bd5be2a14fb20cd93ee78 (diff)
downloadpostgresql-e8d5dd6be79ed532710922105c31a2d25b14430f.tar.gz
postgresql-e8d5dd6be79ed532710922105c31a2d25b14430f.zip
Get rid of duplicate child RTE for a partitioned table.
We've been creating duplicate RTEs for partitioned tables just because we do so for regular inheritance parent tables. But unlike regular-inheritance parents which are themselves regular tables and thus need to be scanned, partitioned tables don't need the extra RTE. This makes the conditions for building a child RTE the same as those for building an AppendRelInfo, allowing minor simplification in expand_single_inheritance_child. Since the planner's actual processing is driven off the AppendRelInfo list, nothing much changes beyond that, we just have one fewer useless RTE entry. Amit Langote, reviewed and hacked a bit by me Discussion: https://postgr.es/m/9d7c5112-cb99-6a47-d3be-cf1ee6862a1d@lab.ntt.co.jp
-rw-r--r--contrib/postgres_fdw/expected/postgres_fdw.out2
-rw-r--r--src/backend/optimizer/util/inherit.c86
2 files changed, 45 insertions, 43 deletions
diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 2be67bca02a..9ad9035c5df 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -8435,7 +8435,7 @@ SELECT t1.a,t2.b,t2.c FROM fprt1 t1 LEFT JOIN (SELECT * FROM fprt2 WHERE a < 10)
Foreign Scan
Output: t1.a, ftprt2_p1.b, ftprt2_p1.c
Relations: (public.ftprt1_p1 t1) LEFT JOIN (public.ftprt2_p1 fprt2)
- Remote SQL: SELECT r6.a, r9.b, r9.c FROM (public.fprt1_p1 r6 LEFT JOIN public.fprt2_p1 r9 ON (((r6.a = r9.b)) AND ((r6.b = r9.a)) AND ((r9.a < 10)))) WHERE ((r6.a < 10)) ORDER BY r6.a ASC NULLS LAST, r9.b ASC NULLS LAST, r9.c ASC NULLS LAST
+ Remote SQL: SELECT r5.a, r7.b, r7.c FROM (public.fprt1_p1 r5 LEFT JOIN public.fprt2_p1 r7 ON (((r5.a = r7.b)) AND ((r5.b = r7.a)) AND ((r7.a < 10)))) WHERE ((r5.a < 10)) ORDER BY r5.a ASC NULLS LAST, r7.b ASC NULLS LAST, r7.c ASC NULLS LAST
(4 rows)
SELECT t1.a,t2.b,t2.c FROM fprt1 t1 LEFT JOIN (SELECT * FROM fprt2 WHERE a < 10) t2 ON (t1.a = t2.b and t1.b = t2.a) WHERE t1.a < 10 ORDER BY 1,2,3;
diff --git a/src/backend/optimizer/util/inherit.c b/src/backend/optimizer/util/inherit.c
index 1fa154e0cb1..1d1e5060e26 100644
--- a/src/backend/optimizer/util/inherit.c
+++ b/src/backend/optimizer/util/inherit.c
@@ -90,9 +90,10 @@ expand_inherited_tables(PlannerInfo *root)
* A childless table is never considered to be an inheritance set. For
* regular inheritance, a parent RTE must always have at least two associated
* AppendRelInfos: one corresponding to the parent table as a simple member of
- * inheritance set and one or more corresponding to the actual children.
- * Since a partitioned table is not scanned, it might have only one associated
- * AppendRelInfo.
+ * the inheritance set and one or more corresponding to the actual children.
+ * (But a partitioned table might have only one associated AppendRelInfo,
+ * since it's not itself scanned and hence doesn't need a second RTE to
+ * represent itself as a member of the set.)
*/
static void
expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
@@ -145,6 +146,9 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
/* Scan the inheritance set and expand it */
if (oldrelation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
{
+ /*
+ * Partitioned table, so set up for partitioning.
+ */
Assert(rte->relkind == RELKIND_PARTITIONED_TABLE);
if (root->glob->partition_directory == NULL)
@@ -161,6 +165,11 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
}
else
{
+ /*
+ * Ordinary table, so process traditional-inheritance children. (Note
+ * that partitioned tables are not allowed to have inheritance
+ * children, so it's not possible for both cases to apply.)
+ */
List *appinfos = NIL;
RangeTblEntry *childrte;
Index childRTindex;
@@ -182,8 +191,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
}
/*
- * This table has no partitions. Expand any plain inheritance
- * children in the order the OIDs were returned by
+ * Expand inheritance children in the order the OIDs were returned by
* find_all_inheritors.
*/
foreach(l, inhOIDs)
@@ -273,11 +281,6 @@ expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte,
root->partColsUpdated =
has_partition_attrs(parentrel, parentrte->updatedCols, NULL);
- /* First expand the partitioned table itself. */
- expand_single_inheritance_child(root, parentrte, parentRTindex, parentrel,
- top_parentrc, parentrel,
- appinfos, &childrte, &childRTindex);
-
/*
* If the partitioned table has no partitions, treat this as the
* non-inheritance case.
@@ -288,6 +291,11 @@ expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte,
return;
}
+ /*
+ * Create a child RTE for each partition. Note that unlike traditional
+ * inheritance, we don't need a child RTE for the partitioned table
+ * itself, because it's not going to be scanned.
+ */
for (i = 0; i < partdesc->nparts; i++)
{
Oid childOID = partdesc->oids[i];
@@ -321,8 +329,7 @@ expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte,
/*
* expand_single_inheritance_child
- * Build a RangeTblEntry and an AppendRelInfo, if appropriate, plus
- * maybe a PlanRowMark.
+ * Build a RangeTblEntry and an AppendRelInfo, plus maybe a PlanRowMark.
*
* We now expand the partition hierarchy level by level, creating a
* corresponding hierarchy of AppendRelInfos and RelOptInfos, where each
@@ -371,9 +378,11 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
childrte->relid = childOID;
childrte->relkind = childrel->rd_rel->relkind;
/* A partitioned child will need to be expanded further. */
- if (childOID != parentOID &&
- childrte->relkind == RELKIND_PARTITIONED_TABLE)
+ if (childrte->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ Assert(childOID != parentOID);
childrte->inh = true;
+ }
else
childrte->inh = false;
childrte->requiredPerms = 0;
@@ -383,36 +392,29 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
*childRTindex_p = childRTindex;
/*
- * We need an AppendRelInfo if paths will be built for the child RTE. If
- * childrte->inh is true, then we'll always need to generate append paths
- * for it. If childrte->inh is false, we must scan it if it's not a
- * partitioned table; but if it is a partitioned table, then it never has
- * any data of its own and need not be scanned.
+ * Build an AppendRelInfo struct for each parent/child pair.
*/
- if (childrte->relkind != RELKIND_PARTITIONED_TABLE || childrte->inh)
- {
- appinfo = make_append_rel_info(parentrel, childrel,
- parentRTindex, childRTindex);
- *appinfos = lappend(*appinfos, appinfo);
+ appinfo = make_append_rel_info(parentrel, childrel,
+ parentRTindex, childRTindex);
+ *appinfos = lappend(*appinfos, appinfo);
- /*
- * Translate the column permissions bitmaps to the child's attnums (we
- * have to build the translated_vars list before we can do this). But
- * if this is the parent table, leave copyObject's result alone.
- *
- * Note: we need to do this even though the executor won't run any
- * permissions checks on the child RTE. The insertedCols/updatedCols
- * bitmaps may be examined for trigger-firing purposes.
- */
- if (childOID != parentOID)
- {
- childrte->selectedCols = translate_col_privs(parentrte->selectedCols,
- appinfo->translated_vars);
- childrte->insertedCols = translate_col_privs(parentrte->insertedCols,
- appinfo->translated_vars);
- childrte->updatedCols = translate_col_privs(parentrte->updatedCols,
- appinfo->translated_vars);
- }
+ /*
+ * Translate the column permissions bitmaps to the child's attnums (we
+ * have to build the translated_vars list before we can do this). But if
+ * this is the parent table, we can leave copyObject's result alone.
+ *
+ * Note: we need to do this even though the executor won't run any
+ * permissions checks on the child RTE. The insertedCols/updatedCols
+ * bitmaps may be examined for trigger-firing purposes.
+ */
+ if (childOID != parentOID)
+ {
+ childrte->selectedCols = translate_col_privs(parentrte->selectedCols,
+ appinfo->translated_vars);
+ childrte->insertedCols = translate_col_privs(parentrte->insertedCols,
+ appinfo->translated_vars);
+ childrte->updatedCols = translate_col_privs(parentrte->updatedCols,
+ appinfo->translated_vars);
}
/*