Skip to content

Commit bf683ee

Browse files
singhpratechclaude
andcommitted
docs: restore the two macOS PASS cells the branch dropped (41 of 46); bench harness reads and writes UTF-8 on Windows
* docs/COMPATIBILITY.md: tidb and percona macOS cells back to PASS -- their results had been pasted onto the SPDX header line instead of their rows, and the Windows branch removed that line; the macOS column is 41 pass, 5 driver/server unavailable, as before. * README.md, bench/README.md, docs/ROADMAP.md: macOS 41 (not 45 or 37); bench/README's macOS row describes the full campaign. * bench/matrix_bench.py: explicit encoding="utf-8" on the four read_text/ write_text sites (Windows wrote the table in cp1252 and choked on × the next run; the second Windows campaign's workaround was PYTHONUTF8=1). * docs/ROADMAP.md: the Ignite narrow-text route is done; two Windows items to verify on the next Windows session (manifest key under MSVC, the Go test's open SQLite handle). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QhuLMRciVAQdqKEpyr7Wbo
1 parent 78d5588 commit bf683ee

5 files changed

Lines changed: 13 additions & 10 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ numbers with these in mind:
9090
| OS | Linux Mint 22.3, kernel 7.0 | macOS 26.5.2 | Windows 11 Home 23H2 (build 22631) |
9191
| Driver manager | unixODBC 2.3.12 | unixODBC 2.3.12 from source (iODBC from source for iODBC-only vendor drivers) | the OS's own (odbc32), ANSI code page 1252 |
9292
| Compiler | gcc 13.3 | Apple clang 21 | MSVC 19.44 (VS 2022 Build Tools) |
93-
| Databases | 46 of 46, Docker containers on the same machine (the full fleet often idling alongside) | 46 of 46 results: 45 pass, servers in Docker Desktop, some amd64 images under emulation | 46 of 46 results: 45 pass, servers in Docker Desktop on WSL2 (20 GB VM cap) |
93+
| Databases | 46 of 46, Docker containers on the same machine (the full fleet often idling alongside) | 46 of 46 results: 41 pass, 5 without an obtainable driver or runnable server; servers in Docker Desktop, some amd64 images under emulation | 46 of 46 results: 45 pass, servers in Docker Desktop on WSL2 (20 GB VM cap) |
9494
| Load during runs | never idle: ~23 GiB of other work resident, 1-minute load typically 2–5, CPU governor `powersave` after a reboot | 1-minute load 2.4–10.5, recorded per entry | up to 8 benchmark runs and ~30 idle containers at once; single samples |
9595
| What the build lacks | — | — | prefetch pipeline and parallel ingest (pthreads, compiled out on `_WIN32`) |
9696

‎bench/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ says nothing about Windows.
1010
|---|---|---|
1111
| Linux (Ubuntu 24.04, unixODBC 2.3.12) | [`BENCHMARKS.md`](BENCHMARKS.md) — PostgreSQL vs native, the write path, partitioned reads; [`MATRIX_BENCHMARKS.md`](MATRIX_BENCHMARKS.md) — 46 databases; [`LANGUAGE_BENCHMARKS.md`](LANGUAGE_BENCHMARKS.md) — five languages × 46; [`RUST_BENCHMARKS.md`](RUST_BENCHMARKS.md) | **measured** |
1212
| Windows 11 (x64, the OS's own driver manager) | [`BENCHMARKS-windows.md`](BENCHMARKS-windows.md) — all 46 entries of the matrix under Docker Desktop on WSL2 on a 14-core / 32 GB machine at `a4d6ce5` (Python compat + `matrix_bench.py` per entry), preceded by the first-build campaign on a 4-core / 8 GB laptop; [`LANGUAGE_BENCHMARKS-windows.md`](LANGUAGE_BENCHMARKS-windows.md) — five languages × 46 databases on the 14-core machine (220 of 230 language rows), preceded by the first machine's 142 cells | **measured, two machines, single samples: 46 of 46 results, 45 pass, 1 fail on vendor-driver Unicode handling** (first build ever on 2026-08-24, ten defects found and fixed the same day; the full re-measure on 2026-08-25 with MySQL Connector/ODBC 26.7.1 retired the "astral `???`" class; no prefetch and no ingest fan-out in the Windows build, so not comparable with Linux) |
13-
| macOS (Apple M4 Max, arm64, unixODBC 2.3.12) | [`BENCHMARKS-macos.md`](BENCHMARKS-macos.md) — SQLite, PostgreSQL 15, SQL Server 2022 | **measured, one machine** (PostgreSQL vs native there: 0.60x fetch, 0.50x ingest -- indicative, not the reference) |
13+
| macOS (Apple M4 Max, arm64, unixODBC 2.3.12 from source; iODBC from source for the vendor drivers that only ship iODBC builds) | [`BENCHMARKS-macos.md`](BENCHMARKS-macos.md) — the 46-entry matrix in batches, servers in Docker Desktop, some amd64 images under emulation; [`LANGUAGE_BENCHMARKS-macos.md`](LANGUAGE_BENCHMARKS-macos.md) — five languages on every macOS-passing database (183 cells) | **measured, one machine: 46 of 46 results, 41 pass, 5 without an obtainable driver or runnable server** (PostgreSQL vs native there: 0.60x fetch, 0.50x ingest -- indicative, not the reference) |
1414

1515
The two unmeasured files carry the exact commands to produce their tables, so
1616
that the first run on each OS is a matter of pasting output. A file that says

‎bench/matrix_bench.py‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -346,13 +346,13 @@ def fmt_rate(v):
346346
sys.exit(0)
347347

348348
cache = HERE / ".matrix_bench.json"
349-
results = json.loads(cache.read_text()) if cache.exists() else {}
349+
results = json.loads(cache.read_text(encoding="utf-8")) if cache.exists() else {}
350350
for name in ([] if args.render else (args.dbs or list(m.DBS))):
351351
r = attempt(bench, name, m.DBS[name])
352352
if r is None:
353353
continue
354354
results[name] = r
355-
cache.write_text(json.dumps(results, indent=1))
355+
cache.write_text(json.dumps(results, indent=1), encoding="utf-8")
356356
if "error" in r:
357357
print("%-11s ERROR %s" % (name, r["error"]))
358358
continue
@@ -373,7 +373,9 @@ def fmt_rate(v):
373373
previous_rows, previous_notes, previous_tail = {}, {}, []
374374
if out.exists():
375375
in_table = False
376-
for line in out.read_text().splitlines():
376+
# The table holds "×" and "—"; without an explicit encoding Windows reads and
377+
# writes it in the ANSI code page and the next run dies decoding its own file.
378+
for line in out.read_text(encoding="utf-8").splitlines():
377379
if line.startswith("| Database"):
378380
in_table = True
379381
elif line.startswith("| ") and in_table and not line.startswith("|---"):
@@ -431,5 +433,5 @@ def fmt_rate(v):
431433
lines += ["", "Failures:", ""] + notes
432434
if previous_tail:
433435
lines += [""] + previous_tail
434-
out.write_text("\n".join(lines) + "\n")
436+
out.write_text("\n".join(lines) + "\n", encoding="utf-8")
435437
print("wrote", out)

‎docs/COMPATIBILITY.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,10 @@ the machine descriptions: `bench/BENCHMARKS-macos.md`, `bench/BENCHMARKS-windows
177177
| mssql | PASS | PASS (SQL Server 2022) | PASS (SQL Server 2022 16.00.4265, mcr.microsoft.com/mssql/server:2022 container; msodbcsql 18.6.2.1) |
178178
| azuresqledge | PASS | PASS (SQL Server 15.00.2000, arm64 image, msodbcsql 18.6.2.1 arm64) | PASS (Azure SQL Edge, SQL Server 16.00.5100; msodbcsql 18.6.2.1) |
179179
| mysql | PASS | PASS (MySQL 8.4.11 arm64, MariaDB Connector/ODBC 3.2.9) — after the maodbc ≥ 3.2 quirk (`187dfac`): at 24dab36 the connector's array path misreported the row count | PASS (MySQL 8.4.11, mysql:8 container; MySQL Connector/ODBC 26.7.1) |
180-
| tidb | PASS | pending | PASS (TiDB v7.5.1, MySQL wire 8.0.11; MySQL Connector/ODBC 26.7.1 with `NO_SSPS=1` from `{no_ssps}` — the 8.4.0-era note that no newer connector is published for Windows is obsolete: dev.mysql.com offers 26.7.1 winx64) |
180+
| tidb | PASS | PASS (TiDB, MySQL wire 8.0.11) | PASS (TiDB v7.5.1, MySQL wire 8.0.11; MySQL Connector/ODBC 26.7.1 with `NO_SSPS=1` from `{no_ssps}` — the 8.4.0-era note that no newer connector is published for Windows is obsolete: dev.mysql.com offers 26.7.1 winx64) |
181181
| dolt | PASS | PASS (Dolt, MySQL wire 8.0.33) | PASS (Dolt, MySQL wire 8.0.33; MySQL Connector/ODBC 26.7.1 + `NO_SSPS=1`) |
182182
| databend | PASS | PASS with MySQL Connector/ODBC 26.7.1 (Oracle's macOS arm64 binary, built for iODBC) through a bridge built against iODBC 3.52.16 — `MySQL (via ODBC) 8.0.90-v1.2.881`; **FAIL through MariaDB Connector/ODBC 3.2.9** at its connect-time probe `SELECT 1 FROM DUAL WHERE @@sql_mode LIKE '%ansi_quotes%'` (`Unknown table "default"."default".DUAL`), identical through pyodbc | PASS (`MySQL (via ODBC) 8.0.90-v1.2.881`; MySQL Connector/ODBC 26.7.1 + `NO_SSPS=1`, `ADBC_BENCH_AUTOCOMMIT=1` for the harness rows) — **with MySQL Connector/ODBC 26.7.1 the astral check passes**; through 8.4.0 (the earlier Windows measurement) the same entry FAILED at that check only: `héllo 🚀` stored byte-exact, read back as `héllo ???` on every read path including pyodbc, because 8.4.0 substitutes `?` for a non-BMP character before either C type sees it (SQL_C_CHAR and SQL_C_WCHAR both return `3f 3f 3f`; `CHARSET=` makes no difference) |
183-
| percona | PASS | pending | PASS (Percona Server 8.4.11-11; MySQL Connector/ODBC 26.7.1, default connection string) |
183+
| percona | PASS | PASS (Percona Server, MySQL wire 8.4.11) | PASS (Percona Server 8.4.11-11; MySQL Connector/ODBC 26.7.1, default connection string) |
184184
| matrixone | PASS | PASS (MatrixOne, MySQL wire 8.0.30) | PASS (MatrixOne v4.2.0, MySQL wire 8.0.30; MySQL Connector/ODBC 26.7.1 + `NO_SSPS=1`) — **with MySQL Connector/ODBC 26.7.1 the astral check passes**; through 8.4.0 (the earlier Windows measurement) the same entry FAILED at that check only: `héllo 🚀` stored byte-exact, read back as `héllo ???` on every read path including pyodbc, because 8.4.0 substitutes `?` for a non-BMP character before either C type sees it (SQL_C_CHAR and SQL_C_WCHAR both return `3f 3f 3f`; `CHARSET=` makes no difference) |
185185
| doris | PASS | PASS with MySQL Connector/ODBC 26.7.1 (Oracle's macOS arm64 binary, built for iODBC) through a bridge built against iODBC 3.52.16 — `MySQL (via ODBC) 5.7.99`, 300/2,000 rows as on Linux; **FAIL through MariaDB Connector/ODBC 3.2.9**: the server NPEs on its server-side prepared INSERT and rejects the `_binary '<raw bytes>'` literal its `PREPONCLIENT=1` path inlines | PASS (Apache Doris, MySQL wire 5.7.99, FE + BE in one container, ~6 min to `Alive`; MySQL Connector/ODBC 26.7.1 + `NO_SSPS=1`) — **with MySQL Connector/ODBC 26.7.1 the astral check passes**; through 8.4.0 (the earlier Windows measurement) the same entry FAILED at that check only: `héllo 🚀` stored byte-exact, read back as `héllo ???` on every read path including pyodbc, because 8.4.0 substitutes `?` for a non-BMP character before either C type sees it (SQL_C_CHAR and SQL_C_WCHAR both return `3f 3f 3f`; `CHARSET=` makes no difference) — restarting a stopped Doris container fails (`boot failed!`), recreate it |
186186
| oceanbase | PASS | PASS (OceanBase CE, MySQL wire 5.7.25) — `MODE=SLIM`, boots in 40 s, 4.3 GiB peak | PASS (OceanBase CE, MySQL wire 5.7.25, `MODE=SLIM`, boots in ~60 s under a 6 GB cap; MySQL Connector/ODBC 26.7.1, user `root@test`) — **needs `NO_SSPS=1` on Windows**: the entry's connection string carries no `{no_ssps}`, and without it every bound parameter fails `No data supplied for parameters in prepared statement` (pyodbc identical); run with an `OCEANBASE_CONN` override that adds it — a one-token patch to the entry |

‎docs/ROADMAP.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ ODBC is the first bridge; the name leaves room for the others.
1515
| Plug-and-play install: `install.sh`, driver manifest, `driver="odbc"` by name (Linux, macOS) | done |
1616
| macOS verified on a real machine: SQLite, PostgreSQL 15, SQL Server 2022 (`bench/BENCHMARKS-macos.md`) | done |
1717
| Windows: first build 2026-08-24 (ten defects across driver, tests and harnesses, three of them the ANSI code page in three disguises); compat campaign on an 8 GB laptop, then the full 46-entry re-measure on a 32 GB machine on 2026-08-25 (45 pass; MySQL Connector/ODBC 26.7.1 retires the astral class) — `bench/BENCHMARKS-windows.md` | done |
18-
| macOS: 46 of 46 results (37 pass); a bridge built against iODBC is a supported configuration for vendor drivers that only ship iODBC builds (MySQL Connector/ODBC for macOS) — three width bugs found and fixed on the way (`docs/TROUBLESHOOTING.md`) | done |
19-
| Windows: per-connection narrow-text switch for ANSI-only drivers (no `W` entry point) — routes statement text and fetch through the narrow UTF-8 path, detected via `GetProcAddress(SQL_DRIVER_HLIB, "SQLExecDirectW")` — so Apache Ignite passes on Windows (prototype measured green; needs a Windows machine to land and re-measure) | next |
18+
| macOS: 46 of 46 results (41 pass, 5 driver/server unavailable); a bridge built against iODBC is a supported configuration for vendor drivers that only ship iODBC builds (MySQL Connector/ODBC for macOS) — three width bugs found and fixed on the way (`docs/TROUBLESHOOTING.md`) | done |
19+
| Windows: per-connection narrow-text route for ANSI-only drivers whose narrow path is UTF-8 (`narrow_sql` + `narrow_params` + `wchar_as_utf8`, keyed on the driver, no global state) — Apache Ignite passes on Windows, measured on the second Windows machine | done |
20+
| Windows, to verify on the next Windows session (reported by the second Windows campaign, not reproduced on a machine still available): (1) whether `cmake --install` under MSVC can write the manifest key `windows_amd64_mingw` (CMake's `MINGW` is only set for a GNU toolchain; the campaign's own build log recorded `windows_amd64`); (2) the Go binding's SQLite test leaves the database file open after `Close` so `t.TempDir()` cleanup fails — the drivermgr `Close` calls `AdbcConnectionRelease`/`AdbcDatabaseRelease` synchronously, so the open handle is either a driver-side pool or a missing release in the test's reader path | next |
2021
| Connection-level reader options (`adbc.odbc.batch_size`, `sqllen_32bit`) set before AdbcConnectionInit are discarded — `OdbcConnectionInit` copies the database defaults over them; re-apply the recorded pre-options after the copy | next |
2122
| Windows: prefetch pipeline and parallel ingest — both pthreads, compiled out on `_WIN32`; a Win32 shim (SRWLOCK, CONDITION_VARIABLE, `_beginthreadex`) restores them | next |
2223
| **Driver bootstrap**: `install.sh` / the Windows and macOS installers fetch the open-licence ODBC drivers a first run needs (sqliteodbc, psqlodbc, MariaDB Connector/ODBC, clickhouse-odbc) so SQLite/PostgreSQL/MySQL work with nothing else installed; vendor drivers (Oracle, Db2, SQL Server, Snowflake…) stay the user's download — their licences do not allow redistribution, and Windows already ships the SQL Server driver | next |

0 commit comments

Comments
 (0)