sqlserverprogrammability
103 Topicsmssql-django 2.0: Now with mssql-python
mssql-django 2.0 is on PyPI. This release adds Microsoft's new mssql-python driver as a second way to connect, moves the supported Python, Django, and SQL Server versions forward, and fixes several connection and query bugs that production teams hit. pip install --upgrade mssql-django Pick your driver, one database at a time Until now, mssql-django spoke to SQL Server through pyodbc and an ODBC driver you installed yourself. That still works, and it's still the default. Version 2.0 adds a second path: mssql-python, Microsoft's Python driver for SQL Server. You choose per database alias. Add one option to the alias you want to move: DATABASES = { "default": { "ENGINE": "mssql", "NAME": "appdb", "HOST": "contoso.database.windows.net", "PORT": "1433", "OPTIONS": { "python_driver": "mssql_python", "extra_params": "Encrypt=yes", }, }, "reporting": { # No python_driver, so this alias stays on pyodbc. "ENGINE": "mssql", "NAME": "reportdb", "HOST": "contoso.database.windows.net", "PORT": "1433", "OPTIONS": { "driver": "ODBC Driver 18 for SQL Server", }, }, } ENGINE doesn't change. Remove the option and the alias is back on pyodbc. That's the whole rollback plan, which is the point: you can try the new driver on one database, run your test suite, and leave everything else alone. The mssql-python path covers the day-to-day work: connections, pooling, retries, transactions and savepoints, datetimeoffset values, introspection, and Microsoft Entra ID authentication. One practical difference worth calling out. On the mssql-python path, pip also installs the mssql-python-odbc companion package, which supplies Microsoft ODBC Driver 18 for SQL Server. There's no separate driver install, which takes a step out of container images and App Service deployments. Know what changes before you switch The two drivers aren't identical, and the differences are the reason we made this per alias instead of a global switch. The mssql-python path ignores driver, dsn, host_is_server, and unicode_results. There's no ODBC Driver 17 fallback. It validates extra_params against an allowlist and rejects pyodbc-only keywords such as ColumnEncryption, APP, and Connect Timeout, so use the connection_timeout option instead of the last one. It also doesn't enable MARS, which means QuerySet.iterator() reads the full result into memory before yielding rows so a nested query can reuse the connection. On a large queryset, that memory is real. Budget for it. Stay on pyodbc if you depend on a named DSN, FreeTDS, MARS, Always Encrypted through ColumnEncryption, or an ODBC driver version you manage yourself. We cleaned up the version matrix This is something we've wanted to get to for a while. mssql-django 2.0 supports Python 3.10 through 3.14, Django 5.2 through 6.1, and SQL Server 2017 through 2025, plus Azure SQL Database, Azure SQL Managed Instance, and SQL database in Microsoft Fabric. Django 6.0 and 6.1 need Python 3.12 or later. Python 3.8 and 3.9 and Django 3.2 through 5.1 are no longer supported. The compatibility code is still in the tree, so nothing breaks the moment you upgrade, but those combinations aren't tested or listed. Fixes MARS settings are honored. If you set MARS_Connection=no in extra_params, the backend used to overwrite it with the Windows default and the connection failed. That's the bug frederiksoftware reported when connecting an on-premises Django app to a Microsoft Fabric Warehouse. The explicit value now wins, case-insensitively, so those connections work. To be clear about scope: this fixes the connection, it doesn't add full Warehouse support for migrations or other SQL Server features. Bracket wildcards are escaped in F() expression lookups. A pattern lookup comparing two fields, such as filter(name__contains=F("code")), didn't escape the SQL Server [ wildcard, so bracket characters in your data were treated as wildcard syntax and matched the wrong rows. Thanks to @Khan3K for the fix. Quotes are escaped in inspectdb schema names. inspectdb --schema produced malformed T-SQL for a schema name containing a single quote. An empty HOST connects to localhost on the mssql-python path. Omitting HOST in Django settings leaves it as an empty string, which mssql-python rejected. It now resolves to localhost, matching the pyodbc behavior for local instances. pytz is gone Time zone handling moved to the standard library zoneinfo module, with the tzdata package supplying the IANA database where the operating system doesn't ship one: Windows, and minimal container images. This fixes offsets for zones with negative daylight saving offsets, and it drops a dependency. Before you upgrade mssql-python is a required dependency in 2.0 even when every alias uses pyodbc. That means mssql-django 2.0 installs only on platforms that have a compatible mssql-python distribution: Windows x64, Windows ARM64 with Python 3.11 and later, macOS 15 and later on Intel or Apple silicon, and Linux x64 or ARM64 with glibc 2.28 or later or musl 1.2 or later. SUSE Linux on ARM64 isn't supported. If you're outside that list, stay on 1.8.0. Upgrade now pip install --upgrade mssql-django Release notes Documentation Report an issue Thanks to @Khan3K and @frederiksoftware for the contributions in this release.105Views0likes0CommentsMicrosoft ODBC Driver 18.7.1: smaller vectors, easier configuration, and better cloud routing
Microsoft ODBC Driver 18.7.1 for SQL Server is now generally available. This release continues the work we started in 18.6 to support modern application patterns while making the driver easier to deploy and operate. It adds float16 vector support, brings familiar connection-string names to ODBC, improves routing for Azure SQL Database Hyperscale, expands platform coverage, and removes a Windows installation dependency. It also includes a substantial set of reliability, security, and diagnostic fixes. Many of those changes happen below the application layer. More compact vector workloads ODBC Driver 18.6.1 introduced support for the SQL Server vector data type using 32-bit floating-point values. Version 18.7.1 adds support for float16 vectors. A float16 element uses two bytes instead of the four bytes required by float32. For applications working with large embedding collections, that can reduce the amount of vector data stored and moved between the application and the database. The right precision depends on the model and workload, but applications that can use half-precision vectors now have that choice through ODBC. This matters because vector support is becoming part of the normal database application stack. You should not need a separate connectivity path just because an application combines relational data, business data, and embeddings. Adding float16 support brings ODBC forward with the vector capabilities being added across SQL Server and Azure SQL. Connection strings that travel more easily ODBC has accumulated its own connection-string vocabulary over many years. Some settings use different names in ODBC, JDBC, OLE DB, and SqlClient even when they configure the same behavior. Version 18.7.1 accepts four additional connection-string keywords: MultipleActiveResultSets FailoverPartner WorkstationID ConnectTimeout The first three are aliases for existing ODBC settings. For example, MultipleActiveResultSets maps to MARS_Connection, while WorkstationID maps to WSID. Existing connection strings continue to work. ConnectTimeout maps to the ODBC login timeout. It supports the same behavior as the underlying ODBC setting, including zero for an infinite timeout and a default of 15 seconds. These additions reduce the small but persistent differences you encounter when moving configuration between Microsoft SQL drivers. Shared configuration systems, deployment templates, and migration tools can use more consistent names instead of maintaining driver-specific translations for common settings. We also spent some time on details that tend to cause production surprises: case-insensitive matching, precedence when an alias and canonical name both appear, invalid values, timeout limits, and DSN interaction. Better routing for Hyperscale read workloads Azure SQL Database Hyperscale named replicas provide independent read scale for applications with large or isolated read workloads. ODBC Driver 18.7.1 adds load-balanced routing for named-replica reader endpoints. Applications can connect through the reader endpoint and allow the service and driver to handle routing across the available read capacity. That makes the endpoint more useful for workloads such as reporting, analytics, and read-heavy application services without requiring applications to manage individual replica destinations themselves. The driver already sits at the point where connection intent becomes a physical connection. Supporting this routing behavior there keeps replica topology out of application code. Less setup on Windows The Windows package no longer requires the Microsoft Visual C++ Runtime to be installed separately. That removes a prerequisite from new machines, container images, automated build agents, and managed desktop deployments. It also reduces one of the common differences between a machine where an application was built and a clean machine where it is installed. The change is small from an application-code perspective. For deployment owners, it means fewer moving parts and one less prerequisite to diagnose. More Linux distributions Version 18.7.1 adds support for: Alpine Linux 3.23 SUSE Linux Enterprise Server 16 Ubuntu 26.04 Platform support is more than producing an RPM, DEB, or APK. The driver must install cleanly, connect successfully, upgrade from prior versions where packages are available, and coexist with ODBC Driver 17 on supported configurations. The installer automation used for this release covers AMD64 and ARM64 variants across RHEL, Azure Linux, Ubuntu, Debian, Alpine, and supported SUSE environments. Windows coverage includes Windows 11 and Windows Server 2019, 2022, and 2025, with fresh installation, upgrade, coexistence, and MSI repair scenarios where applicable. Ubuntu 26.04 currently receives fresh-install validation because previous packages are not yet available from the Ubuntu 26.04 Microsoft package repository. The test pipeline records that distinction instead of treating unsupported upgrade combinations as covered. Reliability work below the application Database drivers operate on untrusted network input, coordinate asynchronous operations, manage native memory, and translate between platform APIs and the Tabular Data Stream protocol. Small mistakes in those paths can produce failures far away from the code that caused them. The 18.7.1 release addresses several of those cases: Protocol parsing is more defensive when processing malformed LOGINACK and ENVCHANGE tokens. Memory corruption issues were corrected in the SQL Server Network Interface packet pool and on Linux ARM64 and macOS ARM64. Multiple Active Result Sets connections now clean up memory correctly when a connection ends abruptly. Asynchronous timeout handling was corrected for zero-length partially length-prefixed data and data-classification tokens. OpenSSL errors left on a calling thread are handled correctly. XA distributed transactions recover more reliably from SQL Server connectivity failures. Always Encrypted performs less redundant logging while acquiring Azure Key Vault tokens. Tabular Data Stream packet tracing reports the correct byte count for overlapped named-pipe writes. Most applications will never encounter the exact failure conditions behind these fixes. That is the goal. A malformed server response should produce a controlled error. A dropped connection should release its memory. A timeout should behave consistently even when it arrives in the middle of an unusual protocol sequence. Get ODBC Driver 18.7.1 Microsoft ODBC Driver 18.7.1 for SQL Server is available now for Windows, Linux, and macOS. Download Microsoft ODBC Driver for SQL Server Read the ODBC Driver release notes Learn about the vector data type in ODBC If your application uses vectors, Azure SQL Database Hyperscale named replicas, shared connection configuration, or newer Linux distributions, 18.7.1 contains changes you can use immediately. For other applications, the deployment, protocol, memory-management, and diagnostic fixes provide a strong reason to include this release in your normal driver update cycle.437Views0likes1Commentmssql-python 1.15.0: Faster, More Reliable, and Built for Your Applications
I am excited to share the release of mssql-python 1.15.0, our 15th release since General Availability. We build mssql-python for Python developers connecting their applications to SQL Server, Azure SQL, and Azure Synapse. Every release is an opportunity to make that experience faster, simpler, and more dependable. Version 1.15.0 delivers improvements across all three. Faster parameterized execution setinputsizes() parameter handling now runs through the native C++ execution pipeline. If your application uses wide statements, batches, or frequently executed parameterized queries, it will spend less time processing parameters in Python. This work moves more of the execution path into the native driver, where it can be handled more efficiently. We also made decimal parameter binding more consistent. Python Decimal values are now bound as SQL_NUMERIC regardless of their runtime value, so parameter types remain stable across queries and batches. The driver now uses current ODBC 3.x parameter type identifiers in place of obsolete ODBC 2.x identifiers. This brings parameter binding in line with the current ODBC standard and avoids mismatches caused by legacy type definitions. Better support for Python data Binary() now accepts memoryview objects directly. Applications using buffer-protocol data sources and zero-copy views no longer need to convert a memoryview to bytes before sending binary data. You can pass the value you already have. SQL Server-specific type constants are also available directly from the mssql_python module. This makes them easier to discover and use when working with parameter declarations or SQL Server type metadata. More reliable production behavior Several fixes in this release address failures that can be difficult to diagnose because they occur under concurrency, during deployment, or while a process is shutting down. We corrected GIL and mutex lock ordering in the native logging path. Multithreaded applications can now use driver logging without risking a deadlock when multiple threads log concurrently. We also corrected native cleanup ordering for connections containing cursors in different lifecycle states. Applications that create multiple cursors and leave some cleanup to process shutdown will no longer encounter the native crash addressed by this fix. On Windows, bundled driver and authentication DLLs are now loaded from directories inside the installed package. Applications no longer have to depend on process-wide DLL search path configuration for those components to resolve correctly. Windows ARM64 wheels now include the matching ARM64 Rust core used by bulk copy. This gives Windows ARM64 applications architecture-compatible native components and working bulk-copy support from the installed wheel. Finally, Connection.getinfo(SQL_DATABASE_NAME) now decodes the returned value correctly, so applications inspecting the active database receive a Python string as expected. Thank you Thank you to everyone who reported an issue, tested a fix, contributed code, or told us where the driver was getting in your way. We are building this driver for you, and your feedback continues to shape what we improve next. Install or upgrade today: pip install --upgrade mssql-python Read the mssql-python 1.15.0 release notes, visit the package on PyPI, or explore the mssql-python repository.322Views1like0Commentsmssql-python 1.13.0: Arrow Bulk Copy, Smarter Tokens, Slimmer Wheels
mssql-python 1.13.0 is now available on PyPI. This release adds an Apache Arrow fast path for bulk copy, first-class support for azure-identity credential objects, identity-aware connection pooling, and it completes the move of the ODBC driver binaries into the standalone mssql-python-odbc package. pip install --upgrade mssql-python Highlights Apache Arrow bulk copy Loading data that already lives in Arrow no longer has to round-trip through Python tuples. The new Cursor.bulkcopy_arrow() reads each batch's typed Arrow buffers directly in the Rust TDS core and streams them into the bulk-load packets, releasing the GIL for the duration of the transfer. import pyarrow as pa from mssql_python import connect conn = connect("Server=<server>.database.windows.net;Database=<database>;Encrypt=yes") cursor = conn.cursor() table = pa.table({"id": [1, 2, 3], "name": ["a", "b", "c"]}) result = cursor.bulkcopy_arrow("dbo.MyTable", table) print(result["rows_copied"], result["rows_per_second"]) Source accepts any of the following: pyarrow.Table, pyarrow.RecordBatch, or pyarrow.RecordBatchReader Any object exposing the Arrow C Data Interface (__arrow_c_stream__ or __arrow_c_array__), which covers polars, pandas 2.2+, DuckDB, and ADBC results Any iterable of record batches A polars DataFrame, a pandas 2.2+ DataFrame, or a DuckDB relation can be passed straight to bulkcopy_arrow() with no explicit conversion step. Everything else carries over from the classic bulkcopy(): same schema handling, same column mappings, same options, same statistics dictionary in return. Bulkcopy() now raises TypeError when passed an Arrow object, with a message pointing at bulkcopy_arrow(), so there is no silent slow path. token_provider= for Microsoft Entra ID credentials connect() accepts a token_provider argument: any object with a .get_token(scope) method that returns an object with a .token attribute. Every azure-identity credential qualifies. from azure.identity import AzureCliCredential from mssql_python import connect conn = connect( "Server=<server>.database.windows.net;Database=<database>", token_provider=AzureCliCredential(), ) Use this when you need explicit control over token acquisition, such as excluding specific providers, using a credential that is not in the built-in map, or passing custom options to the credential constructor. For environment-portable code, Authentication=ActiveDirectoryDefault in the connection string remains the simpler choice. token_provider= is mutually exclusive with Authentication= and with a raw token in attrs_before[SQL_COPT_SS_ACCESS_TOKEN]. The token scope is fixed to the Azure commercial cloud. For sovereign clouds, acquire the token yourself and pass it through attrs_before. Identity-aware connection pooling The connection pool now keys on the security context of a connection, not just the connection string. Two consequences: Connections established under different identities (access tokens, integrated auth) can no longer be handed to the wrong caller. Token acquisition is deferred until a pool miss, so a pool hit no longer pays for a round trip to the identity provider on every connect(). Pooled connections whose token is close to expiry are refreshed automatically rather than being reused until the server rejects them. ODBC driver ships exclusively via mssql-python-odbc v1.12.0 introduced the standalone mssql-python-odbc package while keeping the bundled libs/ tree as a fallback. That fallback is now removed. mssql-python hard-depends on mssql-python-odbc==18.6.2.1, so pip install mssql-python continues to pull the driver transparently, with no extra step for users. Why it matters: Smaller mssql-python wheels. ODBC binary updates ship on their own cadence, independent of mssql-python releases. If your environment installs packages from a private index or an offline mirror, make sure mssql-python-odbc is mirrored alongside mssql-python before upgrading. Bug fixes executemany() could silently insert zero rows. Numeric array parameter binding (TINYINT, SMALLINT, INT, FLOAT) left indicator slots uninitialized when a NULL appeared partway through a batch, which could drop the batch without raising. SQL_WVARCHAR output converters no longer act as a catch-all. The fallback is now gated on columns whose mapped type is str or bytes, so a converter registered for wide strings stops intercepting numeric and date columns. Integer-keyed output converters now fire. add_output_converter(SQL_DECIMAL, ...) and other integer ODBC SQL type codes dispatch correctly, matching pyodbc behavior. RecordBatchReader.close() works for Arrow result sets. Cursor.arrow_reader() returns a wrapper whose close() cancels any in-flight fetch, releases the server-side cursor and its locks, drains diagnostics into cursor.messages, and leaves the parent cursor usable. Teardown also runs on normal exhaustion, on with-block exit, and on garbage collection. No more AttributeError from Cursor.__del__. Cursor.__init__ sets closed and hstmt before anything can raise, and __del__ uses sys.is_finalizing() as its interpreter-shutdown guard. Upgrading For most users, pip install --upgrade mssql-python is all that is needed. Two things to check: Offline or private-index installs need mssql-python-odbc==18.6.2.1 available alongside mssql-python. bulkcopy() now rejects Arrow-shaped input. Anything exposing __arrow_c_stream__ or __arrow_c_array__, which includes pandas 2.2+ and polars DataFrames as well as pyarrow containers, raises TypeError pointing at bulkcopy_arrow(). Those inputs never loaded correctly through bulkcopy(), so this replaces a confusing failure with a clear one. Any code that was catching the old error will see an actionable message. Feedback Full release notes are on the releases page. File issues and feature requests at github.com/microsoft/mssql-python/issues, or email us at mssql-python@microsoft.com.309Views0likes0Commentsmssql-django 1.8.0: Django 6.1 Support within 48 Hours of Django 6.1 GA
Django 6.1 GA'd on August 5. mssql-django 1.8.0 was on PyPI within 48 hours. This is the first time the backend has shipped support for a new Django release in lockstep with Django itself. If you run SQL Server, Azure SQL, or SQL database in Microsoft Fabric, you can move to 6.1 today without code changes. pip install --upgrade mssql-django Django How it shipped this fast The work started in June, against the 6.1 beta. The beta went into the full CI matrix weeks before GA, we knew about every backend API break in June. Fixes were developed on an integration branch and validated on live CI against real 6.1 builds on SQL Server 2025. By GA day, the release was tested and ready to publish. What's new Django 6.1 changed several parts of the database backend API. Every change here is version-gated, so earlier Django versions are unaffected. Query compilation for 6.1's sliced and offset queries. Django 6.1 deprecated SQLCompiler.quote_name_unless_alias() in favor of SQLCompiler.quote_name(); sliced querysets and OFFSET ... FETCH now compile without Django 7.0 deprecation warnings. Database introspection. get_relations() returns 6.1's expanded shape, including the database-level ON DELETE rule, so inspectdb keeps working. Upfront errors for the 6.1 features SQL Server cannot support. Regression tests, CI, and packaging for 6.1 on Windows and Linux with Python 3.12, 3.13, and 3.14. What doesn't work on 6.1 Two 6.1 features are unavailable: Database-level referential actions (DB_CASCADE, DB_SET_NULL, DB_SET_DEFAULT). SQL Server disallows multiple cascade paths to the same table, and that is still true in SQL Server 2025. Using one fails Django's system checks with fields.E324; use Django's on_delete handling instead. Bitwise aggregates (BitAnd, BitOr, BitXor). SQL Server has no native bitwise aggregate function, and the backend doesn't emulate one yet, so these raise NotSupportedError. If this is important to you, drop a comment on issue #572 with your use case. Supported versions Component Supported versions Django 3.2, 4.0, 4.1, 4.2, 5.0, 5.1, 5.2, 6.0, 6.1 Python 3.8 through 3.14; Django 6.0 and 6.1 require Python 3.12+ SQL Server All supported versions Azure SQL Azure SQL Database and Azure SQL Managed Instance Microsoft Fabric SQL database in Microsoft Fabric This matrix is wider than it should be. Django 5.1 and earlier and Python 3.9 and earlier are already past end of life upstream. A separate upcoming release will narrow this list to the versions their own projects still support. Upgrading pip install --upgrade mssql-django Django 1.8.0 release notes: https://github.com/microsoft/mssql-django/releases/tag/1.8.0 README: https://github.com/microsoft/mssql-django#supportability Django 6.1 release notes: https://docs.djangoproject.com/en/6.1/releases/6.1/ PyPI: https://pypi.org/project/mssql-django/ Issues: https://github.com/microsoft/mssql-django/issues205Views0likes0Commentsmssql-python v1.12.0: Standalone ODBC package, bulk copy fixes
We're pleased to announce the 12th release of the Microsoft Python Driver for SQL Server since GA: v1.12.0. Want to try it? pip install --upgrade mssql-python What's new Standalone mssql-python-odbc package for ODBC driver binaries You may remember that we ran out of space to publish on PyPi a few releases ago. To prevent that from happening again, the ODBC driver binaries that mssql-python needs at runtime are now also published as a separate, pure-data companion package: mssql-python-odbc (import name mssql_python_odbc, currently pinned to 18.6.2). mssql-python declares mssql-python-odbc==18.6.2 in install_requires, so pip install mssql-python transparently pulls the driver package alongside it. At import time, the native loader prefers the external mssql_python_odbc package when it is present, and falls back to the ODBC driver binaries still bundled inside the mssql-python wheel when it is not. Existing installations keep working with no code changes. The fallback is GIL-safe and Alpine/musl-safe. Who benefits Users who want to keep driver binaries pinned or updated independently of the Python driver code. Redistributors who want a slimmer mssql-python wheel over time. Anyone who has hit duplicate-ownership issues from bundled ODBC files. Bug fixes Bulk copy now honors the connection timeout cursor.bulkcopy() opens a separate connection through mssql_py_core, which previously defaulted to a hardcoded 15-second connect timeout with no way to override it from Python. The cursor's query timeout (set via connect(timeout=X)) is now forwarded into mssql_py_core's connect_timeout when it is set. timeout=0 is preserved as "no override" and leaves mssql_py_core on its 15-second default. The cursor's timeout snapshot at the time of the bulkcopy() call is what is used, so later changes to the parent connection do not affect an in-flight bulk copy. import mssql_python # Give bulk copy 60 seconds to establish the second connection. conn = mssql_python.connect(conn_str, timeout=60) cursor = conn.cursor() cursor.bulkcopy(rows, table="dbo.MyTable") Who benefits Applications that call bulkcopy() against slow, throttled, or high-latency SQL Server endpoints (VPN, cross-region) Applications that need to fail fast with a shorter timeout. Bulk copy into custom CLR UDT columns cursor.bulkcopy() into a column whose type is a custom, assembly-registered CLR UDT (any UDT other than the built-in geography, geometry, or hierarchyid) previously failed with: Protocol Error: Unsupported TDS type for bulk copy: 0xF0 The native core had no handler for the UDT (0xF0) type token when writing COLMETADATA. The Rust core now maps UDT columns to varbinary(max) on the wire and streams the supplied bytes as the UDT's serialized form (its IBinarySerialize payload), matching how pyodbc and python-tds load UDT columns. SQL Server materializes the UDT on insert. More information PyPI: https://pypi.org/project/mssql-python/1.12.0/ Release notes: https://github.com/microsoft/mssql-python/releases README: https://github.com/microsoft/mssql-python#microsoft-python-driver-for-sql-server Get involved Bug reports, feature requests, and PRs are welcome on GitHub: https://github.com/microsoft/mssql-python306Views0likes0Commentsmssql-django 1.7.4 Released
mssql-django 1.7.4 is now available on PyPI. This release focused on two fixes in raw and annotated GROUP BY query handling. What is fixed 1) Escaped %% handling in GROUP BY params GROUP BY queries that mixed escaped %% literals with real params could raise IndexError. In 1.7.4, placeholder rewriting now only touches %% and %s in the intended paths. These queries now execute correctly instead of failing. Example: from django.db import connection sql = """ SELECT LEFT(name, %s) AS prefix, COUNT(*) FROM testapp_customer_name WHERE notes LIKE 'promo%%' GROUP BY LEFT(name, %s) """ params = [3, 3] with connection.cursor() as cursor: cursor.execute(sql, params) rows = cursor.fetchall() Before 1.7.4: this pattern could raise IndexError when escaped %% and %s placeholders appeared together. In 1.7.4: the query executes and returns grouped rows as expected. 2) IntegerChoices in raw GROUP BY queries Passing IntegerChoices values into raw GROUP BY queries could raise NotImplementedError. In 1.7.4, type checks use isinstance, so IntegerChoices params are handled correctly while bool and plain int behavior stays consistent. Example: from django.db import connection from django.db.models import IntegerChoices class Priority(IntegerChoices): LOW = 1, "Low" HIGH = 2, "High" sql = """ SELECT priority, COUNT(*) FROM testapp_choice_question WHERE priority = %s GROUP BY priority """ with connection.cursor() as cursor: cursor.execute(sql, [Priority.HIGH]) rows = cursor.fetchall() Before 1.7.4: passing Priority.HIGH could raise NotImplementedError. In 1.7.4: IntegerChoices values bind correctly in raw GROUP BY queries. Tests This release also adds regression coverage for: Escaped %% and unescaped % GROUP BY paths IntegerChoices in raw GROUP BY queries Compatibility mssql-django 1.7.4 remains a backward-compatible patch release with no breaking changes. Thank you Thanks to everyone using mssql-django, especially those that reported these issues. Your reports and repros help improve reliability with every patch. If you hit an issue, please open one here: https://github.com/microsoft/mssql-django/issues PyPI: https://pypi.org/project/mssql-django/ Release notes: https://github.com/microsoft/mssql-django/releases/tag/1.7.4160Views0likes0Commentsmssql-python 1.11.0: Fixes for transaction semantics, Apple Silicon imports, and bulk copy
This release is about removing friction in real production paths. It fixes transaction handling in with blocks, restores clean-machine imports on Apple Silicon, improves NULL binary parameter binding, removes a class of hangs in SSH-tunnel-style forwarding setups, and unblocks bulk copy with service principal authentication. Upgrade pip install --upgrade mssql-python Highlights with connection: now commits on success and rolls back on exception The Connection context manager now implements the documented commit-on-success / rollback-on-exception behavior when autocommit=False. The connection still closes on exit. Code like this now behaves the way most users already expected it to: import mssql_python conn = mssql_python.connect(connection_string, autocommit=False) with conn: cursor = conn.cursor() cursor.execute("INSERT INTO dbo.audit_log(message) VALUES (?)", ("created",)) If the code in the block succeeds, the insert is committed. If the code in the block raises an error, the transaction is rolled back. Apple Silicon imports work on clean machines again We fixed the bundled macOS ODBC dylib configuration for every architecture shipped in the universal2 wheel. For Apple Silicon users, this removes a frustrating failure mode where import mssql_python could point at a missing Homebrew unixODBC path on a clean machine. In 1.11.0, the bundled libraries resolve correctly without a separate unixODBC install. NULL BINARY and VARBINARY parameters bind more reliably We fixed the SQLDescribeParam ordinal remapping issue behind GitHub issue #627. 1.11.0 improves parameter binding for NULL binary values, especially in temp-table and table-variable scenarios. When automatic type resolution is not possible, the driver now gives actionable guidance instead of a vague failure, including cursor.setinputsizes() guidance for binary columns. Bug fixes worth calling out Shutdown and parameter-typing paths no longer hang SSH-tunnel-style forwarders We fixed hangs caused by holding the GIL across blocking ODBC operations. This matters most for users routing connections through an in-process Python TCP forwarder, including SSH-tunnel-style setups. Closing connections and cursors after parameterized queries, as well as executing parameterized queries containing None, no longer wedge the interpreter in those paths. Bulk copy with service principal authentication no longer freezes 1.11.0 also picks up mssql-py-core 0.1.6, which fixes a freeze affecting bulk copy with Authentication=ActiveDirectoryServicePrincipal. If you are using service principal authentication for bulk ingest workloads, this release is worth taking promptly. Upgrading For most users, pip install --upgrade mssql-python is all you need. If you had local workarounds for broken with connection: transaction behavior, Apple Silicon import issues, or binary NULL parameter binding, 1.11.0 is the release where those workarounds should become unnecessary. This is not a feature-heavy release. We opted to focus on the friction you are reporting in real production workflows: transactional with blocks now persist successful work Apple Silicon setup is smoother on clean machines binary NULL parameters are more reliable SSH-tunnel and threaded forwarding scenarios are less fragile service principal bulk copy is unblocked Thank you Thanks to everyone who filed issues, sent repros, and reviewed fixes in this cycle. Several of the changes in 1.11.0 came directly from concrete user reports in production-like environments, which made the failure modes easier to reproduce and fix. If you upgrade to 1.11.0 and hit anything unexpected, please open an issue in the repository. Repository: microsoft/mssql-python Issue tracker: open an issue Release notes: mssql-python v1.11.0165Views1like0CommentsMicrosoft Django backend for SQL Server - mssql-django 1.7.3 is now available
We are happy to announce the release of mssql-django 1.7.3. This release improves SQL Server connection compatibility for modern authentication scenarios and fixes a subclassing edge case in backend server-property caching. Highlights 1) Authentication parsing and connection string handling improvements We fixed how extra_params authentication settings are interpreted and now parse ODBC-style key/value segments more robustly. What changed: Authentication mode is parsed from extra_params using a spec-aligned parser. Trusted_Connection and SSPI injection now respects explicit Authentication= modes. Password injection behavior is driven by authentication mode, so password-based modes still receive PWD correctly. Parser behavior is hardened for cases like braced values, embedded semicolons, escaped braces, whitespace, and empty values. Why it matters: Prevents invalid combinations such as appending Trusted_Connection=yes when an explicit authentication mode is provided. Avoids ODBC driver failures (including FA001) in authentication flows such as ActiveDirectoryIntegrated. Improves predictability for advanced connection-string configurations. 2) Server-property cache fix for DatabaseWrapper subclasses We fixed a KeyError when subclassing DatabaseWrapper and accessing server-property cached values. What changed: Replaced mutable default-argument cache patterns with explicit class-level cache dictionaries. Added regression coverage for subclass access paths. Why it matters: Custom backend wrapper subclasses now behave correctly when reading cached server properties. Prevents runtime failures in extensibility scenarios. Upgrade pip install --upgrade mssql-django==1.7.3 If you are building an application that uses Entra authentication, you'll want this as your minimum version. Compatibility 1.7.3 continues the same compatibility range introduced in 1.7.x: Django 3.2 through 6.0 Python 3.8 through 3.14 All supported versions of Microsoft SQL Thank You Thank you to everyone who reported issues, validated fixes, and contributed improvements. As always, please open an issue if you hit regressions or have connection/authentication scenarios you want us to look into.169Views0likes0Commentsmssql-python 1.9.0: Row-friendly Bulk Copy, smarter NULL parameters, and a more portable wheel
We just shipped mssql-python 1.9.0, the official Microsoft SQL driver for Python. This release focuses on day-to-day ergonomics for data loading, a long-standing correctness gap around NULL parameter binding, and a build change that makes the published wheels work on clean macOS and Linux machines. pip install --upgrade mssql-python Highlights Bulk Copy now accepts Row objects (and lists) Bulk Copy previously required tuples. In 1.9.0 you can hand it Row objects straight from a SELECT, or plain lists, and the driver converts each row to a tuple internally before passing data to the Rust backend. rows = source_cursor.execute( "SELECT id, display_name, created_at FROM users" ).fetchall() target_cursor.bulkcopy("staging.users", rows) The common "fetch from one table, bulk-insert into another" pattern just works, with no manual row reshaping and no type errors on the boundary. NULL parameters now resolve to the right SQL type When you bound None to a parameter, the driver used to fall back to SQL_VARCHAR. That was fine for character columns and quietly wrong for everything else, especially VARBINARY and all-NULL columns where the server had no other type signal to lean on. 1.9.0 adds a thread-safe per-statement cache for SQLDescribeParam results, so NULL parameters resolve to the parameter's actual declared type. The cache is invalidated when a new statement is prepared, which also cuts redundant round-trips to the server during repeated executions of the same prepared statement. simdutf is now statically linked into the extension The published wheels (especially the macOS universal2 wheel) previously dynamically linked simdutf against a path that only existed on the CI build machine. On a clean install, import mssql_python could fail with missing-symbol or dlopen errors. The build no longer calls find_package(simdutf). FetchContent is used unconditionally, simdutf is built as a static library, and its symbols are embedded directly in the extension. There is nothing for end users to do; reinstall the wheel and the import works on a clean machine. Thanks to @edgarrmondragon for the contribution. Bug fixes worth calling out executemany with large Decimal values. Batch inserts of Decimal values larger than the SQL Server MONEY range raised an SQL_C_NUMERIC type-mismatch at runtime. executemany now binds DECIMAL / NUMERIC parameters as SQL_C_CHAR and sizes the column to fit the longest string representation, so large-decimal batches (including NULLs and multi-column inserts) succeed. Exception pickle round-trips. ConnectionStringParseError and the DB-API exception subclasses now implement __reduce__, so driver exceptions survive pickle / copy.deepcopy with every attribute intact. multiprocessing, distributed task queues, and anything that ships exceptions across process boundaries no longer lose context on the way through. nextset() and PRINT output. nextset() now collects diagnostic messages whenever SQL returns SQL_SUCCESS_WITH_INFO. Previously, PRINT output from secondary result sets in multi-statement batches and stored procedures was silently dropped after the first set. executemany data-at-execution path with Row objects. The DAE fallback used by large columns such as varchar(max) only recognized primitive types, so passing Row objects in that path failed. The fallback now converts Row to a tuple before mapping types. Fetch methods now type-check under ty. Catalog and metadata result-set handling no longer monkey-patches fetchone, fetchmany, and fetchall as instance attributes. A cached _column_map is built instead, so the fetch APIs stay proper class methods and static type checkers like ty stop tripping on cursor fetch calls. Upgrading For most users, pip install --upgrade mssql-python is all you need. If you had any workarounds for NULL parameter typing (manually setting inputsizes, casting in SQL, or sending sentinel values), you can drop it. If you were converting fetched rows to tuples before handing them to bulkcopy or executemany, that's no longer required either. Thanks Thanks to everyone who filed issues, sent repros, and reviewed PRs in this cycle. The NULL parameter fix, the Row handling in Bulk Copy and executemany, and the simdutf linking change all came directly from user-reported scenarios, and the simdutf change was a community contribution from @edgarrmondragon. Full changelog and PR list: microsoft/mssql-python releases.351Views0likes0Comments