Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3026,7 +3026,7 @@ jobs:
# a "no reactor running" panic. `test_issue_414_mysql_query_params`
# was the single compile-smoke failure this caused. Same set the
# doc-tests job already builds together.
run: cargo build --release -p perry -p perry-runtime -p perry-stdlib -p perry-runtime-static -p perry-stdlib-static -p perry-ext-ioredis -p perry-ext-mongodb -p perry-ext-mysql2 -p perry-ext-pg -p perry-ext-nodemailer
run: cargo build --release -p perry -p perry-runtime -p perry-stdlib -p perry-runtime-static -p perry-stdlib-static -p perry-ext-ioredis -p perry-ext-mongodb -p perry-ext-pg -p perry-ext-nodemailer

- name: Issue #945 scalar method IR guard
run: |
Expand Down Expand Up @@ -3878,7 +3878,7 @@ jobs:
# Build them in this SAME Cargo graph as perry-stdlib: otherwise each
# no-auto fallback build bundles a distinct tokio TLS/runtime and the
# linker rejects the unsafe pair (#507, #7629).
run: cargo build --release -p perry -p perry-runtime -p perry-stdlib -p perry-runtime-static -p perry-stdlib-static -p ${{ matrix.ui_backend }} -p perry-doc-tests -p perry-ext-ioredis -p perry-ext-mongodb -p perry-ext-mysql2 -p perry-ext-pg -p perry-ext-nodemailer -p perry-ext-net
run: cargo build --release -p perry -p perry-runtime -p perry-stdlib -p perry-runtime-static -p perry-stdlib-static -p ${{ matrix.ui_backend }} -p perry-doc-tests -p perry-ext-ioredis -p perry-ext-mongodb -p perry-ext-pg -p perry-ext-nodemailer -p perry-ext-net

