Skip to content

feat!: drop support for TDS 7.1 - #1769

Draft
arthurschreiber wants to merge 2 commits into
masterfrom
drop-tds-7-1
Draft

feat!: drop support for TDS 7.1#1769
arthurschreiber wants to merge 2 commits into
masterfrom
drop-tds-7-1

Conversation

@arthurschreiber

Copy link
Copy Markdown
Collaborator

TDS 7.1 is only spoken by SQL Server 2000, which left extended support in April 2013. It was deprecated with a runtime warning in #1768; this PR removes it, along with every pre-7.2 code path - tedious was the last maintained SQL Server driver still speaking this protocol version. The minimum supported protocol version becomes TDS 7.2 (SQL Server 2005).

What is removed

  • The client-side emulated transaction state. On pre-7.2 connections, beginTransaction/commitTransaction/rollbackTransaction/saveTransaction were emulated as SQL batches with hand-maintained bookkeeping. That bookkeeping was unfixably wrong around cancellation (see the discussion on fix: only update emulated transaction state when the statement succeeds #1767 - the outcome of a canceled transaction statement is indeterminate at the protocol level). All of it is gone: the SQL-batch wrappers, the private transactionDepth and isSqlBatch properties, and the batch-error transaction reset in the response handling. Transaction state is now always ENVCHANGE-driven.
  • The pre-7.2 wire format variants: 32-bit DONE row counts, 16-bit ERROR/INFO line numbers, 16-bit column metadata user types, single-part table names (ColumnMetadata#tableName is now always string[] when present), and the conditional ALL_HEADERS prefix on SQL batch and RPC requests (now always written).
  • The TDS 7.1 deprecation warning (TEDIOUS_DEP_TDS71) added in feat: deprecate TDS 7.1 support #1768, which can no longer fire.

New behavior

config.options.tdsVersion is now validated against the supported versions map. Configuring 7_1 - or any unknown version string - throws a RangeError naming the supported values, instead of silently sending a garbage protocol version in the LOGIN7 packet. A server that answers the LOGIN7 request with a TDS 7.1 LOGINACK gets the existing "Server responded with unknown TDS version" error.

Sequencing - why this is a draft

🤖 Generated with Claude Code


Generated by Claude Code

TDS 7.1 is only spoken by SQL Server 2000, which left extended support
in April 2013. It was deprecated with a runtime warning in #1768.
Removing it deletes every pre-7.2 code path:

- the client-side emulated transaction state (the SQL batch based
  `BEGIN`/`COMMIT`/`ROLLBACK`/`SAVE TRAN` wrappers, the private
  `transactionDepth` and `isSqlBatch` bookkeeping, and the
  batch-error transaction reset)
- the pre-7.2 wire format variants (32-bit `DONE` row counts, 16-bit
  `ERROR`/`INFO` line numbers, 16-bit column metadata user types,
  single-part table names, and the conditional `ALL_HEADERS` prefix
  on SQL batch and RPC requests)
- the TDS 7.1 deprecation warning itself, which can no longer fire

`config.options.tdsVersion` is now validated against the supported
versions, so configuring `7_1` (or any unknown version) fails with a
clear `RangeError` instead of silently sending a garbage protocol
version in the `LOGIN7` packet.

BREAKING CHANGE: Support for TDS 7.1 (SQL Server 2000) has been
removed. The minimum supported protocol version is TDS 7.2
(SQL Server 2005). Configuring `options.tdsVersion` with an
unsupported value now throws a `RangeError`.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@claude

claude Bot commented Aug 31, 2026

Copy link
Copy Markdown

Review

Clean, well-scoped removal — the diff matches the PR description closely and I didn't find any leftover TDS 7.1 code paths (grep for 7_1, isSqlBatch, transactionDepth, tds71 across src/ and test/ comes back empty).

Correctness

  • connection.ts: the new versions[config.options.tdsVersion] === undefined check (src/connection.ts:1700) correctly rejects '7_1' and any other unrecognized version string with a RangeError that enumerates the supported values — good UX improvement over the old silent-garbage-protocol-version behavior.
  • Removing transactionDepth/isSqlBatch and the associated SQL-batch transaction emulation looks safe: the 7.2+ ENVCHANGE-driven inTransaction bookkeeping in transaction()/commitTransaction()/rollbackTransaction() (src/connection.ts:3095-3150) didn't depend on those fields, so nothing was left dangling.
  • colmetadata-token-parser.ts: narrowing tableName from string | string[] | undefined to string[] | undefined is a real (intentional, semver-major) type-level breaking change — confirmed no downstream code in src/ assumed a plain string.
  • bulk-load.ts, sqlbatch-payload.ts, rpcrequest-payload.ts, done-token-parser.ts, infoerror-token-parser.ts, metadata-parser.ts: all straightforward "always take the 7.2+ branch" simplifications, look correct.

Test coverage gap

  • The new RangeError thrown for an invalid/unknown tdsVersion (src/connection.ts:1700-1702) has no unit test. test/unit/connection-config-validation.ts only has a test for tdsVersion combined with Azure AD auth, not for the new validation itself. Since this is called out explicitly as new behavior in the PR description, it'd be worth a small test asserting e.g. new Connection({..., options: { tdsVersion: '7_1' }}) throws a RangeError mentioning the supported versions.

Minor / non-blocking

  • examples/minimal.js:58 still has a comment // In SQL Server 2000 you may need: connection.execSqlBatch(request); — stale now that SQL Server 2000 (TDS 7.1) support is being dropped. Not part of the diff, so feel free to leave for a follow-up.

Sequencing note carried over from the description: this is correctly marked draft pending #1766 and the soak time for the #1768 deprecation warning — no action needed from me there, just confirming I read that context.

Nice, focused cleanup overall — no security or performance concerns, and the removed transaction-emulation code was a good thing to delete given the cancellation-correctness issues described in #1767.

@claude

claude Bot commented Aug 31, 2026

Copy link
Copy Markdown

Review

Nicely scoped removal — the diff matches the description well and each deleted branch corresponds to a real pre-7.2 code path. A few things worth a look before this comes out of draft:

Bug: appveyor.yml still exercises TDS 7.1

.github/workflows/nodejs.yml had its TEDIOUS_TDS_VERSION: 7_1 integration run removed, but appveyor.yml (lines 70-72) still sets $env:TEDIOUS_TDS_VERSION = '7_1' and runs test-integration. With the new validation in connection.ts (versions[config.options.tdsVersion] === undefinedRangeError), that AppVeyor job will now fail outright as soon as Connection is constructed with tdsVersion: '7_1'. This should be trimmed the same way the GitHub Actions workflow was.

Missing test coverage for the new validation behavior

The PR's headline new behavior — config.options.tdsVersion throwing a RangeError for 7_1 or any unknown version instead of silently accepting it — isn't covered by a unit test. test/unit/connection-config-validation.ts already has patterns for TypeError assertions on tdsVersion (see the "bad tds version for with azure ad" test around line 89), so a companion test asserting new Connection({ ...options: { tdsVersion: '7_1' } }) throws RangeError with the expected message would pin down this behavior and guard against regressions.

Minor: dead parameter

In src/token/colmetadata-token-parser.ts, readTableName(buf, offset, metadata, options) no longer uses options now that the tdsVersion < '7_2' branch is gone. ESLint won't flag it (args: 'none'), but since this PR is specifically about scrubbing pre-7.2 branching, it'd be worth dropping the now-unused parameter for consistency with the rest of the cleanup.

What looks solid

  • tds-versions.ts / loginack-token-parser.ts / handler.ts: a server that negotiates TDS 7.1 now correctly falls through to versions[tdsVersionNumber] === undefinedtoken.tdsVersion falsy → the existing "Server responded with unknown TDS version" ETDS error path. Verified this wiring end-to-end.
  • Transaction state removal (transactionDepth, isSqlBatch, the SQL-batch-emulated BEGIN/COMMIT/ROLLBACK/SAVE TRAN wrappers) is fully removed with no dangling references anywhere in src/ or test/.
  • ColumnMetadata#tableName narrowing from string | string[] | undefined to string[] | undefined is consistent — no remaining call site assumes the single-string shape.
  • Wire-format changes (32-bit vs 64-bit DONE row counts, 16/32-bit line numbers, unconditional ALL_HEADERS) all correctly collapse to the TDS ≥ 7.2 branch with no leftover conditionals.
  • Good catch documenting why the client-side transaction emulation was unfixable (indeterminate outcome of a canceled transaction statement at the protocol level) rather than just deleting it silently.

Nothing here blocks the general direction — just the AppVeyor config and a test for the new validation before this is ready to come out of draft.

Support for TDS 7.1 has been removed, so requesting it in the test
configuration would now fail validation. The remaining integration
test runs (TDS 7.2 through 7.4) cover all supported protocol versions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@claude

claude Bot commented Aug 31, 2026

Copy link
Copy Markdown

Review

Clean removal — I traced the TDS-version-gated branches across connection.ts, bulk-load.ts, rpcrequest-payload.ts, sqlbatch-payload.ts, metadata-parser.ts, and the done/colmetadata/infoerror token parsers, and didn't find any leftover '7_1'/tds71/pre-7.2 references, dead code, or now-unreachable branches. The versionsByValue lookup naturally makes an unrecognized LOGINACK version (including a hypothetical 7.1 response) fall into the existing "Server responded with unknown TDS version" (ETDS) error path, so that failure mode is still handled without new code.

Correctness

  • RangeError validation in connection.ts (versions[config.options.tdsVersion] === undefined) is a solid replacement for silently sending garbage in LOGIN7, and the error message enumerates the valid values, which is friendly for anyone upgrading from '7_1'.
  • The ColumnMetadata#tableName type narrowing to string[] | undefined (dropping the pre-7.2 single-string variant) is correctly threaded through readTableName — no remaining call site expects a bare string.
  • Transaction state is now purely ENVCHANGE-driven; inTransaction continues to be set from onBeginTransaction/onCommitTransaction/onRollbackTransaction in token/handler.ts, so removing transactionDepth/isSqlBatch doesn't leave a gap.

Test coverage gap

  • test/unit/connection-config-validation.ts doesn't gain a case for the new RangeError behavior. There's an existing 'bad tds version for with azure ad' test, but it sets tdsVersion = '7_2' (a valid value) to test an unrelated AD-auth incompatibility — it doesn't exercise the new "unsupported version string" branch at all. Given this is new, user-facing validation behavior (and a breaking change for anyone still passing '7_1'), it'd be worth adding a unit test asserting new Connection(config) throws a RangeError (and ideally checking the message content) for both '7_1' and an arbitrary garbage string. The deleted test/unit/tds71-deprecation-test.ts had good coverage of the old warning behavior, so this fills the equivalent gap for the new behavior it replaces.
  • No integration/unit test appears to directly assert the "Server responded with unknown TDS version" path is still reached for a 7.1 LOGINACK, though this is a pre-existing gap, not introduced by this PR.

Security
No concerns — this is protocol surface reduction, and the new validation is strictly more defensive (rejects invalid input early instead of forwarding it to the wire).

Style/best practices
Consistent with the rest of the codebase; the CI and appveyor.yml/README updates are appropriately scoped to match the code changes. Nice touch keeping the commit split into the feature removal and the follow-up CI cleanup.

Sequencing note
The PR description flags this correctly as a draft pending #1766 and soak time for the #1768 deprecation warning — no action needed here, just confirming that context matches what's in the diff.

Overall: the removal is thorough and mechanically sound. The one thing I'd want before merging is a unit test for the new RangeError validation path.

@codecov

codecov Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 80.00000% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.60%. Comparing base (3aba7c7) to head (e282191).

Files with missing lines Patch % Lines
src/connection.ts 0.00% 1 Missing and 1 partial ⚠️
src/bulk-load.ts 75.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1769      +/-   ##
==========================================
- Coverage   80.86%   80.60%   -0.27%     
==========================================
  Files          90       90              
  Lines        4887     4842      -45     
  Branches      929      908      -21     
==========================================
- Hits         3952     3903      -49     
- Misses        638      642       +4     
  Partials      297      297              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant