|
| 1 | +# Changelog |
| 2 | + |
| 3 | +## v0.1 — initial release |
| 4 | + |
| 5 | +Milestones M1 → M7, all shipped: |
| 6 | + |
| 7 | +- **M1 — Framing + low-level codecs.** 3-byte length + 1-byte seq id packet |
| 8 | + framing, >16 MB continuation handling, length-encoded integer + string |
| 9 | + codecs, little-endian buffer cursor, NULL-bitmap helpers (with the |
| 10 | + server→client +2 reserved-bit offset baked in). |
| 11 | +- **M2 — Handshake + text query.** `HandshakeV10` decoding, |
| 12 | + `HandshakeResponse41` building, `COM_QUERY` / `COM_QUIT` / `COM_PING`, |
| 13 | + structured `MyError` (errno + SQLSTATE + message), cross-runtime |
| 14 | + socket adapter (Node, Bun, Perry). |
| 15 | +- **M3 — Auth plugins.** Dispatcher handling `AuthSwitchRequest` and |
| 16 | + `AuthMoreData` mid-handshake. Built-in plugins: |
| 17 | + `mysql_native_password`, `caching_sha2_password` (with RSA-OAEP-SHA1 |
| 18 | + public-key retrieval, gated by `allowPublicKeyRetrieval`), |
| 19 | + `sha256_password`, `mysql_clear_password` (TLS-gated), MariaDB |
| 20 | + `client_ed25519`. Custom plugins pluggable via `registerAuthPlugin`. |
| 21 | +- **M4 — Prepared protocol.** `COM_STMT_PREPARE` / `COM_STMT_EXECUTE` / |
| 22 | + `COM_STMT_CLOSE` / `COM_STMT_RESET` / `COM_STMT_SEND_LONG_DATA`. |
| 23 | + Per-connection prepared-statement cache keyed on SQL text. |
| 24 | + Binary-resultset decoder with the +2 server→client NULL-bitmap offset. |
| 25 | +- **M5 — Type codec registry + 23 codecs.** Parallel-array registry |
| 26 | + keyed on MYSQL_TYPE_* + column flags. Built-in codecs for TINY, |
| 27 | + SHORT, LONG, LONGLONG, INT24, FLOAT, DOUBLE, NEWDECIMAL (+ legacy |
| 28 | + DECIMAL), NULL, YEAR, BIT, VAR_STRING, STRING, VARCHAR, BLOB (+ TINY, |
| 29 | + MEDIUM, LONG), ENUM, SET, GEOMETRY, JSON, DATE, DATETIME, TIMESTAMP, |
| 30 | + TIME. `Decimal` wrapper (string-backed, lossless). `MyDate`, |
| 31 | + `MyDateTime`, `MyTime` wrappers preserving microsecond precision. |
| 32 | + Callers can override codecs via `registerType()`. |
| 33 | +- **M6 — TLS, pool, cancel, sql tag, URL/env resolution.** |
| 34 | + `SSLRequest` + mid-stream TLS upgrade (`sslmode`: |
| 35 | + `disable` / `require` / `verify-ca` / `verify-full`) with a single |
| 36 | + Perry-vs-Node adapter. `Pool` with idle / acquire timeouts and a |
| 37 | + `withConnection` / `transaction` surface. `Connection.cancel()` opens |
| 38 | + a second connection and runs `KILL QUERY <connection_id>`. |
| 39 | + `sql\`\`` tagged template with `?` placeholders and `raw()` for |
| 40 | + identifiers. `parseConnectionString` for `mysql://` / `mariadb://` |
| 41 | + DSNs with `ssl-mode`, `charset`, `allowPublicKeyRetrieval` query |
| 42 | + params. `resolveConnectOptions` for libmysqlclient-style env |
| 43 | + precedence (`MYSQL_HOST`, `MYSQL_TCP_PORT`, `MYSQL_USER`, `MYSQL_PWD`, |
| 44 | + `MYSQL_DATABASE`, `MYSQL_SSL_MODE`). |
| 45 | +- **M7 — Multi-resultset, LOCAL_INFILE guard, polish.** |
| 46 | + Multi-statement / multi-resultset handling gated on |
| 47 | + `multipleStatements: true`; each set surfaces on |
| 48 | + `QueryResult.resultSets`. `LOCAL INFILE` requests default to a clean |
| 49 | + `MyError` refusal with the requested filename in the message. |
| 50 | + Benchmark harness + shared workloads against `mysql2` / `mysql`. |
| 51 | + Additional smoke examples (`perry-smoke-prepared`, `perry-smoke-tls`, |
| 52 | + `select-one`). |
| 53 | + |
| 54 | +### Polish after M7 |
| 55 | + |
| 56 | +- **Positive-path TLS integration tests.** `tests-node/tls-node-tests.ts` |
| 57 | + drives full `SSLRequest` → TLS handshake → `HandshakeResponse41` |
| 58 | + round-trips against an in-process mock server with a throwaway |
| 59 | + self-signed cert. Runs under `node --import tsx --test` (Bun 1.3's |
| 60 | + `tls.connect({socket})` stalls; negative paths still covered under |
| 61 | + `bun test`). |
| 62 | +- **Cancel integration test.** Mock server supports `simulatedSleepMs` |
| 63 | + + `KILL QUERY <id>` relay between connections; verifies |
| 64 | + `conn.cancel()` returns errno 1317 / SQLSTATE 70100 on the target. |
| 65 | +- **Bench harness vs mysql2 and legacy mysql.** `bench/bench-mysql2.ts` |
| 66 | + and `bench/bench-mysql.ts` mirror `bench-this.ts`; `bench/package.json` |
| 67 | + keeps comparison drivers out of the main package. |
| 68 | +- **Docker real-server matrix.** `scripts/test-real.sh` brings up MySQL 8 |
| 69 | + + MariaDB 11 via `docker-compose.yml`, runs |
| 70 | + `tests/integration/real-server.test.ts` against both (skipped by |
| 71 | + default without `MYSQL_REAL=1`). |
| 72 | +- **Warning event hook.** `conn.on('warning', cb)` fires a summary |
| 73 | + `MyWarning` whenever a query returns `warningCount > 0`. |
| 74 | +- **`scripts/verify.sh`** — one-shot gate: typecheck → bun test → node |
| 75 | + TLS → build. |
| 76 | + |
| 77 | +### Bug fixes found via real-server testing (MySQL 8.0.45) |
| 78 | + |
| 79 | +- **HandshakeResponse41 caps mismatch over TLS.** The SSLRequest |
| 80 | + advertised `CLIENT_CONNECT_ATTRS` while `HandshakeResponse41` (built |
| 81 | + after the upgrade) stripped it when no attrs were supplied. MySQL |
| 82 | + cross-checks the two and rejected with errno 1043 "Bad handshake". |
| 83 | + Now both frames are computed from a single `initialCaps` up front, |
| 84 | + guaranteeing exact equality. |
| 85 | +- **Prepared INSERT/UPDATE/DELETE hung.** `COM_STMT_EXECUTE` responses |
| 86 | + for statements that return no resultset are a single OK packet, but |
| 87 | + the driver jumped straight to the row-collection phase and tried to |
| 88 | + decode the OK as a binary row. Fixed by always entering the exec |
| 89 | + response through the column-count phase — its first-packet branch |
| 90 | + correctly recognises the OK. |
| 91 | +- **`Buffer.isBuffer()` not lowered by Perry AOT codegen.** Replaced |
| 92 | + with a duck-type check (`typeof v.readUInt8 === 'function' && |
| 93 | + typeof v.length === 'number'`) so the driver source compiles cleanly |
| 94 | + under `perry compile`. |
| 95 | + |
| 96 | +### Perry AOT status |
| 97 | + |
| 98 | +- `perry check --check-deps examples/perry-aot-smoke.ts` passes. |
| 99 | +- `perry compile examples/perry-aot-smoke.ts` produces a 3.6 MB arm64 |
| 100 | + Mach-O binary. |
| 101 | +- **Full end-to-end connect + text query + prepared query + close runs |
| 102 | + natively** against a real MySQL 8.0.45 server with the driver source |
| 103 | + identical across all three runtimes (Node, Bun, Perry AOT). Confirmed |
| 104 | + on perry 0.5.99. |
| 105 | +- Bringing the AOT target up surfaced eight Perry compiler issues — |
| 106 | + #78, #79, #80, #81, #82 (fixed in 0.5.95); #85 (fixed in 0.5.97); #87, |
| 107 | + #88 (fixed in 0.5.98); #91 (fixed in 0.5.99). All driver-side |
| 108 | + workarounds were removed once the upstream fixes landed. |
| 109 | +- The one driver fix that stuck (and would have been correct against |
| 110 | + every Node/Bun version too) was switching `raw[raw.length - 1]` to |
| 111 | + `raw.readUInt8(raw.length - 1)` in `decoder.decodeHandshakeV10` — |
| 112 | + Perry-stdlib's Buffer doesn't lower bracket indexing, and the |
| 113 | + spurious truthiness left a stray NUL in the auth challenge that |
| 114 | + silently corrupted the SCRAM scramble. |
0 commit comments