Bind integer parameters as strings on MySQL connections - #16
Merged
Merged
Conversation
MySQL 9.0.x re-prepares a statement on every execute that carries a PARAM_INT parameter; mysqlnd silently retries, adding two round trips per int-bound query. Measured at 226 reprepares/s (54% of executes) in production. Binding the same values as PARAM_STR produces identical plans and results with zero reprepares. Opt out with OCTANE_MYSQL_STRING_BINDINGS=false.
- The gate now honors '0'/'off'/'no' via FILTER_VALIDATE_BOOL, not just boolean false - operators disable features with '0' during incidents. - The class comment claimed string parameters behave 'exactly like a quoted literal'; parameters are exact where literals compare as DOUBLE (adjacent-bigint probe beyond 2^53). Rewritten so nobody extends the literal reasoning into interpolated SQL. - The unit test mixed positional and named placeholders in one statement, which real PDO rejects; split into two statements.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
MySQL 9.0.1 re-prepares a statement server-side on every execute that carries an integer-typed binary-protocol parameter. Production: 226 Com_stmt_reprepare/s — 54% of all statement executes — each one a full re-parse + re-plan of the statement on the DB server, in the same prepared-statement subsystem that produced the 1461 max_prepared_stmt_count outage.
Isolated with a clean-room PDO probe (same-DC VPS, 0.14ms RTT, EMULATE_PREPARES=false):
~15–50µs of server CPU per int-bound query, scaling with statement size. mysql-connector-python with int params does not trigger it — this is specific to how mysqlnd types parameters. MySQL 8.0.36 with the identical stack: zero reprepares.
Fix
MySqlStringBindingConnectionoverridesbindValues()to send PHP ints as decimal strings withPARAM_STR(otherwise byte-identical to the framework's implementation), registered viaConnection::resolverFor('mysql', …). Escape hatch:OCTANE_MYSQL_STRING_BINDINGS=false(also0/off/no).A string parameter is converted to the column type with full precision at execute time — verified exact for adjacent bigints beyond 2^53, where a quoted literal would compare as DOUBLE. E2E on Octane + Swoole: an 18-probe battery (inserts, whereIn, whereIntegerInRaw, paginate, limit/offset, aggregates, joins, update/delete counts, PHP_INT_MAX roundtrip) is byte-identical main vs branch; against prod 9.0.1 the per-request reprepare probe goes 1-per-int-query → 0.
Semantic footnote: an int bound against a varchar column previously compared numerically ('05' matched 5, index defeated) and now compares as a string (exact, indexed). Every id-like varchar/char column in modelslab_prod and gpulab_prod was scanned for non-canonical numeric values: zero found.
Tests
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.