fix: resolve parameter lengths for all types that can resolve one - #1771
fix: resolve parameter lengths for all types that can resolve one#1771arthurschreiber wants to merge 1 commit into
Conversation
RPC request and bulk load parameter serialization only resolved a parameter's length when the type's id matched the legacy variable-length type id bit pattern ((type.id & 0x30) === 0x20). Per MS-TDS s2.2.5.4.2, that pattern holds for all variable-length type ids up to TDS 7.1, but not for the ids introduced in TDS 7.2 and later (XMLTYPE 0xF1, UDTTYPE 0xF0, JSONTYPE 0xF4, VECTORTYPE 0xF5). For a modern-id type with a length, the length was silently never resolved, producing corrupt type info (e.g. `Buffer.writeUInt16LE(NaN)` writing a zero length). Resolve lengths based on whether the type can resolve one instead, mirroring how precision and scale are already resolved. For all existing types this is behavior-preserving: every type with `resolveLength` has a legacy-pattern id today, and no type without `resolveLength` reads a resolved length. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fxv5h4UMCGJEpjgCKcAxug
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
ReviewSolid, well-scoped bug fix. Summary of what I checked: Correctness
Style
Test coverage
Minor observation (pre-existing, not introduced by this PR)
No performance or security concerns — this is a narrow protocol-serialization fix with no new I/O, allocation patterns, or attacker-controlled input handling beyond what already existed. Nice work tracking this down against the MS-TDS spec and validating against the full integration suite. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1771 +/- ##
==========================================
- Coverage 81.02% 81.01% -0.01%
==========================================
Files 92 92
Lines 4948 4946 -2
Branches 938 936 -2
==========================================
- Hits 4009 4007 -2
Misses 640 640
Partials 299 299 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
- `BulkLoad.addColumn` no longer gates length resolution on the legacy variable-length type id bit pattern, so the RPC and bulk load paths agree and #1771 is covered in full. - `resolveParameter` treats an explicitly specified length, precision or scale of 0 as specified instead of falling through to the type's resolver. Every existing resolver re-checked for an explicit value itself, so this changes no bytes for existing types; it removes the trap for a future type whose resolver does not. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fxv5h4UMCGJEpjgCKcAxug
Problem
RPC request and bulk load parameter serialization only resolve a parameter's length when the type's id matches the legacy variable-length type id bit pattern:
Validated against [MS-TDS] v20260617 s2.2.5.4.2 (Variable-Length Data Types): every BYTELEN/USHORTLEN/LONGLEN type id defined up to TDS 7.1 does match that pattern (
0x2X/0x6X/0xAX/0xEX— e.g.BIGVARBINARYTYPE 0xA5,NVARCHARTYPE 0xE7,TEXTTYPE 0x23), but the type ids introduced in TDS 7.2 and later do not:UDTTYPE 0xF0,XMLTYPE 0xF1,JSONTYPE 0xF4, andVECTORTYPE 0xF5all have(id & 0x30) === 0x30.For a modern-id type that has a length, the length is therefore silently never resolved, and its
generateTypeInfocomputes withundefined— concretely,Buffer.writeUInt16LE(NaN)writes a zero max length into the TYPE_INFO, which the server rejects with an opaque protocol error (Data type 0xF5 has an invalid data length or metadata length). This was discovered while implementing the SQL Server 2025vectortype (VECTORTYPE 0xF5, the first modern-id type with a length), where it broke RPC parameters and bulk load columns; thejsontype (JSONTYPE 0xF4) would hit the same landmine.Fix
Resolve lengths based on whether the type can resolve one (
type.resolveLength), mirroring howprecisionandscaleare already resolved in the same functions, in bothsrc/rpcrequest-payload.tsandsrc/bulk-load.ts.Behavior-preserving for all existing types, verified two ways:
resolveLength(Binary, Char, Image, NChar, NText, NVarChar, Text, UniqueIdentifier, VarBinary, VarChar) has a legacy-pattern id, and no type withoutresolveLengthreads a resolved length (the mask-matching N-types, date/time types, and sql_variant never consumeparam.length).New unit tests cover length resolution for a modern-id type, explicit-length precedence, and the unchanged legacy-type byte output.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Fxv5h4UMCGJEpjgCKcAxug
Generated by Claude Code