aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/optimizer/path/allpaths.c20
-rw-r--r--src/backend/optimizer/path/equivclass.c12
-rw-r--r--src/backend/optimizer/plan/createplan.c2
-rw-r--r--src/test/regress/expected/union.out28
-rw-r--r--src/test/regress/sql/union.sql18
5 files changed, 71 insertions, 9 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 715f44675f8..59b72339163 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -635,10 +635,15 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
* accumulate_append_subpath
* Add a subpath to the list being built for an Append or MergeAppend
*
- * It's possible that the child is itself an Append path, in which case
- * we can "cut out the middleman" and just add its child paths to our
- * own list. (We don't try to do this earlier because we need to
- * apply both levels of transformation to the quals.)
+ * It's possible that the child is itself an Append or MergeAppend path, in
+ * which case we can "cut out the middleman" and just add its child paths to
+ * our own list. (We don't try to do this earlier because we need to apply
+ * both levels of transformation to the quals.)
+ *
+ * Note that if we omit a child MergeAppend in this way, we are effectively
+ * omitting a sort step, which seems fine: if the parent is to be an Append,
+ * its result would be unsorted anyway, while if the parent is to be a
+ * MergeAppend, there's no point in a separate sort on a child.
*/
static List *
accumulate_append_subpath(List *subpaths, Path *path)
@@ -650,6 +655,13 @@ accumulate_append_subpath(List *subpaths, Path *path)
/* list_copy is important here to avoid sharing list substructure */
return list_concat(subpaths, list_copy(apath->subpaths));
}
+ else if (IsA(path, MergeAppendPath))
+ {
+ MergeAppendPath *mpath = (MergeAppendPath *) path;
+
+ /* list_copy is important here to avoid sharing list substructure */
+ return list_concat(subpaths, list_copy(mpath->subpaths));
+ }
else
return lappend(subpaths, path);
}
diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c
index 2a3826cfa5e..d89feb34b32 100644
--- a/src/backend/optimizer/path/equivclass.c
+++ b/src/backend/optimizer/path/equivclass.c
@@ -1850,16 +1850,20 @@ add_child_rel_equivalences(PlannerInfo *root,
if (cur_ec->ec_has_volatile)
continue;
- /* No point in searching if parent rel not mentioned in eclass */
- if (!bms_is_subset(parent_rel->relids, cur_ec->ec_relids))
+ /*
+ * No point in searching if parent rel not mentioned in eclass; but
+ * we can't tell that for sure if parent rel is itself a child.
+ */
+ if (parent_rel->reloptkind == RELOPT_BASEREL &&
+ !bms_is_subset(parent_rel->relids, cur_ec->ec_relids))
continue;
foreach(lc2, cur_ec->ec_members)
{
EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc2);
- if (cur_em->em_is_child)
- continue; /* ignore children here */
+ if (cur_em->em_is_const)
+ continue; /* ignore consts here */
/* Does it reference (only) parent_rel? */
if (bms_equal(cur_em->em_relids, parent_rel->relids))
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index c246468c929..682217d1503 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -700,7 +700,7 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
/* Compute sort column info, and adjust MergeAppend's tlist as needed */
(void) prepare_sort_from_pathkeys(root, plan, pathkeys,
- NULL,
+ best_path->path.parent->relids,
NULL,
true,
&node->numCols,
diff --git a/src/test/regress/expected/union.out b/src/test/regress/expected/union.out
index 2c30e485c82..9b6eb8a26ab 100644
--- a/src/test/regress/expected/union.out
+++ b/src/test/regress/expected/union.out
@@ -500,9 +500,37 @@ explain (costs off)
Index Cond: (ab = 'ab'::text)
(6 rows)
+--
+-- Test that ORDER BY for UNION ALL can be pushed down to inheritance
+-- children.
+--
reset enable_seqscan;
reset enable_indexscan;
reset enable_bitmapscan;
+create table events (event_id int primary key);
+NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "events_pkey" for table "events"
+create table other_events (event_id int primary key);
+NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "other_events_pkey" for table "other_events"
+create table events_child () inherits (events);
+explain (costs off)
+select event_id
+ from (select event_id from events
+ union all
+ select event_id from other_events) ss
+ order by event_id;
+ QUERY PLAN
+----------------------------------------------------------------
+ Result
+ -> Merge Append
+ Sort Key: public.events.event_id
+ -> Index Scan using events_pkey on events
+ -> Sort
+ Sort Key: public.events.event_id
+ -> Seq Scan on events_child events
+ -> Index Scan using other_events_pkey on other_events
+(8 rows)
+
+drop table events_child, events, other_events;
-- Test constraint exclusion of UNION ALL subqueries
explain (costs off)
SELECT * FROM
diff --git a/src/test/regress/sql/union.sql b/src/test/regress/sql/union.sql
index f3c9d113827..86207d25b09 100644
--- a/src/test/regress/sql/union.sql
+++ b/src/test/regress/sql/union.sql
@@ -196,10 +196,28 @@ explain (costs off)
SELECT * FROM t2) t
WHERE ab = 'ab';
+--
+-- Test that ORDER BY for UNION ALL can be pushed down to inheritance
+-- children.
+--
+
reset enable_seqscan;
reset enable_indexscan;
reset enable_bitmapscan;
+create table events (event_id int primary key);
+create table other_events (event_id int primary key);
+create table events_child () inherits (events);
+
+explain (costs off)
+select event_id
+ from (select event_id from events
+ union all
+ select event_id from other_events) ss
+ order by event_id;
+
+drop table events_child, events, other_events;
+
-- Test constraint exclusion of UNION ALL subqueries
explain (costs off)
SELECT * FROM