Skip to content

Stabilize regression tests against non-deterministic Heap Fetches#51

Merged
danolivo merged 3 commits into
mainfrom
multiple-shifts
Apr 4, 2026
Merged

Stabilize regression tests against non-deterministic Heap Fetches#51
danolivo merged 3 commits into
mainfrom
multiple-shifts

Conversation

@danolivo
Copy link
Copy Markdown
Owner

@danolivo danolivo commented Apr 3, 2026

The parallel Index Only Scan test was failing intermittently because Heap Fetches depends on the visibility map state, which varies with autovacuum activity between runs.

Switch the bare EXPLAIN to portable_explain_analyze() and extend it with a regexp_replace that normalises "Heap Fetches: N" to a stable token, matching the existing treatment of row counts and buffer sizes.

Also fix test ordering in the Makefile (interface before pg_track_optimizer so the reset counter starts at zero), remove an early DROP FUNCTION portable_explain_analyze that broke subsequent tests, and add missing includes for tuplestore.h and executor/instrument.h that were flagged by stricter builds.

The parallel Index Only Scan test was failing intermittently because
Heap Fetches depends on the visibility map state, which varies with
autovacuum activity between runs.

Switch the bare EXPLAIN to portable_explain_analyze() and extend it
with a regexp_replace that normalises "Heap Fetches: N" to a stable
token, matching the existing treatment of row counts and buffer sizes.

Also fix test ordering in the Makefile (interface before
pg_track_optimizer so the reset counter starts at zero), remove an
early DROP FUNCTION portable_explain_analyze that broke subsequent
tests, and add missing includes for tuplestore.h and
executor/instrument.h that were flagged by stricter builds.
@danolivo danolivo self-assigned this Apr 3, 2026
@danolivo danolivo added the bug Something isn't working label Apr 3, 2026
danolivo added 2 commits April 3, 2026 16:07
Extend portable_explain_analyze() to normalise additional sources of
version-specific output variation:

- Strip "Index Searches: N" lines introduced in PG 18 so that a single
  expected file covers both PG 17 and PG 18+.  This also lets us drop
  expected/join_filtering_1.out entirely, leaving one canonical file.
- Normalise "actual rows=N.00" to "actual rows=N".  PG 18 started
  printing row counts with two decimal places inside EXPLAIN ANALYZE
  output; the normalisation hides this from all callers of the helper.
- Normalise "Heap Fetches: N" to mask the non-deterministic value that
  depends on visibility-map state at test time.

Switch subplan.sql to route both EXPLAIN calls through
portable_explain_analyze() so that the normalisation rules apply there
too.  Add "AND query LIKE 'EXPLAIN%'" to the tracking-result query so
that only the inner EXPLAIN query appears in pg_track_optimizer(), not
the portable_explain_analyze() wrapper itself.

Update expected output files accordingly:
- expected/subplan.out     – PG 19+ (SubPlan expr_1 naming)
- expected/subplan_1.out   – PG 17–18 (SubPlan 1 naming)
- expected/subplan_2.out   – deleted; PG 16 is no longer supported
- expected/join_filtering_1.out – deleted; consolidated into one file
- expected/pg_track_optimizer.out / _1.out – updated for the
  portable_explain_analyze() change in the verify_test block

Add a "Regression Test Expected Output Files" section to README.md
documenting which file covers which PostgreSQL version and why.
Route all bare EXPLAIN ANALYZE calls in the test suite through
portable_explain_analyze() so that version-specific output differences
are normalised away in one place rather than duplicated across alternate
expected files.

Specific changes:

- portable_explain_analyze() already stripped "actual rows=N.00",
  "Heap Fetches: N", and "Index Searches" lines.  Apply it to the two
  remaining bare EXPLAIN ANALYZE calls in pg_track_optimizer.sql
  (pto_test and t1) that still exposed the rows=N.00 difference between
  PG 17 and PG 18+.  Add AND query LIKE 'EXPLAIN%' to the t1 tracking
  check to exclude the portable_explain_analyze wrapper query from the
  results.

- Replace the opening SELECT * FROM pg_track_optimizer_reset() with
  SELECT pg_track_optimizer_reset() >= 0 AS cleaned to mask a
  version-specific count (0 on PG 17, 1 on PG 18+) caused by the
  persistent DSM segment retaining the previous test's final reset call.

- Delete expected/pg_track_optimizer_1.out: now that all EXPLAIN output
  is normalised, both PG 17 and PG 18+ produce identical output and a
  single expected file covers all supported versions.

- Delete expected/join_filtering_1.out: portable_explain_analyze already
  filtered "Index Searches" lines, so the primary file was never matched
  and the _1 variant was doing all the work.  Collapse to one file.

- Delete expected/subplan_2.out: PG 16 is no longer supported.  Rebuild
  expected/subplan_1.out (PG 17–18, SubPlan 1 naming) directly from
  actual test results to ensure correct column widths and trailing spaces
  rather than hand-writing it.

- Update README to document the remaining alternate files and why they
  exist.

After these changes only one variant remains: expected/subplan_1.out,
kept solely because PG 19 renamed "SubPlan 1" to "SubPlan expr_1" — a
content difference that output normalisation cannot bridge.
@danolivo danolivo merged commit 2df63f0 into main Apr 4, 2026
4 checks passed
@danolivo danolivo deleted the multiple-shifts branch April 4, 2026 09:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant