handle-exact-tlist-for-append-plans-1.patch
text/x-diff
Filename: handle-exact-tlist-for-append-plans-1.patch
Type: text/x-diff
Part: 0
Patch
Format: unified
| File | + | − |
|---|---|---|
| src/backend/optimizer/path/pathkeys.c | 0 | 0 |
| src/backend/optimizer/plan/createplan.c | 0 | 0 |
| src/test/regress/expected/union.out | 0 | 0 |
| src/test/regress/sql/union.sql | 0 | 0 |
diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c
index 68b2204..7ed8279 100644
*** a/src/backend/optimizer/path/pathkeys.c
--- b/src/backend/optimizer/path/pathkeys.c
*************** build_expression_pathkey(PlannerInfo *ro
*** 771,779 ****
* 'subquery_pathkeys': the subquery's output pathkeys, in its terms.
* 'subquery_tlist': the subquery's output targetlist, in its terms.
*
! * It is not necessary for caller to do truncate_useless_pathkeys(),
! * because we select keys in a way that takes usefulness of the keys into
! * account.
*/
List *
convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
--- 771,781 ----
* 'subquery_pathkeys': the subquery's output pathkeys, in its terms.
* 'subquery_tlist': the subquery's output targetlist, in its terms.
*
! * We intentionally don't do truncate_useless_pathkeys() here, because there
! * are situations where seeing the raw ordering of the subquery is helpful.
! * For example, if it returns ORDER BY x DESC, that may prompt us to
! * construct a mergejoin using DESC order rather than ASC order; but the
! * right_merge_direction heuristic would have us throw the knowledge away.
*/
List *
convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index efe073a..270c119 100644
*** a/src/backend/optimizer/plan/createplan.c
--- b/src/backend/optimizer/plan/createplan.c
*************** static List *get_gating_quals(PlannerInf
*** 81,88 ****
static Plan *create_gating_plan(PlannerInfo *root, Path *path, Plan *plan,
List *gating_quals);
static Plan *create_join_plan(PlannerInfo *root, JoinPath *best_path);
! static Plan *create_append_plan(PlannerInfo *root, AppendPath *best_path);
! static Plan *create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path);
static Result *create_group_result_plan(PlannerInfo *root,
GroupResultPath *best_path);
static ProjectSet *create_project_set_plan(PlannerInfo *root, ProjectSetPath *best_path);
--- 81,90 ----
static Plan *create_gating_plan(PlannerInfo *root, Path *path, Plan *plan,
List *gating_quals);
static Plan *create_join_plan(PlannerInfo *root, JoinPath *best_path);
! static Plan *create_append_plan(PlannerInfo *root, AppendPath *best_path,
! int flags);
! static Plan *create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path,
! int flags);
static Result *create_group_result_plan(PlannerInfo *root,
GroupResultPath *best_path);
static ProjectSet *create_project_set_plan(PlannerInfo *root, ProjectSetPath *best_path);
*************** create_plan_recurse(PlannerInfo *root, P
*** 390,400 ****
break;
case T_Append:
plan = create_append_plan(root,
! (AppendPath *) best_path);
break;
case T_MergeAppend:
plan = create_merge_append_plan(root,
! (MergeAppendPath *) best_path);
break;
case T_Result:
if (IsA(best_path, ProjectionPath))
--- 392,404 ----
break;
case T_Append:
plan = create_append_plan(root,
! (AppendPath *) best_path,
! flags);
break;
case T_MergeAppend:
plan = create_merge_append_plan(root,
! (MergeAppendPath *) best_path,
! flags);
break;
case T_Result:
if (IsA(best_path, ProjectionPath))
*************** create_join_plan(PlannerInfo *root, Join
*** 1054,1063 ****
* Returns a Plan node.
*/
static Plan *
! create_append_plan(PlannerInfo *root, AppendPath *best_path)
{
Append *plan;
List *tlist = build_path_tlist(root, &best_path->path);
List *pathkeys = best_path->path.pathkeys;
List *subplans = NIL;
ListCell *subpaths;
--- 1058,1069 ----
* Returns a Plan node.
*/
static Plan *
! create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags)
{
Append *plan;
List *tlist = build_path_tlist(root, &best_path->path);
+ int orig_tlist_length = list_length(tlist);
+ bool tlist_was_changed = false;
List *pathkeys = best_path->path.pathkeys;
List *subplans = NIL;
ListCell *subpaths;
*************** create_append_plan(PlannerInfo *root, Ap
*** 1112,1118 ****
if (pathkeys != NIL)
{
! /* Compute sort column info, and adjust the Append's tlist as needed */
(void) prepare_sort_from_pathkeys((Plan *) plan, pathkeys,
best_path->path.parent->relids,
NULL,
--- 1118,1129 ----
if (pathkeys != NIL)
{
! /*
! * Compute sort column info, and adjust the Append's tlist as needed.
! * Because we pass adjust_tlist_in_place = true, we may ignore the
! * function result; it must be the same plan node. However, we then
! * need to detect whether any tlist entries were added.
! */
(void) prepare_sort_from_pathkeys((Plan *) plan, pathkeys,
best_path->path.parent->relids,
NULL,
*************** create_append_plan(PlannerInfo *root, Ap
*** 1122,1127 ****
--- 1133,1139 ----
&nodeSortOperators,
&nodeCollations,
&nodeNullsFirst);
+ tlist_was_changed = (orig_tlist_length != list_length(plan->plan.targetlist));
}
/* Build the plan for each child */
*************** create_append_plan(PlannerInfo *root, Ap
*** 1231,1237 ****
copy_generic_path_info(&plan->plan, (Path *) best_path);
! return (Plan *) plan;
}
/*
--- 1243,1262 ----
copy_generic_path_info(&plan->plan, (Path *) best_path);
! /*
! * If prepare_sort_from_pathkeys added sort columns, but we were told to
! * produce either the exact tlist or a narrow tlist, we should get rid of
! * the sort columns again. We must inject a projection node to do so.
! */
! if (tlist_was_changed && (flags & (CP_EXACT_TLIST | CP_SMALL_TLIST)))
! {
! tlist = list_truncate(list_copy(plan->plan.targetlist),
! orig_tlist_length);
! return inject_projection_plan((Plan *) plan, tlist,
! plan->plan.parallel_safe);
! }
! else
! return (Plan *) plan;
}
/*
*************** create_append_plan(PlannerInfo *root, Ap
*** 1242,1252 ****
* Returns a Plan node.
*/
static Plan *
! create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
{
MergeAppend *node = makeNode(MergeAppend);
Plan *plan = &node->plan;
List *tlist = build_path_tlist(root, &best_path->path);
List *pathkeys = best_path->path.pathkeys;
List *subplans = NIL;
ListCell *subpaths;
--- 1267,1280 ----
* Returns a Plan node.
*/
static Plan *
! create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path,
! int flags)
{
MergeAppend *node = makeNode(MergeAppend);
Plan *plan = &node->plan;
List *tlist = build_path_tlist(root, &best_path->path);
+ int orig_tlist_length = list_length(tlist);
+ bool tlist_was_changed;
List *pathkeys = best_path->path.pathkeys;
List *subplans = NIL;
ListCell *subpaths;
*************** create_merge_append_plan(PlannerInfo *ro
*** 1265,1271 ****
plan->lefttree = NULL;
plan->righttree = NULL;
! /* Compute sort column info, and adjust MergeAppend's tlist as needed */
(void) prepare_sort_from_pathkeys(plan, pathkeys,
best_path->path.parent->relids,
NULL,
--- 1293,1304 ----
plan->lefttree = NULL;
plan->righttree = NULL;
! /*
! * Compute sort column info, and adjust MergeAppend's tlist as needed.
! * Because we pass adjust_tlist_in_place = true, we may ignore the
! * function result; it must be the same plan node. However, we then need
! * to detect whether any tlist entries were added.
! */
(void) prepare_sort_from_pathkeys(plan, pathkeys,
best_path->path.parent->relids,
NULL,
*************** create_merge_append_plan(PlannerInfo *ro
*** 1275,1280 ****
--- 1308,1314 ----
&node->sortOperators,
&node->collations,
&node->nullsFirst);
+ tlist_was_changed = (orig_tlist_length != list_length(plan->targetlist));
/*
* Now prepare the child plans. We must apply prepare_sort_from_pathkeys
*************** create_merge_append_plan(PlannerInfo *ro
*** 1371,1377 ****
node->mergeplans = subplans;
node->part_prune_info = partpruneinfo;
! return (Plan *) node;
}
/*
--- 1405,1422 ----
node->mergeplans = subplans;
node->part_prune_info = partpruneinfo;
! /*
! * If prepare_sort_from_pathkeys added sort columns, but we were told to
! * produce either the exact tlist or a narrow tlist, we should get rid of
! * the sort columns again. We must inject a projection node to do so.
! */
! if (tlist_was_changed && (flags & (CP_EXACT_TLIST | CP_SMALL_TLIST)))
! {
! tlist = list_truncate(list_copy(plan->targetlist), orig_tlist_length);
! return inject_projection_plan(plan, tlist, plan->parallel_safe);
! }
! else
! return plan;
}
/*
diff --git a/src/test/regress/expected/union.out b/src/test/regress/expected/union.out
index da70438..c4405ca 100644
*** a/src/test/regress/expected/union.out
--- b/src/test/regress/expected/union.out
*************** ORDER BY x;
*** 915,920 ****
--- 915,994 ----
2 | 4
(1 row)
+ -- Test cases where the native ordering of a sub-select has more pathkeys
+ -- than the outer query cares about
+ explain (costs off)
+ select distinct q1 from
+ (select distinct * from int8_tbl i81
+ union all
+ select distinct * from int8_tbl i82) ss
+ where q2 = q2;
+ QUERY PLAN
+ ----------------------------------------------------------
+ Unique
+ -> Merge Append
+ Sort Key: "*SELECT* 1".q1
+ -> Subquery Scan on "*SELECT* 1"
+ -> Unique
+ -> Sort
+ Sort Key: i81.q1, i81.q2
+ -> Seq Scan on int8_tbl i81
+ Filter: (q2 IS NOT NULL)
+ -> Subquery Scan on "*SELECT* 2"
+ -> Unique
+ -> Sort
+ Sort Key: i82.q1, i82.q2
+ -> Seq Scan on int8_tbl i82
+ Filter: (q2 IS NOT NULL)
+ (15 rows)
+
+ select distinct q1 from
+ (select distinct * from int8_tbl i81
+ union all
+ select distinct * from int8_tbl i82) ss
+ where q2 = q2;
+ q1
+ ------------------
+ 123
+ 4567890123456789
+ (2 rows)
+
+ explain (costs off)
+ select distinct q1 from
+ (select distinct * from int8_tbl i81
+ union all
+ select distinct * from int8_tbl i82) ss
+ where -q1 = q2;
+ QUERY PLAN
+ ----------------------------------------------------------------
+ Unique
+ -> Result
+ -> Merge Append
+ Sort Key: "*SELECT* 1".q1, ((- "*SELECT* 1".q1))
+ -> Subquery Scan on "*SELECT* 1"
+ -> Unique
+ -> Sort
+ Sort Key: i81.q1, i81.q2
+ -> Seq Scan on int8_tbl i81
+ Filter: ((- q1) = q2)
+ -> Subquery Scan on "*SELECT* 2"
+ -> Unique
+ -> Sort
+ Sort Key: i82.q1, i82.q2
+ -> Seq Scan on int8_tbl i82
+ Filter: ((- q1) = q2)
+ (16 rows)
+
+ select distinct q1 from
+ (select distinct * from int8_tbl i81
+ union all
+ select distinct * from int8_tbl i82) ss
+ where -q1 = q2;
+ q1
+ ------------------
+ 4567890123456789
+ (1 row)
+
-- Test proper handling of parameterized appendrel paths when the
-- potential join qual is expensive
create function expensivefunc(int) returns int
diff --git a/src/test/regress/sql/union.sql b/src/test/regress/sql/union.sql
index eed7c8d..5f4881d 100644
*** a/src/test/regress/sql/union.sql
--- b/src/test/regress/sql/union.sql
*************** SELECT * FROM
*** 379,384 ****
--- 379,412 ----
WHERE x > 3
ORDER BY x;
+ -- Test cases where the native ordering of a sub-select has more pathkeys
+ -- than the outer query cares about
+ explain (costs off)
+ select distinct q1 from
+ (select distinct * from int8_tbl i81
+ union all
+ select distinct * from int8_tbl i82) ss
+ where q2 = q2;
+
+ select distinct q1 from
+ (select distinct * from int8_tbl i81
+ union all
+ select distinct * from int8_tbl i82) ss
+ where q2 = q2;
+
+ explain (costs off)
+ select distinct q1 from
+ (select distinct * from int8_tbl i81
+ union all
+ select distinct * from int8_tbl i82) ss
+ where -q1 = q2;
+
+ select distinct q1 from
+ (select distinct * from int8_tbl i81
+ union all
+ select distinct * from int8_tbl i82) ss
+ where -q1 = q2;
+
-- Test proper handling of parameterized appendrel paths when the
-- potential join qual is expensive
create function expensivefunc(int) returns int