You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
mysql2: the bundled stdlib fallback (linked silently when cargo is unavailable) diverges from perry-ext-mysql2 — prepared-only query(), errors without .message, string-form dispatch crash #9517
When perry cannot run cargo at compile time it prints
auto-optimize: failed to spawn cargo (No such file or directory (os error 2)), using prebuilt libraries
and links perry-stdlib's bundledmysql2 module (crates/perry-stdlib/src/mysql2/) instead of perry-ext-mysql2 — silently: the same note: serving mysql2 from the bundled native binding perry-ext-mysql2 line is printed either way, and the only tell is nm out | grep js_mysql2_handle_method_dispatch (present only for the ext). The two implementations behave differently in ways that break real programs. Found while reproducing #9356 on perrymaster (main f1e9c37, MySQL 8.0.46).
Divergences (bundled build; the ext build passes all of these)
pool.query(sql) with no bind values is sent as a prepared statement, so statements MySQL refuses to prepare fail:
pool.query("begin") → Query failed: error returned from database: 1295 (HY000): This command is not supported in the prepared statement protocol yet
(strace shows COM_STMT_PREPARE for a plain pool.query("SELECT …") too.) Node's mysql2 and perry-ext-mysql2 use the text protocol for query() without values.
Server errors reject with a value whose .message is undefined (String(e) still renders the text), so catch (e) { e.message } and every logger that reads it print undefined.
Dynamic dispatch of the string form crashes: with the static type lost (const client: any = pool; await client.query("SELECT 6 AS x")) the process dumps core (timeout: the monitored command dumped core). The options-object form (client.query({ sql, rowsAsArray: true }, []), drizzle's shape) works.
Reproduction
/root/claude-9356/repro/probe.ts on perrymaster: compile once without ~/.cargo/bin on PATH (bundled build) and once with it (ext build) and run both; DB user perry9356.
Suggested direction
Either make the fallback loud (fail the compile when the well-known wrapper cannot be built, or at least print which implementation was linked), or bring the bundled module up to the ext's behaviour (sqlx::raw_sql for no-value query(), MysqlPromiseError-style rejections, string-form dispatch).
Closing: fixed in #9564 (align bundled mysql2 fallback semantics: text-protocol query() without bind values, query options and rowsAsArray, Error objects with mysql2 code/errno, reflective and dynamic dispatch), landed via merge train #9569 on 2026-09-02. Verified there with a live MySQL E2E with cargo removed from PATH. Not in release candidate r27.
Activity
proggeramlug commentedon Sep 2, 2026
Closing: fixed in #9564 (align bundled mysql2 fallback semantics: text-protocol query() without bind values, query options and rowsAsArray, Error objects with mysql2 code/errno, reflective and dynamic dispatch), landed via merge train #9569 on 2026-09-02. Verified there with a live MySQL E2E with cargo removed from PATH. Not in release candidate r27.