From a6df2e9c63b99e63647deda712101c31488c0761 Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Wed, 4 Nov 2026 12:37:54 -0500 Subject: [PATCH 1/4] test: on-file floats round-trip exactly, ahead of the fix serde_json's default float parser is not correctly rounded, so 123456789.12345679 lands one ULP off and both tests fail. --- packages/rust/tests/on_file_float.rs | 40 ++++++++++++++++++++++++ packages/rust/tests/on_file_float_e2e.rs | 37 ++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 packages/rust/tests/on_file_float.rs create mode 100644 packages/rust/tests/on_file_float_e2e.rs diff --git a/packages/rust/tests/on_file_float.rs b/packages/rust/tests/on_file_float.rs new file mode 100644 index 00000000..635e6160 --- /dev/null +++ b/packages/rust/tests/on_file_float.rs @@ -0,0 +1,40 @@ +//! A float an `on-file` hook prints is stored as the REAL a correctly +//! rounded JSON parser reads. + +use std::fs; + +use dirsql::{DirSQL, Value}; +use tempfile::TempDir; + +#[test] +fn a_real_column_keeps_the_exact_double() { + let doubles = [ + "123456789.12345679", + "0.30000000000000004", + "1.7976931348623157e308", + ]; + let root = TempDir::new().unwrap(); + fs::write( + root.path().join(".dirsql.toml"), + "[[table]]\nname = \"t\"\nddl = \"CREATE TABLE t (v REAL)\"\nglob = \"*.ndjson\"\non-file = \"cat\"\n", + ) + .unwrap(); + let lines: String = doubles.iter().map(|d| format!("{{\"v\":{d}}}\n")).collect(); + fs::write(root.path().join("a.ndjson"), lines).unwrap(); + let db = DirSQL::builder() + .root(root.path()) + .config(root.path().join(".dirsql.toml")) + .build() + .unwrap(); + let stored: Vec = db + .query("SELECT v FROM t ORDER BY rowid") + .unwrap() + .into_iter() + .map(|row| row["v"].clone()) + .collect(); + let expected: Vec = doubles + .iter() + .map(|d| Value::Real(d.parse().unwrap())) + .collect(); + assert_eq!(stored, expected); +} diff --git a/packages/rust/tests/on_file_float_e2e.rs b/packages/rust/tests/on_file_float_e2e.rs new file mode 100644 index 00000000..e0f5081b --- /dev/null +++ b/packages/rust/tests/on_file_float_e2e.rs @@ -0,0 +1,37 @@ +//! End-to-end: a float an `on-file` hook prints reaches SQLite as the same +//! REAL a correctly rounded JSON parser reads, through the real `dirsql` +//! binary. Nothing is mocked. + +#![cfg(feature = "cli")] + +use assert_cmd::prelude::*; +use tempfile::TempDir; + +#[test] +fn an_on_file_float_round_trips_exactly() { + let root = TempDir::new().unwrap(); + std::fs::write(root.path().join("a.ndjson"), "{\"v\":123456789.12345679}\n").unwrap(); + let out = std::process::Command::cargo_bin("dirsql") + .expect("binary must exist") + .args([ + "query", + "SELECT v, v = 123456789.12345679 AS eq FROM './a.ndjson'", + "--on-file", + "cat", + "--format", + "json", + ]) + .env("DIRSQL_PROGRESS", "never") + .current_dir(root.path()) + .output() + .expect("spawning `dirsql` failed"); + assert!( + out.status.success(), + "expected success, stderr: {}", + String::from_utf8_lossy(&out.stderr) + ); + assert_eq!( + String::from_utf8(out.stdout).unwrap(), + "[{\"v\":123456789.12345679,\"eq\":1}]\n" + ); +} From 4696a76d81c3080df86c416ef418d3d9b2dc0062 Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Wed, 4 Nov 2026 12:48:01 -0500 Subject: [PATCH 2/4] fix: parse JSON floats exactly with serde_json float_roundtrip --- Cargo.toml | 2 +- .../2026-11-04-exact-json-floats.md | 1 + .../2026-11-04-exact-json-floats.md | 21 +++++++++++++++++++ .../2026-11-04-exact-json-floats.md | 1 + .../2026-11-04-exact-json-floats.md | 21 +++++++++++++++++++ .../2026-11-04-exact-json-floats.md | 1 + .../2026-11-04-exact-json-floats.md | 21 +++++++++++++++++++ 7 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 packages/python/changelog.d/2026-11-04-exact-json-floats.md create mode 100644 packages/python/migrations.d/2026-11-04-exact-json-floats.md create mode 100644 packages/rust/changelog.d/2026-11-04-exact-json-floats.md create mode 100644 packages/rust/migrations.d/2026-11-04-exact-json-floats.md create mode 100644 packages/ts/changelog.d/2026-11-04-exact-json-floats.md create mode 100644 packages/ts/migrations.d/2026-11-04-exact-json-floats.md diff --git a/Cargo.toml b/Cargo.toml index 85be7191..bf0e783a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ dirsql = { path = "packages/rust" } serde = { version = "1", features = ["derive"] } # `preserve_order`: a serialized row must keep the projection order the SELECT # list asked for, which the default BTreeMap-backed object discards. -serde_json = { version = "1", features = ["preserve_order"] } +serde_json = { version = "1", features = ["preserve_order", "float_roundtrip"] } regex = "1" thiserror = "2" tokio = { version = "1", features = ["rt", "sync"] } diff --git a/packages/python/changelog.d/2026-11-04-exact-json-floats.md b/packages/python/changelog.d/2026-11-04-exact-json-floats.md new file mode 100644 index 00000000..45059b89 --- /dev/null +++ b/packages/python/changelog.d/2026-11-04-exact-json-floats.md @@ -0,0 +1 @@ +**Fixed** JSON numbers from `on-file` hooks and worker functions now parse to the exact double: `123456789.12345679` was stored one ULP off as `123456789.1234568`. diff --git a/packages/python/migrations.d/2026-11-04-exact-json-floats.md b/packages/python/migrations.d/2026-11-04-exact-json-floats.md new file mode 100644 index 00000000..fdf4eabe --- /dev/null +++ b/packages/python/migrations.d/2026-11-04-exact-json-floats.md @@ -0,0 +1,21 @@ +### Exact JSON float parsing + +#### Summary + +A JSON float an `on-file` hook or worker function prints is stored as the correctly rounded REAL, where some were one ULP off before. No API or configuration changes are required. + +#### Required changes + +_None._ + +#### Deprecations removed + +_None._ + +#### Behavior changes without code changes + +A REAL column fed from JSON can hold a value one ULP different from before the upgrade: the correct one. + +#### Verification + +In an empty directory, write `{"v":123456789.12345679}` to `a.ndjson` and run `dirsql query "SELECT v = 123456789.12345679 AS eq FROM './a.ndjson'" --on-file cat --format json`; the output is `[{"eq":1}]`. diff --git a/packages/rust/changelog.d/2026-11-04-exact-json-floats.md b/packages/rust/changelog.d/2026-11-04-exact-json-floats.md new file mode 100644 index 00000000..45059b89 --- /dev/null +++ b/packages/rust/changelog.d/2026-11-04-exact-json-floats.md @@ -0,0 +1 @@ +**Fixed** JSON numbers from `on-file` hooks and worker functions now parse to the exact double: `123456789.12345679` was stored one ULP off as `123456789.1234568`. diff --git a/packages/rust/migrations.d/2026-11-04-exact-json-floats.md b/packages/rust/migrations.d/2026-11-04-exact-json-floats.md new file mode 100644 index 00000000..fdf4eabe --- /dev/null +++ b/packages/rust/migrations.d/2026-11-04-exact-json-floats.md @@ -0,0 +1,21 @@ +### Exact JSON float parsing + +#### Summary + +A JSON float an `on-file` hook or worker function prints is stored as the correctly rounded REAL, where some were one ULP off before. No API or configuration changes are required. + +#### Required changes + +_None._ + +#### Deprecations removed + +_None._ + +#### Behavior changes without code changes + +A REAL column fed from JSON can hold a value one ULP different from before the upgrade: the correct one. + +#### Verification + +In an empty directory, write `{"v":123456789.12345679}` to `a.ndjson` and run `dirsql query "SELECT v = 123456789.12345679 AS eq FROM './a.ndjson'" --on-file cat --format json`; the output is `[{"eq":1}]`. diff --git a/packages/ts/changelog.d/2026-11-04-exact-json-floats.md b/packages/ts/changelog.d/2026-11-04-exact-json-floats.md new file mode 100644 index 00000000..45059b89 --- /dev/null +++ b/packages/ts/changelog.d/2026-11-04-exact-json-floats.md @@ -0,0 +1 @@ +**Fixed** JSON numbers from `on-file` hooks and worker functions now parse to the exact double: `123456789.12345679` was stored one ULP off as `123456789.1234568`. diff --git a/packages/ts/migrations.d/2026-11-04-exact-json-floats.md b/packages/ts/migrations.d/2026-11-04-exact-json-floats.md new file mode 100644 index 00000000..fdf4eabe --- /dev/null +++ b/packages/ts/migrations.d/2026-11-04-exact-json-floats.md @@ -0,0 +1,21 @@ +### Exact JSON float parsing + +#### Summary + +A JSON float an `on-file` hook or worker function prints is stored as the correctly rounded REAL, where some were one ULP off before. No API or configuration changes are required. + +#### Required changes + +_None._ + +#### Deprecations removed + +_None._ + +#### Behavior changes without code changes + +A REAL column fed from JSON can hold a value one ULP different from before the upgrade: the correct one. + +#### Verification + +In an empty directory, write `{"v":123456789.12345679}` to `a.ndjson` and run `dirsql query "SELECT v = 123456789.12345679 AS eq FROM './a.ndjson'" --on-file cat --format json`; the output is `[{"eq":1}]`. From 0340207c463df4173a0e59f0993bde832ee2c50e Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Wed, 4 Nov 2026 12:53:14 -0500 Subject: [PATCH 3/4] e2e attestation for bot/1586-float-roundtrip-1104 --- .../e2e-attestations/bot-1586-float-roundtrip-1104.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 packages/python/e2e-attestations/bot-1586-float-roundtrip-1104.json diff --git a/packages/python/e2e-attestations/bot-1586-float-roundtrip-1104.json b/packages/python/e2e-attestations/bot-1586-float-roundtrip-1104.json new file mode 100644 index 00000000..cd45a869 --- /dev/null +++ b/packages/python/e2e-attestations/bot-1586-float-roundtrip-1104.json @@ -0,0 +1,7 @@ +{ + "command": "uv run python -m pytest tests/e2e/on_file_query_test.py tests/e2e/jsonl_parse_speed_test.py tests/e2e/use_case_transcripts_test.py tests/e2e/query_contract_test.py -x -q", + "ran_at": 1793814794, + "exit_code": 0, + "commit": "4696a76d81c3080df86c416ef418d3d9b2dc0062", + "branch": "bot/1586-float-roundtrip-1104" +} From 9041083ae21793db7c05f72d99bf22ad18c64d80 Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Wed, 4 Nov 2026 12:54:48 -0500 Subject: [PATCH 4/4] e2e attestation for bot/1586-float-roundtrip-1104 --- .../ts/e2e-attestations/bot-1586-float-roundtrip-1104.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 packages/ts/e2e-attestations/bot-1586-float-roundtrip-1104.json diff --git a/packages/ts/e2e-attestations/bot-1586-float-roundtrip-1104.json b/packages/ts/e2e-attestations/bot-1586-float-roundtrip-1104.json new file mode 100644 index 00000000..dc79d184 --- /dev/null +++ b/packages/ts/e2e-attestations/bot-1586-float-roundtrip-1104.json @@ -0,0 +1,7 @@ +{ + "command": "pnpm exec vitest run --dir tests/e2e query-contract query-params", + "ran_at": 1793814888, + "exit_code": 0, + "commit": "0340207c463df4173a0e59f0993bde832ee2c50e", + "branch": "bot/1586-float-roundtrip-1104" +}