Skip to content

fix: send the PLP terminator when an NVarChar or VarBinary length is missing - #1811

Merged
arthurschreiber merged 1 commit into
tediousjs:masterfrom
dhensby:fix/plp-terminator
Oct 5, 2026
Merged

arthurschreiber merged 1 commit into
tediousjs:masterfrom
dhensby:fix/plp-terminator

Conversation

@dhensby

@dhensby dhensby commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Fixes #1810.

Since 20.3.0 (#1774), NVarChar and VarBinary write the PLP header unless length <= maximumLength, but the PLP terminator only if length > maximumLength. A length that is neither, such as undefined for a TVP column whose length was left out, or NaN, gets a max TYPE_INFO and PLP header but no terminator, and the server fails the request with "The stream ended unexpectedly". VarChar decides both in one if/else and isn't affected. (node-mssql's length: 'max' took the same path; node-mssql now converts that on its side.)

Changes

  • Both types decide the header and the terminator from the same test, so such a value is sent as a terminated max value again: what writeTypeInfo declares, and what 20.2.3 sent.
  • Bytes for numeric lengths are unchanged. I compared whole payloads against 20.2.3 for callProcedure (input and output), execSql, execute, TVPs and bulk load, across lengths undefined, null, 0, 1, the maximum, maximum + 1, 65535, Infinity, NaN, 'max' and numeric strings, with null, empty, short, surrogate-pair and over-maximum values: every case matches 20.2.3 byte for byte.

This is deliberately minimal so it can ship as a 20.3.x patch. #1780 replaces writeValue with compileWriter, whose single if/else already handles this, so #1780 can supersede it: when rebasing #1780, take its side of the two writeValue hunks, and the new tests pass unchanged on top of it.

Tests

  • test/unit/data-type.ts: NVarChar (string) and VarBinary (Buffer) values with length: undefined and length: NaN serialize as PLP values ending with the terminator. These four fail on master. The writeTypeInfo tests also pin that both lengths are declared as max; those assertions already pass on master.
  • test/integration/tvp-test.ts: returns the same data when string column lengths are left out sends a TVP whose VarChar and NVarChar columns have no length. On master it fails with an AggregateError wrapping "The stream ended unexpectedly". The shared test type has no binary column, so VarBinary is covered by the unit tests; I also checked a TVP VarBinary column without a length and execSql with length: NaN by hand against SQL Edge (both fail on master, both work with this change and on 20.2.3).

Checks

  • npm run lint (eslint and tsc)
  • npm run build
  • Unit tests: 603 passing
  • Integration tests against Azure SQL Edge: all passing except the UDT test in datatypes-in-results-test.ts, which needs CLR, which SQL Edge doesn't have
  • commitlint was not run: it isn't installed in the dev dependencies. The commit message follows the conventional format.

🤖 Generated with Claude Code

…missing

NVarChar and VarBinary wrote a value's PLP header unless its length was
`<= maximumLength`, but its PLP terminator only if the length was
`> maximumLength`. A length that is neither, such as `undefined` for a
TVP column whose length was left out, or `NaN`, got the `max` TYPE_INFO
and PLP header but no terminator, and the server rejected the request
with "The stream ended unexpectedly".

Decide the header and the terminator from the same test, so these
values are sent as terminated `max` values again, as `writeTypeInfo`
declares them and as before 20.3.0. Numeric lengths serialize exactly
as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@arthurschreiber

Copy link
Copy Markdown
Collaborator

Thanks for catching this! ❤️

@arthurschreiber
arthurschreiber merged commit 5446adb into tediousjs:master Oct 5, 2026
28 of 29 checks passed
@dhensby
dhensby deleted the fix/plp-terminator branch October 5, 2026 07:57
@github-actions

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 20.3.5 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NVarChar/VarBinary max values sent without a PLP terminator when length is omitted (TVP) or non-numeric — regression in 20.3.0

2 participants