refactor(stdlib): remove mysql2 native binding - #10680
proggeramlug wants to merge 5 commits into
Conversation
|
Warning Review limit reachedNext included review available in 2 minutes. View limit detailsLimit details: You’ve used all 8 included reviews currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (39)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Heads-up before this is queued: this PR's recorded workspace baseline is stale and will fail It records Full table and reasoning in #10739. The short version, for whoever rebases this:
Also relevant to the acceptance run whenever it happens: #10735 is live on main — |
|
This PR reports It records Nothing about this is visible in the diff: the counts sit on different JSON lines from the deleted crate entry, so git auto-merges cleanly and GitHub reports the PR mergeable. See #10739 for the general mechanism. A distinction worth drawing, because it caught me outThis PR's file is internally consistent: So the three-way check is necessary but not sufficient. It validates the file against itself, not against the tree the PR will land on. A file can be perfectly self-consistent and still describe a workspace that no longer exists. Both checks are needed:
This PR passes (1) and fails (2). #10691 earlier failed (1) while looking plausible on (2). They are independent failure modes and neither check subsumes the other. What this needsA rebase onto current
|
Deletes perry-ext-mysql2 (the well-known-table crate that provided js_mysql2_* symbols for plain `import mysql from "mysql2"`) and perry-stdlib/src/mysql2/ (a second, duplicate hand-written mysql2 implementation gated behind the bundled-mysql2 feature). Removes the supporting registry wiring: well_known_bindings.toml, NATIVE_MODULES / manifest entries in perry-api-manifest, the native_table/databases.rs MySQL2 codegen rows, ext_registry.rs FFI routing, the bundled-mysql2 HIR heuristic for bundler-inlined mysql2 (superseded by #10675's dyn_eval class-expression support), stdlib_features.rs / optimized_libs driver+freshness wiring, workspace-architecture.json, and the unrooted-local-shape baseline entries for the deleted files. Based on wip/10661-dyn-eval-class-expr (#10675) — mysql2 does not compile from real source without that fix. # Conflicts: # Cargo.lock # crates/perry-api-manifest/src/entries/part_1.rs # crates/perry-ui-android/src/stdlib_stubs.rs # crates/perry/src/commands/compile/collect_modules/binding_faithfulness.rs # crates/perry/src/commands/compile/resolve.rs # workspace-architecture.json
…docs) - cargo fmt after the removal (entries.rs / resolve.rs realignment) - drop the two explicit -p perry-ext-mysql2 args from .github/workflows/test.yml (compile-smoke + UI-backend jobs) and from run_doc_tests.sh/.ps1 - drop the 14 js_mysql2_* rows from scripts/native_result_ledger.tsv and update its EXPECTED_ROWS/EXPECTED_PROVIDERS counts (343/308) - refresh workspace-architecture.json's baseline counts (82 members, externalize=32) so scripts/workspace_architecture.py --check passes - rewrite scripts/string_payload_access_baseline.txt via --write-baseline (perry-ext-mysql2 row dropped, perry-stdlib 40 -> 38) - regenerate docs/src/api/reference.md, docs/api/perry.d.ts, and docs/src/native-libraries/governance.md's generated table; add a "Completed source migrations" entry for mysql2 run_lint_gates.sh (SKIP_COMPILE_GATES=1): 76/77 passed, only the pre-existing "Public benchmark evidence freshness" red. # Conflicts: # crates/perry-api-manifest/src/entries.rs # crates/perry/src/commands/compile/resolve.rs # docs/api/perry.d.ts # docs/src/api/reference.md # docs/src/native-libraries/governance.md # scripts/native_result_ledger.py # scripts/string_payload_access_baseline.txt # workspace-architecture.json
…ysql2-removal rebase Removes the stray perry-ext-mysql2 crate entry that survived the rebase's auto-merge in workspace-architecture.json (the baseline block alone would have passed --check while the per-crate map still named a deleted crate). Resyncs Cargo.lock, recomputes native_result_ledger EXPECTED_ROWS/PROVIDERS from the resolved tree (328 rows, 293 providers), and regenerates the unrooted-local-shape / string-payload-access baselines, the generated binding-governance table, and docs/api/perry.d.ts + docs/src/api/reference.md from a fresh perry-dev build.
424c46d to
2a434bd
Compare
Squashed rebase of #10680 on top of #10677. Generated/absolute-count files are left at main's values here and regenerated from their owning scripts in a later commit (#10739). Non-obvious conflict call: #10680's side of crates/perry-hir/src/lower/expr_call/native_module.rs still contained native_module_member_path(), which main deleted with the node-forge binding. Taking 'theirs' would have resurrected it as dead code, so the whole hunk resolves to empty.
#10677 deleted perry-ext-pg and perry-stdlib/src/pg but left the call sites that reference their symbols: - lower_call/builtin.rs still lowered `new Client(cfg)`/`new Pool(cfg)` from an `import ... from "pg"` to `js_pg_client_new`/`js_pg_pool_new`. With no provider those are undefined at link time, which is exactly the failure the real `pg` package would hit (it constructs `new Client`). Dropped the two arms and the `"Client" | "Pool" => Some(&["pg"])" import gate together, so a user-defined Pool/Client falls through to the generic path (#536). - runtime_decls/stdlib_ffi/data_stores.rs declared the ten js_pg_* externs. - perry-ui-android/src/stdlib_stubs.rs defined seven js_pg_* stubs (#10680 had already dropped the matching mysql2 ones). - perry-codegen-js browser-emit list and a native_table/mod.rs comment. - scripts/run_doc_tests.sh / .ps1 still passed -p perry-ext-pg to cargo build, which no longer resolves.
…ysql2 removal that is now 28 commits behind `main`, so neither side's numbers could be merged (#10739). Every count below is what the owning script reports on this resolved tree — none of it is arithmetic on the two PRs' figures: Cargo.lock cargo metadata --offline (drops perry-ext-pg, perry-ext-mysql2 and, via sqlx's mysql-rsa edge, rsa/pkcs1/ crypto-primes) workspace-architecture.json scripts/workspace_architecture.py --check --print-summary: members 66 -> 64, externalize 17 -> 15 (keep/merge/remove/ review unchanged). The two `crates` policy entries are deleted; the script errors on a policy entry with no workspace crate. native_result_ledger.py/.tsv scripts/native_result_ledger.py: 349 -> 314 rows, 300 -> 279 providers. Both PRs landed on 349/300 for unrelated reasons, so the textual auto-merge agreed and was wrong. unrooted_local_shape_baseline scripts/unrooted_local_shape.py --update-baseline: total 527 -> 428. string_payload_access_baseline scripts/string_payload_access_inventory.py --write-baseline: perry-stdlib 36 -> 28, the perry-ext-pg/mysql2 rows dropped. docs/src/api/reference.md target/<profile>/perry --print-api-manifest docs/api/perry.d.ts (run directly: regen_api_docs.sh hardcodes <worktree>/target/release/perry and silently truncates both files when that path is absent). 2870 -> 2829 entries across 120 -> 117 modules, which is exactly the 41 manifest rows (9 pg + 32 mysql2) and 3 specifiers removed; tails intact. Also folded in here: a stray `}` left in perry-hir's native_module.rs by the conflict markers), the changelog fragments corrected to the results actually measured on this branch, and a `pg` entry in governance.md's "Completed source migrations" list to match the one #10680 added for mysql2.
|
Landed via merge train 245 (#10845), released as v0.5.1624 — merge commit Carried together with its sibling removal, deliberately: #10678's duplicate-symbol hazard is only closed by removing both bindings, because each existed twice (the Two things were redone rather than carried through the rebase onto v0.5.1623:
Validation on the union: Closing here rather than merging — a train lands the commits directly, so the source PR has nothing left to merge. |
Summary
Removes the mysql2 native binding so
import mysql from "mysql2"resolves tothe real npm package, per the owner's decision to stop shipping hand-written
Rust reimplementations of npm packages (they drift from the real thing — see
the
jsonwebtoken.verifyexample in the campaign background).Must not merge before #10675 (
wip/10661-dyn-eval-class-expr, this PR'sbase). mysql2's real source does not compile without that PR's
dyn_evalclass-expression support —
generate-functionbuilds mysql2's row parserswith a runtime
new Function(...)that returns a class expression.What was removed and why
Two candidate locations turned out to be genuinely separate, both hand-written
reimplementations of mysql2 using
sqlxdirectly:crates/perry-ext-mysql2— the governance-tracked binding(
docs/src/native-libraries/governance.md: "Source package", target"Compile the upstream package source"). Wired into
well_known_bindings.toml's[bindings.mysql2]/[bindings."mysql2/promise"],and the crate a plain
import mysql from "mysql2"(nocompilePackages)actually linked against.
crates/perry-stdlib/src/mysql2/(~1870 lines) — a second,independent mysql2 implementation gated behind perry-stdlib's
bundled-mysql2feature (default-on viafull). It defined the exact samejs_mysql2_*symbol names as perry-ext-mysql2, in a separate handleregistry (perry-ffi's handle table and perry-stdlib's
common::handletable are explicitly documented as disjoint integer spaces — see
crates/perry-ffi/src/handle.rs). Itsdispatch_mysql2_method/dispatch_mysql2_propertydynamic-dispatch fallback (for Drizzle'sinterface-typed client fields) could only ever resolve handles created by
its own
js_mysql2_create_connection/createPool— which lose the linkto whichever archive the linker picks between two archives exporting the
same symbol names. In the default (
full) feature build both crates shipjs_mysql2_*, so this was already a live footgun, not merely inert.Both were removed. Neither is separable from "the mysql2 native binding"
— they are the same category of hand-written duplicate the campaign targets,
just delivered through two different mechanisms (well-known ext-crate flip vs.
a default-on stdlib feature).
Also removed the
bundled-mysql2HIR heuristic inperry-hir/src/lower/expr_call/native_module.rs(mysql2_config_signature/detect_bundled_mysql2_create) that recognized a bundler-inlined(webpack/turbopack)
createPool/createConnectioncall by its config-objectshape and routed it to
perry-ext-mysql2's FFI symbols. That workaroundexisted only because the AOT binary couldn't run mysql2's
generate-functionrow parsers; #10675 fixes that generally via
dyn_eval, so the heuristic (andits
bundled_mysql2_testsmodule, trimmed rather than deleted — it alsocovered an unrelated
is_process_active_array_helpertest, kept under arenamed
native_module_helper_testsmod) is no longer needed.Left alone, deliberately: a handful of shared perry-hir files
(
local_natives.rs,native_new.rs,native_fetch.rs,misc.rs,module_decl.rs,static_and_instance.rs) still pattern-match on the stringliterals
"mysql2"/"mysql2/promise"for class-shape inference (e.g.tagging
createPool()'s result as aPool). These are now structurallyunreachable — the only two producers of a
NativeMethodCall/NativeModuleRefwith that module string were
NATIVE_MODULESmembership (removed) and thebundled-heuristic above (removed) — but hand-editing every multi-package match
arm in files shared with the concurrent axios/pg removal branches risked a
larger, conflict-prone diff for no behavioral change. Also left alone:
prose comments across perry-runtime/perry-codegen that cite real mysql2
source shapes (
MockBuffer,generate-function, drizzle transactions) asmotivating examples for unrelated compiler features — those describe why the
compiler behaves a certain way, not the binding being removed.
Registries and gates touched
crates/perry/well_known_bindings.toml— drop[bindings.mysql2]/[bindings."mysql2/promise"]crates/perry-api-manifest/src/entries.rs(+entries/part_1.rs,entries/part_3.rs) — dropNATIVE_MODULESentries and all mysql2manifest rows
crates/perry-codegen/src/lower_call/native_table/databases.rs— drop theMySQL2NativeModSigsectioncrates/perry-codegen/src/ext_registry.rs— drop the mysql2FFI_REGISTRYrows
crates/perry/src/commands/stdlib_features.rs,optimized_libs/driver.rs,optimized_libs/freshness.rs— drop themysql2→bundled-mysql2wiringcrates/perry/src/commands/compile/resolve.rs—PERRY_NATIVE_EXTENSION_PACKAGES(this is what let mysql2's real.jssource reach the module walker instead of being silently skipped as
"handled by native stdlib")
workspace-architecture.json— drop theperry-ext-mysql2decision entryand refresh the baseline counts (
workspace_members,externalize)scripts/unrooted_local_shape_baseline.json,scripts/string_payload_access_baseline.txt,scripts/native_result_ledger.tsv(+EXPECTED_ROWS/EXPECTED_PROVIDERSin
native_result_ledger.py) — drop entries for the deleted files/symbols.github/workflows/test.yml,scripts/run_doc_tests.sh/.ps1— drop the twoexplicit
-p perry-ext-mysql2cargo build args (compile-smoke + UI-backendjobs, doc-tests harness); these would otherwise fail with "no such package"
crates/perry-ui-android/src/stdlib_stubs.rs— drop the 14js_mysql2_*Android stub exports
docs/src/api/reference.md,docs/api/perry.d.ts— regenerated(
--print-api-manifest)docs/src/native-libraries/governance.md— regenerated table (drops theperry-ext-mysql2row) + a new "Completed source migrations" bullet,matching the existing
slugifyentry's patterncrates/perry/src/commands/compile/collect_modules/binding_faithfulness.rs— dropped
lookup_preserves_registered_subpaths_before_falling_back, theone test whose only real-world fixture (
mysql2/promise'salias-of = "mysql2") no longer exists inwell_known_bindings.toml(itwas the only root+subpath alias in the whole table); the sibling test
using
"mysql2"as an arbitrary on-disk-directory fixture name is untouchedsince it doesn't depend on the registry.
Acceptance test: real query round-trip, no
compilePackagesentryBuilt on the perrymaster host (
--profile perry-dev,-p perry -p perry-runtime-static -p perry-stdlib-static, thenPERRY_WORKSPACE_ROOTsetso auto-optimize could pull in the wrapper crates the real mysql2 source
needs —
perry-wasm-host,perry-ext-net,perry-ext-events,perry-ext-zlib). Test program:with
package.json:{ "dependencies": { "mysql2": "^3" } }No
perry.compilePackagesentry at all — not formysql2, not for itstransitive deps. Compile log:
Compile package wildcard: expanded to 60 installed package(s)(Perry's default automatic package-routing path,already used by the
slugifymigration) compiled real mysql2 + itsdependency tree (
generate-function,iconv-lite,long,lru.min,named-placeholders,sql-escaper,aws-ssl-profiles, ...) from source.One informational notice:
generate-function/index.js:362's runtimenew Function(...)— mysql2's row-parser factory — was "handled at runtime:runtime interpreter (#6559)", i.e.
dyn_eval, exactly the mechanism #10675added.
Ran the resulting binary against the real local MySQL 8.0.46 server:
CREATE TABLE/INSERT/SELECT/DROP TABLEall round-tripped with thereal row parser, real wire protocol, real auth handshake.
Verification
cargo check/cargo build --profile perry-dev -p perry -p perry-runtime-static -p perry-stdlib-static: clean (confirmed.amtimesmoved after the edits)
cargo test -p perry-api-manifest -p perry-hir: all passingcargo test -p perry-codegen --test manifest_consistency: all 5 passing(
every_native_module_has_at_least_one_manifest_entry,every_dispatch_entry_has_manifest_counterpart, etc.) — confirms theregistry edits are internally consistent
python3 scripts/binding_governance.py --check: OK (39 extension cratesclassified)
node scripts/binding_pins.mjs --check: OK (37 pinned, lock-step holds)scripts/run_lint_gates.sh(SKIP_COMPILE_GATES=1): 76 of 77 passed.The one failure, "Public benchmark evidence freshness", is pre-existing on
every PR in this repo (per the campaign's own fix-agent contract) — not
touched here.
Not run / out of scope
run_lint_gates.sh(known-red on Linux per the campaigncontract; not run)
ran the targeted registry/consistency tests instead
CLAUDE.mdedit — per this campaign's convention, themaintainer bumps at merge time
Rebase note (2026-09-20)
Rebased onto
main@b9ba951ff861c61afb845bfbdfa574cb0fa4080e(train 239) as part of a4-PR sequential rebase campaign together with #10795, #10677, #10704 — all four
independently rebased onto this same main SHA and pushed together. This PR's base is now
main, notwip/10661-dyn-eval-class-expr: that branch squash-merged into main sometime ago, so this needed the two-step unstack —
git rebase --onto origin/main <wip/10661 tip> pr-10680followed bygh pr edit --base main.Conflicts spanned 8 files on the removal commit (
Cargo.lock,crates/perry-api-manifest/ src/entries/part_1.rs— a genuinely large one: main had independently inserted 40+fastifymanifest rows into the exact list position this PR's mysql2 rows occupied, sincefastify's own binding was removed by a different PR after this branch forked; resolved by
taking current main's file verbatim and deleting only the mysql2-specific entries, not
hand-merging the two unrelated changes —
crates/perry-ui-android/src/stdlib_stubs.rssame shape,
crates/perry/src/commands/compile/collect_modules/binding_faithfulness.rs,crates/perry/src/commands/compile/resolve.rs,docs/api/perry.d.ts,docs/src/api/reference.md,docs/src/native-libraries/governance.md,scripts/native_result_ledger.py,scripts/string_payload_access_baseline.txt,workspace-architecture.json) plus 6 more on the second commit.Recomputed triple:
workspace_members=69(decision_counts: externalize=20, keep=44,merge=1, remove=1, review=3) — needed a full recompute; a stray
"perry-ext-mysql2"entryalso survived the auto-merge in the per-crate map even after the baseline numbers were
fixed, which
--checkcaught on a second pass (a technically-self-consistent baseline blockcan still describe a workspace that no longer exists — the two checks are independent);
native_result_ledger: 328 rows / 293 providers (main's real ledger minus mysql2's 28declarations, matching the original PR's own "leaving 343... 356→343" note's arithmetic
once resynced against a rebased main whose own baseline had also since moved to 356/307);
unrooted-local-shapetotal: 491.These numbers assume main is still at the stated SHA — whichever of the four PRs lands
first moves the ground under the other three's counts; re-derive before queuing a second
or third one.
Gates:
cargo fmt --all -- --checkOK (onecargo fmt --allpass needed after conflictresolution, same comment-alignment class as #10677);
cargo check --workspace --all-targetsunder-D warningson the defaultdevprofile (excl.perry-ui-gtk4) —clean;
run_lint_gates.sh SKIP_COMPILE_GATES=1— 78 of 79 passed (1 pre-existing, #10707,not chased);
binding_governance.py --checkOK;binding_pins.mjs --checkunder Node26.5.1 OK;
check_file_size.shOK..github/workflows/test.yml's own-p perry-ext-mysql2removal (already part of this PR) auto-merged clean; verified
-p perry-ext-pgon thosesame two lines is untouched, since removing it is #10677's job landing independently.
Compile tier not run. No gap sweep run. No acceptance re-run.