Change Log

All notable changes to this project will be documented in this file. This project adheres to Semantic Versioning.

Unreleased

v2.1.1

Fixed

  • FreeTDS 1.5.11 build failure on GCC 14+ due to -Wincompatible-pointer-types error in iconv.c.

  • Switched aarch64 wheel builds to native ARM runners, removing QEMU emulation.

v2.1.0

Added

  • Python 3.14 support.

  • __repr__ for Connection, Cursor, and Row objects for easier debugging. Examples:

    • <k_ctds.Connection database='master' spid=54>

    • <k_ctds.Cursor (open, 3 columns)>

    • <k_ctds.Row(Col1=1, Col2='hello')>

Fixed

  • Memory leak in Cursor.fetchall/fetchmany/fetchone when a SQL Server warning was promoted to a Python error via warnings.filterwarnings('error'). Row buffers allocated during dbnextrow were not freed on the warning-as-error exit path in Cursor_fetchrows. Detectable under Valgrind as definitely-lost bytes.

v2.0.0

Breaking Changes

  • Renamed import from ctds to k_ctds. Users must now write import k_ctds instead of import ctds to align with the PyPI package name (pip install k-ctds).

  • Dropped FreeTDS 0.95 support. FreeTDS 1.0 or later is now required.

New Features

  • auto_encode parameter for bulk_insert. bulk_insert(..., auto_encode=True) queries INFORMATION_SCHEMA.COLUMNS to determine each column’s type and collation, then automatically encodes Python str values: NVARCHAR/NCHAR/NTEXT columns are encoded to UTF-16LE, and VARCHAR/CHAR/TEXT columns are encoded to the column’s collation code page.

  • SqlNVarChar now produces correct output for bulk_insert. Previously, Parameter_bcp_bind sent UTF-8 bytes unchanged for NVARCHAR columns, silently corrupting data. It now re-encodes from UTF-8 to UTF-16LE when downgrading an explicit SqlNVarChar wrapper for FreeTDS BCP compatibility.

Build & Packaging

  • Migrated to pyproject.toml with FreeTDS + OpenSSL bundled in wheels via cibuildwheel

  • Updated wheel builds to use OpenSSL 3.0 (built from source) across all platforms

  • Upgraded bundled FreeTDS to 1.5.11

  • Updated license files to reflect LGPL-2.0/Apache-2.0 compliance for bundled dependencies

Internal

  • Moved C extension from top-level _tds to k_ctds._tds

  • Updated all tp_name strings, DEFAULT_APPNAME, and C docstrings to use k_ctds

  • Renamed CI scripts and Docker container names (ctds-k-ctds-)

  • Simplified test infrastructure by removing legacy FreeTDS 0.92/0.95 checks

  • Updated warning assertion tests to use assertIn for substring matching

1.15.0 - 2026-02-11

Added

  • Support for SQL Server DATETIMEOFFSET data type (timezone-aware datetimes)

  • Support for Python 3.10, 3.11, 3.12, and 3.13

  • Comprehensive test suite for DATETIMEOFFSET operations (65 new tests)

    • Reading DATETIMEOFFSET values from SQL Server

    • Writing timezone-aware datetime values to SQL Server

    • Bulk insert operations with DATETIMEOFFSET

    • Backward compatibility tests for FreeTDS < 0.95

Changed

  • FreeTDS 0.95+ required for DATETIMEOFFSET (older versions still work but feature unavailable)

Compatibility

  • No breaking changes for existing code

[1.14.0] - 2021-03-25

Fixed

  • Replaced travis-ci with Github Actions.

  • Replaced custom Docker-based testing infrastructure with tox.

  • Fixed translation of SQL Server errors to Python exceptions for all errors with severity > 10. https://github.com/zillow/ctds/issues/84

[1.13.0] - 2020-11-12

Added

  • Offical support for Python 3.9.

  • Expose ctds.Row type so that it can be used as a type annotation.

  • Add description attribute to rowlists and rows.

  • Add ctds.Row.dict() method.

Fixed

  • Cache cursor.description rather than creating a new instance every time.

[1.12.0] - 2020-03-07

