Skip to content

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

Description

@proggeramlug

Summary

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 bundled mysql2 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)

  1. 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.
  2. 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.
  3. 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).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions