fix(tables): compare order_key bytewise (COLLATE "C") to stop insert collation errors#4908
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview Migration 0228 sets
Adds Adds fractional-indexing tests that lock in bytewise ordering (append, prepend across Reviewed by Cursor Bugbot for commit e537aa5. Bugbot is set up for automated code reviews on this repo. Configure here. |
|
@greptile review |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit f14bde6. Configure here.
Greptile SummaryThis PR fixes a production insert crash caused by
Confidence Score: 5/5Safe to merge — the migration, neighbor-lookup hardening, and repair script all address the root cause cleanly with no regressions in existing call paths. The migration is a single ALTER with no data movement; the service change is a narrowly scoped query logic fix with correct null handling in both the flag-on and flag-off code paths; the repair script is idempotent and isolated behind the same per-table advisory lock the app uses; and the new tests directly cover the Z/a boundary that the en_US locale inverts. No files require special attention. The schema.ts comment correctly documents the Drizzle collation limitation so future maintainers won't be surprised if drizzle-kit generate omits the COLLATE "C" clause. Important Files Changed
Reviews (3): Last reviewed commit: "improvement(tables): make repair-script ..." | Re-trigger Greptile |
|
Good catch — fixed in 075f3fe. The detection query was ordering the window by |
Greptile SummaryThis PR fixes a production-only collation bug where
Confidence Score: 4/5The core fix — migration 0228 + the neighbour-query change — is correct and safe to deploy; the only rough edge is in the one-off repair script's dry-run output. The migration, service change, and tests are all well-reasoned and internally consistent. The advisory lock key in the repair script matches the one in the application. The one concrete issue is that the repair script's --dry-run output says 're-keyed' and 'Repair complete.' with the same stat format as a live run — an operator following the PR's own instructions ('dry-run to size, then for real') could read the dry-run summary as confirmation the repair already completed and skip the real run. It does not affect the migration or service fix itself. apps/sim/scripts/repair-table-order-key-collation.ts — the dry-run stat labels and completion message. Important Files Changed
Sequence DiagramsequenceDiagram
participant App
participant DB as Postgres (COLLATE "C")
participant Lib as fractional-indexing lib
Note over DB: Migration 0228: order_key SET DATA TYPE text COLLATE "C"
App->>DB: acquireRowOrderLock(tableId)
App->>DB: SELECT anchor row (orderKey, position)
alt afterRowId insert
App->>DB: "SELECT orderKey WHERE orderKey > anchorKey ORDER BY orderKey ASC LIMIT 1"
DB-->>App: nextKey (bytewise-correct neighbour)
App->>Lib: keyBetween(anchorKey, nextKey)
Lib-->>App: "newKey (always anchorKey < newKey < nextKey)"
else beforeRowId insert
App->>DB: "SELECT orderKey WHERE orderKey < anchorKey ORDER BY orderKey DESC LIMIT 1"
DB-->>App: prevKey (bytewise-correct neighbour)
App->>Lib: keyBetween(prevKey, anchorKey)
Lib-->>App: "newKey (always prevKey < newKey < anchorKey)"
end
App->>DB: INSERT row with newKey
Note over App,DB: Repair script (one-off, post-migration)
App->>DB: "SELECT DISTINCT table_id WHERE order_key COLLATE C >= next_key COLLATE C"
loop each mis-ordered table
App->>DB: pg_advisory_xact_lock(user_table_rows_pos:tableId)
App->>DB: SELECT id ORDER BY position, id
App->>Lib: nKeysBetween(null, null, count)
Lib-->>App: fresh evenly-spaced key run
App->>DB: "UPDATE rows SET order_key = new_key (chunked)"
end
Reviews (2): Last reviewed commit: "fix(tables): detect mis-keyed tables by ..." | Re-trigger Greptile |
|
@greptile review |

Summary
user_table_rows.order_keytoCOLLATE "C"(migration 0228) so Postgres compares fractional-index keys bytewise, matching the in-house fractional-indexing library. The prod DB defaulten_US.UTF-8sorts lowercase before uppercase (the opposite of theZ < aASCII boundary the keys rely on), somax()/neighbor lookups returned out-of-order bounds andgenerateKeyBetweenthrewa >= bon insert (and rows displayed out of order). Local DBs default toC.UTF-8, so it never reproduced locally.repair-table-order-key-collation.tsthat re-keys any table with bytewise inversions/duplicates from(position, id)order, under the per-table advisory lock (idempotent,--dry-run). Separate from the NULL backfill, which already ran.resolveInsertByNeighborto anchor on the next/prev distinct key so a stray duplicate can never throw.Z/aboundary that en_US inverts.Type of Change
Testing
Tested manually.
bun run lintclean,bun run check:api-validation:strictpassed,tsc --noEmitclean, fractional-indexing tests (5) + table suite (196) pass,drizzle-kit checkclean.Operational
Run after deploy: apply migration 0228, then
repair-table-order-key-collation.ts --dry-runto size, then for real. Migration + neighbor fix stop the error independent of theTABLES_FRACTIONAL_ORDERINGflag; the repair is pre-cleaning needed before the flag is enabled.Checklist