Fixed

  • Fixed Python -> SQL type conversion to consider client TDS version when choosing SQL type. https://github.com/zillow/ctds/issues/68.

  • Added Sphinx extension to auto-generate the .nojekyll file required by Github pages.

  • Consolidate coverage output to a single directory.

[1.11.0] - 2019-11-14

Added

  • Official support for Python3.8.

  • Automate Python egg publishing to pypi.

  • Automate documentation publishing.

Fixed

  • Fix handling of IDENTITY columns in ctds.Connection.bulk_insert(). https://github.com/zillow/ctds/issues/59.

[1.10.1] - 2019-06-27

Fixed

  • Properly handle errors in the ctds.pool.ConnectionPool.connection context manager.

[1.10.0] - 2019-04-15

Added

  • Add FreeTDS 1.1 to test matrix.

Fixed

  • Preserve microsecond precision of TIME and DATETIME2 SQL types when converting to Python (and supported by FreeTDS).

  • Fix improper conversion of empty strings to NULL in ctds.Connection.bulk_insert(). https://github.com/zillow/ctds/issues/35.

[1.9.0] - 2018-11-05

Added

  • Add support for passing sequences of dict values to ctds.Connection.bulk_insert. The mapping key is used to determine the column order based on the column info available after bcp_init. https://github.com/zillow/ctds/issues/38

Fixed

  • Fix truncation of strings containing multi-byte sequences when not using sp_executesql.

  • Fix ctds.Cursor.executemany() truncating data for integer types. https://github.com/zillow/ctds/issues/43.

[1.8.0] - 2018-09-07

Added

  • Official support for Python 3.7.

  • Add optional hostname parameter to ctds.connect(). https://github.com/zillow/ctds/issues/20.

  • Add optional ntlmv2 parameter to ctds.connect(). https://github.com/zillow/ctds/issues/27.

Fixed

  • Retry on SQL Server unittest database setup failures due to race conditions when starting SQL Server. This should make the unit tests much more reliable.

  • Add python_requires specifier to setup.py.

  • Properly handle decimal.Decimal values specified in scientific notation.

  • Properly set autocommit in ctds.connect(), even when ansi_defaults is False.

  • Download FreeTDS packages from HTTP URL for compatibility with Travis CI builds (FTP no longer works due to firewall issues.)

  • Fix OS X Travis CI build.

  • Improve SQL Server -> DB API 2.0 error mappings. https://github.com/zillow/ctds/issues/12

  • Remove Python 2.6 from Appveyor CI due to lack of support.

  • Fix ctds.Cursor.executemany() truncating data for variable width types. https://github.com/zillow/ctds/issues/25.

[1.7.0] - 2018-01-24

Added

  • Add rich comparison support and repr to ctds.Parameter.

Fixed

  • Compiler warnings on older version of gcc.

  • Debug assert when passing invalid parameters to ctds.Cursor.execute*().

[1.6.3] - 2017-12-05

Fixed

  • Raise proper warning from ctds.Connection.messages.

[1.6.2] - 2017-11-27

Fixed

  • Support values longer than 8000 characters in ctds.SqlVarChar.

[1.6.1] - 2017-11-20

Fixed

  • Revert passing BINARY 0x00 for (N)VARCHAR arguments.

[1.6.0] - 2017-11-17

Added

  • Documentation improvements.

  • Add an optional paramstyle argument to ctds.connect, with support for the named paramstyle.

  • Add valgrind support for memory leak detection and integrate it into the CI build process (Travis only).

  • Add optional read_only argument to ctds.connect for indication of read-only intent. Note: Requires as yet unreleased FreeTDS support.

Fixed

  • Pass a BINARY 0x00 byte instead of an empty string for (N)VARCHAR arguments. This is to work around the inability of the db-lib API to pass empty string parameters via RPC.

[1.5.0] - 2017-10-16

Added

  • Windows support, with Appveyor continuous integration.

  • Python egg-related metadata checks.

  • Moved source code under ./src directory, per best practices.

[1.4.1] - 2017-09-29

