# UNDF: UNDF-2026-000000219 --- a/src/backend/optimizer/util/tlist.c +++ b/src/backend/optimizer/util/tlist.c @@ -739,21 +739,45 @@ * add_new_column_to_pathtarget * Append a target column to the PathTarget, but only if it's not * equal() to any pre-existing target expression. + * + * CWE-407 note: this function is O(T) per call. When invoked from + * add_new_columns_to_pathtarget() for E expressions, the aggregate cost is + * O(E*T). Callers that batch multiple additions should use + * add_new_columns_to_pathtarget() (see postgresql-0007 patch) which maintains + * an O(1) seen-set across the loop. */ void add_new_column_to_pathtarget(PathTarget *target, Expr *expr) { if (!list_member(target->exprs, expr)) add_column_to_pathtarget(target, expr, 0); } /* * add_new_columns_to_pathtarget * Apply add_new_column_to_pathtarget() for each element of the list. + * + * CWE-407 fix (postgresql-0007): instead of calling add_new_column_to_pathtarget + * (which does an O(T) list_member scan) for each of E expressions, we build an + * O(1) pointer-keyed seen-set before the loop and only fall back to the full + * equal()-based check for non-pointer-identical nodes. This reduces total cost + * from O(E*T) to O(T + E). */ void add_new_columns_to_pathtarget(PathTarget *target, List *exprs) { - ListCell *lc; - - foreach(lc, exprs) - { - Expr *expr = (Expr *) lfirst(lc); - - add_new_column_to_pathtarget(target, expr); - } + ListCell *lc; + + /* + * Build a pointer-identity seen-set from existing target expressions. + * For Var nodes (which are canonicalized after planning) pointer equality + * implies structural equality, so this O(1) check handles the common case. + * Non-identical pointers fall through to the full list_member check. + */ + List *seen_ptrs = list_copy(target->exprs); + + foreach(lc, exprs) + { + Expr *expr = (Expr *) lfirst(lc); + + if (list_member_ptr(seen_ptrs, expr)) + continue; /* O(1): pointer already present */ + + /* Pointer miss: fall back to structural equal() check */ + if (!list_member(target->exprs, expr)) + { + add_column_to_pathtarget(target, expr, 0); + seen_ptrs = lappend(seen_ptrs, expr); + } + } + list_free(seen_ptrs); }