diff --git a/src/backend/nodes/list.c b/src/backend/nodes/list.c index 750ee5a7e5..17d96a9291 100644 --- a/src/backend/nodes/list.c +++ b/src/backend/nodes/list.c @@ -349,6 +349,37 @@ lappend(List *list, void *datum) return list; } +/* + * Append a pointer to the new list (copy). + * A pointer to the modified list is returned. + * Note that this function may or may not destructively + * modify the list; callers should always use this function's return + * value, rather than continuing to use the pointer passed as the + * first argument. + */ +List * +lappend_copy(List *list, void *datum) +{ + Assert(IsPointerList(list)); + + if (list == NIL) + list = new_list(T_List, 1); + else + { + List *newlist; + + newlist = new_list(list->type, list->length + 1); + memcpy(newlist->elements, list->elements, + list->length * sizeof(ListCell)); + + list = newlist; + } + + llast(list) = datum; + check_list_invariants(list); + return list; +} + /* * Append an integer to the specified list. See lappend() */ @@ -541,6 +572,78 @@ lcons_oid(Oid datum, List *list) return list; } +/* + * Prepend a new element to the new list (copy). + * A pointer to the modified list is returned. + * Note that this function may or may not destructively + * modify the list; callers should always use this function's return + * value, rather than continuing to use the pointer passed as the + * second argument. + * + * Note that this takes time proportional to the length of the list, + * since the existing entries must be moved. + * + * Caution: before Postgres 8.0, the original List was unmodified and + * could be considered to retain its separate identity. This is no longer + * the case. + */ +List * +lcons_copy(void *datum, List *list) +{ + Assert(IsPointerList(list)); + + if (list == NIL) + list = new_list(T_List, 1); + else + { + List *newlist; + + newlist = new_list(list->type, list->length + 1); + memcpy(newlist->elements + 1, list->elements, + list->length * sizeof(ListCell)); + + list = newlist; + } + + linitial(list) = datum; + check_list_invariants(list); + return list; +} + +/* + * Prepend a new element to the new list (copy) and + * delete the n'th cell (counting from 0) in new list (copy). + * + * The List is pfree'd if this was the last member. + * + * Note that this takes time proportional to the distance to the end of the + * list, since the following entries must be moved. + */ + +List * +lcons_copy_delete(void *datum, List *list, int n) +{ + check_list_invariants(list); + Assert(IsPointerList(list)); + + if (list == NIL) + list = new_list(T_List, 1); + else if (n > 1 && list->length > n) + { + List *newlist; + + newlist = new_list(list->type, list->length - 1 - n); + memcpy(&newlist->elements[n], &list->elements[n + 1], + (list->length - 1 - n) * sizeof(ListCell)); + + list = newlist; + } + + linitial(list) = datum; + check_list_invariants(list); + return list; +} + /* * Concatenate list2 to the end of list1, and return list1. * diff --git a/src/include/nodes/pg_list.h b/src/include/nodes/pg_list.h index 529a382d28..78376158dc 100644 --- a/src/include/nodes/pg_list.h +++ b/src/include/nodes/pg_list.h @@ -324,6 +324,17 @@ list_nth_oid(const List *list, int n) return lfirst_oid(list_nth_cell(list, n)); } +/* + * Return the TransactionId value contained in the n'th element of the specified + * list. + */ +static inline TransactionId +list_nth_xid(const List *list, int n) +{ + Assert(IsA(list, TransactionList)); + return lfirst_xid(list_nth_cell(list, n)); +} + #define list_nth_node(type,list,n) castNode(type, list_nth(list, n)) /* @@ -569,6 +580,8 @@ extern pg_nodiscard List *list_insert_nth_oid(List *list, int pos, Oid datum); extern pg_nodiscard List *lcons(void *datum, List *list); extern pg_nodiscard List *lcons_int(int datum, List *list); extern pg_nodiscard List *lcons_oid(Oid datum, List *list); +extern pg_nodiscard List *lcons_copy(void *datum, List *list); +extern pg_nodiscard List *lcons_copy_delete(void *datum, List *list, int n); extern pg_nodiscard List *list_concat(List *list1, const List *list2); extern pg_nodiscard List *list_concat_copy(const List *list1, const List *list2);