Fixed

  • Only clear Connection.messages on calls to execute, executemany or callproc. Add support for raising multiple non-zero severity messages as warnings.

[1.4.0] - 2017-09-13

Fixed

  • Changed the implementation of Cursor.execute to only perform parameter substitution if parameters are provided. When no parameters are passed, the SQL format string is treated as raw SQL.

Added

  • Connection.messages read-only property.

  • Improved code coverage.

[1.3.2] - 2017-07-25

Fixed

  • Register RowListType to support pickling/unpickling.

Added

  • Convert test framework to use Docker-based containers for SQL Server and for each supported combination of Python and FreeTDS.

  • Integrate codecov support for code coverage tracking.

  • Move documentation hosting to GitHub pages.

  • Include change log in generated documentation.

[1.3.1] - 2017-05-31

Fixed

  • Fix connection failures when connecting to high port numbers on OS X.

  • Fix unit test infrastructure to respect configured port number.

  • Work around inconsistencies between FreeTDS versions in the bcp_getl/ BCP_SETL interfaces.

[1.3.0] - 2017-03-15

Fixed

  • Replace usage of the deprecated PyErr_Warn API with PyErr_WarnEx. This will allow clients to indicate that warnings should be raised as exceptions.

[1.2.3] - 2017-03-13

Fixed

  • Improve repr implementation for SQL type wrapper objects.

  • Fixed informational (warning) message reporting where many SQL Server reported messages were not reported as warnings due if not returned to the client promptly enough.

[1.2.2] - 2017-01-10

Fixed

  • Fix multi-byte UTF-16 character conversion.

[1.2.1] - 2016-12-27

Fixed

  • Include ctds.pool in egg package.

[1.2.0] - 2016-12-27

Fixed

  • Documentation improvements around (N)VARCHAR handling.

Added

  • ctds.pool.ConnectionPool class.

  • Support the in keyword for resultset rows.

  • Add code coverage support for Python code.

  • Improve code coverage support for c code.

[1.1.0] - 2016-11-14

Added

  • ctds.SqlNVarChar type.

  • Ignore the replacement parameter markers inside of string literals in SQL statements passed to ctds.Cursor.execute() and ctds.Cursor.executemany().

Fixed

  • Work around a Memory leak in FreeTDS when specifying the database at connection time.

  • Fixed failure in ctds.Cursor.execute() and ctds.Cursor.executemany() when passing a SQL statement longer than 4000 characters.

[1.0.8] - 2016-08-17

Fixed

  • Configure connections to use UTF-16 when supported (i.e. FreeTDS 1.00+). Don’t replace codepoints outside of the UCS-2 range if the connection is using UTF-16 as it is no longer necessary and causes data loss.

[1.0.7] - 2016-08-15

Fixed

  • Only use strict compile options for debug/development builds. Allow the client (e.g. pip) to specify the desired options when installing as an egg.

[1.0.6] - 2016-08-15

Fixed

  • Compile under the c90 standard for better future portability.

  • Don’t overwrite more useful error messages with the useless “The statement has been terminated.” error.

Added

  • Minor documentation improvements.

[1.0.5] - 2016-05-23

Fixed

  • Fix the ctds.Connection.timeout property to raise an appropriate error when the option is supported, but the set fails.

[1.0.4] - 2016-05-19

Fixed

  • Fix the ctds.Connection.timeout property to work with the DBSETTIME option added in FreeTDS version 1.00.

Added

  • Support for TDS version 7.4, introduced with FreeTDS version 1.00.

[1.0.3] - 2016-03-31

Fixed

  • Fix execute() and executemany() to work with older versions of FreeTDS (prior to 0.92.405). Format the SQL command manually, instead of using sp_executesql, since older versions of FreeTDS don’t seem to support passing NVARCHAR arguments to remote procedure calls.

Added

  • Transaction documentation

  • Bulk insert documentation

[1.0.2] - 2016-03-15

Fixed

  • Documentation typos and improvements

Added

[1.0.1] - 2016-03-14

Fixed

  • Build on OS X

Added

  • Hypothetical integration with readthdocs.org

[1.0.0] - 2016-03-14

Initial Release