github sqlalchemy/sqlalchemy rel_2_1_4
2.1.4

3 hours ago

2.1.4

Released: October 7, 2026

orm

  • [orm] [bug] [regression] Fixed regression caused by #13333 where assigning a
    MetaData object to the metadata attribute of a mapped
    Declarative class, in order to place that class's Table in a
    MetaData collection other than that of the
    _orm.registry, would emit a warning that the attribute name
    metadata should be left reserved. The warning is now emitted only
    when the metadata attribute is assigned to an object other than a
    MetaData.

    References: #13659

engine

  • [engine] [bug] [regression] Fixed regression from the 1.4 series where the DBAPI cursor used for a
    compiled statement that returns no rows, which includes DDL constructs
    such as CreateTable and DropTable as well as the
    SAVEPOINT, ROLLBACK TO SAVEPOINT and RELEASE SAVEPOINT statements emitted
    by _engine.Connection.begin_nested(), was not closed after
    execution, and was instead left to be released when garbage collected.
    The cursor is now closed immediately, as was the case in 1.3 and as is
    already the case for INSERT, UPDATE, DELETE and _sql.text()
    statements.

    This change is also backported to: 2.0.55

    References: #13640

  • [engine] [bug] Fixed issue in the
    _engine.Connection.execution_options.logging_token option
    where setting the value to None or another false value would raise
    AttributeError if a logging token had not already been established on
    that _engine.Connection, such as on a newly checked out
    connection, when the option was set at the _engine.Engine level,
    or when the token was reset to None more than once. Regression
    introduced in 2.0.30 as part of #11210.

    This change is also backported to: 2.0.55

    References: #13641

  • [engine] [bug] [regression] Fixed regression where iterating a Result directly would create
    reference cycles that prevented the Result along with the DBAPI
    cursor from being freed immediately, instead relying upon cyclic GC to free
    it; also fixed a similar issue when using scalar-returning methods such as
    Result.scalars(). The issues were introduced as part of a 2.1
    refactoring of Result into Cython code.

    References: #13639

  • [engine] [bug] Fixed issue where an exception raised by the rollback performed within
    _engine.Connection.close(), which was not otherwise classified as a
    disconnect, would leave the _engine.Connection open and its
    pooled DBAPI connection checked out, emitting a warning when later
    garbage collected; for an asyncio driver, the connection could not be
    closed at that point and was leaked. The DBAPI connection is now
    returned to the pool, which resets it as usual, invalidating it if that
    reset fails as well, and the original exception is raised.

    References: #13657

sql

  • [sql] [bug] Fixed issue where the
    UpdateBase.return_defaults.supplemental_cols parameter of
    UpdateBase.return_defaults() was not included in the cache key of
    an Insert or Update construct, causing a statement
    that used this parameter to share a cached compiled form with an otherwise
    identical statement that did not, or that used different supplemental
    columns. This would cause the supplemental RETURNING rows to be missing
    or incorrect depending on which form of the statement was compiled first.

    This change is also backported to: 2.0.55

  • [sql] [bug] [regression] Fixed regression where stringifying a statement that includes the
    _functions.aggregate_strings function, such as via str(),
    would raise TypeError. Additionally, compiling the function with the
    default dialect or with a third party dialect that doesn't provide its own
    rendering for this function now raises CompileError rather than
    TypeError.

    References: #13642

postgresql

  • [postgresql] [bug] Fixed regression where copying a _postgresql.DOMAIN datatype,
    as occurs when using TypeEngine.copy(), Table.to_metadata(),
    or when a Column referring to a _postgresql.DOMAIN is
    placed on a declarative mixin, would drop the
    _postgresql.DOMAIN.collation,
    _postgresql.DOMAIN.default,
    _postgresql.DOMAIN.constraint_name,
    _postgresql.DOMAIN.not_null and
    _postgresql.DOMAIN.check parameters, causing the
    CREATE DOMAIN statement emitted for the copied type to omit these
    elements. The regression was introduced in version 2.0.42.

    Additionally, copies of _postgresql.ENUM now retain the
    _types.Enum.sort_key_function,
    _types.Enum.create_constraint and
    _types.Enum.length parameters, and copies of
    _types.Enum now retain the
    _types.Enum.sort_key_function parameter, all of which were
    previously reset to their default values.

    This change is also backported to: 2.0.55

    References: #13644

  • [postgresql] [bug] [regression] Fixed regression in the asyncpg dialect where a failure to start a
    transaction, such as when an asyncpg connection is used from a different
    event loop than the one it was created on, would leave the failed asyncpg
    transaction in place, so that the subsequent rollback raised an
    InterfaceError that masked the original error.

    References: #13657

mssql

  • [mssql] [bug] Fixed issue where the Python true division operator / would truncate
    the fractional part of the divisor on SQL Server when the divisor's type
    was not numeric, such as when using a SQL function like NULLIF() that
    has no known return type. The divisor was rendered as CAST(... AS NUMERIC), which on SQL Server implies a scale of zero; the divisor is
    now rendered as (... + 0.0), the same approach used by the SQLite
    dialect, which promotes it to a decimal value without truncation.
    Pull request courtesy James Guthrie.

    This change is also backported to: 2.0.55

    References: #13631

misc

  • [bug] [ext] Fixed issue in the mutable_toplevel extension where the in-place
    |= operator on MutableDict and the in-place *= operator
    on MutableList did not emit change events, so that the
    modification was not detected and was not persisted on the next flush.
    These operators now invoke Mutable.changed() in the same way as
    the in-place set operators of MutableSet and the +=
    operator of MutableList.

    This change is also backported to: 2.0.55

    References: #13643

Don't miss a new sqlalchemy release

NewReleases is sending notifications on new releases.