CommitFest 6315 review — RelabelType strip in exprs_known_equal

code-review · generated from canonical Markdown

Type
code-review
Source
postgresql-master
Slug
commitfest-6315-review
Tags
code-reviewcommitfest-6315patch-reviewpostgresqlreview-report-v2
Updated
2026-08-27T13:55:13.673513+00:00
Verdict / Summarywaiting-on-author
Front matter
schema: review-report-v2
source: postgresql-master
slug: commitfest-6315-review
target: "CommitFest 6315: Enable partitionwise join for partition keys wrapped by RelabelType (exprs_known_equal RelabelType strip)"
head: 2866d8c7dbfc9d882a7d80fef93fbbe763709932
base: 2866d8c7dbfc9d882a7d80fef93fbbe763709932
diff_blob_sha: 558b801ee367e1a71373fb74e368c1397612a1fc
scope_identity: 2866d8c7dbfc9d882a7d80fef93fbbe763709932-558b801ee367e1a71373fb74e368c1397612a1fc
verdict: waiting-on-author
blocker_counts:
  verified: 1
  unverified: 0
model: glm-5.2:cloud
reviewer_seats: pg-patch-reviewer, pg-security-reviewer, pg-finding-verifier, pg-change-coverage-reviewer
artifact: review-artifact-v2.json
artifact_schema: pg-review-artifact-v2

CommitFest 6315 — Review Report (v2)

Subject: Enable partitionwise join for partition keys wrapped by RelabelType Author: Matheus Alcantara (matheusssilv97@gmail.com) Thread: pgsql-hackers Thread-ID 631171 Verdict: waiting-on-author (1 verified BLOCKER) Model: glm-5.2:cloud (user override for all seats)

Scope

The staged diff (uncommitted; base == head == 2866d8c7dbfc9d882a7d80fef93fbbe763709932, diff blob sha 558b801ee367e1a71373fb74e368c1397612a1fc) modifies three files (+44/-2):

The staged patch is the author's v1, which the author already superseded with v3 on-list after a demonstrated regression. The reviewers' and author's agreed fix direction (collation-guarded strip) is captured in the repair below.

Verdict

waiting-on-author — the staged v1 must be replaced with the collation-guarded v3 (or symmetric equivalent) and a core estimation regression test added.

Findings

F1

— BLOCKER / correctness — collation-distinguish estimation regression

  • Location: src/backend/optimizer/path/equivclass.c:2676-2687 (unconditional strip in exprs_known_equal), manifesting in src/backend/utils/adt/selfuncs.c:3708 (add_unique_group_var).
  • Mechanism: exprs_known_equal unconditionally strips every RelabelType from em->em_expr before equal(). canonicalize_ec_expression (~equivclass.c:517-595) deliberately adds RelabelType to force each EC member's exposed collation to match the EC collation, so collation-differing source expressions are not equal() to the underlying Var. Stripping them makes exprs_known_equal wrongly return true for two Vars equal only under a different collation.
  • Failure: Wrong ndistinct estimate (regression vs master) for add_unique_group_var. For GROUP BY t1.c, t2.c with t1.c (text) and t2.c (domain d_txt_ci collate case_insensitive), the estimate collapses from 144 to 12.
  • Verification status: verified (method: repro). Reproduced live on PostgreSQL 20devel (UTF8+ICU) across three binaries: master → 144 (correct); v1 staged → 12 (REGRESSION); v3 patched → 144 (restored). The partitionwise-join caller (relnode.c:2442) is independently guarded by partcoll1 == exprcoll1 (relnode.c:2453); only the estimation caller is exposed.
  • Thread: already-raised (jian 2026-01-15 + 2026-02-25 demonstrated; author agreed v3 fixes it 2026-02-25).
  • Repair: Replace the unconditional strip with strip_collation_neutral_relabels(), applied symmetrically to item1, item2, and em->em_expr. The helper strips only RelabelType layers whose resultcollid == exprCollation(arg) (collation-neutral), stopping at the first collation-changing layer.
  • Patch: unified diff bound to HEAD 2866d8c7..., sha256 91efdb172de34f5c5d87f95df1ab9e2f756d9f116489a8661344338be34df9d0.
  • Test: new src/test/regress/sql/collate.icu.utf8.sql block asserting est_rows = 144 (fails on v1 with 12).
F2

— MAJOR / correctness — caller/item strip asymmetry

  • Location: src/backend/optimizer/path/equivclass.c:2676-2687.
  • Mechanism: Only EC members (em->em_expr) are stripped, not caller-supplied item1/item2. Two different equality notions depending on which side is wrapped. Latent for current callers (relnode.c passes bare partexprs; selfuncs.c passes bare Vars) but fragile for future callers.
  • Verification status: verified (static analysis of both callers).
  • Repair: strip both sides symmetrically with the same collation-guarded helper (resolves F2 and also F1 for the add_unique_group_var path).
