From ddb8f46b5f0137bf6d65b3b743ff62b7416a2860 Mon Sep 17 00:00:00 2001 From: Sven Klemm Date: Fri, 4 Oct 2019 15:19:27 +0200 Subject: [PATCH] Fix ordered append with space partitioning Ordered append for space partitioned hypertable would lead to an error when the ORDER BY clause was not a column reference on PG 9.6 and PG 10. This patch fixes ordered append for space partitioned hypertable and allows arbitary expressions to be used in the ORDER BY clause. --- src/chunk_append/planner.c | 27 ++++---- test/expected/plan_ordered_append-10.out | 63 +++++++++++++++++++ test/expected/plan_ordered_append-11.out | 63 +++++++++++++++++++ test/expected/plan_ordered_append-9.6.out | 47 ++++++++++++++ .../sql/include/plan_ordered_append_query.sql | 11 ++++ 5 files changed, 198 insertions(+), 13 deletions(-) diff --git a/src/chunk_append/planner.c b/src/chunk_append/planner.c index 78026e985..052b01d6d 100644 --- a/src/chunk_append/planner.c +++ b/src/chunk_append/planner.c @@ -53,6 +53,7 @@ adjust_childscan(PlannerInfo *root, Plan *plan, Path *path, List *pathkeys, List Oid *sortOperators; Oid *collations; bool *nullsFirst; + AttrNumber *childColIdx; /* push down targetlist to children */ plan->targetlist = (List *) adjust_appendrel_attrs_compat(root, (Node *) tlist, appinfo); @@ -64,7 +65,7 @@ adjust_childscan(PlannerInfo *root, Plan *plan, Path *path, List *pathkeys, List sortColIdx, true, &childSortCols, - &sortColIdx, + &childColIdx, &sortOperators, &collations, &nullsFirst); @@ -73,7 +74,7 @@ adjust_childscan(PlannerInfo *root, Plan *plan, Path *path, List *pathkeys, List if (!pathkeys_contained_in(pathkeys, path->pathkeys)) { plan = (Plan *) - make_sort(plan, childSortCols, sortColIdx, sortOperators, collations, nullsFirst); + make_sort(plan, childSortCols, childColIdx, sortOperators, collations, nullsFirst); } return plan; } @@ -186,17 +187,17 @@ chunk_append_plan_create(PlannerInfo *root, RelOptInfo *rel, CustomPath *path, L MergeAppend *merge_plan = castNode(MergeAppend, lfirst(lc_plan)); MergeAppendPath *merge_path = castNode(MergeAppendPath, lfirst(lc_path)); - /* Compute sort column info, and adjust MergeAppend's tlist as needed */ - ts_prepare_sort_from_pathkeys((Plan *) merge_plan, - pathkeys, - merge_path->path.parent->relids, - NULL, - true, - &numCols, - &sortColIdx, - &sortOperators, - &collations, - &nullsFirst); + /* + * Since for space partitioning the MergeAppend below ChunkAppend + * still has the hypertable as rel we can copy sort properties and + * target list from toplevel ChunkAppend. + */ + merge_plan->plan.targetlist = cscan->scan.plan.targetlist; + merge_plan->sortColIdx = sortColIdx; + merge_plan->sortOperators = sortOperators; + merge_plan->collations = collations; + merge_plan->nullsFirst = nullsFirst; + forboth (lc_childpath, merge_path->subpaths, lc_childplan, merge_plan->mergeplans) { lfirst(lc_childplan) = adjust_childscan(root, diff --git a/test/expected/plan_ordered_append-10.out b/test/expected/plan_ordered_append-10.out index 19c25d8d7..3eb802294 100644 --- a/test/expected/plan_ordered_append-10.out +++ b/test/expected/plan_ordered_append-10.out @@ -1281,6 +1281,69 @@ ORDER BY time DESC; Heap Fetches: 6720 (38 rows) +-- expressions in ORDER BY clause +:PREFIX SELECT + time_bucket('1h',time) +FROM space +ORDER BY 1 LIMIT 10; + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------- + Limit (actual rows=10 loops=1) + -> Custom Scan (ChunkAppend) on space (actual rows=10 loops=1) + Order: time_bucket('@ 1 hour'::interval, space."time") + -> Merge Append (actual rows=10 loops=1) + Sort Key: (time_bucket('@ 1 hour'::interval, _hyper_7_24_chunk."time")) + -> Index Only Scan Backward using _hyper_7_24_chunk_space_time_idx on _hyper_7_24_chunk (actual rows=10 loops=1) + Heap Fetches: 10 + -> Index Only Scan Backward using _hyper_7_26_chunk_space_time_idx on _hyper_7_26_chunk (actual rows=1 loops=1) + Heap Fetches: 1 + -> Index Only Scan Backward using _hyper_7_28_chunk_space_time_idx on _hyper_7_28_chunk (actual rows=1 loops=1) + Heap Fetches: 1 + -> Index Only Scan Backward using _hyper_7_30_chunk_space_time_idx on _hyper_7_30_chunk (actual rows=1 loops=1) + Heap Fetches: 1 + -> Merge Append (never executed) + Sort Key: (time_bucket('@ 1 hour'::interval, _hyper_7_23_chunk."time")) + -> Index Only Scan Backward using _hyper_7_23_chunk_space_time_idx on _hyper_7_23_chunk (never executed) + Heap Fetches: 0 + -> Index Only Scan Backward using _hyper_7_25_chunk_space_time_idx on _hyper_7_25_chunk (never executed) + Heap Fetches: 0 + -> Index Only Scan Backward using _hyper_7_27_chunk_space_time_idx on _hyper_7_27_chunk (never executed) + Heap Fetches: 0 + -> Index Only Scan Backward using _hyper_7_29_chunk_space_time_idx on _hyper_7_29_chunk (never executed) + Heap Fetches: 0 +(23 rows) + +:PREFIX SELECT + time_bucket('1h',time) +FROM space +ORDER BY 1 DESC LIMIT 10; + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- + Limit (actual rows=10 loops=1) + -> Custom Scan (ChunkAppend) on space (actual rows=10 loops=1) + Order: time_bucket('@ 1 hour'::interval, space."time") DESC + -> Merge Append (actual rows=10 loops=1) + Sort Key: (time_bucket('@ 1 hour'::interval, _hyper_7_29_chunk."time")) DESC + -> Index Only Scan using _hyper_7_29_chunk_space_time_idx on _hyper_7_29_chunk (actual rows=3 loops=1) + Heap Fetches: 3 + -> Index Only Scan using _hyper_7_27_chunk_space_time_idx on _hyper_7_27_chunk (actual rows=2 loops=1) + Heap Fetches: 2 + -> Index Only Scan using _hyper_7_25_chunk_space_time_idx on _hyper_7_25_chunk (actual rows=6 loops=1) + Heap Fetches: 6 + -> Index Only Scan using _hyper_7_23_chunk_space_time_idx on _hyper_7_23_chunk (actual rows=2 loops=1) + Heap Fetches: 2 + -> Merge Append (never executed) + Sort Key: (time_bucket('@ 1 hour'::interval, _hyper_7_30_chunk."time")) DESC + -> Index Only Scan using _hyper_7_30_chunk_space_time_idx on _hyper_7_30_chunk (never executed) + Heap Fetches: 0 + -> Index Only Scan using _hyper_7_28_chunk_space_time_idx on _hyper_7_28_chunk (never executed) + Heap Fetches: 0 + -> Index Only Scan using _hyper_7_26_chunk_space_time_idx on _hyper_7_26_chunk (never executed) + Heap Fetches: 0 + -> Index Only Scan using _hyper_7_24_chunk_space_time_idx on _hyper_7_24_chunk (never executed) + Heap Fetches: 0 +(23 rows) + -- test LATERAL with correlated query -- only last chunk should be executed :PREFIX SELECT * diff --git a/test/expected/plan_ordered_append-11.out b/test/expected/plan_ordered_append-11.out index 19c25d8d7..3eb802294 100644 --- a/test/expected/plan_ordered_append-11.out +++ b/test/expected/plan_ordered_append-11.out @@ -1281,6 +1281,69 @@ ORDER BY time DESC; Heap Fetches: 6720 (38 rows) +-- expressions in ORDER BY clause +:PREFIX SELECT + time_bucket('1h',time) +FROM space +ORDER BY 1 LIMIT 10; + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------- + Limit (actual rows=10 loops=1) + -> Custom Scan (ChunkAppend) on space (actual rows=10 loops=1) + Order: time_bucket('@ 1 hour'::interval, space."time") + -> Merge Append (actual rows=10 loops=1) + Sort Key: (time_bucket('@ 1 hour'::interval, _hyper_7_24_chunk."time")) + -> Index Only Scan Backward using _hyper_7_24_chunk_space_time_idx on _hyper_7_24_chunk (actual rows=10 loops=1) + Heap Fetches: 10 + -> Index Only Scan Backward using _hyper_7_26_chunk_space_time_idx on _hyper_7_26_chunk (actual rows=1 loops=1) + Heap Fetches: 1 + -> Index Only Scan Backward using _hyper_7_28_chunk_space_time_idx on _hyper_7_28_chunk (actual rows=1 loops=1) + Heap Fetches: 1 + -> Index Only Scan Backward using _hyper_7_30_chunk_space_time_idx on _hyper_7_30_chunk (actual rows=1 loops=1) + Heap Fetches: 1 + -> Merge Append (never executed) + Sort Key: (time_bucket('@ 1 hour'::interval, _hyper_7_23_chunk."time")) + -> Index Only Scan Backward using _hyper_7_23_chunk_space_time_idx on _hyper_7_23_chunk (never executed) + Heap Fetches: 0 + -> Index Only Scan Backward using _hyper_7_25_chunk_space_time_idx on _hyper_7_25_chunk (never executed) + Heap Fetches: 0 + -> Index Only Scan Backward using _hyper_7_27_chunk_space_time_idx on _hyper_7_27_chunk (never executed) + Heap Fetches: 0 + -> Index Only Scan Backward using _hyper_7_29_chunk_space_time_idx on _hyper_7_29_chunk (never executed) + Heap Fetches: 0 +(23 rows) + +:PREFIX SELECT + time_bucket('1h',time) +FROM space +ORDER BY 1 DESC LIMIT 10; + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- + Limit (actual rows=10 loops=1) + -> Custom Scan (ChunkAppend) on space (actual rows=10 loops=1) + Order: time_bucket('@ 1 hour'::interval, space."time") DESC + -> Merge Append (actual rows=10 loops=1) + Sort Key: (time_bucket('@ 1 hour'::interval, _hyper_7_29_chunk."time")) DESC + -> Index Only Scan using _hyper_7_29_chunk_space_time_idx on _hyper_7_29_chunk (actual rows=3 loops=1) + Heap Fetches: 3 + -> Index Only Scan using _hyper_7_27_chunk_space_time_idx on _hyper_7_27_chunk (actual rows=2 loops=1) + Heap Fetches: 2 + -> Index Only Scan using _hyper_7_25_chunk_space_time_idx on _hyper_7_25_chunk (actual rows=6 loops=1) + Heap Fetches: 6 + -> Index Only Scan using _hyper_7_23_chunk_space_time_idx on _hyper_7_23_chunk (actual rows=2 loops=1) + Heap Fetches: 2 + -> Merge Append (never executed) + Sort Key: (time_bucket('@ 1 hour'::interval, _hyper_7_30_chunk."time")) DESC + -> Index Only Scan using _hyper_7_30_chunk_space_time_idx on _hyper_7_30_chunk (never executed) + Heap Fetches: 0 + -> Index Only Scan using _hyper_7_28_chunk_space_time_idx on _hyper_7_28_chunk (never executed) + Heap Fetches: 0 + -> Index Only Scan using _hyper_7_26_chunk_space_time_idx on _hyper_7_26_chunk (never executed) + Heap Fetches: 0 + -> Index Only Scan using _hyper_7_24_chunk_space_time_idx on _hyper_7_24_chunk (never executed) + Heap Fetches: 0 +(23 rows) + -- test LATERAL with correlated query -- only last chunk should be executed :PREFIX SELECT * diff --git a/test/expected/plan_ordered_append-9.6.out b/test/expected/plan_ordered_append-9.6.out index a69bdaf38..5faa90343 100644 --- a/test/expected/plan_ordered_append-9.6.out +++ b/test/expected/plan_ordered_append-9.6.out @@ -1236,6 +1236,53 @@ ORDER BY time DESC; -> Index Only Scan using _hyper_9_50_chunk_space3_time_idx on _hyper_9_50_chunk (22 rows) +-- expressions in ORDER BY clause +:PREFIX SELECT + time_bucket('1h',time) +FROM space +ORDER BY 1 LIMIT 10; + QUERY PLAN +-------------------------------------------------------------------------------------------------------- + Limit + -> Custom Scan (ChunkAppend) on space + Order: time_bucket('@ 1 hour'::interval, space."time") + -> Merge Append + Sort Key: (time_bucket('@ 1 hour'::interval, _hyper_7_24_chunk."time")) + -> Index Only Scan Backward using _hyper_7_24_chunk_space_time_idx on _hyper_7_24_chunk + -> Index Only Scan Backward using _hyper_7_26_chunk_space_time_idx on _hyper_7_26_chunk + -> Index Only Scan Backward using _hyper_7_28_chunk_space_time_idx on _hyper_7_28_chunk + -> Index Only Scan Backward using _hyper_7_30_chunk_space_time_idx on _hyper_7_30_chunk + -> Merge Append + Sort Key: (time_bucket('@ 1 hour'::interval, _hyper_7_23_chunk."time")) + -> Index Only Scan Backward using _hyper_7_23_chunk_space_time_idx on _hyper_7_23_chunk + -> Index Only Scan Backward using _hyper_7_25_chunk_space_time_idx on _hyper_7_25_chunk + -> Index Only Scan Backward using _hyper_7_27_chunk_space_time_idx on _hyper_7_27_chunk + -> Index Only Scan Backward using _hyper_7_29_chunk_space_time_idx on _hyper_7_29_chunk +(15 rows) + +:PREFIX SELECT + time_bucket('1h',time) +FROM space +ORDER BY 1 DESC LIMIT 10; + QUERY PLAN +----------------------------------------------------------------------------------------------- + Limit + -> Custom Scan (ChunkAppend) on space + Order: time_bucket('@ 1 hour'::interval, space."time") DESC + -> Merge Append + Sort Key: (time_bucket('@ 1 hour'::interval, _hyper_7_29_chunk."time")) DESC + -> Index Only Scan using _hyper_7_29_chunk_space_time_idx on _hyper_7_29_chunk + -> Index Only Scan using _hyper_7_27_chunk_space_time_idx on _hyper_7_27_chunk + -> Index Only Scan using _hyper_7_25_chunk_space_time_idx on _hyper_7_25_chunk + -> Index Only Scan using _hyper_7_23_chunk_space_time_idx on _hyper_7_23_chunk + -> Merge Append + Sort Key: (time_bucket('@ 1 hour'::interval, _hyper_7_30_chunk."time")) DESC + -> Index Only Scan using _hyper_7_30_chunk_space_time_idx on _hyper_7_30_chunk + -> Index Only Scan using _hyper_7_28_chunk_space_time_idx on _hyper_7_28_chunk + -> Index Only Scan using _hyper_7_26_chunk_space_time_idx on _hyper_7_26_chunk + -> Index Only Scan using _hyper_7_24_chunk_space_time_idx on _hyper_7_24_chunk +(15 rows) + -- test LATERAL with correlated query -- only last chunk should be executed :PREFIX SELECT * diff --git a/test/sql/include/plan_ordered_append_query.sql b/test/sql/include/plan_ordered_append_query.sql index 62689bd6e..e352af2d8 100644 --- a/test/sql/include/plan_ordered_append_query.sql +++ b/test/sql/include/plan_ordered_append_query.sql @@ -315,6 +315,17 @@ ORDER BY time DESC; FROM space3 ORDER BY time DESC; +-- expressions in ORDER BY clause +:PREFIX SELECT + time_bucket('1h',time) +FROM space +ORDER BY 1 LIMIT 10; + +:PREFIX SELECT + time_bucket('1h',time) +FROM space +ORDER BY 1 DESC LIMIT 10; + -- test LATERAL with correlated query -- only last chunk should be executed :PREFIX SELECT *