aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/indexcmds.c4
-rw-r--r--src/backend/executor/functions.c3
-rw-r--r--src/backend/nodes/list.c50
-rw-r--r--src/backend/optimizer/path/allpaths.c13
-rw-r--r--src/backend/optimizer/path/costsize.c3
-rw-r--r--src/backend/optimizer/path/indxpath.c18
-rw-r--r--src/backend/optimizer/plan/createplan.c4
-rw-r--r--src/backend/optimizer/plan/initsplan.c1
-rw-r--r--src/backend/optimizer/plan/planner.c13
-rw-r--r--src/backend/optimizer/plan/setrefs.c2
-rw-r--r--src/backend/optimizer/prep/prepjointree.c1
-rw-r--r--src/backend/optimizer/prep/prepqual.c12
-rw-r--r--src/backend/optimizer/util/clauses.c54
-rw-r--r--src/backend/optimizer/util/orclauses.c2
-rw-r--r--src/backend/optimizer/util/relnode.c34
-rw-r--r--src/backend/optimizer/util/tlist.c5
-rw-r--r--src/backend/parser/parse_agg.c12
-rw-r--r--src/backend/parser/parse_clause.c5
-rw-r--r--src/backend/partitioning/partprune.c8
-rw-r--r--src/backend/replication/syncrep.c5
-rw-r--r--src/backend/rewrite/rewriteHandler.c8
-rw-r--r--src/backend/utils/adt/ruleutils.c2
-rw-r--r--src/backend/utils/adt/selfuncs.c1
-rw-r--r--src/include/nodes/pg_list.h2
24 files changed, 122 insertions, 140 deletions
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 8dc7a398706..ef953953711 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -516,8 +516,8 @@ DefineIndex(Oid relationId,
* is part of the key columns, and anything equal to and over is part of
* the INCLUDE columns.
*/
- allIndexParams = list_concat(list_copy(stmt->indexParams),
- list_copy(stmt->indexIncludingParams));
+ allIndexParams = list_concat_copy(stmt->indexParams,
+ stmt->indexIncludingParams);
numberOfAttributes = list_length(allIndexParams);
if (numberOfAttributes <= 0)
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 64a9e584627..83337c2eed4 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -719,8 +719,7 @@ init_sql_fcache(FmgrInfo *finfo, Oid collation, bool lazyEvalOK)
fcache->pinfo,
NULL);
queryTree_list = lappend(queryTree_list, queryTree_sublist);
- flat_query_list = list_concat(flat_query_list,
- list_copy(queryTree_sublist));
+ flat_query_list = list_concat(flat_query_list, queryTree_sublist);
}
check_sql_fn_statements(flat_query_list);
diff --git a/src/backend/nodes/list.c b/src/backend/nodes/list.c
index 9163464de24..6bf13ae0d4a 100644
--- a/src/backend/nodes/list.c
+++ b/src/backend/nodes/list.c
@@ -501,12 +501,15 @@ lcons_oid(Oid datum, List *list)
}
/*
- * Concatenate list2 to the end of list1, and return list1. list1 is
- * destructively changed, list2 is not. (However, in the case of pointer
- * lists, list1 and list2 will point to the same structures.) Callers
- * should be sure to use the return value as the new pointer to the
- * concatenated list: the 'list1' input pointer may or may not be the
- * same as the returned pointer.
+ * Concatenate list2 to the end of list1, and return list1.
+ *
+ * This is equivalent to lappend'ing each element of list2, in order, to list1.
+ * list1 is destructively changed, list2 is not. (However, in the case of
+ * pointer lists, list1 and list2 will point to the same structures.)
+ *
+ * Callers should be sure to use the return value as the new pointer to the
+ * concatenated list: the 'list1' input pointer may or may not be the same
+ * as the returned pointer.
*/
List *
list_concat(List *list1, const List *list2)
@@ -535,6 +538,41 @@ list_concat(List *list1, const List *list2)
}
/*
+ * Form a new list by concatenating the elements of list1 and list2.
+ *
+ * Neither input list is modified. (However, if they are pointer lists,
+ * the output list will point to the same structures.)
+ *
+ * This is equivalent to, but more efficient than,
+ * list_concat(list_copy(list1), list2).
+ * Note that some pre-v13 code might list_copy list2 as well, but that's
+ * pointless now.
+ */
+List *
+list_concat_copy(const List *list1, const List *list2)
+{
+ List *result;
+ int new_len;
+
+ if (list1 == NIL)
+ return list_copy(list2);
+ if (list2 == NIL)
+ return list_copy(list1);
+
+ Assert(list1->type == list2->type);
+
+ new_len = list1->length + list2->length;
+ result = new_list(list1->type, new_len);
+ memcpy(result->elements, list1->elements,
+ list1->length * sizeof(ListCell));
+ memcpy(result->elements + list1->length, list2->elements,
+ list2->length * sizeof(ListCell));
+
+ check_list_invariants(result);
+ return result;
+}
+
+/*
* Truncate 'list' to contain no more than 'new_size' elements. This
* modifies the list in-place! Despite this, callers should use the
* pointer returned by this function to refer to the newly truncated
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index e9ee32b7f43..db3a68a51dd 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1266,7 +1266,7 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
if (rel->part_scheme)
rel->partitioned_child_rels =
list_concat(rel->partitioned_child_rels,
- list_copy(childrel->partitioned_child_rels));
+ childrel->partitioned_child_rels);
/*
* Child is live, so add it to the live_childrels list for use below.
@@ -1347,9 +1347,8 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
component = root->simple_rel_array[relid];
Assert(component->part_scheme != NULL);
Assert(list_length(component->partitioned_child_rels) >= 1);
- partrels =
- list_concat(partrels,
- list_copy(component->partitioned_child_rels));
+ partrels = list_concat(partrels,
+ component->partitioned_child_rels);
}
partitioned_rels = list_make1(partrels);
@@ -2048,8 +2047,7 @@ accumulate_append_subpath(Path *path, List **subpaths, List **special_subpaths)
if (!apath->path.parallel_aware || apath->first_partial_path == 0)
{
- /* list_copy is important here to avoid sharing list substructure */
- *subpaths = list_concat(*subpaths, list_copy(apath->subpaths));
+ *subpaths = list_concat(*subpaths, apath->subpaths);
return;
}
else if (special_subpaths != NULL)
@@ -2072,8 +2070,7 @@ accumulate_append_subpath(Path *path, List **subpaths, List **special_subpaths)
{
MergeAppendPath *mpath = (MergeAppendPath *) path;
- /* list_copy is important here to avoid sharing list substructure */
- *subpaths = list_concat(*subpaths, list_copy(mpath->subpaths));
+ *subpaths = list_concat(*subpaths, mpath->subpaths);
return;
}
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 3a9a994733b..bc6bc999573 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -4443,8 +4443,7 @@ get_parameterized_baserel_size(PlannerInfo *root, RelOptInfo *rel,
* restriction clauses. Note that we force the clauses to be treated as
* non-join clauses during selectivity estimation.
*/
- allclauses = list_concat(list_copy(param_clauses),
- rel->baserestrictinfo);
+ allclauses = list_concat_copy(param_clauses, rel->baserestrictinfo);
nrows = rel->tuples *
clauselist_selectivity(root,
allclauses,
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 5f339fdfde7..37b257cd0e9 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -656,7 +656,7 @@ get_join_index_paths(PlannerInfo *root, RelOptInfo *rel,
}
}
- /* Add restriction clauses (this is nondestructive to rclauseset) */
+ /* Add restriction clauses */
clauseset.indexclauses[indexcol] =
list_concat(clauseset.indexclauses[indexcol],
rclauseset->indexclauses[indexcol]);
@@ -1204,8 +1204,7 @@ build_paths_for_OR(PlannerInfo *root, RelOptInfo *rel,
{
/* Form all_clauses if not done already */
if (all_clauses == NIL)
- all_clauses = list_concat(list_copy(clauses),
- other_clauses);
+ all_clauses = list_concat_copy(clauses, other_clauses);
if (!predicate_implied_by(index->indpred, all_clauses, false))
continue; /* can't use it at all */
@@ -1270,7 +1269,7 @@ generate_bitmap_or_paths(PlannerInfo *root, RelOptInfo *rel,
* We can use both the current and other clauses as context for
* build_paths_for_OR; no need to remove ORs from the lists.
*/
- all_clauses = list_concat(list_copy(clauses), other_clauses);
+ all_clauses = list_concat_copy(clauses, other_clauses);
foreach(lc, clauses)
{
@@ -1506,8 +1505,7 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel, List *paths)
pathinfo = pathinfoarray[i];
paths = list_make1(pathinfo->path);
costsofar = bitmap_scan_cost_est(root, rel, pathinfo->path);
- qualsofar = list_concat(list_copy(pathinfo->quals),
- list_copy(pathinfo->preds));
+ qualsofar = list_concat_copy(pathinfo->quals, pathinfo->preds);
clauseidsofar = bms_copy(pathinfo->clauseids);
for (j = i + 1; j < npaths; j++)
@@ -1543,10 +1541,8 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel, List *paths)
{
/* keep new path in paths, update subsidiary variables */
costsofar = newcost;
- qualsofar = list_concat(qualsofar,
- list_copy(pathinfo->quals));
- qualsofar = list_concat(qualsofar,
- list_copy(pathinfo->preds));
+ qualsofar = list_concat(qualsofar, pathinfo->quals);
+ qualsofar = list_concat(qualsofar, pathinfo->preds);
clauseidsofar = bms_add_members(clauseidsofar,
pathinfo->clauseids);
}
@@ -1849,7 +1845,7 @@ find_indexpath_quals(Path *bitmapqual, List **quals, List **preds)
*quals = lappend(*quals, iclause->rinfo->clause);
}
- *preds = list_concat(*preds, list_copy(ipath->indexinfo->indpred));
+ *preds = list_concat(*preds, ipath->indexinfo->indpred);
}
else
elog(ERROR, "unrecognized node type: %d", nodeTag(bitmapqual));
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index f2325694c53..0c036209f09 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -559,8 +559,8 @@ create_scan_plan(PlannerInfo *root, Path *best_path, int flags)
* For paranoia's sake, don't modify the stored baserestrictinfo list.
*/
if (best_path->param_info)
- scan_clauses = list_concat(list_copy(scan_clauses),
- best_path->param_info->ppi_clauses);
+ scan_clauses = list_concat_copy(scan_clauses,
+ best_path->param_info->ppi_clauses);
/*
* Detect whether we have any pseudoconstant quals to deal with. Then, if
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 73da0c2d8e1..274fea076cb 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -973,7 +973,6 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
*postponed_qual_list = lappend(*postponed_qual_list, pq);
}
}
- /* list_concat is nondestructive of its second argument */
my_quals = list_concat(my_quals, (List *) j->quals);
/*
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 0f918dd358d..17c5f086fbf 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -3572,10 +3572,6 @@ reorder_grouping_sets(List *groupingsets, List *sortclause)
}
}
- /*
- * Safe to use list_concat (which shares cells of the second arg)
- * because we know that new_elems does not share cells with anything.
- */
previous = list_concat(previous, new_elems);
gs->set = list_copy(previous);
@@ -4287,8 +4283,8 @@ consider_groupingsets_paths(PlannerInfo *root,
*/
if (!rollup->hashable)
return;
- else
- sets_data = list_concat(sets_data, list_copy(rollup->gsets_data));
+
+ sets_data = list_concat(sets_data, rollup->gsets_data);
}
foreach(lc, sets_data)
{
@@ -4473,7 +4469,7 @@ consider_groupingsets_paths(PlannerInfo *root,
{
if (bms_is_member(i, hash_items))
hash_sets = list_concat(hash_sets,
- list_copy(rollup->gsets_data));
+ rollup->gsets_data);
else
rollups = lappend(rollups, rollup);
++i;
@@ -5642,8 +5638,7 @@ make_pathkeys_for_window(PlannerInfo *root, WindowClause *wc,
errdetail("Window ordering columns must be of sortable datatypes.")));
/* Okay, make the combined pathkeys */
- window_sortclauses = list_concat(list_copy(wc->partitionClause),
- list_copy(wc->orderClause));
+ window_sortclauses = list_concat_copy(wc->partitionClause, wc->orderClause);
window_pathkeys = make_pathkeys_for_sortclauses(root,
window_sortclauses,
tlist);
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 329ebd5f287..566ee96da8c 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -893,7 +893,7 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
splan->resultRelIndex = list_length(root->glob->resultRelations);
root->glob->resultRelations =
list_concat(root->glob->resultRelations,
- list_copy(splan->resultRelations));
+ splan->resultRelations);
/*
* If the main target relation is a partitioned table, also
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index ccb32530ad2..d13cb582272 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -2659,7 +2659,6 @@ reduce_outer_joins_pass2(Node *jtnode,
pass_nonnullable_rels = find_nonnullable_rels(f->quals);
pass_nonnullable_rels = bms_add_members(pass_nonnullable_rels,
nonnullable_rels);
- /* NB: we rely on list_concat to not damage its second argument */
pass_nonnullable_vars = find_nonnullable_vars(f->quals);
pass_nonnullable_vars = list_concat(pass_nonnullable_vars,
nonnullable_vars);
diff --git a/src/backend/optimizer/prep/prepqual.c b/src/backend/optimizer/prep/prepqual.c
index e9a94976b73..ee919575c52 100644
--- a/src/backend/optimizer/prep/prepqual.c
+++ b/src/backend/optimizer/prep/prepqual.c
@@ -328,12 +328,6 @@ pull_ands(List *andlist)
{
Node *subexpr = (Node *) lfirst(arg);
- /*
- * Note: we can destructively concat the subexpression's arglist
- * because we know the recursive invocation of pull_ands will have
- * built a new arglist not shared with any other expr. Otherwise we'd
- * need a list_copy here.
- */
if (is_andclause(subexpr))
out_list = list_concat(out_list,
pull_ands(((BoolExpr *) subexpr)->args));
@@ -360,12 +354,6 @@ pull_ors(List *orlist)
{
Node *subexpr = (Node *) lfirst(arg);
- /*
- * Note: we can destructively concat the subexpression's arglist
- * because we know the recursive invocation of pull_ors will have
- * built a new arglist not shared with any other expr. Otherwise we'd
- * need a list_copy here.
- */
if (is_orclause(subexpr))
out_list = list_concat(out_list,
pull_ors(((BoolExpr *) subexpr)->args));
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 7ad9d9ab79e..a04b62274d2 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -1009,8 +1009,8 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
max_parallel_hazard_test(PROPARALLEL_RESTRICTED, context))
return true;
save_safe_param_ids = context->safe_param_ids;
- context->safe_param_ids = list_concat(list_copy(subplan->paramIds),
- context->safe_param_ids);
+ context->safe_param_ids = list_concat_copy(context->safe_param_ids,
+ subplan->paramIds);
if (max_parallel_hazard_walker(subplan->testexpr, context))
return true; /* no need to restore safe_param_ids */
list_free(context->safe_param_ids);
@@ -3697,18 +3697,12 @@ simplify_or_arguments(List *args,
/* flatten nested ORs as per above comment */
if (is_orclause(arg))
{
- List *subargs = list_copy(((BoolExpr *) arg)->args);
+ List *subargs = ((BoolExpr *) arg)->args;
+ List *oldlist = unprocessed_args;
- /* overly tense code to avoid leaking unused list header */
- if (!unprocessed_args)
- unprocessed_args = subargs;
- else
- {
- List *oldhdr = unprocessed_args;
-
- unprocessed_args = list_concat(subargs, unprocessed_args);
- pfree(oldhdr);
- }
+ unprocessed_args = list_concat_copy(subargs, unprocessed_args);
+ /* perhaps-overly-tense code to avoid leaking old lists */
+ list_free(oldlist);
continue;
}
@@ -3718,14 +3712,14 @@ simplify_or_arguments(List *args,
/*
* It is unlikely but not impossible for simplification of a non-OR
* clause to produce an OR. Recheck, but don't be too tense about it
- * since it's not a mainstream case. In particular we don't worry
- * about const-simplifying the input twice.
+ * since it's not a mainstream case. In particular we don't worry
+ * about const-simplifying the input twice, nor about list leakage.
*/
if (is_orclause(arg))
{
- List *subargs = list_copy(((BoolExpr *) arg)->args);
+ List *subargs = ((BoolExpr *) arg)->args;
- unprocessed_args = list_concat(subargs, unprocessed_args);
+ unprocessed_args = list_concat_copy(subargs, unprocessed_args);
continue;
}
@@ -3799,18 +3793,12 @@ simplify_and_arguments(List *args,
/* flatten nested ANDs as per above comment */
if (is_andclause(arg))
{
- List *subargs = list_copy(((BoolExpr *) arg)->args);
+ List *subargs = ((BoolExpr *) arg)->args;
+ List *oldlist = unprocessed_args;
- /* overly tense code to avoid leaking unused list header */
- if (!unprocessed_args)
- unprocessed_args = subargs;
- else
- {
- List *oldhdr = unprocessed_args;
-
- unprocessed_args = list_concat(subargs, unprocessed_args);
- pfree(oldhdr);
- }
+ unprocessed_args = list_concat_copy(subargs, unprocessed_args);
+ /* perhaps-overly-tense code to avoid leaking old lists */
+ list_free(oldlist);
continue;
}
@@ -3820,14 +3808,14 @@ simplify_and_arguments(List *args,
/*
* It is unlikely but not impossible for simplification of a non-AND
* clause to produce an AND. Recheck, but don't be too tense about it
- * since it's not a mainstream case. In particular we don't worry
- * about const-simplifying the input twice.
+ * since it's not a mainstream case. In particular we don't worry
+ * about const-simplifying the input twice, nor about list leakage.
*/
if (is_andclause(arg))
{
- List *subargs = list_copy(((BoolExpr *) arg)->args);
+ List *subargs = ((BoolExpr *) arg)->args;
- unprocessed_args = list_concat(subargs, unprocessed_args);
+ unprocessed_args = list_concat_copy(subargs, unprocessed_args);
continue;
}
@@ -4188,7 +4176,7 @@ add_function_defaults(List *args, HeapTuple func_tuple)
defaults = list_copy_tail(defaults, ndelete);
/* And form the combined argument list, not modifying the input list */
- return list_concat(list_copy(args), defaults);
+ return list_concat_copy(args, defaults);
}
/*
diff --git a/src/backend/optimizer/util/orclauses.c b/src/backend/optimizer/util/orclauses.c
index 18ebc51bcac..412a3964c30 100644
--- a/src/backend/optimizer/util/orclauses.c
+++ b/src/backend/optimizer/util/orclauses.c
@@ -236,7 +236,7 @@ extract_or_clause(RestrictInfo *or_rinfo, RelOptInfo *rel)
subclause = (Node *) make_ands_explicit(subclauses);
if (is_orclause(subclause))
clauselist = list_concat(clauselist,
- list_copy(((BoolExpr *) subclause)->args));
+ ((BoolExpr *) subclause)->args);
else
clauselist = lappend(clauselist, subclause);
}
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index 582c5dd979b..19e5a449f75 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -1718,43 +1718,39 @@ build_joinrel_partition_info(RelOptInfo *joinrel, RelOptInfo *outer_rel,
*/
for (cnt = 0; cnt < partnatts; cnt++)
{
- List *outer_expr;
- List *outer_null_expr;
- List *inner_expr;
- List *inner_null_expr;
+ /* mark these const to enforce that we copy them properly */
+ const List *outer_expr = outer_rel->partexprs[cnt];
+ const List *outer_null_expr = outer_rel->nullable_partexprs[cnt];
+ const List *inner_expr = inner_rel->partexprs[cnt];
+ const List *inner_null_expr = inner_rel->nullable_partexprs[cnt];
List *partexpr = NIL;
List *nullable_partexpr = NIL;
- outer_expr = list_copy(outer_rel->partexprs[cnt]);
- outer_null_expr = list_copy(outer_rel->nullable_partexprs[cnt]);
- inner_expr = list_copy(inner_rel->partexprs[cnt]);
- inner_null_expr = list_copy(inner_rel->nullable_partexprs[cnt]);
-
switch (jointype)
{
case JOIN_INNER:
- partexpr = list_concat(outer_expr, inner_expr);
- nullable_partexpr = list_concat(outer_null_expr,
- inner_null_expr);
+ partexpr = list_concat_copy(outer_expr, inner_expr);
+ nullable_partexpr = list_concat_copy(outer_null_expr,
+ inner_null_expr);
break;
case JOIN_SEMI:
case JOIN_ANTI:
- partexpr = outer_expr;
- nullable_partexpr = outer_null_expr;
+ partexpr = list_copy(outer_expr);
+ nullable_partexpr = list_copy(outer_null_expr);
break;
case JOIN_LEFT:
- partexpr = outer_expr;
- nullable_partexpr = list_concat(inner_expr,
- outer_null_expr);
+ partexpr = list_copy(outer_expr);
+ nullable_partexpr = list_concat_copy(inner_expr,
+ outer_null_expr);
nullable_partexpr = list_concat(nullable_partexpr,
inner_null_expr);
break;
case JOIN_FULL:
- nullable_partexpr = list_concat(outer_expr,
- inner_expr);
+ nullable_partexpr = list_concat_copy(outer_expr,
+ inner_expr);
nullable_partexpr = list_concat(nullable_partexpr,
outer_null_expr);
nullable_partexpr = list_concat(nullable_partexpr,
diff --git a/src/backend/optimizer/util/tlist.c b/src/backend/optimizer/util/tlist.c
index 7ccb10e4e1b..d75796ac8b9 100644
--- a/src/backend/optimizer/util/tlist.c
+++ b/src/backend/optimizer/util/tlist.c
@@ -665,9 +665,8 @@ make_tlist_from_pathtarget(PathTarget *target)
* copy_pathtarget
* Copy a PathTarget.
*
- * The new PathTarget has its own List cells, but shares the underlying
- * target expression trees with the old one. We duplicate the List cells
- * so that items can be added to one target without damaging the other.
+ * The new PathTarget has its own exprs List, but shares the underlying
+ * target expression trees with the old one.
*/
PathTarget *
copy_pathtarget(PathTarget *src)
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index 354030e549b..f418c615458 100644
--- a/src/backend/parser/parse_agg.c
+++ b/src/backend/parser/parse_agg.c
@@ -1649,9 +1649,8 @@ expand_groupingset_node(GroupingSet *gs)
Assert(gs_current->kind == GROUPING_SET_SIMPLE);
- current_result
- = list_concat(current_result,
- list_copy(gs_current->content));
+ current_result = list_concat(current_result,
+ gs_current->content);
/* If we are done with making the current group, break */
if (--i == 0)
@@ -1691,11 +1690,8 @@ expand_groupingset_node(GroupingSet *gs)
Assert(gs_current->kind == GROUPING_SET_SIMPLE);
if (mask & i)
- {
- current_result
- = list_concat(current_result,
- list_copy(gs_current->content));
- }
+ current_result = list_concat(current_result,
+ gs_current->content);
mask <<= 1;
}
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 2a6b2ff153b..260ccd4d7fa 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -1214,9 +1214,6 @@ transformFromClauseItem(ParseState *pstate, Node *n,
*
* Notice that we don't require the merged namespace list to be
* conflict-free. See the comments for scanNameSpaceForRefname().
- *
- * NB: this coding relies on the fact that list_concat is not
- * destructive to its second argument.
*/
lateral_ok = (j->jointype == JOIN_INNER || j->jointype == JOIN_LEFT);
setNamespaceLateralState(l_namespace, true, lateral_ok);
@@ -2116,9 +2113,7 @@ flatten_grouping_sets(Node *expr, bool toplevel, bool *hasGroupingSets)
if (IsA(n1, GroupingSet) &&
((GroupingSet *) n1)->kind == GROUPING_SET_SETS)
- {
result_set = list_concat(result_set, (List *) n2);
- }
else
result_set = lappend(result_set, n2);
}
diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c
index 2ee47b8c8a9..a1bd4efd0b0 100644
--- a/src/backend/partitioning/partprune.c
+++ b/src/backend/partitioning/partprune.c
@@ -642,8 +642,8 @@ gen_partprune_steps(RelOptInfo *rel, List *clauses, PartClauseTarget target,
if (rel->relid != 1)
ChangeVarNodes((Node *) partqual, 1, rel->relid, 0);
- /* Use list_copy to avoid modifying the passed-in List */
- clauses = list_concat(list_copy(clauses), partqual);
+ /* Make a copy to avoid modifying the passed-in List */
+ clauses = list_concat_copy(clauses, partqual);
}
/* Down into the rabbit-hole. */
@@ -1485,7 +1485,7 @@ gen_prune_steps_from_opexps(GeneratePruningStepsContext *context,
pc->keyno,
NULL,
prefix);
- opsteps = list_concat(opsteps, list_copy(pc_steps));
+ opsteps = list_concat(opsteps, pc_steps);
}
}
break;
@@ -1556,7 +1556,7 @@ gen_prune_steps_from_opexps(GeneratePruningStepsContext *context,
pc->keyno,
nullkeys,
prefix);
- opsteps = list_concat(opsteps, list_copy(pc_steps));
+ opsteps = list_concat(opsteps, pc_steps);
}
}
break;
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index 79c7c13ada0..a21f7d33471 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -865,8 +865,6 @@ SyncRepGetSyncStandbysPriority(bool *am_sync)
*/
if (list_length(result) + list_length(pending) <= SyncRepConfig->num_sync)
{
- bool needfree = (result != NIL && pending != NIL);
-
/*
* Set *am_sync to true if this walsender is in the pending list
* because all pending standbys are considered as sync.
@@ -875,8 +873,7 @@ SyncRepGetSyncStandbysPriority(bool *am_sync)
*am_sync = am_in_pending;
result = list_concat(result, pending);
- if (needfree)
- pfree(pending);
+ list_free(pending);
return result;
}
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index c96ef8595af..3e38007643e 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -1041,11 +1041,11 @@ process_matched_tle(TargetEntry *src_tle,
/* combine the two */
memcpy(fstore, prior_expr, sizeof(FieldStore));
fstore->newvals =
- list_concat(list_copy(((FieldStore *) prior_expr)->newvals),
- list_copy(((FieldStore *) src_expr)->newvals));
+ list_concat_copy(((FieldStore *) prior_expr)->newvals,
+ ((FieldStore *) src_expr)->newvals);
fstore->fieldnums =
- list_concat(list_copy(((FieldStore *) prior_expr)->fieldnums),
- list_copy(((FieldStore *) src_expr)->fieldnums));
+ list_concat_copy(((FieldStore *) prior_expr)->fieldnums,
+ ((FieldStore *) src_expr)->fieldnums);
}
else
{
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 13d5d542f94..3e64390d819 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -10097,7 +10097,7 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
List *args = ((FuncExpr *) rtfunc->funcexpr)->args;
- allargs = list_concat(allargs, list_copy(args));
+ allargs = list_concat(allargs, args);
}
appendStringInfoString(buf, "UNNEST(");
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 7eba59eff32..17101298fb0 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -5768,7 +5768,6 @@ add_predicate_to_index_quals(IndexOptInfo *index, List *indexQuals)
if (!predicate_implied_by(oneQual, indexQuals, false))
predExtraQuals = list_concat(predExtraQuals, oneQual);
}
- /* list_concat avoids modifying the passed-in indexQuals list */
return list_concat(predExtraQuals, indexQuals);
}
diff --git a/src/include/nodes/pg_list.h b/src/include/nodes/pg_list.h
index 146340877c3..409d840e793 100644
--- a/src/include/nodes/pg_list.h
+++ b/src/include/nodes/pg_list.h
@@ -519,6 +519,8 @@ extern List *lcons_int(int datum, List *list);
extern List *lcons_oid(Oid datum, List *list);
extern List *list_concat(List *list1, const List *list2);
+extern List *list_concat_copy(const List *list1, const List *list2);
+
extern List *list_truncate(List *list, int new_size);
extern bool list_member(const List *list, const void *datum);