From 16045c4b92f2257b194176c4624660799f81d0a4 Mon Sep 17 00:00:00 2001 From: "Joshua D. Drake" Date: Tue, 13 Oct 2026 21:52:00 +0000 Subject: [PATCH 1/3] test: collation_change and tier_partition, the #1339 findings in both twins collation_change (round two, items 2 and 7): - The pytest twin called cannot_run with "no en_US collation", which is not one of UNRUNNABLE_REASONS, so a server without en_US raised VacuityError instead of recording the test unrunnable. It is MISSING_DEPENDENCY now. Shown with the lookup pointed at a collation that does not exist: main raises VacuityError; here, UNRUN MISSING_DEPENDENCY (and the run exits 67, as an unexpected unrunnable must). - same()/same2()/_same said "same" for two empty answers. They now require one. With the min/max query pointed at an empty set: main passes 11/11; here, "columnar [] heap []" in both twins. - The extent arm accepts "none", because the fix forgets the extent, so a column_extent() that never returns a row passed it. A new arm requires the extent to hold C's bound before the change. Under column_extent() returning no row: main 11/11 and pytest green; here red in both twins. tier_partition:150: the other-wrapper refusal also requires that no file was written. With the wrapper branch removed, main's arm was already red (HV00D, not 42809), so this is an accuracy fix: the arm now says what a refusal after the export would leave behind. Co-Authored-By: Claude Opus 5.5 --- test/collation_change.sh | 12 ++++++++++-- test/pytest/test_collation_change.py | 14 ++++++++++++-- test/pytest/test_tier_partition.py | 7 +++++-- test/tier_partition.sh | 5 ++++- 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/test/collation_change.sh b/test/collation_change.sh index c81fdac3d..233950b3e 100755 --- a/test/collation_change.sh +++ b/test/collation_change.sh @@ -47,6 +47,12 @@ for t in cc ch; do done check "premise: the columnar table has several row groups" \ "$(q "SELECT count(*) FROM pgcolumnar.row_group WHERE storage_id = pgcolumnar.get_storage_id('cc');")" "3" +# THE EXTENT EXISTED, AND HELD C'S BOUND (#1339). The arm after the change accepts +# "none", because the fix forgets the extent; without this one, a column_extent() +# that never returns a row passed it too. +check "before the change the column's extent is the C collation's bound" \ + "$(q "SELECT coalesce((SELECT minimum || '|' || maximum FROM pgcolumnar.column_extent('cc', 's')), 'none');")" \ + "$(q "SELECT min(s) || '|' || max(s) FROM ch;")" before="$(q "SELECT pg_relation_filenode('cc');")" for t in cc ch; do q "ALTER TABLE $t ALTER COLUMN s TYPE text COLLATE \"$COLL\";" >/dev/null @@ -56,7 +62,8 @@ check "premise: the collation change rewrote nothing" "$(q "SELECT pg_relation_f same() { # same SQL-with-%T -> "same", or both answers when they differ local c h c="$(q "${1//%T/cc}")"; h="$(q "${1//%T/ch}")" - [ "$c" = "$h" ] && echo same || echo "columnar [$c] heap [$h]" + # An answer is required (#1339): two empty answers are not the same answer. + [ -n "$c" ] && [ "$c" = "$h" ] && echo same || echo "columnar [$c] heap [$h]" } check "after the collation change min and max are heap's" "$(same "SELECT min(s) || '|' || max(s) FROM %T;")" "same" check "and a range below an upper-case bound returns heap's rows" \ @@ -104,7 +111,8 @@ done same2() { # same2 SQL-with-%T over vs and vh local c h c="$(q "${1//%T/vs}")"; h="$(q "${1//%T/vh}")" - [ "$c" = "$h" ] && echo same || echo "columnar [$c] heap [$h]" + # An answer is required (#1339): two empty answers are not the same answer. + [ -n "$c" ] && [ "$c" = "$h" ] && echo same || echo "columnar [$c] heap [$h]" } check "a table sorted under the old collation orders ORDER BY ... LIMIT as heap does" \ "$(same2 "SELECT string_agg(s, ',') FROM (SELECT s FROM %T ORDER BY s, k LIMIT 6) x;")" "same" diff --git a/test/pytest/test_collation_change.py b/test/pytest/test_collation_change.py index 7cfe87759..44745ba43 100644 --- a/test/pytest/test_collation_change.py +++ b/test/pytest/test_collation_change.py @@ -26,7 +26,8 @@ def _one(conn, sql): def _same(conn, sql, columnar, heap): c = _one(conn, sql.replace("%T", columnar)) h = _one(conn, sql.replace("%T", heap)) - return "same" if c == h else f"columnar [{c}] heap [{h}]" + # An answer is required (#1339): None on both sides is not the same answer. + return "same" if c is not None and c == h else f"columnar [{c}] heap [{h}]" def _value(g): @@ -41,7 +42,10 @@ def test_a_collation_change_without_a_rewrite(pgc_conn, expect): " AND collencoding IN (-1, pg_char_to_encoding(current_setting('server_encoding')))" " ORDER BY collname LIMIT 1") if coll is None: - expect.cannot_run("no en_US collation", name="the server has no en_US collation to change a C column to") + # A reason cannot_run knows (#1339): "no en_US collation" is not one, and it + # raised VacuityError instead of recording the test as unrunnable. + expect.cannot_run("MISSING_DEPENDENCY", "no en_US collation", + name="the server has no en_US collation to change a C column to") return expect.text(_one(conn, f"SELECT ('c' < 'Q' COLLATE \"{coll}\")::text || '|' || ('c' < 'Q' COLLATE \"C\")::text"), "true|false", "premise: the new collation orders a lower-case letter before an upper-case one that C puts first") @@ -54,6 +58,12 @@ def test_a_collation_change_without_a_rewrite(pgc_conn, expect): cur.execute(f"INSERT INTO {t} SELECT g, {_value('g')} FROM generate_series(1, {4 * GROUP}) g") expect.num(_one(conn, "SELECT count(*) FROM pgcolumnar.row_group WHERE storage_id = pgcolumnar.get_storage_id('xc')"), 4, "premise: the columnar table has several row groups") + # The extent existed, and held C's bound (#1339): the arm after the change accepts + # "none", so without this a column_extent() that never returns a row passed it. + expect.text(_one(conn, "SELECT coalesce((SELECT minimum || '|' || maximum" + " FROM pgcolumnar.column_extent('xc', 's')), 'none')"), + _one(conn, "SELECT min(s) || '|' || max(s) FROM xh"), + "before the change the column's extent is the C collation's bound") before = _one(conn, "SELECT pg_relation_filenode('xc')") for t in ("xc", "xh"): conn.execute(f'ALTER TABLE {t} ALTER COLUMN s TYPE text COLLATE "{coll}"') diff --git a/test/pytest/test_tier_partition.py b/test/pytest/test_tier_partition.py index 339742395..ad306382a 100644 --- a/test/pytest/test_tier_partition.py +++ b/test/pytest/test_tier_partition.py @@ -147,8 +147,11 @@ def plan(sql): "42809", "a partition that is not columnar is refused") expect.text(_sqlstate(conn, f"SELECT pgcolumnar.tier_partition('s_rest', 'tq', '{server_dir}/rest.parquet')"), "0A000", "a DEFAULT partition is refused") - expect.text(_sqlstate(conn, f"SELECT pgcolumnar.tier_partition('s_apr', 'ti', '{server_dir}/apr.parquet')"), - "42809", "a server of another wrapper is refused") + # Before anything moves (#1339): a refusal from a later step, after the export, + # would leave the file behind with the same SQLSTATE. + other = _sqlstate(conn, f"SELECT pgcolumnar.tier_partition('s_apr', 'ti', '{server_dir}/apr.parquet')") + expect.text(f"{other}|{'file' if (server_dir / 'apr.parquet').exists() else 'nofile'}", + "42809|nofile", "a server of another wrapper is refused") expect.text(_sqlstate(conn, f"SELECT pgcolumnar.tier_partition('s_apr', 'tq', '{path}')"), "58P02", "an existing path is refused, so no file a table reads is overwritten") expect.text(_digest(conn, "s"), rb, "and the refusals moved nothing") diff --git a/test/tier_partition.sh b/test/tier_partition.sh index 976bb4a45..03b3540d8 100755 --- a/test/tier_partition.sh +++ b/test/tier_partition.sh @@ -123,8 +123,11 @@ psql_run "CREATE TABLE m_def PARTITION OF m DEFAULT USING pgcolumnar;" check "a DEFAULT partition is refused" \ "$(sqlstate "SELECT pgcolumnar.tier_partition('m_def', 'tier_pq', '$W/m_def.parquet');")" "0A000" psql_run "CREATE SERVER tier_ice FOREIGN DATA WRAPPER pgcolumnar_iceberg;" +# Before anything moves (#1339): a refusal that came only from a later step, after +# the export, would leave the file behind with the same SQLSTATE. check "a server of another wrapper is refused" \ - "$(sqlstate "SELECT pgcolumnar.tier_partition('m_feb', 'tier_ice', '$W/m_feb.parquet');")" "42809" + "$(sqlstate "SELECT pgcolumnar.tier_partition('m_feb', 'tier_ice', '$W/m_feb.parquet');")|$([ -e "$W/m_feb.parquet" ] && echo file || echo nofile)" \ + "42809|nofile" check "an existing path is refused, so no file a table reads is overwritten" \ "$(sqlstate "SELECT pgcolumnar.tier_partition('m_feb', 'tier_pq', '$W/m_jan.parquet');")" "58P02" check "and the refusals moved nothing" "$(digest m)" "$rb" From 6a4586ee74410899bd0d4bb55afcbd86cc4e1ebd Mon Sep 17 00:00:00 2001 From: "Joshua D. Drake" Date: Tue, 13 Oct 2026 21:52:00 +0000 Subject: [PATCH 2/3] test: column_extent, the #1339 findings in both twins - :288/:225: TRUNCATE, DROP and "it did move" proved removal or movement of an extent nobody showed existed. "Fifty committing writers leave a bounded number of extent rows" now also requires at least one, and new arms require an extent before expire and rows before DROP. With no extent row ever written, main's fifty-writers, TRUNCATE and DROP arms all PASS; here each of those three is red. - :306: the 42501 for a role without SELECT has a control: given SELECT, the same role reads the extent. Under column_extent() refused to every non-superuser, main is 36/36 green; here the control is red. - :129/:237: three checks named premise: test product code (parallel_copy, expire, compact_rewrite) and are arms (#1236), renamed in both twins. expire returning 0 and compact_rewrite returning 0 redden two of them. Clean: 39/39 and pytest 7 passed on each of 15-19. Co-Authored-By: Claude Opus 5.5 --- test/column_extent.sh | 19 +++++++++++++++---- test/pytest/test_column_extent.py | 18 ++++++++++++++---- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/test/column_extent.sh b/test/column_extent.sh index b81c750f3..bba291034 100755 --- a/test/column_extent.sh +++ b/test/column_extent.sh @@ -112,7 +112,7 @@ q "CREATE TABLE cw (ts timestamptz, v int) USING pgcolumnar; INSERT INTO cw SELECT '2026-06-01'::timestamptz + g * interval '1 s', g FROM generate_series(1, 2000) g;" >/dev/null q "COPY (SELECT '2020-01-01'::timestamptz + g * interval '1 day', g FROM generate_series(1, 4000) g) TO '$PGC_WORKDIR/cw.txt' WITH (FORMAT text);" >/dev/null -check "premise: parallel_copy's loaders, flushing into one table at once, all commit" \ +check "parallel_copy's loaders, flushing into one table at once, all commit" \ "$(q "SELECT pgcolumnar.parallel_copy('cw', '$PGC_WORKDIR/cw.txt', 4);")" "4000" check "and the extent covers what they loaded" "$(ext cw ts)" "$(truth cw ts)" @@ -189,8 +189,11 @@ q "CREATE TABLE ex (ts timestamptz, v int) USING pgcolumnar; INSERT INTO ex SELECT now() - interval '400 days' + g * interval '1 min', g FROM generate_series(1, 3000) g; INSERT INTO ex SELECT now() - interval '1 day' + g * interval '1 s', g FROM generate_series(1, 3000) g;" >/dev/null ex_before="$(ext ex ts)" +# The extent was there before expire (#1339): the arms below say it MOVED, which +# means nothing if it was never written. +check "before expire the extent covers the table" "$ex_before" "$(truth ex ts)" retired="$(q "SELECT pgcolumnar.expire('ex');")" -check "premise: expire retires the old row groups with the extent in place" "$([ "${retired:-0}" -ge 1 ] && echo yes || echo no)" "yes" +check "expire retires the old row groups with the extent in place" "$([ "${retired:-0}" -ge 1 ] && echo yes || echo no)" "yes" check "after expire the extent is recomputed to the data that is left" "$(ext ex ts)" "$(truth ex ts)" check "and it did move: the retired groups held the old minimum" \ "$([ "$ex_before" != "$(ext ex ts)" ] && echo yes || echo no)" "yes" @@ -200,7 +203,7 @@ q "CREATE TABLE cr (ts timestamptz, v int) USING pgcolumnar; INSERT INTO cr SELECT '2026-01-01'::timestamptz + g * interval '1 min', g FROM generate_series(1, 4000) g; DELETE FROM cr WHERE v > 3500 OR v <= 400;" >/dev/null rewritten="$(q "SELECT pgcolumnar.compact_rewrite('cr', 0.1);")" -check "premise: compact_rewrite rewrites the groups the deletes thinned" "$([ "${rewritten:-0}" -ge 1 ] && echo yes || echo no)" "yes" +check "compact_rewrite rewrites the groups the deletes thinned" "$([ "${rewritten:-0}" -ge 1 ] && echo yes || echo no)" "yes" check "after compact_rewrite the extent is the live rows'" "$(ext cr ts)" "$(truth cr ts)" q "CREATE TABLE vr (ts timestamptz, v int) USING pgcolumnar; @@ -234,13 +237,16 @@ q "CREATE TABLE hk (ts timestamptz, v int) USING pgcolumnar;" >/dev/null for k in $(seq 1 50); do q "INSERT INTO hk VALUES ('2026-01-01'::timestamptz + interval '$k min', $k);" >/dev/null; done hk_rows="$(q "SELECT count(*) FROM pgcolumnar.column_extent WHERE storage_id = $(sid hk) AND column_index = 0;")" check "fifty committing writers leave a bounded number of extent rows" \ - "$([ "${hk_rows:-99}" -le 9 ] && echo yes || echo "no (${hk_rows:-none})")" "yes" + "$([ "${hk_rows:-0}" -ge 1 ] && [ "${hk_rows:-99}" -le 9 ] && echo yes || echo "no (${hk_rows:-none})")" "yes" check "and the extent still covers all fifty" "$(ext hk ts)" "$(truth hk ts)" hk_old="$(sid hk)" q "TRUNCATE hk;" >/dev/null check "TRUNCATE removes the old storage's extent rows" \ "$(q "SELECT count(*) FROM pgcolumnar.column_extent WHERE storage_id = $hk_old;")" "0" cw_old="$(sid cw)" +# Rows to remove (#1339): a count of zero after the DROP proves nothing without it. +check "before DROP the table has extent rows to remove" \ + "$(q "SELECT (count(*) > 0)::text FROM pgcolumnar.column_extent WHERE storage_id = $cw_old;")" "true" q "DROP TABLE cw;" >/dev/null check "DROP TABLE removes them" "$(q "SELECT count(*) FROM pgcolumnar.column_extent WHERE storage_id = $cw_old;")" "0" @@ -251,5 +257,10 @@ check "the extent catalog is not readable by an ordinary role (it holds column v "$(as_role ce_r "SELECT count(*) FROM pgcolumnar.column_extent" | sed -n 's/^ERROR: *\([0-9A-Z]\{5\}\).*/\1/p')" "42501" check "nor is a table's extent through the function, without SELECT on the table" \ "$(as_role ce_r "SELECT * FROM pgcolumnar.column_extent('public.ty', 'ts')" | sed -n 's/^ERROR: *\([0-9A-Z]\{5\}\).*/\1/p')" "42501" +# The control (#1339): the same role, given SELECT, reads it. Without this, a function +# refused to everyone -- by EXECUTE, or by the schema -- passed the arm above. +q "GRANT SELECT ON ty TO ce_r;" >/dev/null +check "and with SELECT on the table the same role reads its extent" \ + "$(as_role ce_r "SELECT count(*) FROM pgcolumnar.column_extent('public.ty', 'ts')")" "1" pgc_summary diff --git a/test/pytest/test_column_extent.py b/test/pytest/test_column_extent.py index 302b22498..add40cc65 100644 --- a/test/pytest/test_column_extent.py +++ b/test/pytest/test_column_extent.py @@ -127,7 +127,7 @@ def test_writers_concurrent_aborted_and_prepared(pgc_own_db, pgc_cluster, expect _run(conn, "COPY (SELECT '2018-03-03'::timestamptz + g * interval '13 hours', g" f" FROM generate_series(1, 5200) g) TO '{path}' WITH (FORMAT text)") expect.num(_one(conn, f"SELECT pgcolumnar.parallel_copy('cw', '{path}', 3)"), 5200, - "premise: parallel_copy's loaders, flushing into one table at once, all commit") + "parallel_copy's loaders, flushing into one table at once, all commit") expect.text(_ext(conn, "cw", "ts"), _truth(conn, "cw", "ts"), "and the extent covers what they loaded") with psycopg.connect(dsn) as c: @@ -221,9 +221,11 @@ def test_a_shrink_is_recomputed_never_guessed(pgc_own_db, expect): _run(conn, "INSERT INTO ex SELECT now() - interval '700 days' + g * interval '90 s', g FROM generate_series(1, 2500) g", "INSERT INTO ex SELECT now() - interval '2 days' + g * interval '7 s', g FROM generate_series(1, 2500) g") before = _ext(conn, "ex", "ts") + # The extent was there before expire (#1339): "it did move" means nothing otherwise. + expect.text(before, _truth(conn, "ex", "ts"), "before expire the extent covers the table") retired = _one(conn, "SELECT pgcolumnar.expire('ex')") expect.text("yes" if (retired or 0) >= 1 else f"no ({retired})", "yes", - "premise: expire retires the old row groups with the extent in place") + "expire retires the old row groups with the extent in place") after = _ext(conn, "ex", "ts") expect.text(after, _truth(conn, "ex", "ts"), "after expire the extent is recomputed to the data that is left") expect.text("yes" if before != after else "no", "yes", @@ -235,7 +237,7 @@ def test_a_shrink_is_recomputed_never_guessed(pgc_own_db, expect): "DELETE FROM cr WHERE v > 4200 OR v <= 650") rewritten = _one(conn, "SELECT pgcolumnar.compact_rewrite('cr', 0.1)") expect.text("yes" if (rewritten or 0) >= 1 else f"no ({rewritten})", "yes", - "premise: compact_rewrite rewrites the groups the deletes thinned") + "compact_rewrite rewrites the groups the deletes thinned") expect.text(_ext(conn, "cr", "ts"), _truth(conn, "cr", "ts"), "after compact_rewrite the extent is the live rows'") _run(conn, "CREATE TABLE vr (ts timestamptz, v int) USING pgcolumnar") @@ -274,7 +276,7 @@ def test_housekeeping_and_privilege(pgc_own_db, pgc_cluster, expect): _run(conn, f"INSERT INTO hk VALUES ('2025-01-01'::timestamptz + interval '{k} hours', {k})") rows = _one(conn, f"SELECT count(*) FROM pgcolumnar.column_extent WHERE storage_id = {_sid(conn, 'hk')}" " AND column_index = 0") - expect.text("yes" if rows <= 9 else f"no ({rows})", "yes", + expect.text("yes" if 1 <= rows <= 9 else f"no ({rows})", "yes", "fifty committing writers leave a bounded number of extent rows") expect.text(_ext(conn, "hk", "ts"), _truth(conn, "hk", "ts"), "and the extent still covers all fifty") old = _sid(conn, "hk") @@ -284,6 +286,9 @@ def test_housekeeping_and_privilege(pgc_own_db, pgc_cluster, expect): _run(conn, "CREATE TABLE dr (ts timestamptz) USING pgcolumnar", "INSERT INTO dr SELECT now() FROM generate_series(1, 10)") old = _sid(conn, "dr") + # Rows to remove (#1339): a count of zero after the DROP proves nothing without it. + expect.text(str(_one(conn, f"SELECT count(*) > 0 FROM pgcolumnar.column_extent WHERE storage_id = {old}")), + "True", "before DROP the table has extent rows to remove") _run(conn, "DROP TABLE dr") expect.num(_one(conn, f"SELECT count(*) FROM pgcolumnar.column_extent WHERE storage_id = {old}"), 0, "DROP TABLE removes them") @@ -305,3 +310,8 @@ def as_role(sql): "the extent catalog is not readable by an ordinary role (it holds column values)") expect.text(as_role("SELECT * FROM pgcolumnar.column_extent('public.priv', 'ts')"), "42501", "nor is a table's extent through the function, without SELECT on the table") + # The control (#1339): given SELECT, the same role reads it. Without this, a + # function refused to everyone passed the arm above. + _run(conn, "GRANT SELECT ON priv TO ce_py") + expect.text(as_role("SELECT * FROM pgcolumnar.column_extent('public.priv', 'ts')"), "ok", + "and with SELECT on the table the same role reads its extent") From 9c1113caaccde495464748140e520874ca1b65ff Mon Sep 17 00:00:00 2001 From: "Joshua D. Drake" Date: Tue, 13 Oct 2026 21:52:00 +0000 Subject: [PATCH 3/3] test: ledger for the collation_change, tier_partition and column_extent fixes (#1339) Five-major clean runs of the three suites, each mutation merged with --target naming every arm it reddens. Three column_extent rows renamed (premise: dropped) with their history. Rows 2316 -> 2320, never 1796 -> 1794. Co-Authored-By: Claude Opus 5.5 --- test/check_ledger.tsv | 50 +++++++++++++++++++----------------- test/check_ledger_budget.txt | 22 +++++++++++++++- 2 files changed, 48 insertions(+), 24 deletions(-) diff --git a/test/check_ledger.tsv b/test/check_ledger.tsv index 68d5b1587..cb4c291d7 100644 --- a/test/check_ledger.tsv +++ b/test/check_ledger.tsv @@ -210,6 +210,7 @@ collation_change collation_change a table sorted under the old collation orders collation_change collation_change after the collation change min and max are heap's 15;16;17;18;19 2026-10-13 nothing forgotten after a collation change (main's behaviour);the min/max fold skips a group with values and no bounds as all-NULL collation_change collation_change and a range below an upper-case bound returns heap's rows 15;16;17;18;19 2026-10-13 nothing forgotten after a collation change (main's behaviour) collation_change collation_change and an equality on a value C sorts first returns heap's rows 15;16;17;18;19 2026-10-13 nothing forgotten after a collation change (main's behaviour) +collation_change collation_change before the change the column's extent is the C collation's bound 15;16;17;18;19 2026-10-14 column_extent() returning no row collation_change collation_change premise: the collation change rewrote nothing 15;16;17;18;19 never - collation_change collation_change premise: the columnar table has several row groups 15;16;17;18;19 never - collation_change collation_change premise: the new collation orders a lower-case letter before an upper-case one that C puts first 15;16;17;18;19 never - @@ -218,38 +219,41 @@ collation_change collation_change the column's extent is not the old collation's column_extent column_extent DROP TABLE removes them 15;16;17;18;19 2026-10-13 PgColumnarDeleteMetadata leaves the extent rows column_extent column_extent TRUNCATE removes the old storage's extent rows 15;16;17;18;19 2026-10-13 PgColumnarDeleteMetadata leaves the extent rows column_extent column_extent a column added after older groups has no complete extent (those groups have no zone map for it) 15;16;17;18;19 2026-10-13 a recompute that ignores a group with no zone map for the column;pgcolumnar.column_extent returns a row with no complete extent;the extent trusted without a complete row -column_extent column_extent a prepared transaction's groups are inside the extent after COMMIT PREPARED 15;16;17;18;19 2026-10-13 a writer that finds no complete extent does not recompute one;no extent row written at pre-commit;no extent rows written at PRE_PREPARE -column_extent column_extent a savepoint rolled back after flushing may widen the extent, never narrow it 15;16;17;18;19 2026-10-13 a writer that finds no complete extent does not recompute one;no extent row written at pre-commit;no extent rows written at PRE_PREPARE;the extent folded by comparing Datums as words, not with the type's comparison;the writer's fold keeps the largest minimum +column_extent column_extent a prepared transaction's groups are inside the extent after COMMIT PREPARED 15;16;17;18;19 2026-10-14 a writer that finds no complete extent does not recompute one;no extent row is ever written (PgColumnarExtentPreCommit returns at once);no extent row written at pre-commit;no extent rows written at PRE_PREPARE +column_extent column_extent a savepoint rolled back after flushing may widen the extent, never narrow it 15;16;17;18;19 2026-10-14 a writer that finds no complete extent does not recompute one;no extent row is ever written (PgColumnarExtentPreCommit returns at once);no extent row written at pre-commit;no extent rows written at PRE_PREPARE;the extent folded by comparing Datums as words, not with the type's comparison;the writer's fold keeps the largest minimum column_extent column_extent a table created in a rolled-back savepoint leaves no extent rows 15;16;17;18;19 2026-10-13 pre-commit writes extent rows for a storage that does not exist -column_extent column_extent a transaction's own flushed groups are inside the extent it reads before commit 15;16;17;18;19 2026-10-13 the extent a transaction reads leaves out its own pending fold (the tree before the fix) +column_extent column_extent a transaction's own flushed groups are inside the extent it reads before commit 15;16;17;18;19 2026-10-14 no extent row is ever written (PgColumnarExtentPreCommit returns at once);the extent a transaction reads leaves out its own pending fold (the tree before the fix) column_extent column_extent a type with no ordering gets no extent 15;16;17;18;19 2026-10-13 a recompute that skips values without an ordering;pgcolumnar.column_extent returns a row with no complete extent -column_extent column_extent a writer that finds no complete extent recomputes one over every group 15;16;17;18;19 2026-10-13 a writer that finds no complete extent does not recompute one -column_extent column_extent a writer that rolls back leaves the extent as the data has it 15;16;17;18;19 2026-10-13 a writer that finds no complete extent does not recompute one;no extent row written at pre-commit;no extent rows written at PRE_PREPARE;the writer's fold keeps the largest minimum -column_extent column_extent after VACUUM retires a fully deleted group the extent is the live rows' 15;16;17;18;19 2026-10-13 PgColumnarRetireGroup without marking the storage for a recompute;a recompute that leaves the rows it folded -column_extent column_extent after compact_rewrite the extent is the live rows' 15;16;17;18;19 2026-10-13 PgColumnarRetireGroup without marking the storage for a recompute;a recompute that leaves the rows it folded -column_extent column_extent after expire the extent is recomputed to the data that is left 15;16;17;18;19 2026-10-13 PgColumnarRetireGroup without marking the storage for a recompute;a recompute that leaves the rows it folded +column_extent column_extent a writer that finds no complete extent recomputes one over every group 15;16;17;18;19 2026-10-14 a writer that finds no complete extent does not recompute one;no extent row is ever written (PgColumnarExtentPreCommit returns at once) +column_extent column_extent a writer that rolls back leaves the extent as the data has it 15;16;17;18;19 2026-10-14 a writer that finds no complete extent does not recompute one;no extent row is ever written (PgColumnarExtentPreCommit returns at once);no extent row written at pre-commit;no extent rows written at PRE_PREPARE;the writer's fold keeps the largest minimum +column_extent column_extent after VACUUM retires a fully deleted group the extent is the live rows' 15;16;17;18;19 2026-10-14 PgColumnarRetireGroup without marking the storage for a recompute;a recompute that leaves the rows it folded;no extent row is ever written (PgColumnarExtentPreCommit returns at once) +column_extent column_extent after compact_rewrite the extent is the live rows' 15;16;17;18;19 2026-10-14 PgColumnarRetireGroup without marking the storage for a recompute;a recompute that leaves the rows it folded;compact_rewrite returning 0 before rewriting anything;no extent row is ever written (PgColumnarExtentPreCommit returns at once) +column_extent column_extent after expire the extent is recomputed to the data that is left 15;16;17;18;19 2026-10-14 PgColumnarRetireGroup without marking the storage for a recompute;a recompute that leaves the rows it folded;no extent row is ever written (PgColumnarExtentPreCommit returns at once) column_extent column_extent and a plan made in that transaction estimates as the zone maps do 15;16;17;18;19 2026-10-13 the extent a transaction reads leaves out its own pending fold (the tree before the fix) -column_extent column_extent and it did move: the retired groups held the old minimum 15;16;17;18;19 2026-10-13 PgColumnarRetireGroup without marking the storage for a recompute;a recompute that leaves the rows it folded +column_extent column_extent and it did move: the retired groups held the old minimum 15;16;17;18;19 2026-10-14 PgColumnarRetireGroup without marking the storage for a recompute;a recompute that leaves the rows it folded;no extent row is ever written (PgColumnarExtentPreCommit returns at once) column_extent column_extent and the estimate is the one the zone maps give 15;16;17;18;19 2026-10-13 the planner takes the extent's minimum as its upper bound too;the planner's zone-map fallback removed: with no complete extent it reads nothing and bounds nothing -column_extent column_extent and the extent covers what they loaded 15;16;17;18;19 2026-10-13 a writer that finds no complete extent does not recompute one;no extent row written at pre-commit;no extent rows written at PRE_PREPARE;the writer's fold keeps the largest minimum -column_extent column_extent and the extent still covers all fifty 15;16;17;18;19 2026-10-13 a writer that finds no complete extent does not recompute one;no extent row written at pre-commit +column_extent column_extent and the extent covers what they loaded 15;16;17;18;19 2026-10-14 a writer that finds no complete extent does not recompute one;no extent row is ever written (PgColumnarExtentPreCommit returns at once);no extent row written at pre-commit;no extent rows written at PRE_PREPARE;the writer's fold keeps the largest minimum +column_extent column_extent and the extent still covers all fifty 15;16;17;18;19 2026-10-14 a writer that finds no complete extent does not recompute one;no extent row is ever written (PgColumnarExtentPreCommit returns at once);no extent row written at pre-commit +column_extent column_extent and with SELECT on the table the same role reads its extent 15;16;17;18;19 2026-10-14 column_extent() refused to every non-superuser;no extent row is ever written (PgColumnarExtentPreCommit returns at once) column_extent column_extent and with no extent rows the function reports no complete extent 15;16;17;18;19 2026-10-13 pgcolumnar.column_extent returns a row with no complete extent -column_extent column_extent fifty committing writers leave a bounded number of extent rows 15;16;17;18;19 2026-10-13 a recompute that leaves the rows it folded;a writer that finds no complete extent does not recompute one;no merge however many extent rows a column has +column_extent column_extent before DROP the table has extent rows to remove 15;16;17;18;19 2026-10-14 no extent row is ever written (PgColumnarExtentPreCommit returns at once) +column_extent column_extent before expire the extent covers the table 15;16;17;18;19 2026-10-14 no extent row is ever written (PgColumnarExtentPreCommit returns at once) +column_extent column_extent compact_rewrite rewrites the groups the deletes thinned 15;16;17;18;19 2026-10-14 compact_rewrite returning 0 before rewriting anything +column_extent column_extent expire retires the old row groups with the extent in place 15;16;17;18;19 2026-10-14 expire returning 0 whatever it retired +column_extent column_extent fifty committing writers leave a bounded number of extent rows 15;16;17;18;19 2026-10-14 a recompute that leaves the rows it folded;a writer that finds no complete extent does not recompute one;no extent row is ever written (PgColumnarExtentPreCommit returns at once);no merge however many extent rows a column has column_extent column_extent nor is a table's extent through the function, without SELECT on the table 15;16;17;18;19 2026-10-13 pgcolumnar.column_extent without its SELECT check -column_extent column_extent planning a bucketed GROUP BY scans zone_map not at all when the extent is complete 15;16;17;18;19 2026-10-13 a writer that finds no complete extent does not recompute one;the planner's time range ignores the extent -column_extent column_extent premise: compact_rewrite rewrites the groups the deletes thinned 15;16;17;18;19 never - -column_extent column_extent premise: expire retires the old row groups with the extent in place 15;16;17;18;19 never - -column_extent column_extent premise: parallel_copy's loaders, flushing into one table at once, all commit 15;16;17;18;19 never - +column_extent column_extent parallel_copy's loaders, flushing into one table at once, all commit 15;16;17;18;19 never - +column_extent column_extent planning a bucketed GROUP BY scans zone_map not at all when the extent is complete 15;16;17;18;19 2026-10-14 a writer that finds no complete extent does not recompute one;no extent row is ever written (PgColumnarExtentPreCommit returns at once);the planner's time range ignores the extent column_extent column_extent premise: the extent function exists 15;16;17;18;19 never - column_extent column_extent premise: the transaction's plans gave two estimates 15;16;17;18;19 never - column_extent column_extent premise: the typed fixture spans several row groups 15;16;17;18;19 never - column_extent column_extent the extent catalog is not readable by an ordinary role (it holds column values) 15;16;17;18;19 2026-10-13 the column_extent catalog granted to PUBLIC -column_extent column_extent the extent of ty.d is the data's min and max, in the type's order 15;16;17;18;19 2026-10-13 a writer that finds no complete extent does not recompute one -column_extent column_extent the extent of ty.i is the data's min and max, in the type's order 15;16;17;18;19 2026-10-13 a writer that finds no complete extent does not recompute one -column_extent column_extent the extent of ty.n is the data's min and max, in the type's order 15;16;17;18;19 2026-10-13 a writer that finds no complete extent does not recompute one;the extent folded by comparing Datums as words, not with the type's comparison -column_extent column_extent the extent of ty.s is the data's min and max, in the type's order 15;16;17;18;19 2026-10-13 a writer that finds no complete extent does not recompute one -column_extent column_extent the extent of ty.ts is the data's min and max, in the type's order 15;16;17;18;19 2026-10-13 a writer that finds no complete extent does not recompute one -column_extent column_extent while the column that was there from the start still has one 15;16;17;18;19 2026-10-13 a writer that finds no complete extent does not recompute one +column_extent column_extent the extent of ty.d is the data's min and max, in the type's order 15;16;17;18;19 2026-10-14 a writer that finds no complete extent does not recompute one;no extent row is ever written (PgColumnarExtentPreCommit returns at once) +column_extent column_extent the extent of ty.i is the data's min and max, in the type's order 15;16;17;18;19 2026-10-14 a writer that finds no complete extent does not recompute one;no extent row is ever written (PgColumnarExtentPreCommit returns at once) +column_extent column_extent the extent of ty.n is the data's min and max, in the type's order 15;16;17;18;19 2026-10-14 a writer that finds no complete extent does not recompute one;no extent row is ever written (PgColumnarExtentPreCommit returns at once);the extent folded by comparing Datums as words, not with the type's comparison +column_extent column_extent the extent of ty.s is the data's min and max, in the type's order 15;16;17;18;19 2026-10-14 a writer that finds no complete extent does not recompute one;no extent row is ever written (PgColumnarExtentPreCommit returns at once) +column_extent column_extent the extent of ty.ts is the data's min and max, in the type's order 15;16;17;18;19 2026-10-14 a writer that finds no complete extent does not recompute one;no extent row is ever written (PgColumnarExtentPreCommit returns at once) +column_extent column_extent while the column that was there from the start still has one 15;16;17;18;19 2026-10-14 a writer that finds no complete extent does not recompute one;no extent row is ever written (PgColumnarExtentPreCommit returns at once) column_extent column_extent without the extent rows the planner falls back to one zone_map scan 15;16;17;18;19 2026-10-13 the planner's zone-map fallback removed: with no complete extent it reads nothing and bounds nothing differential differential agg avg 15;16;17;18;19 never - differential differential agg count 15;16;17;18;19 never - @@ -2181,7 +2185,7 @@ tier_partition tier_partition a query on the other range scans only the local pa tier_partition tier_partition a query on the tiered range scans only the foreign partition 15;16;17;18;19 never - tier_partition tier_partition a retry over the failed attempt's file moves the partition, exactly once 15;16;17;18;19 2026-10-13 tier_partition naming the foreign table with a suffix;tier_partition refusing every existing path (the first version's rule);tier_partition returning 0 rows moved tier_partition tier_partition a rollback after the whole call leaves the rows local, exactly once 15;16;17;18;19 never - -tier_partition tier_partition a server of another wrapper is refused 15;16;17;18;19 2026-10-13 tier_partition without the wrapper check +tier_partition tier_partition a server of another wrapper is refused 15;16;17;18;19 2026-10-14 tier_partition without its wrong-wrapper branch, so the iceberg wrapper refuses only after the export;tier_partition without the wrapper check tier_partition tier_partition a server that does not exist is refused before anything moves 15;16;17;18;19 2026-10-13 tier_partition without its missing-server branch, so core refuses only after the export tier_partition tier_partition a stored generated column moves and reads back the same 15;16;17;18;19 2026-10-13 tier_partition naming the foreign table with a suffix;tier_partition returning 0 rows moved;tier_partition's foreign table without generation expressions;tier_partition's foreign table without generation expressions (PG18, where the virtual arm runs) tier_partition tier_partition a table that is not a partition is refused 15;16;17;18;19 2026-10-13 tier_partition without the is-a-partition check diff --git a/test/check_ledger_budget.txt b/test/check_ledger_budget.txt index b21ca9c6f..01290e6c6 100644 --- a/test/check_ledger_budget.txt +++ b/test/check_ledger_budget.txt @@ -1783,4 +1783,24 @@ suites_not_covered 246 # never 1803 + 0 = 1803 # dated 524 + 9 = 533 # 1803 + 533 == 2336 -checks_never_observed_red 1803 +# +# #1339 audit, my assigned files, batch one: collation_change, tier_partition, +# column_extent (OffgridwithJD): 1803 -> 1801. Four new arms, each dated: +# - before the change the column's extent is the C collation's bound +# (column_extent() returning no row); +# - before expire the extent covers the table, before DROP the table has extent +# rows to remove (no extent row ever written); +# - and with SELECT on the table the same role reads its extent (column_extent() +# refused to every non-superuser). +# Three column_extent checks named `premise:` test product code and lose the +# prefix, their rows renamed with their history (#1236). Two are now dated: +# "expire retires ..." (expire returning 0), "compact_rewrite rewrites ..." +# (compact_rewrite returning 0). "parallel_copy's loaders ... all commit" stays +# never. Five-major runs: collation_change 12/12, column_extent 39/39, +# tier_partition 71/71 on 18-19 and 70 + 1 named SKIP on 15-17. +# +# ledger rows 2336 + 4 = 2340 +# never 1803 - 2 = 1801 +# dated 533 + 4 + 2 = 539 +# 1801 + 539 == 2340 +checks_never_observed_red 1801