Sub-issue of #247 (axis: Precomputation). ⚠️ Overlaps #197 — coordinate before starting.
Problem statement
The hot TokenType::NbcRow arm does vec![0u8; bitmap_len] per row. On the PoC benchmark that is ~1M allocate/free pairs for a value that is 6 bytes (48 columns → ceil(48/8)).
Proposed solution
Read the bitmap into a fixed-size stack array, with a heap fallback for oversized (malformed) COLMETADATA.
Feasibility: ✅ proven. Prototyped in 56a836f6, green on all six configs in #247. This is by far the cheapest item in the set.
Findings
Affected crate
mssql-tds
Alternatives considered
SmallVec. Adds a dependency for something a plain array plus a fallback handles.
Reuse a per-result-set scratch buffer. Needs plumbing and lifetime management for zero benefit over a stack array of a statically known maximum.
Additional context
Related but separate, and more expensive on the cursor path: read_row_header does columns.to_vec() per paused row, cloning every column_name: String. Tracked as a cleanup in #247 — far larger than the 6 bytes this item saves, though it is on the pause/resume path rather than the bulk-scan path.
Nothing here is benchmarked. This PR must carry its own measurement.
Sub-issue of #247 (axis: Precomputation).⚠️ Overlaps #197 — coordinate before starting.
Problem statement
The hot
TokenType::NbcRowarm doesvec![0u8; bitmap_len]per row. On the PoC benchmark that is ~1M allocate/free pairs for a value that is 6 bytes (48 columns →ceil(48/8)).Proposed solution
Read the bitmap into a fixed-size stack array, with a heap fallback for oversized (malformed) COLMETADATA.
Feasibility: ✅ proven. Prototyped in
56a836f6, green on all six configs in #247. This is by far the cheapest item in the set.Findings
No plumbing and no per-result-set state is needed. SQL Server caps a result set at 4096 columns, so
[u8; 512]covers every legal shape. The heap fallback exists only to stop a malformed COLMETADATA from indexing out of bounds — it is a safety valve, not a real code path.Only one of the two NBCROW sites can be converted.
read_row_header's bitmap gets moved intoRowPauseState.nbc_null_bitmap, so it must stay owned. The convertible site is the hot asyncTokenType::NbcRowarm intoken_stream.rs.TokenType::NbcRowarm there still callsvec![0u8; bitmap_len]. Whoever reviews or ports POC: reduce per-row cost in the TDS row decode path #238 should verify against the async path specifically — the deck's claim overstates what the PoC actually does.Overlaps Sans-I/O TDS core (4c/N): invert the NBCROW null-bitmap read to sync #197, which does the same thing inside the sans-I/O stack. Either land this standalone and let Sans-I/O TDS core (4c/N): invert the NBCROW null-bitmap read to sync #197 rebase, or fold it in. Decide before starting.
Affected crate
mssql-tds
Alternatives considered
SmallVec. Adds a dependency for something a plain array plus a fallback handles.Reuse a per-result-set scratch buffer. Needs plumbing and lifetime management for zero benefit over a stack array of a statically known maximum.
Additional context
Related but separate, and more expensive on the cursor path:
read_row_headerdoescolumns.to_vec()per paused row, cloning everycolumn_name: String. Tracked as a cleanup in #247 — far larger than the 6 bytes this item saves, though it is on the pause/resume path rather than the bulk-scan path.Nothing here is benchmarked. This PR must carry its own measurement.