- name: Verify macOS application bundle packaging
if: matrix.os == 'macos-14'
Expand Down
15 changes: 0 additions & 15 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ members = [
"crates/perry-ext-cron",
"crates/perry-ext-ioredis",
"crates/perry-ext-pg",
"crates/perry-ext-mysql2",
"crates/perry-ext-fetch",
"crates/perry-ext-undici",
"crates/perry-ext-mongodb",
Expand Down Expand Up @@ -476,7 +475,6 @@ perry-ext-nodemailer = { path = "crates/perry-ext-nodemailer" }
perry-ext-cron = { path = "crates/perry-ext-cron" }
perry-ext-ioredis = { path = "crates/perry-ext-ioredis" }
perry-ext-pg = { path = "crates/perry-ext-pg" }
perry-ext-mysql2 = { path = "crates/perry-ext-mysql2" }
perry-ext-fetch = { path = "crates/perry-ext-fetch" }
perry-ext-undici = { path = "crates/perry-ext-undici" }
perry-ext-mongodb = { path = "crates/perry-ext-mongodb" }
Expand Down
54 changes: 54 additions & 0 deletions changelog.d/10680-mysql2-native-binding-removal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
Removed the mysql2 native binding so `import mysql from "mysql2"` resolves to
the real npm package, per the owner's decision to stop shipping hand-written
Rust reimplementations of npm packages that drift from the real thing.

Two locations turned out to be separate hand-written mysql2
reimplementations, both removed: `crates/perry-ext-mysql2` (the
governance-tracked, well-known-table crate a plain `import mysql from
"mysql2"` actually linked against) and `crates/perry-stdlib/src/mysql2/`
(~1870 lines, gated behind the default-on `bundled-mysql2` perry-stdlib
feature). The two defined identical `js_mysql2_*` symbol names in **separate,
documented-as-disjoint handle registries** (perry-ffi's vs. perry-stdlib's
`common::handle`), so in the default (`full`-feature) build both crates'
archives carried the same symbols — a live footgun, not merely dead code.

Also removed the `bundled-mysql2` HIR heuristic in
`perry-hir/src/lower/expr_call/native_module.rs` that recognized a
bundler-inlined (webpack/turbopack) `createPool`/`createConnection` call by
its config-object shape and routed it to perry-ext-mysql2's FFI symbols. That
workaround existed only because an AOT binary couldn't run mysql2's
`generate-function`-built row parsers (`new Function` at runtime); #10675's
`dyn_eval` class-expression support fixes that generally, so the workaround
is no longer needed.

Removed the supporting registry wiring: `well_known_bindings.toml`,
`NATIVE_MODULES` + manifest rows in `perry-api-manifest`, the
`native_table/databases.rs` MySQL2 codegen section, `ext_registry.rs` FFI
routing, `stdlib_features.rs` / `optimized_libs` driver+freshness wiring,
`PERRY_NATIVE_EXTENSION_PACKAGES` in `resolve.rs`, `workspace-architecture.json`,
the Android `stdlib_stubs.rs` FFI stubs, and the `unrooted-local-shape` /
`string-payload-access` / `native-result-ledger` baselines for the deleted
files and symbols. Fixed the two explicit `-p perry-ext-mysql2` cargo build
args in `.github/workflows/test.yml` and `run_doc_tests.sh`/`.ps1`, which
would otherwise fail with "no such package". Regenerated
`docs/src/api/reference.md`, `docs/api/perry.d.ts`, and
`docs/src/native-libraries/governance.md`'s generated table, and added a
"Completed source migrations" entry for mysql2 matching the existing
`slugify` entry.

Validated with a real query round trip against a local MySQL 8.0.46 server:
`CREATE TABLE`/`INSERT`/`SELECT`/`DROP TABLE` all passed using the real
`mysql2` npm package with **no `perry.compilePackages` entry at all** —
Perry's default automatic package-routing path (`Compile package wildcard:
expanded to 60 installed package(s)`) compiled mysql2 and its full dependency
tree from source, with the `generate-function` row-parser factory handled at
runtime via `dyn_eval` (#6559 notice). `cargo test -p perry-api-manifest -p
perry-hir` and `cargo test -p perry-codegen --test manifest_consistency`
(all 5 tests, including `every_dispatch_entry_has_manifest_counterpart`) pass;
`scripts/run_lint_gates.sh` (`SKIP_COMPILE_GATES=1`) is 76 of 77 green — the
one red gate, "Public benchmark evidence freshness", is pre-existing on every
PR in this repo.

Must not merge before #10675 (`wip/10661-dyn-eval-class-expr`) — mysql2's
real source does not compile without that PR's `dyn_eval` class-expression
support.
10 changes: 4 additions & 6 deletions crates/perry-api-manifest/src/entries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,10 @@ use crate::{ApiEntry, ApiKind, ApiSource, ParamSpec, TypeSpec};
/// `perry-hir`. Order matches the original list to keep diffs minimal.
pub const NATIVE_MODULES: &[&str] = &[
// ── Third-party npm packages (native wrappers; see well_known_bindings.toml) ──
"mysql2", // MySQL/MariaDB client
"mysql2/promise", // mysql2's promise-API subpath
"pg", // PostgreSQL client
"bcrypt", // bcrypt password hashing (replaces the N-API addon)
"argon2", // Argon2 password hashing (replaces the N-API addon)
"ioredis", // Redis/Valkey client
"pg", // PostgreSQL client
"bcrypt", // bcrypt password hashing (replaces the N-API addon)
"argon2", // Argon2 password hashing (replaces the N-API addon)
"ioredis", // Redis/Valkey client
// iovalkey: the Valkey fork of ioredis (valkey-io/iovalkey), served by the
// same perry-ext-ioredis surface — see well_known_bindings.toml.
"iovalkey",
Expand Down
58 changes: 0 additions & 58 deletions crates/perry-api-manifest/src/entries/part_1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,64 +13,6 @@ pub(crate) const API_MANIFEST_PART_1: &[ApiEntry] = &[
// (extracted from crates/perry-codegen/src/lower_call.rs;
// drift guarded by perry-codegen's manifest_consistency test)
// ===========================================================
method_sig(
"mysql2",
"createConnection",
false,
None,
&[p_any("p0")],
TypeSpec::Any,
),
method_sig(
"mysql2",
"createPool",
false,
None,
&[p_any("p0")],
TypeSpec::Any,
),
method_sig(
"mysql2/promise",
"createConnection",
false,
None,
&[p_any("p0")],
TypeSpec::Any,
),
method_sig(
"mysql2/promise",
"createPool",
false,
None,
&[p_any("p0")],
TypeSpec::Any,
),
method("mysql2", "query", true, Some("Pool")),
method("mysql2", "execute", true, Some("Pool")),
method("mysql2", "end", true, Some("Pool")),
method("mysql2/promise", "query", true, Some("Pool")),
method("mysql2/promise", "execute", true, Some("Pool")),
method("mysql2/promise", "end", true, Some("Pool")),
method("mysql2", "query", true, Some("PoolConnection")),
method("mysql2", "execute", true, Some("PoolConnection")),
method("mysql2/promise", "query", true, Some("PoolConnection")),
method("mysql2/promise", "execute", true, Some("PoolConnection")),
method("mysql2", "query", true, None),
method("mysql2", "execute", true, None),
method("mysql2", "end", true, None),
method("mysql2", "getConnection", true, None),
method("mysql2", "release", true, None),
method("mysql2", "beginTransaction", true, None),
method("mysql2", "commit", true, None),
method("mysql2", "rollback", true, None),
method("mysql2/promise", "query", true, None),
method("mysql2/promise", "execute", true, None),
method("mysql2/promise", "end", true, None),
method("mysql2/promise", "getConnection", true, None),
method("mysql2/promise", "release", true, None),
method("mysql2/promise", "beginTransaction", true, None),
method("mysql2/promise", "commit", true, None),
method("mysql2/promise", "rollback", true, None),
method_sig("pg", "connect", false, None, &[p_any("p0")], TypeSpec::Any),
method_sig("pg", "Pool", false, None, &[p_any("p0")], TypeSpec::Any),
method("pg", "connect", true, Some("Client")),
Expand Down
2 changes: 0 additions & 2 deletions crates/perry-api-manifest/src/entries/part_3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -534,8 +534,6 @@ pub(crate) const API_MANIFEST_PART_3: &[ApiEntry] = &[
class("net", "BlockList"),
class("net", "SocketAddress"),
class("ioredis", "Redis"),
class("mysql2/promise", "Pool"),
class("mysql2", "Pool"),
class("pg", "Pool"),
class("pg", "Client"),
class("url", "URL"),
Expand Down
2 changes: 1 addition & 1 deletion crates/perry-codegen-js/src/emit/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ impl JsEmitter {
.push_str("(console.warn('spawnBackground not available in browser'), 0)");
}
// --- Fastify/HTTP (throw in browser) ---
"fastify" | "ws" | "mysql2" | "mysql2/promise" | "pg" | "net" | "worker_threads" => {
"fastify" | "ws" | "pg" | "net" | "worker_threads" => {
let _ = write!(
self.output,
"((() => {{ throw new Error('{} not available in browser'); }})())",
Expand Down
27 changes: 0 additions & 27 deletions crates/perry-codegen/src/ext_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -592,33 +592,6 @@ const FFI_REGISTRY: &[(&str, OwnerKind)] = &[
("js_ext_net_socket_write3", OwnerKind::WellKnown("net")),
("js_ext_net_socket_end3", OwnerKind::WellKnown("net")),

// ── mysql2 (perry-ext-mysql2) ────────────────────────────────────
// Normally `import "mysql2"` flips the `[bindings.mysql2]` well-known
// and links perry-ext-mysql2. But a bundler (webpack/turbopack) inlines
// mysql2 under a NUMERIC module id, so there is no bare import for perry
// to see — and JS mysql2 JIT-compiles its row parsers with `new Function`
// (via `generate-function`), which an AOT binary cannot execute. The HIR
// pass in `perry-hir`'s native-module lowering recognizes a bundled
// `createPool`/`createConnection` by its mysql2 config-object signature
// and emits these FFIs directly, WITHOUT adding "mysql2" to the import
// set. Tag them here so the well-known flip fires off codegen provenance
// — same mechanism as the http/net/events rows above — and the staticlib
// joins the link line instead of leaving `_js_mysql2_*` undefined.
("js_mysql2_create_pool", OwnerKind::WellKnown("mysql2")),
("js_mysql2_create_connection", OwnerKind::WellKnown("mysql2")),
("js_mysql2_pool_query", OwnerKind::WellKnown("mysql2")),
("js_mysql2_pool_execute", OwnerKind::WellKnown("mysql2")),
("js_mysql2_pool_get_connection", OwnerKind::WellKnown("mysql2")),
("js_mysql2_pool_end", OwnerKind::WellKnown("mysql2")),
("js_mysql2_pool_connection_query", OwnerKind::WellKnown("mysql2")),
("js_mysql2_pool_connection_execute", OwnerKind::WellKnown("mysql2")),
("js_mysql2_pool_connection_release", OwnerKind::WellKnown("mysql2")),
("js_mysql2_connection_query", OwnerKind::WellKnown("mysql2")),
("js_mysql2_connection_execute", OwnerKind::WellKnown("mysql2")),
("js_mysql2_connection_begin_transaction", OwnerKind::WellKnown("mysql2")),
("js_mysql2_connection_commit", OwnerKind::WellKnown("mysql2")),
("js_mysql2_connection_rollback", OwnerKind::WellKnown("mysql2")),
("js_mysql2_connection_end", OwnerKind::WellKnown("mysql2")),
];

/// Prefix-based routing for ext-binding FFI whose emitted symbols follow the
Expand Down
Loading
Loading