diff --git a/test/check_ledger.tsv b/test/check_ledger.tsv index 227404e32..3fb2ec680 100644 --- a/test/check_ledger.tsv +++ b/test/check_ledger.tsv @@ -2241,6 +2241,7 @@ latest_reading latest_reading premise: the document's index exists 15;16;17;18;1 latest_reading latest_reading premise: the document's three recipe blocks were found 15;16;17;18;19 never - latest_reading latest_reading premise: the indexed LATERAL form read the table at all 15;16;17;18;19 never - latest_reading latest_reading premise: the table holds every row 15;16;17;18;19 never - +latest_reading latest_reading the GROUP BY form reads the table once 15;16;17;18;19 2026-10-16 the document's GROUP BY recipe as a per-device subquery over devices, which returns the same rows and reads the table once per device latest_reading latest_reading the GROUP BY form returns what DISTINCT ON returns 15;16;17;18;19 never - latest_reading latest_reading the LATERAL form returns what DISTINCT ON returns 15;16;17;18;19 2026-10-12 the document's LATERAL recipe orders by ts ascending, so it returns each device's FIRST reading latest_reading latest_reading with the btree the LATERAL form reads under a tenth of the table 15;16;17;18;19 never - diff --git a/test/check_ledger_budget.txt b/test/check_ledger_budget.txt index 42ac8aaa6..9c79c6274 100644 --- a/test/check_ledger_budget.txt +++ b/test/check_ledger_budget.txt @@ -3534,4 +3534,15 @@ suites_not_covered 190 # never 3058 - 3 = 3055 # dated 1330 + 11 = 1341 # 3055 + 1341 == 4396 +# +# #1339, latest_reading's GROUP BY form is held to reading the table once (jdatcmd): +# 3055 -> 3055. The document says the form reads the table once, and the arms compared +# only its rows, so a per-device subquery returning the same rows passed. The new arm +# arrives dated by exactly that mutation, red on each of 15-19 in both twins while the +# rows arm stayed green. From five-major runs, 9 checks green on each of 15-19. +# +# ledger rows 4396 + 1 = 4397 +# never 3055 + 0 = 3055 +# dated 1341 + 1 = 1342 +# 3055 + 1342 == 4397 checks_never_observed_red 3055 diff --git a/test/latest_reading.sh b/test/latest_reading.sh index 035a0f241..a97d58912 100755 --- a/test/latest_reading.sh +++ b/test/latest_reading.sh @@ -80,6 +80,13 @@ check_num "without the btree the LATERAL form reads the table once per device" \ check "the GROUP BY form returns what DISTINCT ON returns" \ "$(q "$GROUP_SQL" | md5sum | cut -c1-12)" "$ORACLE" +# The document says this form reads the table once (#1339): rows alone cannot tell it +# from a per-device subquery, which returns the same rows and reads the table once +# per device. Reading nothing is refused, as for the LATERAL form below. +grp_blocks="$(blocks "$GROUP_SQL")" +echo "-- table $pages pages; the GROUP BY form read $grp_blocks blocks" +check_num "the GROUP BY form reads the table once" \ + "$( [ -n "$grp_blocks" ] && [ "$grp_blocks" -ge 1 ] && at_least $((pages + 1 - grp_blocks)) 1 || echo "read ${grp_blocks:-nothing}" )" "1" q "$INDEX_SQL" >/dev/null check_num "premise: the document's index exists" \ diff --git a/test/pytest/TESTS.md b/test/pytest/TESTS.md index fc76e2ba7..2253c4cd2 100644 --- a/test/pytest/TESTS.md +++ b/test/pytest/TESTS.md @@ -6600,7 +6600,7 @@ Removal proof: the document's `LATERAL` edited to `ORDER BY ts` (ascending) retu | test | what it holds | | --- | --- | -| `test_the_latest_reading_recipe_does_what_the_document_says` | the document's three blocks are found; the table holds its rows; without the btree the `LATERAL` form reads the table about once per device; the `GROUP BY` form and, with the document's index, the `LATERAL` form return the rows `DISTINCT ON` returns; the indexed `LATERAL` reads at least one block and under a tenth of the table | +| `test_the_latest_reading_recipe_does_what_the_document_says` | the document's three blocks are found; the table holds its rows; without the btree the `LATERAL` form reads the table about once per device; the `GROUP BY` form and, with the document's index, the `LATERAL` form return the rows `DISTINCT ON` returns; the `GROUP BY` form reads at least one block and no more than the table, as the document says (#1339); the indexed `LATERAL` reads at least one block and under a tenth of the table | ## 88. test_storage_row_repair.py: the alpha5 release notes' repair procedure works as written diff --git a/test/pytest/test_latest_reading.py b/test/pytest/test_latest_reading.py index 582d529bf..9b072a783 100644 --- a/test/pytest/test_latest_reading.py +++ b/test/pytest/test_latest_reading.py @@ -6,10 +6,10 @@ blocks in 5.6 s; a btree on (device, ts) plus LATERAL read 1,013 blocks in 45 ms; the same LATERAL without the btree read 8.7 million blocks in 12.6 minutes. -Asserted here: each documented form returns the rows DISTINCT ON returns; with -the btree the LATERAL form reads under a tenth of the table, and at least one -block (a query that reads nothing would otherwise pass); without it, it reads the -table about once per device. +Asserted here: each documented form returns the rows DISTINCT ON returns; the +GROUP BY form reads the table at most once; with the btree the LATERAL form reads +under a tenth of the table, and at least one block (a query that reads nothing +would otherwise pass); without it, it reads the table about once per device. ON A PRIVATE DATABASE (`pgc_own_db`): the document names its tables, `readings` and `devices`, so they cannot carry a per-test prefix. Independent of @@ -95,6 +95,13 @@ def test_the_latest_reading_recipe_does_what_the_document_says(pgc_own_db, expec expect.text(str(_rows(conn, group_sql)), str(oracle), "the GROUP BY form returns what DISTINCT ON returns") + # The document says this form reads the table once (#1339). Rows alone cannot tell + # it from a per-device subquery, which returns the same rows and reads the table + # once per device. Reading nothing also reads under the table, so a zero is refused. + grp = _blocks(conn, group_sql) + print(f"-- table {pages} pages; the GROUP BY form read {grp} blocks") + expect.at_least(pages + 1 - grp if grp else 0, 1, + "the GROUP BY form reads the table once") with conn.cursor() as cur: cur.execute(index_sql)