F3

— MAJOR / tests — test does not cover the collation-distinguish regression

  • Location: contrib/postgres_fdw/sql/postgres_fdw.sql:3696-3741.
  • Mechanism: The staged test only exercises the positive partitionwise-join case (default collation varchar hash). It does not assert the negative/estimation behavior; a revert to unconditional strip would pass the suite.
  • Verification status: verified. Confirmed empirically that a naive non-partitioned collation test does NOT distinguish v1 from v3; the regression only manifests in the partitionwise-join path where EC members for partition keys carry the collation-changing RelabelType.
  • Repair: new core collate.icu.utf8 regression test mirroring the thread repro, asserting est_rows = 144.
F4

— NIT / maintainability — NULL-guard stylistic consistency

  • Location: src/backend/optimizer/path/equivclass.c:2679.
  • while (IsA(expr, RelabelType)) omits the expr && NULL guard used by the three sibling loops (lines 924, 950, 2762). Functionally safe (IsA(NULL, RelabelType) is false) but inconsistent. verified. Repair: the helper uses while (expr && IsA(expr, RelabelType)).
F5

— NIT / maintainability — comment/header documentation

  • Location: src/backend/optimizer/path/equivclass.c:2678.
  • The terse comment does not explain the collation guard rationale or reference canonicalize_ec_expression. verified. Repair: expanded comment documenting the collation-neutral strip.
F6

— NIT / docs — SQL comment grammar + test-object cleanup

  • Location: contrib/postgres_fdw/sql/postgres_fdw.sql:3738.
  • Subject-verb agreement ("types ... is removed"). Test objects fprt3/fprt4 not dropped (consistent with fprt1/fprt2 precedent; kept by design). verified. Repair: grammar fix; objects kept.

Verification Summary

FindingSeverityClassStatusMethod
F1BLOCKERcorrectnessverifiedrepro (live, three-binary A/B/C)
F2MAJORcorrectnessverifiedstatic-check (caller analysis)
F3MAJORtestsverifiedstatic-check (test-adequacy)
F4NITmaintainabilityverifiedstatic-check (sibling-loop comparison)
F5NITmaintainabilityverifiedstatic-check (comment inspection)
F6NITdocsverifiedstatic-check (comment/lifecycle inspection)

All six findings survived verification (none refuted, none cannot-verify). No typed safety waivers were required.

Repair Validation Summary

A single concrete repair patch (unified diff bound to frozen HEAD 2866d8c7...) covers F1, F2, F4, F5, F6 (C helper + comment + SQL comment grammar) and adds the F3 regression test.

The repair resolves F1 (estimation regression), F2 (symmetry), F4 (NULL-guard), F5 (comment), F6 (grammar) and adds the F3 test. A successful repair does not prove the finding; the finding was independently verified by reproduction first.

Changed-Code Coverage

Metrics (changed lines = the staged v1 additions: lines 2676, 2679, 2680)

MetricValue
changed_executable_lines3
covered_changed_lines3
compiler_uncovered_changed_lines0
uncovered_changed_lines0
structural_uncovered_changed_lines0
changed_lines_without_coverage_coordinates0
changed_branches2
covered_changed_branches2

Per-line evidence (patched equivclass.c)

Uncovered regions / branches

None. All 3 changed executable lines and both changed branches are covered. No COV-* findings.

Touched function

exprs_known_equal (src/backend/optimizer/path/equivclass.c:2645-2694): entered=true; whole-function lines 21/22 covered; whole-function branches 26/28 covered. (The 2 uncovered whole-function branches are pre-existing error/edge paths outside the changed region, not introduced by this patch.)

Non-instrumented changes

Test commands

Integrity / residual limitations

pgsql-hackers Thread Ledger

Aggregated Test Plan

  1. New core regression test (F1/F3 oracle): src/test/regress/sql/collate.icu.utf8.sql — ec_estimated_rows helper + partitioned LIST repro with case_insensitive ICU collation + domain d_txt_ci, asserting est_rows = 144. Fails on v1 (12), passes on v3 (144). Requires ICU (already gated in parallel_schedule).
  2. Smoke test (kept): contrib/postgres_fdw/sql/postgres_fdw.sql fprt3/fprt4 positive partitionwise-join case.

Verified-clean / non-findings

Residual risk

If the staged v1 is committed without the collation guard, GROUP BY/DISTINCT cardinality estimates regress for any case where two EC members share an EC but differ in exposed collation via a domain COLLATE on an ICU nondeterministic collation. This is a planner estimate regression (no wrong results, no crash, no corruption), but it can produce noticeably worse plans. The repair restores master behavior while preserving the intended varchar partitionwise-join benefit.

Provenance