Skip to content

driver-sql (MySQL): find() answers 1/0 for a declared boolean field — the read coercion is gated to SQLite, so the storage form leaks on the row-read door #11782

Description

@huangyiirene

Found while implementing #11635 (boolean aggregand answers), measured through the driver boundary on live MySQL 8.0.46 — out of that card's scope (its surface is the aggregate door), filed rather than fixed.

Measurement

Through SqlDriver.find() on live MySQL 8.0.46, over a table whose flag field is declared type: 'boolean' (stored as tinyint(1)), current main (2a6122bd9d):

[mysql] find().flag => 1 (typeof number)
[pg] find().flag => true (typeof boolean)
[sqlite] (converted by the booleanFields read coercion)

Instrument: a plain driver.create(...) + driver.find(...) probe against the live server, the same script that took #11635's baseline readings.

Mechanism

formatOutput's booleanFields read coercion (packages/drivers/driver-sql/src/sql-driver.ts, the Boolean(data[field]) loop) sits inside if (this.isSqlite). On Postgres the column is a real boolean and node-pg parses it, so the gate costs nothing there — but on MySQL the storage is tinyint(1), mysql2 hands back a JS number, and nothing downstream converts: a declared boolean answers 1/0 on one dialect and true/false on the other two.

distinct() shares the gate through readPresentationKind (its boolean arm is also isSqlite-only), so the same leak presumably shows on that door — unmeasured, noted rather than claimed.

Why it matters

Scope note

The fix direction (un-gate the coercion for MySQL vs. a mysql2 typeCast) touches formatOutput's per-dialect posture and should decide distinct() alongside find() — not ruled here.


Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions