Skip to content

v0.9.0

Choose a tag to compare

@github-actions github-actions released this 15 Apr 21:20
· 516 commits to main since this release
7760f0c

⚠️ This release has been yanked from crates.io

v0.9.0 contains two critical bugs that prevent Always Encrypted from
functioning:

  1. LOGIN7 ibExtension pointer indirection — the feature extension
    wire format was wrong per MS-TDS §2.2.6.4. SQL Server read garbage as
    a u32 offset and dropped the connection with no diagnostic. Affected
    every AE-enabled connection attempt in v0.5.x through v0.9.x.
  2. EncryptionContext provider loss under Config cloneArc::try_unwrap
    fails when refcount > 1 (which happens on every retry/redirect),
    silently dropping all registered key store providers. Every CEK lookup
    failed as KeyStoreNotFound.

Both are fixed in v0.10.0.
If you were using or evaluating Always Encrypted, upgrade to v0.10.0.

Non-AE features in v0.9.0 functioned correctly, but upgrading is
recommended regardless for the connection string, performance, and bulk
insert improvements shipped in v0.10.0. See
CHANGELOG
for details.


Added

  • Always Encrypted decryption integration — wired CryptoMetadata parsing and AEAD_AES_256_CBC_HMAC_SHA256 decryption into query execution. Encrypted columns are transparently decrypted when Column Encryption Setting=Enabled is set in the connection string. Decryption is supported across all response readers: query(), call_procedure(), and query_multiple(). CEK resolution is performed asynchronously at ColMetaData time; per-row decryption is synchronous in the hot path.
  • Native Windows SSPI authentication — integrated auth (Integrated Security=true) now uses the native Windows SSPI subsystem (secur32.dll) instead of sspi-rs on Windows, supporting all account types including Microsoft Accounts, domain accounts, and local accounts without explicit credentials (closes #65)
  • FILESTREAM BLOB access (Windows only, filestream feature) — async read/write access to SQL Server FILESTREAM data via OpenSqlFilestream. FileStream implements AsyncRead + AsyncWrite for tokio compatibility. Accessed via Client<InTransaction>::open_filestream() or the low-level FileStream::open() API. Requires the Microsoft OLE DB Driver for SQL Server at runtime. (closes #67)
  • 34 new unit tests for tds-protocol token parsing (ReturnValue, ReturnStatus, DoneProc, DoneInProc, ServerError, multi-token streams) and mssql-auth error/provider classification
  • ADO.NET connection string conformance — comprehensive parser rewrite:
    • Quoted value supportPassword="my;complex;pass" and Password='it''s complex' now work per ADO.NET spec. Previously, passwords with semicolons were silently truncated.
    • tcp: prefix strippingServer=tcp:host.database.windows.net,1433 (Azure Portal format) now works. np: and lpc: prefixes return clear errors.
    • New Server aliasesAddr, Address, Network Address now accepted per Microsoft docs
    • Timeout alias for Connect Timeout per ADO.NET spec
    • ApplicationIntentReadOnly/ReadWrite for AlwaysOn AG read-only routing, wired to LOGIN7 TypeFlags READONLY_INTENT bit
    • Workstation ID / WSID — client machine name for audit trails via sys.dm_exec_sessions.host_name
    • Current Language / Language — session language, wired to LOGIN7 Language field
    • ConnectRetryCount / ConnectRetryInterval — wired to RetryPolicy
    • Pool keywords (Max Pool Size, Min Pool Size, Pooling, etc.) — recognized with info-level guidance to use PoolConfig
    • 30+ known ADO.NET keywords recognized at info level instead of silently ignored at debug level
    • Boolean validation — invalid values like TrustServerCertificate=banana now return errors instead of silently defaulting to false
    • Encrypt=Mandatory/Optional — Microsoft.Data.SqlClient v5+ aliases for true/false now accepted
    • Case-insensitive protocol prefixesTcp:, TCP:, tCp: all stripped correctly (not just tcp: and TCP:)
    • Empty values reset optional fieldsDatabase=; now results in None instead of Some(""), matching ADO.NET reset-to-default behavior

Changed

  • unwrap() audit — replaced ~20 production unwrap() calls with expect() containing descriptive context strings across library code
  • panic! audit — audited all panic-family macros (panic!, unreachable!, unimplemented!, todo!) in library code; converted one unjustified unreachable! to proper error propagation
  • Updated LIMITATIONS.md to reflect v0.8.0+ features (stored procedures, SQL Browser, pool health checks, Always Encrypted)

Fixed

  • Always Encrypted in procedures and multi-result queries — decryption was missing from read_procedure_result() and read_multi_result_response(), causing encrypted columns to return raw ciphertext instead of plaintext when accessed via call_procedure() or query_multiple()
  • windows-certstore compilation errors — resolved 9 compilation errors in the Always Encrypted Windows Certificate Store provider caused by API changes in the windows 0.62 crate (#83)
  • Silent error swallowing — replaced filter_map(|r| r.ok()) in test code with explicit unwrap() so failures are visible; documented intentional best-effort parsing in bulk insert type resolution
  • (local) host aliasServer=(local)\SQLEXPRESS now correctly resolves to 127.0.0.1, matching ADO.NET behavior. Previously only . was normalized to localhost (#66)
  • LOGIN7 HostName field — now sends the actual client machine hostname (or Workstation ID if configured) instead of the server hostname. Previously sys.dm_exec_sessions.host_name showed the server's own name. Per MS-TDS spec, the LOGIN7 HostName field is "the name of the client machine."

What's Changed

Full Changelog: v0.8.0...v0.9.0