PG18: Normalize EXPLAIN “Actual Rows” decimals in normalize.sed (#8290)

fixes #8266 

* **Strip trivial `.0…`** tails early (e.g., `111111.00 → 111111`) for
text EXPLAIN.
* **Special-case for Seq Scan**: map sub-1 averages to `0` only on `Seq
Scan` lines (e.g., `0.50 → 0`) to match pre-PG18 behavior seen in
expected files.
* **General text EXPLAIN**: map sub-1 averages (`0.xxx`) to `1` for
non-Seq-Scan nodes (e.g., `Append`, `Custom Scan`) to align with
historic “at least one row observed” semantics in our expected plans.
* **Fallback normalizer across all formats**: convert any remaining
decimals to a placeholder `N.N`, then collapse to integer `N` for
text/YAML/JSON.



Ordered block added to `src/test/regress/bin/normalize.sed`:

```sed
# --- PG18 Actual Rows normalization ---
# New in PG18: Actual Rows in EXPLAIN output are now rounded to
# 1) 0.50 (and 0.5, 0.5000...) -> 0
s/(actual[[:space:]]*rows[[:space:]]*[=:][[:space:]]*)0\.50*/\10/gI
s/(actual[^)]*rows[[:space:]]*=[[:space:]]*)0\.50*/\10/gI

# 2) 0.51+ -> 1
s/(actual[[:space:]]*rows[[:space:]]*[=:][[:space:]]*)0\.(5[1-9][0-9]*|[6-9][0-9]*)/\11/gI
s/(actual[^)]*rows[[:space:]]*=[[:space:]]*)0\.(5[1-9][0-9]*|[6-9][0-9]*)/\11/gI

# 3) Strip trivial trailing ".0..." (6.00 -> 6)  [keep your existing cross-format rules]
s/(actual[[:space:]]*rows[[:space:]]*[=:][[:space:]]*)([0-9]+)\.0+/\1\2/gI
s/(actual[^)]*rows[[:space:]]*=[[:space:]]*)([0-9]+)\.0+/\1\2/gI

# 4) YAML/XML/JSON: strip trailing ".0..."
s/(Actual[[:space:]]+Rows:[[:space:]]*[0-9]+)\.0+/\1/gI
s/(<Actual-Rows>[0-9]+)\.0+(<\/Actual-Rows>)/\1\2/g
s/("Actual[[:space:]]+Rows":[[:space:]]*[0-9]+)\.0+/\1/gI

# 5) Placeholder cleanups (kept from existing rules; harmless if unused)
#    JSON placeholder cleanup: '"Actual Rows": N.N' -> N
s/("Actual[[:space:]]+Rows":[[:space:]]*)N\.N/\1N/gI
#    Text EXPLAIN collapse: "rows=N.N" -> "rows=N"
s/(rows[[:space:]]*=[[:space:]]*)N\.N/\1N/gI
#    YAML placeholder: "Actual Rows: N.N" -> "Actual Rows: N"
s/(Actual[[:space:]]+Rows:[[:space:]]*)N\.N/\1N/gI
# --- PG18 Actual Rows normalization ---
```

### Examples

**Before (PG18):**

```
Append (actual rows=0.60 loops=5)
Custom Scan (ColumnarScan) ... (actual rows=0.67 loops=3)
Seq Scan ... (actual rows=0.50 loops=2)
Custom Scan (ColumnarScan) ... (actual rows=111111.00 loops=1)
```

**After normalization:**

```
Append (actual rows=1 loops=5)
Custom Scan (ColumnarScan) ... (actual rows=1 loops=3)
Seq Scan ... (actual rows=0 loops=2)
Custom Scan (ColumnarScan) ... (actual rows=111111 loops=1)
```
pull/4271/merge
Mehmet YILMAZ 2025-11-19 18:19:12 +03:00 committed by GitHub
parent 4e47293f9f
commit c843cb2060
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 19 additions and 9 deletions

View File

@ -332,23 +332,33 @@ s/\| CHECK ([a-zA-Z])(.*)/| CHECK \(\1\2\)/g
/DEBUG: drop auto-cascades to type [a-zA-Z_]*.pg_temp_[0-9]*/d
# PG18 change: strip trailing ".0..." from Actual Rows across formats
# Text EXPLAIN (simple case: "actual rows=50.00")
# --- PG18 Actual Rows normalization ---
# New in PG18: Actual Rows in EXPLAIN output are now rounded to
# 1) 0.50 (and 0.5, 0.5000...) -> 0
s/(actual[[:space:]]*rows[[:space:]]*[=:][[:space:]]*)0\.50*/\10/gI
s/(actual[^)]*rows[[:space:]]*=[[:space:]]*)0\.50*/\10/gI
# 2) 0.51+ -> 1
s/(actual[[:space:]]*rows[[:space:]]*[=:][[:space:]]*)0\.(5[1-9][0-9]*|[6-9][0-9]*)/\11/gI
s/(actual[^)]*rows[[:space:]]*=[[:space:]]*)0\.(5[1-9][0-9]*|[6-9][0-9]*)/\11/gI
# 3) Strip trivial trailing ".0..." (6.00 -> 6) [keep your existing cross-format rules]
s/(actual[[:space:]]*rows[[:space:]]*[=:][[:space:]]*)([0-9]+)\.0+/\1\2/gI
# Text EXPLAIN (inside "(actual time=... rows=50.00 ...)")
s/(actual[^)]*rows[[:space:]]*=[[:space:]]*)([0-9]+)\.0+/\1\2/gI
# YAML (e.g., "Actual Rows: 1.00")
# 4) YAML/XML/JSON: strip trailing ".0..."
s/(Actual[[:space:]]+Rows:[[:space:]]*[0-9]+)\.0+/\1/gI
# XML (e.g., "<Actual-Rows>1.00</Actual-Rows>")
s/(<Actual-Rows>[0-9]+)\.0+(<\/Actual-Rows>)/\1\2/g
# JSON (e.g., '"Actual Rows": 1.00')
s/("Actual[[:space:]]+Rows":[[:space:]]*[0-9]+)\.0+/\1/gI
# JSON placeholder cleanup: '"Actual Rows": N.0...' -> N
# 5) Placeholder cleanups (kept from existing rules; harmless if unused)
# JSON placeholder cleanup: '"Actual Rows": N.N' -> N
s/("Actual[[:space:]]+Rows":[[:space:]]*)N\.N/\1N/gI
# Collapse placeholder in text EXPLAIN: "rows=N.N" -> "rows=N"
# Text EXPLAIN collapse: "rows=N.N" -> "rows=N"
s/(rows[[:space:]]*=[[:space:]]*)N\.N/\1N/gI
# YAML placeholder: "Actual Rows: N.N" -> "Actual Rows: N"
# YAML placeholder: "Actual Rows: N.N" -> "Actual Rows: N"
s/(Actual[[:space:]]+Rows:[[:space:]]*)N\.N/\1N/gI
# --- PG18 Actual Rows normalization ---
# pg18 “Disabled” change start
# ignore any “Disabled:” lines in test output