java-topology/tools/tickets/defects/postgresql-0004.md
russell@unturf.com db29a08762 undefect. CWE-407 — 92 sites, 42 ecosystems
B&W print-friendly diagrams + tinkerpop-0001 + wave-3 proof sections.
Squash of 94 local commits onto remote master.
2026-03-26 19:48:18 -04:00

2.4 KiB
Raw Permalink Blame History

id repo severity status created
postgresql-0004 postgres/postgres HIGH DEFERRED 2026-03-23

Defect

File: src/backend/optimizer/util/analyzejoins.c:1914 Pattern: list_member(toKeep->reltarget->exprs, node) inside foreach(lc, toRemove->reltarget->exprs) Complexity: O(|toRemove.exprs|² × |toKeep.exprs|) per join elimination pass Language: C

Description

analyzejoins.c implements join elimination — removing redundant joins from the query plan when the optimizer can prove the join does not affect the result set. During join relation merging, line 1914 calls list_member() inside foreach(lc, toRemove->reltarget->exprs) to check whether each expression from the removed relation already exists in the kept relation's target list.

Join elimination runs on every query that has self-joins, redundant outer joins, or joins to views. For a query that eliminates a join between relations with E expressions each, this is O(E²). Since reltarget->exprs contains all expressions needed from that relation (not just the join key), complex queries with many projected columns trigger quadratic behavior.

Fix

Replace: list_member(toKeep->reltarget->exprs, node) — O(n) per check With: Pre-build a pointer-identity hash set over toKeep->reltarget->exprs before the foreach loop; check O(1) per expression. Data structure: Simple array-backed hash set over Node * pointers; palloc'd for the duration of the join elimination pass.

Work required

  • Patch in defects/postgresql/patch/
  • Unit test — asserts exact operation counts before/after (in defects/postgresql/unit/)
  • Integration test — query with self-join on table with C=5,10,20,50 projected columns (in defects/postgresql/integration/)
  • Benchmark — EXPLAIN ANALYZE planning time, join elimination enabled vs disabled (in defects/postgresql/bench/)
  • White paper section — whitepaper/vectors/database/postgresql.rst

DEFERRED (2026-03-23)

PostgreSQL uses structural deep equality (equal()) for expression comparison. No generic expression hash function exists in PostgreSQL core. A correct fix requires either: (a) a structural hash based on Node type+fields, or (b) sort+merge using a total order on Expr* — neither is available without significant framework additions. PostgreSQL developers explicitly note the O(n²) cost in comments and say "really you should be using some other data structure."