diff --git a/src/backend/nodes/list.c b/src/backend/nodes/list.c index a709d23ef1..5f1f675e44 100644 --- a/src/backend/nodes/list.c +++ b/src/backend/nodes/list.c @@ -1654,6 +1654,37 @@ list_copy_deep(const List *oldlist) return newlist; } +/* + * Reverses the order of 'list' elements in place and returns the input list + */ +List * +list_reverse(List *list) +{ + ListCell *head; + ListCell *tail; + + if (list == NIL) + return NIL; + + head = &list->elements[0]; + tail = &list->elements[list->length - 1]; + + while (head < tail) + { + ListCell tmp; + + /* Swap data at the head and tail position */ + memcpy(&tmp, head, sizeof(ListCell)); + memcpy(head, tail, sizeof(ListCell)); + memcpy(tail, &tmp, sizeof(ListCell)); + + head++; + tail--; + } + + return list; +} + /* * Sort a list according to the specified comparator function. * diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index ae0f9bdc8a..4356102399 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -1801,7 +1801,7 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel, * Collect the appropriate child paths. The required logic varies * for the Append and MergeAppend cases. */ - if (match_partition_order) + if (match_partition_order || match_partition_order_desc) { /* * We're going to make a plain Append path. We don't need @@ -1822,25 +1822,6 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel, fractional_subpaths = lappend(fractional_subpaths, cheapest_fractional); } } - else if (match_partition_order_desc) - { - /* - * As above, but we need to reverse the order of the children, - * because nodeAppend.c doesn't know anything about reverse - * ordering and will scan the children in the order presented. - */ - cheapest_startup = get_singleton_append_subpath(cheapest_startup); - cheapest_total = get_singleton_append_subpath(cheapest_total); - - startup_subpaths = lcons(cheapest_startup, startup_subpaths); - total_subpaths = lcons(cheapest_total, total_subpaths); - - if (cheapest_fractional) - { - cheapest_fractional = get_singleton_append_subpath(cheapest_fractional); - fractional_subpaths = lcons(cheapest_fractional, fractional_subpaths); - } - } else { /* @@ -1861,6 +1842,13 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel, /* ... and build the Append or MergeAppend paths */ if (match_partition_order || match_partition_order_desc) { + /* + * When in DESC partition order, reverse the order of the list + * so that we scan the partitions in reverse order + */ + if (match_partition_order_desc) + startup_subpaths = list_reverse(startup_subpaths); + /* We only need Append */ add_path(rel, (Path *) create_append_path(root, rel, @@ -1872,6 +1860,11 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel, false, -1)); if (startup_neq_total) + { + /* reverse order of path list when in partition DESC order */ + if (match_partition_order_desc) + total_subpaths = list_reverse(total_subpaths); + add_path(rel, (Path *) create_append_path(root, rel, total_subpaths, @@ -1881,8 +1874,13 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel, 0, false, -1)); - + } if (fractional_subpaths) + { + /* reverse order of path list when in partition DESC order */ + if (match_partition_order_desc) + fractional_subpaths = list_reverse(fractional_subpaths); + add_path(rel, (Path *) create_append_path(root, rel, fractional_subpaths, @@ -1892,6 +1890,7 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel, 0, false, -1)); + } } else { diff --git a/src/include/nodes/pg_list.h b/src/include/nodes/pg_list.h index 529a382d28..5a2cc38f78 100644 --- a/src/include/nodes/pg_list.h +++ b/src/include/nodes/pg_list.h @@ -626,6 +626,8 @@ extern pg_nodiscard List *list_copy_head(const List *oldlist, int len); extern pg_nodiscard List *list_copy_tail(const List *oldlist, int nskip); extern pg_nodiscard List *list_copy_deep(const List *oldlist); +extern List *list_reverse(List *list); + typedef int (*list_sort_comparator) (const ListCell *a, const ListCell *b); extern void list_sort(List *list, list_sort_comparator cmp);