From 63970d00c18886292746fdfcabcb67fb539854b3 Mon Sep 17 00:00:00 2001 From: "Joshua D. Drake" Date: Fri, 16 Oct 2026 17:55:58 +0000 Subject: [PATCH] test: native_parquet_pushdown checks the row-group edges, where an inclusive bound read as exclusive skips the match (#1496 review) Every oracle predicate in the suite stayed clear of a row-group edge (group 0 ends at 49999, group 1 starts at 50000). With the FDW's skip test for `col >= const` changed to skip on max <= const, the suite was 36/36 green in both twins; the same held for `<=` read as `<` and for `=` read as half-open at the max. Both twins gain six "row-group edge [pred] == oracle" arms on those constants. Measured, PG17, each mutant reddens exactly its arm in both twins: - >= skipping on max <= const: [id >= 49999] - <= skipping on min >= const: [id <= 50000] - = skipping on const >= max: [id = 49999] - = skipping on const <= min: [id = 50000] Main's shell under the <= and = (max) mutants: 36/36 green. Ledger: six rows on 15-19 from clean logs of each major, four dated by those mutations; "id > 49998" and "id < 50001" enter never. Census 4310 -> 4316 rows, 3010 -> 3012 never, 1300 -> 1304 dated. Co-Authored-By: Claude Opus 5.5 --- test/check_ledger.tsv | 6 ++++++ test/check_ledger_budget.txt | 12 +++++++++++- test/native_parquet_pushdown.sh | 18 ++++++++++++++++++ test/pytest/test_native_parquet_pushdown.py | 6 ++++++ 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/test/check_ledger.tsv b/test/check_ledger.tsv index ab3782fc5..72906a1f4 100644 --- a/test/check_ledger.tsv +++ b/test/check_ledger.tsv @@ -2968,6 +2968,12 @@ native_parquet_pushdown native_parquet_pushdown predicate [val > 90000 AND val < native_parquet_pushdown native_parquet_pushdown range in one group skips 3 15;16;17;18;19 2026-10-16 columnar_parquet_reader.c: pqfdw_compute_skip never marks a row group skippable native_parquet_pushdown native_parquet_pushdown read_parquet same file == oracle 15;16;17;18;19 never - native_parquet_pushdown native_parquet_pushdown reports 4 row groups 15;16;17;18;19 never - +native_parquet_pushdown native_parquet_pushdown row-group edge [id < 50001] == oracle 15;16;17;18;19 never - +native_parquet_pushdown native_parquet_pushdown row-group edge [id <= 50000] == oracle 15;16;17;18;19 2026-10-16 col <= const skipping a group whose min equals const (mutation, #1496 review) +native_parquet_pushdown native_parquet_pushdown row-group edge [id = 49999] == oracle 15;16;17;18;19 2026-10-16 col = const skipping a group whose max equals const (mutation, #1496 review) +native_parquet_pushdown native_parquet_pushdown row-group edge [id = 50000] == oracle 15;16;17;18;19 2026-10-16 col = const skipping a group whose min equals const (mutation, #1496 review) +native_parquet_pushdown native_parquet_pushdown row-group edge [id > 49998] == oracle 15;16;17;18;19 never - +native_parquet_pushdown native_parquet_pushdown row-group edge [id >= 49999] == oracle 15;16;17;18;19 2026-10-16 col >= const skipping a group whose max equals const (mutation, #1496 review) native_parquet_pushdown native_parquet_pushdown spanning predicate skips 0 15;16;17;18;19 2026-10-16 columnar_parquet_reader.c: col < const skips the row groups that do hold matches native_parquet_schema native_parquet_schema OPTIONAL column reports nullable=t 15;16;17;18;19 never - native_parquet_schema native_parquet_schema REQUIRED column reports nullable=f 15;16;17;18;19 2026-10-16 columnar_parquet_reader.c: parquet_schema reports every column nullable diff --git a/test/check_ledger_budget.txt b/test/check_ledger_budget.txt index a14fe9df7..ad7309ba1 100644 --- a/test/check_ledger_budget.txt +++ b/test/check_ledger_budget.txt @@ -3629,4 +3629,14 @@ suites_not_covered 185 # never 3079 - 1 = 3078 # dated 1369 + 1 = 1370 # 3078 + 1370 == 4448 -checks_never_observed_red 3078 +# #1496 review, native_parquet_pushdown's row-group edges (jdatcmd): 3078 -> 3080. +# Six oracle arms whose constants sit on a group's max (49999) or min (50000), where +# an inclusive bound read as exclusive skips the group holding the match. Four are +# dated by that mutation for >=, <=, and = at the max and at the min; "id > 49998" +# and "id < 50001" enter never, as no natural off-by-one over-skips them. +# +# ledger rows 4448 + 6 = 4454 +# never 3078 + 2 = 3080 +# dated 1370 + 4 = 1374 +# 3080 + 1374 == 4454 +checks_never_observed_red 3080 diff --git a/test/native_parquet_pushdown.sh b/test/native_parquet_pushdown.sh index 0c31eaf77..a680fab59 100755 --- a/test/native_parquet_pushdown.sh +++ b/test/native_parquet_pushdown.sh @@ -62,6 +62,24 @@ do "$(pgc_set_hash "SELECT * FROM h WHERE $pred")" done +# ---- the row-group edges: an inclusive bound skips nothing it matches -------- +# Group 0 ends at 49999 and group 1 starts at 50000. A predicate whose constant is +# a group's max or min is where an inclusive comparison read as exclusive skips a +# group that holds the matching row -- and every predicate above stays clear of +# them (#1496 review): with `col >= c` skipping on max <= c, this suite was green. +for pred in \ + "id >= 49999" \ + "id > 49998" \ + "id <= 50000" \ + "id < 50001" \ + "id = 49999" \ + "id = 50000" +do + check "row-group edge [$pred] == oracle" \ + "$(pgc_set_hash "SELECT * FROM ft WHERE $pred")" \ + "$(pgc_set_hash "SELECT * FROM h WHERE $pred")" +done + # ---- skipping actually happens (EXPLAIN ANALYZE counter) -------------------- skipped_for() { # skipped_for WHERE q "EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF, SUMMARY OFF) diff --git a/test/pytest/test_native_parquet_pushdown.py b/test/pytest/test_native_parquet_pushdown.py index d0e2827b3..e78561294 100644 --- a/test/pytest/test_native_parquet_pushdown.py +++ b/test/pytest/test_native_parquet_pushdown.py @@ -70,6 +70,12 @@ def test_skipping_never_changes_the_answer_and_really_skips(pgc_conn, server_dir "id > 60000 AND id < 60010", "id <= 5 OR id >= 199995", "val > 90000 AND val < 90030"): expect.text(_hash(cur, f"SELECT * FROM ft WHERE {pred}"), _hash(cur, f"SELECT * FROM h WHERE {pred}"), f"predicate [{pred}] == oracle") + # THE ROW-GROUP EDGES (#1496 review): group 0 ends at 49999, group 1 starts at + # 50000, and an inclusive bound read as exclusive skips the group holding the + # match. Every predicate above stays clear of an edge. + for pred in ("id >= 49999", "id > 49998", "id <= 50000", "id < 50001", "id = 49999", "id = 50000"): + expect.text(_hash(cur, f"SELECT * FROM ft WHERE {pred}"), _hash(cur, f"SELECT * FROM h WHERE {pred}"), + f"row-group edge [{pred}] == oracle") expect.text(_counter(cur, "ft", "id >= 0", "Row Groups:"), "4", "reports 4 row groups") for name, where, want in (