Skip to content

Add experimental TDS performance baseline - #303

Draft
Saurabh Singh (saurabh500) wants to merge 1 commit into
mainfrom
saurabh500-experimental-tds-perf-baseline
Draft

Add experimental TDS performance baseline#303
Saurabh Singh (saurabh500) wants to merge 1 commit into
mainfrom
saurabh500-experimental-tds-perf-baseline

Conversation

@saurabh500

@saurabh500 Saurabh Singh (saurabh500) commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Description

Creates an experimental, independently reviewable performance baseline on current main by duplicating the PR-level changes from #291 and the updated #299.

  • forwards ResultSet row reads through native futures and keeps row-fetch futures within the size budget
  • expands synchronous buffered probes for fixed-width scalar decoding, falling back to async reads only when data is unavailable
  • preserves current main behavior unrelated to the source changes

This is a separate performance exploration. It does not replace, close, retarget, or modify #291 or #299, and it is not part of stack #287.

Standalone adaptation: #291's generic RowWriter dispatch depends on AnyTransport from its separate native-stack prerequisite. Current main intentionally stores Box<dyn TdsTransport>, so this layer retains the boxed transport and dynamic writer boundary while preserving #291's native ResultSet future forwarding, future-size checks, and explicit error cleanup.

Related Issues

Source context only (does not close either PR):

Checklist

  • cargo bfmt passes
  • cargo bclippy passes
  • cargo btest passes (1666/1670 mssql-tds library tests pass; four unrelated certificate tests cannot find the repository's absent tests/test_certificates/valid_cert.{pem,der} fixtures)
  • New/changed functionality has tests
  • Public API changes are documented

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 5bcfe214-06ab-401e-9b36-bbba2e053d19
@github-actions

Copy link
Copy Markdown

📊 Code Coverage Report

🔥 Diff Coverage

98%

🎯 Overall Coverage

91.6%

📦 Project: mssql-tds + mssql-odbc + mssql-py-core
ℹ️ Note: diff coverage is reported, not enforced.


Diff Coverage

Diff: main...HEAD, staged and unstaged changes

  • mssql-tds/src/connection/tds_client.rs (94.9%): Missing lines 3631-3633,3666
  • mssql-tds/src/connection/transport/buffers.rs (100%)
  • mssql-tds/src/connection/transport/network_transport.rs (100%)
  • mssql-tds/src/datatypes/decoder.rs (97.2%): Missing lines 866,1867,1873
  • mssql-tds/src/io/packet_reader.rs (100%)

Summary

  • Total: 441 lines
  • Missing: 7 lines
  • Coverage: 98%

mssql-tds/src/connection/tds_client.rs

  3627 
  3628         let metadata = Arc::clone(self.current_metadata.as_ref().unwrap());
  3629         let decryptor = match self.resolve_cell_decryptor(&metadata).await {
  3630             Ok(decryptor) => decryptor,
! 3631             Err(error) => {
! 3632                 self.abort_pending_prepare_capture();
! 3633                 return Err(error);
  3634             }
  3635         };
  3636         let parser_context = ParserContext::ColumnMetadata(metadata, decryptor);
  3637         loop {

  3662                     return Ok(true);
  3663                 }
  3664                 RowReadResult::RowPaused(_) | RowReadResult::PlpPaused(_) => {
  3665                     // DecodeAll never pauses; a pause here is a protocol/logic error.
! 3666                     self.abort_pending_prepare_capture();
  3667                     return Err(crate::error::Error::ProtocolError(
  3668                         "Unexpected pause while decoding a full row (ColumnPolicy::DecodeAll)"
  3669                             .to_string(),
  3670                     ));

mssql-tds/src/datatypes/decoder.rs

  862         let value: ColumnValues = match byte_len {
  863             1 => ColumnValues::TinyInt(read_sync_first!(reader, try_read_byte, read_byte)),
  864             2 => ColumnValues::SmallInt(read_sync_first!(reader, try_read_int16, read_int16)),
  865             4 => ColumnValues::Int(read_sync_first!(reader, try_read_int32, read_int32)),
! 866             8 => ColumnValues::BigInt(read_sync_first!(reader, try_read_int64, read_int64)),
  867             0 => ColumnValues::Null,
  868             _ => {
  869                 return Err(crate::error::Error::from(Error::new(
  870                     std::io::ErrorKind::InvalidData,

  1863             // Allocates buffer and reads data
  1864             // Creates SqlString with appropriate encoding type
  1865             // NULL handling works (textptr_len = 0)
  1866             // LCID-based decoding implemented (see sql_string.rs)
! 1867             let text_ptr_len = read_sync_first!(reader, try_read_byte, read_byte) as usize;
  1868 
  1869             let length = if text_ptr_len > 0 {
  1870                 const TIMESTAMP_BYTE_COUNT: usize = 8;
  1871                 reader.skip_bytes(text_ptr_len).await?;

  1869             let length = if text_ptr_len > 0 {
  1870                 const TIMESTAMP_BYTE_COUNT: usize = 8;
  1871                 reader.skip_bytes(text_ptr_len).await?;
  1872                 reader.skip_bytes(TIMESTAMP_BYTE_COUNT).await?;
! 1873                 read_sync_first!(reader, try_read_uint32, read_uint32) as usize
  1874             } else {
  1875                 // text_ptr_len == 0 means NULL value
  1876                 return Ok(ColumnValues::Null);
  1877             };


🔗 Quick Links

View Azure DevOps Build · Coverage Report

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