[wrangler] fix: normalize CRLF before sending D1 commands to the remote query API - #15044
[wrangler] fix: normalize CRLF before sending D1 commands to the remote query API#15044stareezy-1 wants to merge 2 commits into
Conversation
The D1 query API splits multi-statement SQL on ';' server-side and mishandles CRLF line endings inside compound statements such as a CREATE TRIGGER ... BEGIN ... END; body, producing 'incomplete input: SQLITE_ERROR'. wrangler d1 migrations apply --remote sends the whole migration (plus the tracking INSERT) as one command string, so CRLF migrations with triggers failed while the same bytes via the import-based execute --remote --file succeeded. Normalize CRLF to LF in the command path before sending. Closes cloudflare#14991.
🦋 Changeset detectedLatest commit: 4527e2a The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Codeowners approval required for this PR:
Show detailed file reviewers
|
- Remove the conventional-commit prefix from the changeset title (REVIEW.md forbids type prefixes in changeset titles). - Re-indent the new execute test to the describe nesting level and apply oxfmt so the repository formatting check passes.
| // mishandles CRLF line endings inside compound statements such as a | ||
| // `CREATE TRIGGER ... BEGIN ... END;` body (issue #14991). Normalize | ||
| // to LF so the server receives the same input that works for LF files. | ||
| const sql = input.command?.replace(/\r\n/g, "\n"); |
There was a problem hiding this comment.
🟡 Windows-style line breaks inside quoted text values are silently changed when running against the remote database
Every carriage return in the SQL is stripped out (input.command?.replace(/\r\n/g, "\n") at packages/wrangler/src/d1/execute.ts:510) before the statement is sent, so text values that intentionally contain Windows line breaks are stored differently on the remote database than locally.
Impact: Data inserted or updated through remote commands or migrations loses its carriage returns, producing values that differ from the same command run locally.
Blanket replacement also rewrites string literals, not just statement separators
The replacement is applied to the whole command text, including the inside of quoted SQL string literals. For example wrangler d1 execute db --remote --command "INSERT INTO t(msg) VALUES ('a\r\nb')" (and any migration file with CRLF-containing literals applied via packages/wrangler/src/d1/migrations/apply.ts:158-165) stores a\nb remotely. The local path at packages/wrangler/src/d1/execute.ts:340 does no such normalization, so local and remote execution of identical SQL now diverge. A narrower fix would normalize only outside of quoted literals (e.g. reuse the existing tokenizer in packages/wrangler/src/d1/splitter.ts).
Prompt for agents
The remote query path in packages/wrangler/src/d1/execute.ts normalizes CRLF to LF across the entire command string. This also rewrites the contents of quoted SQL string literals, so text values containing Windows line breaks are silently stored with LF on the remote database, while the local path (same file, around line 340) leaves them untouched — local and remote execution of the same SQL now produce different stored data. Consider normalizing only line endings that are outside of string literals/comments, e.g. by reusing the SQL tokenizer in packages/wrangler/src/d1/splitter.ts, or otherwise limiting the normalization to statement whitespace.
Was this helpful? React with 👍 or 👎 to provide feedback.
Fixes #14991
wrangler d1 migrations apply --remotefailed withincomplete input: SQLITE_ERROR [7500]whenever a migration file had CRLF line endings and contained aCREATE TRIGGER ... BEGIN ... END;body — the default situation for Windows checkouts withcore.autocrlf=true.Root cause:
migrations apply --remotesends the whole migration (plus the trackingINSERT) as onesqlstring to the D1/queryendpoint, which splits multi-statement SQL on;server-side and mishandles CRLF inside compound statement bodies. The identical bytes succeed viaexecute --remote --filebecause that path uses the D1 import API; the client-side splitter is not involved in the command path (verified against the isolation matrix in the issue: only CRLF + trigger +migrations apply --remotefails).Fix: normalize CRLF to LF in the remote command path before sending to the query API (
input.command.replace(/\r\n/g, "\n")), so the server receives the same input that already works for LF files.Note
This is a contribution from an AI agent: stareezy-1.