Commit 107bb4b
fix(driver-sql): carry an over-long UNIQUE index on a hash-shadow column (MySQL utf8mb4) (#12198)
* fix(driver-sql): carry an over-long UNIQUE index on a hash-shadow column (MySQL utf8mb4)
On utf8mb4 InnoDB a key part holds at most 3072 bytes (768 characters), so a
full-value UNIQUE index over a longer column is inexpressible rather than merely
expensive. Measured on live MySQL 8.0.46: 7 of 44 exported platform objects
failed syncSchema (6 ER_BLOB_KEY_WITHOUT_LENGTH + 1 ER_TOO_LONG_KEY); Postgres
16.13 took all 44.
Such a UNIQUE index is now carried by a driver-owned `<index>__hash` column: a
STORED GENERATED VARBINARY(32) holding the full, untruncated SHA-256 of the key
values. A generated column rather than an application-computed one so every
writer maintains it, existing rows are hashed by the ALTER itself, and no write
can disagree with its source columns.
Selected by the server's own error code, only after the direct index is refused:
Postgres and SQLite never refuse and are byte-identical to before. Non-unique
indexes stay refused — an index over a digest accelerates no lookup the planner
can reach without rewriting the read side.
The drift differ learns the shadow is driver-owned, so its orphan pass cannot
propose dropping the column that carries a live constraint.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W6HFzyH98W1YaQXhJUJt6o
* test(driver-sql): move #11374's refusal pins to the non-unique case
#11627 made a UNIQUE index over an unkeyable column expressible — carried on a
hash-shadow column — so the two pins that asserted "unkeyable ⇒ refused" for
UNIQUE objects were pinning a branch the ruling deliberately replaced. Rewritten
rather than deleted or silenced.
The refusal is not gone: it is the disposition for a NON-UNIQUE unkeyable index,
where a digest serves no lookup the planner can reach. Both refusal pins keep a
live subject via new non-unique fixtures, and a new pin asserts the unique cases
land on a shadow whose key part reports no sub_part — so the constraint moving
onto a shadow cannot quietly become the prefix constraint the ruling rejected.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W6HFzyH98W1YaQXhJUJt6o
* fix(driver-sql): name a shadow-carried duplicate instead of MySQL's binary digest
Once uniqueness is enforced over a SHA-256 shadow, ER_DUP_ENTRY quotes the raw
digest and names the shadow index, so a genuine duplicate and a digest collision
are indistinguishable from the error alone and neither says which value
conflicted. `create` now resolves it with one read on the failure path: a row
matching the source columns is a real duplicate, named in the declared terms; no
such row is a collision, named as such and asked to be reported.
Wired into `create` only — `update` issues through three paths with no shared
catch, and every flow in this repo that writes these columns inserts. Named in
the docblock rather than left to be discovered.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W6HFzyH98W1YaQXhJUJt6o
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent dd391ce commit 107bb4b
5 files changed
Lines changed: 791 additions & 15 deletions
File tree
- .changeset
- packages/drivers/driver-sql/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
327 | 327 | | |
328 | 328 | | |
329 | 329 | | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
330 | 360 | | |
331 | 361 | | |
332 | 362 | | |
| |||
838 | 868 | | |
839 | 869 | | |
840 | 870 | | |
| 871 | + | |
| 872 | + | |
| 873 | + | |
| 874 | + | |
841 | 875 | | |
842 | 876 | | |
843 | 877 | | |
| |||
0 commit comments