Bug Fixes
• SSH-tunnel / in-process forwarder deadlock (#604)
What changed: The driver now releases the GIL around blocking ODBC network round-trips that previously held it — the teardown path (SQLFreeHandle / SQLFreeStmt(SQL_CLOSE) when closing a statement with an open server-side cursor) and the SQLDescribeParam call issued for parametrized queries containing a None argument. The teardown release is guarded against interpreter finalization to stay safe during shutdown.
Who benefits: Users whose connection is routed through an in-process Python TCP forwarder (SSH-tunnel-style setups), where a GIL held across a blocking network syscall wedged the forwarder thread.
Impact: conn.close() / cursor.close() after a parametrized query, and parametrized queries with None values, no longer deadlock the interpreter.
• BINARY/VARBINARY NULL parameters in temp tables and table variables (#654)
What changed: Unknown NULL parameter types are now proactively resolved before any parameter is bound (for both single and batch execution paths). When SQLDescribeParam fails and the type falls back to SQL_VARCHAR, the driver emits a Python warning with concrete cursor.setinputsizes() guidance for binary columns.
Who benefits: Users inserting NULL values into BINARY / VARBINARY columns of temp tables or table variables, which previously hit driver errors or SQL Server implicit-conversion failures.
Impact: NULL binary parameters bind reliably, and when automatic resolution is not possible users get actionable guidance instead of an opaque error.
• Context manager transaction semantics (#639)
What changed: The Connection context manager (__exit__) now implements commit-on-success / rollback-on-exception semantics. With autocommit=False, a clean exit commits the transaction and an exception rolls it back; with autocommit=True behavior is unchanged. The connection is always closed on exit.
Who benefits: Users relying on with connection: blocks who previously saw every block roll back — because __exit__ only called close() regardless of how the block exited.
Impact: with blocks now persist committed work on clean exit and safely roll back on error, matching the documented behavior.
• macOS Apple Silicon import failure (#661)
What changed: configure_dylibs.sh now rewrites the bundled ODBC dylib dependencies to @loader_path for every architecture shipped in the universal2 wheel (arm64 and x86_64), not just the build host's arch. The committed arm64 and x86_64 dylibs were also re-fixed.
Who benefits: Apple Silicon users on a clean machine, where the arm64 driver previously pointed at an absolute Homebrew path (/opt/homebrew/lib/libodbcinst.2.dylib) that is absent until brew install unixodbc is run. Regressed in 1.8.0.
Impact: import mssql_python works out of the box on Apple Silicon with no separate unixODBC install.
• Service Principal bulk copy freeze (#666)
What changed: Fixed a GIL-deadlock in the Rust core that froze bulk copy when authenticating with a service principal. The fix lands in mssql_py_core and is picked up by bumping the bundled dependency from 0.1.5 to 0.1.6. (via mssql_py_core)
Who benefits: Users running bulkcopy with Authentication=ActiveDirectoryServicePrincipal, which previously froze mid-operation.
Impact: Service principal bulk copy completes without freezing.