diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/nodes/list.c | 56 |
1 files changed, 40 insertions, 16 deletions
diff --git a/src/backend/nodes/list.c b/src/backend/nodes/list.c index 083538f70a1..f3e18007086 100644 --- a/src/backend/nodes/list.c +++ b/src/backend/nodes/list.c @@ -1250,41 +1250,65 @@ list_copy_tail(const List *oldlist, int nskip) } /* - * Sort a list using qsort. A sorted list is built but the cells of the - * original list are re-used. The comparator function receives arguments of - * type ListCell ** + * Sort a list as though by qsort. + * + * A new list is built and returned. Like list_copy, this doesn't make + * fresh copies of any pointed-to data. + * + * The comparator function receives arguments of type ListCell **. */ List * list_qsort(const List *list, list_qsort_comparator cmp) { - ListCell *cell; - int i; int len = list_length(list); ListCell **list_arr; - List *new_list; + List *newlist; + ListCell *newlist_prev; + ListCell *cell; + int i; + /* Empty list is easy */ if (len == 0) return NIL; + /* Flatten list cells into an array, so we can use qsort */ + list_arr = (ListCell **) palloc(sizeof(ListCell *) * len); i = 0; - list_arr = palloc(sizeof(ListCell *) * len); foreach(cell, list) list_arr[i++] = cell; qsort(list_arr, len, sizeof(ListCell *), cmp); - new_list = (List *) palloc(sizeof(List)); - new_list->type = list->type; - new_list->length = len; - new_list->head = list_arr[0]; - new_list->tail = list_arr[len - 1]; + /* Construct new list (this code is much like list_copy) */ + newlist = new_list(list->type); + newlist->length = len; + + /* + * Copy over the data in the first cell; new_list() has already allocated + * the head cell itself + */ + newlist->head->data = list_arr[0]->data; + + newlist_prev = newlist->head; + for (i = 1; i < len; i++) + { + ListCell *newlist_cur; + + newlist_cur = (ListCell *) palloc(sizeof(*newlist_cur)); + newlist_cur->data = list_arr[i]->data; + newlist_prev->next = newlist_cur; - for (i = 0; i < len - 1; i++) - list_arr[i]->next = list_arr[i + 1]; + newlist_prev = newlist_cur; + } - list_arr[len - 1]->next = NULL; + newlist_prev->next = NULL; + newlist->tail = newlist_prev; + + /* Might as well free the workspace array */ pfree(list_arr); - return new_list; + + check_list_invariants(newlist); + return newlist; } /* |